X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=libempathy%2Fempathy-tp-contact-list.c;h=95ec3bea2109631ee34d9ef2d22b599996792b68;hp=49168cdb1e670e3ca20a06d50aa6d42ee75c52c3;hb=940d0e9778828657a6ffbcadd35a8a84d706ac70;hpb=fff76809babe6a154cd548e9bc3aa43199e9eda9 diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c index 49168cdb..95ec3bea 100644 --- a/libempathy/empathy-tp-contact-list.c +++ b/libempathy/empathy-tp-contact-list.c @@ -53,6 +53,8 @@ typedef struct { GHashTable *add_to_group; /* group name -> GArray of handles */ EmpathyContactListFlags flags; + + TpProxySignalConnection *new_channels_sig; } EmpathyTpContactListPriv; typedef enum { @@ -696,45 +698,113 @@ tp_contact_list_finalize (GObject *object) G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object); } +static gboolean +received_all_list_channels (EmpathyTpContactList *self) +{ + EmpathyTpContactListPriv *priv = GET_PRIV (self); + + return (priv->stored != NULL && priv->publish != NULL && + priv->subscribe != NULL); +} + static void -list_ensure_channel_cb (TpConnection *conn, - gboolean yours, - const gchar *path, - GHashTable *properties, - const GError *error, - gpointer user_data, - GObject *weak_object) +got_list_channel (EmpathyTpContactList *list, + TpChannel *channel) { - EmpathyTpContactList *list = user_data; EmpathyTpContactListPriv *priv = GET_PRIV (list); const gchar *id; - TpChannel *channel; - - if (error != NULL) { - DEBUG ("failed: %s\n", error->message); - return; - } /* We requested that channel by providing TargetID property, so it's * guaranteed that tp_channel_get_identifier will return it. */ - channel = tp_channel_new_from_properties (conn, path, properties, NULL); id = tp_channel_get_identifier (channel); /* TpChannel emits initial set of members just before being ready */ if (!tp_strdiff (id, "stored")) { - priv->stored = channel; + if (priv->stored != NULL) + return; + priv->stored = g_object_ref (channel); } else if (!tp_strdiff (id, "publish")) { - priv->publish = channel; + if (priv->publish != NULL) + return; + priv->publish = g_object_ref (channel); g_signal_connect (priv->publish, "group-members-changed", G_CALLBACK (tp_contact_list_publish_group_members_changed_cb), list); } else if (!tp_strdiff (id, "subscribe")) { - priv->subscribe = channel; + if (priv->subscribe != NULL) + return; + priv->subscribe = g_object_ref (channel); g_signal_connect (priv->subscribe, "group-members-changed", G_CALLBACK (tp_contact_list_subscribe_group_members_changed_cb), list); - } else { - g_warn_if_reached (); + } + + if (received_all_list_channels (list) && priv->new_channels_sig != NULL) { + /* We don't need to watch NewChannels anymore */ + tp_proxy_signal_connection_disconnect (priv->new_channels_sig); + priv->new_channels_sig = NULL; + } +} + +static void +list_ensure_channel_cb (TpConnection *conn, + gboolean yours, + const gchar *path, + GHashTable *properties, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpContactList *list = user_data; + TpChannel *channel; + + if (error != NULL) { + DEBUG ("failed: %s\n", error->message); + return; + } + + channel = tp_channel_new_from_properties (conn, path, properties, NULL); + got_list_channel (list, channel); + g_object_unref (channel); +} + +static void +new_channels_cb (TpConnection *conn, + const GPtrArray *channels, + gpointer user_data, + GObject *weak_object) +{ + EmpathyTpContactList *list = EMPATHY_TP_CONTACT_LIST (weak_object); + guint i; + + for (i = 0; i < channels->len ; i++) { + GValueArray *arr = g_ptr_array_index (channels, i); + const gchar *path; + GHashTable *properties; + const gchar *id; + TpChannel *channel; + + path = g_value_get_boxed (g_value_array_get_nth (arr, 0)); + properties = g_value_get_boxed (g_value_array_get_nth (arr, 1)); + + if (tp_strdiff (tp_asv_get_string (properties, + TP_IFACE_CHANNEL ".ChannelType"), + TP_IFACE_CHANNEL_TYPE_CONTACT_LIST)) + return; + + if (tp_asv_get_uint32 (properties, + TP_IFACE_CHANNEL ".TargetHandleType", NULL) + != TP_HANDLE_TYPE_LIST) + return; + + id = tp_asv_get_string (properties, + TP_IFACE_CHANNEL ".TargetID"); + if (id == NULL) + return; + + channel = tp_channel_new_from_properties (conn, path, + properties, NULL); + got_list_channel (list, channel); g_object_unref (channel); } } @@ -758,6 +828,13 @@ conn_ready_cb (TpConnection *connection, TP_IFACE_CHANNEL ".TargetHandleType", G_TYPE_UINT, TP_HANDLE_TYPE_LIST, NULL); + /* Watch the NewChannels signal so if ensuring list channels fails (for + * example because the server is slow and the D-Bus call timeouts before CM + * fetches the roster), we have a chance to get them later. */ + priv->new_channels_sig = + tp_cli_connection_interface_requests_connect_to_new_channels ( + priv->connection, new_channels_cb, NULL, NULL, G_OBJECT (list), NULL); + /* Request the 'stored' list. */ tp_asv_set_static_string (request, TP_IFACE_CHANNEL ".TargetID", "stored"); tp_cli_connection_interface_requests_call_ensure_channel (priv->connection,