1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Xavier Claessens <xclaesse@gmail.com>
4 * Copyright (C) 2007 Collabora Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Authors: Xavier Claessens <xclaesse@gmail.com>
28 #include <libtelepathy/tp-helpers.h>
29 #include <libtelepathy/tp-conn.h>
30 #include <libtelepathy/tp-chan.h>
31 #include <libtelepathy/tp-chan-type-contact-list-gen.h>
32 #include <libtelepathy/tp-conn-iface-aliasing-gen.h>
33 #include <libtelepathy/tp-conn-iface-presence-gen.h>
34 #include <libtelepathy/tp-conn-iface-avatars-gen.h>
36 #include "empathy-tp-contact-list.h"
37 #include "empathy-contact-list.h"
38 #include "gossip-telepathy-group.h"
39 #include "gossip-debug.h"
40 #include "gossip-utils.h"
42 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
43 EMPATHY_TYPE_TP_CONTACT_LIST, EmpathyTpContactListPriv))
45 #define DEBUG_DOMAIN "TpContactList"
46 #define MAX_AVATAR_REQUESTS 10
48 struct _EmpathyTpContactListPriv {
52 GossipContact *user_contact;
55 GossipTelepathyGroup *known;
56 GossipTelepathyGroup *publish;
57 GossipTelepathyGroup *subscribe;
62 DBusGProxy *aliasing_iface;
63 DBusGProxy *avatars_iface;
64 DBusGProxy *presence_iface;
66 GList *avatar_requests_queue;
70 TP_CONTACT_LIST_TYPE_KNOWN,
71 TP_CONTACT_LIST_TYPE_PUBLISH,
72 TP_CONTACT_LIST_TYPE_SUBSCRIBE,
73 TP_CONTACT_LIST_TYPE_UNKNOWN,
74 TP_CONTACT_LIST_TYPE_COUNT
83 EmpathyTpContactList *list;
85 } TpContactListAvatarRequestData;
88 EmpathyTpContactList *list;
90 } TpContactListAliasesRequestData;
92 static void empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass);
93 static void tp_contact_list_iface_init (EmpathyContactListIface *iface);
94 static void empathy_tp_contact_list_init (EmpathyTpContactList *list);
95 static void tp_contact_list_finalize (GObject *object);
96 static void tp_contact_list_finalize_proxies (EmpathyTpContactList *list);
97 static void tp_contact_list_setup (EmpathyContactList *list);
98 static GossipContact * tp_contact_list_find (EmpathyContactList *list,
100 static void tp_contact_list_add (EmpathyContactList *list,
101 GossipContact *contact,
102 const gchar *message);
103 static void tp_contact_list_remove (EmpathyContactList *list,
104 GossipContact *contact,
105 const gchar *message);
106 static GList * tp_contact_list_get_contacts (EmpathyContactList *list);
107 static void tp_contact_list_contact_removed_foreach (guint handle,
108 GossipContact *contact,
109 EmpathyTpContactList *list);
110 static void tp_contact_list_destroy_cb (DBusGProxy *proxy,
111 EmpathyTpContactList *list);
112 static gboolean tp_contact_list_find_foreach (guint handle,
113 GossipContact *contact,
115 static void tp_contact_list_newchannel_cb (DBusGProxy *proxy,
116 const gchar *object_path,
117 const gchar *channel_type,
118 TelepathyHandleType handle_type,
119 guint channel_handle,
120 gboolean suppress_handle,
121 EmpathyTpContactList *list);
122 static TpContactListType tp_contact_list_get_type (EmpathyTpContactList *list,
124 static void tp_contact_list_contact_added_cb (GossipTelepathyGroup *group,
128 const gchar *message,
129 EmpathyTpContactList *list);
130 static void tp_contact_list_contact_removed_cb (GossipTelepathyGroup *group,
134 const gchar *message,
135 EmpathyTpContactList *list);
136 static void tp_contact_list_local_pending_cb (GossipTelepathyGroup *group,
140 const gchar *message,
141 EmpathyTpContactList *list);
142 static void tp_contact_list_groups_updated_cb (GossipContact *contact,
144 EmpathyTpContactList *list);
145 static void tp_contact_list_subscription_updated_cb (GossipContact *contact,
147 EmpathyTpContactList *list);
148 static void tp_contact_list_name_updated_cb (GossipContact *contact,
150 EmpathyTpContactList *list);
151 static void tp_contact_list_update_groups_foreach (gchar *object_path,
152 GossipTelepathyGroup *group,
153 TpContactListData *data);
154 static GossipTelepathyGroup * tp_contact_list_get_group (EmpathyTpContactList *list,
156 static gboolean tp_contact_list_find_group (gchar *key,
157 GossipTelepathyGroup *group,
159 static void tp_contact_list_get_groups_foreach (gchar *key,
160 GossipTelepathyGroup *group,
162 static void tp_contact_list_group_channel_closed_cb (TpChan *channel,
163 EmpathyTpContactList *list);
164 static void tp_contact_list_group_members_added_cb (GossipTelepathyGroup *group,
168 const gchar *message,
169 EmpathyTpContactList *list);
170 static void tp_contact_list_group_members_removed_cb (GossipTelepathyGroup *group,
174 const gchar *message,
175 EmpathyTpContactList *list);
176 static void tp_contact_list_get_contacts_foreach (guint handle,
177 GossipContact *contact,
179 static void tp_contact_list_get_info (EmpathyTpContactList *list,
181 static void tp_contact_list_request_avatar (EmpathyTpContactList *list,
183 static void tp_contact_list_start_avatar_requests (EmpathyTpContactList *list);
184 static void tp_contact_list_avatar_update_cb (DBusGProxy *proxy,
187 EmpathyTpContactList *list);
188 static void tp_contact_list_request_avatar_cb (DBusGProxy *proxy,
192 TpContactListAvatarRequestData *data);
193 static void tp_contact_list_aliases_update_cb (DBusGProxy *proxy,
195 EmpathyTpContactList *list);
196 static void tp_contact_list_request_aliases_cb (DBusGProxy *proxy,
197 gchar **contact_names,
199 TpContactListAliasesRequestData *data);
200 static void tp_contact_list_presence_update_cb (DBusGProxy *proxy,
201 GHashTable *handle_table,
202 EmpathyTpContactList *list);
203 static void tp_contact_list_parse_presence_foreach (guint handle,
204 GValueArray *presence_struct,
205 EmpathyTpContactList *list);
206 static void tp_contact_list_presences_table_foreach (const gchar *state_str,
207 GHashTable *presences_table,
208 GossipPresence **presence);
209 static void tp_contact_list_status_changed_cb (MissionControl *mc,
210 TelepathyConnectionStatus status,
212 TelepathyConnectionStatusReason reason,
213 const gchar *unique_name,
214 EmpathyTpContactList *list);
221 static guint signals[LAST_SIGNAL];
222 static guint n_avatar_requests = 0;
224 G_DEFINE_TYPE_WITH_CODE (EmpathyTpContactList, empathy_tp_contact_list, G_TYPE_OBJECT,
225 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
226 tp_contact_list_iface_init));
229 empathy_tp_contact_list_class_init (EmpathyTpContactListClass *klass)
231 GObjectClass *object_class = G_OBJECT_CLASS (klass);
233 object_class->finalize = tp_contact_list_finalize;
236 g_signal_new ("destroy",
237 G_TYPE_FROM_CLASS (klass),
241 g_cclosure_marshal_VOID__VOID,
245 g_type_class_add_private (object_class, sizeof (EmpathyTpContactListPriv));
249 tp_contact_list_iface_init (EmpathyContactListIface *iface)
251 iface->setup = tp_contact_list_setup;
252 iface->find = tp_contact_list_find;
253 iface->add = tp_contact_list_add;
254 iface->remove = tp_contact_list_remove;
255 iface->get_contacts = tp_contact_list_get_contacts;
259 empathy_tp_contact_list_init (EmpathyTpContactList *list)
261 EmpathyTpContactListPriv *priv;
263 priv = GET_PRIV (list);
265 priv->groups = g_hash_table_new_full (g_str_hash,
267 (GDestroyNotify) g_free,
268 (GDestroyNotify) g_object_unref);
269 priv->contacts = g_hash_table_new_full (g_direct_hash,
272 (GDestroyNotify) g_object_unref);
276 tp_contact_list_finalize (GObject *object)
278 EmpathyTpContactListPriv *priv;
279 EmpathyTpContactList *list;
281 list = EMPATHY_TP_CONTACT_LIST (object);
282 priv = GET_PRIV (list);
284 gossip_debug (DEBUG_DOMAIN, "finalize: %p", object);
286 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
287 "AccountStatusChanged",
288 G_CALLBACK (tp_contact_list_status_changed_cb),
291 tp_contact_list_finalize_proxies (list);
294 g_object_unref (priv->tp_conn);
298 g_object_unref (priv->known);
301 if (priv->subscribe) {
302 g_object_unref (priv->subscribe);
306 g_object_unref (priv->publish);
309 g_object_unref (priv->account);
310 g_object_unref (priv->user_contact);
311 g_object_unref (priv->mc);
312 g_hash_table_destroy (priv->groups);
313 g_hash_table_destroy (priv->contacts);
315 G_OBJECT_CLASS (empathy_tp_contact_list_parent_class)->finalize (object);
318 EmpathyTpContactList *
319 empathy_tp_contact_list_new (McAccount *account)
321 EmpathyTpContactListPriv *priv;
322 EmpathyTpContactList *list;
325 GError *error = NULL;
327 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
329 mc = gossip_mission_control_new ();
331 if (mission_control_get_connection_status (mc, account, NULL) != 0) {
332 /* The account is not connected, nothing to do. */
336 list = g_object_new (EMPATHY_TYPE_TP_CONTACT_LIST, NULL);
337 priv = GET_PRIV (list);
339 priv->tp_conn = mission_control_get_connection (mc, account, NULL);
340 priv->account = g_object_ref (account);
343 g_signal_connect (priv->tp_conn, "destroy",
344 G_CALLBACK (tp_contact_list_destroy_cb),
346 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
347 "AccountStatusChanged",
348 G_CALLBACK (tp_contact_list_status_changed_cb),
351 priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn,
352 TELEPATHY_CONN_IFACE_ALIASING_QUARK);
353 priv->avatars_iface = tp_conn_get_interface (priv->tp_conn,
354 TELEPATHY_CONN_IFACE_AVATARS_QUARK);
355 priv->presence_iface = tp_conn_get_interface (priv->tp_conn,
356 TELEPATHY_CONN_IFACE_PRESENCE_QUARK);
358 if (priv->aliasing_iface) {
359 dbus_g_proxy_connect_signal (priv->aliasing_iface,
361 G_CALLBACK (tp_contact_list_aliases_update_cb),
365 if (priv->avatars_iface) {
366 dbus_g_proxy_connect_signal (priv->avatars_iface,
368 G_CALLBACK (tp_contact_list_avatar_update_cb),
372 if (priv->presence_iface) {
373 dbus_g_proxy_connect_signal (priv->presence_iface,
375 G_CALLBACK (tp_contact_list_presence_update_cb),
379 /* Get our own handle and contact */
380 if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn),
382 gossip_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
383 error ? error->message : "No error given");
384 g_clear_error (&error);
386 priv->user_contact = empathy_tp_contact_list_get_from_handle (list, handle);
393 tp_contact_list_setup (EmpathyContactList *list)
395 EmpathyTpContactListPriv *priv;
397 GError *error = NULL;
400 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
402 priv = GET_PRIV (list);
404 gossip_debug (DEBUG_DOMAIN, "setup contact list: %p", list);
407 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
408 G_CALLBACK (tp_contact_list_newchannel_cb),
411 /* Get existing channels */
412 if (!tp_conn_list_channels (DBUS_G_PROXY (priv->tp_conn),
415 gossip_debug (DEBUG_DOMAIN,
416 "Failed to get list of open channels: %s",
417 error ? error->message : "No error given");
418 g_clear_error (&error);
422 for (i = 0; channels->len > i; i++) {
423 GValueArray *chan_struct;
424 const gchar *object_path;
425 const gchar *chan_iface;
426 TelepathyHandleType handle_type;
429 chan_struct = g_ptr_array_index (channels, i);
430 object_path = g_value_get_boxed (g_value_array_get_nth (chan_struct, 0));
431 chan_iface = g_value_get_string (g_value_array_get_nth (chan_struct, 1));
432 handle_type = g_value_get_uint (g_value_array_get_nth (chan_struct, 2));
433 handle = g_value_get_uint (g_value_array_get_nth (chan_struct, 3));
435 tp_contact_list_newchannel_cb (DBUS_G_PROXY (priv->tp_conn),
436 object_path, chan_iface,
439 EMPATHY_TP_CONTACT_LIST (list));
441 g_value_array_free (chan_struct);
444 g_ptr_array_free (channels, TRUE);
447 static GossipContact *
448 tp_contact_list_find (EmpathyContactList *list,
451 EmpathyTpContactListPriv *priv;
453 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
455 priv = GET_PRIV (list);
457 return g_hash_table_find (priv->contacts,
458 (GHRFunc) tp_contact_list_find_foreach,
463 tp_contact_list_add (EmpathyContactList *list,
464 GossipContact *contact,
465 const gchar *message)
467 EmpathyTpContactListPriv *priv;
470 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
472 priv = GET_PRIV (list);
474 handle = gossip_contact_get_handle (contact);
475 gossip_telepathy_group_add_member (priv->subscribe, handle, message);
479 tp_contact_list_remove (EmpathyContactList *list,
480 GossipContact *contact,
481 const gchar *message)
483 EmpathyTpContactListPriv *priv;
486 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
488 priv = GET_PRIV (list);
490 handle = gossip_contact_get_handle (contact);
491 gossip_telepathy_group_remove_member (priv->subscribe, handle, message);
492 gossip_telepathy_group_remove_member (priv->publish, handle, message);
493 gossip_telepathy_group_remove_member (priv->known, handle, message);
497 tp_contact_list_get_contacts (EmpathyContactList *list)
499 EmpathyTpContactListPriv *priv;
500 GList *contacts = NULL;
502 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
504 priv = GET_PRIV (list);
506 /* FIXME: we should only return contacts that are in the contact list */
507 g_hash_table_foreach (priv->contacts,
508 (GHFunc) tp_contact_list_get_contacts_foreach,
515 empathy_tp_contact_list_get_account (EmpathyTpContactList *list)
517 EmpathyTpContactListPriv *priv;
519 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
521 priv = GET_PRIV (list);
523 return priv->account;
527 empathy_tp_contact_list_get_user (EmpathyTpContactList *list)
529 EmpathyTpContactListPriv *priv;
531 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
533 priv = GET_PRIV (list);
535 return priv->user_contact;
539 empathy_tp_contact_list_get_from_id (EmpathyTpContactList *list,
542 EmpathyTpContactListPriv *priv;
543 GossipContact *contact;
544 const gchar *contact_ids[] = {id, NULL};
547 GError *error = NULL;
549 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
550 g_return_val_if_fail (id != NULL, NULL);
552 priv = GET_PRIV (list);
554 contact = tp_contact_list_find (EMPATHY_CONTACT_LIST (list), id);
559 /* The id is unknown, requests a new handle */
560 if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn),
561 TP_HANDLE_TYPE_CONTACT,
564 gossip_debug (DEBUG_DOMAIN,
565 "RequestHandle for %s failed: %s", id,
566 error ? error->message : "No error given");
567 g_clear_error (&error);
571 handle = g_array_index(handles, guint, 0);
572 g_array_free (handles, TRUE);
574 return empathy_tp_contact_list_get_from_handle (list, handle);
578 empathy_tp_contact_list_get_from_handle (EmpathyTpContactList *list,
581 GossipContact *contact;
585 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
587 handles = g_array_new (FALSE, FALSE, sizeof (guint));
588 g_array_append_val (handles, handle);
590 contacts = empathy_tp_contact_list_get_from_handles (list, handles);
591 g_array_free (handles, TRUE);
597 contact = contacts->data;
598 g_list_free (contacts);
604 empathy_tp_contact_list_get_from_handles (EmpathyTpContactList *list,
607 EmpathyTpContactListPriv *priv;
608 gchar **handles_names;
611 GList *contacts = NULL;
613 GError *error = NULL;
615 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
616 g_return_val_if_fail (handles != NULL, NULL);
618 priv = GET_PRIV (list);
620 /* Search all handles we already have */
621 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
622 for (i = 0; i < handles->len; i++) {
623 GossipContact *contact;
626 handle = g_array_index (handles, guint, i);
632 contact = g_hash_table_lookup (priv->contacts,
633 GUINT_TO_POINTER (handle));
636 contacts = g_list_prepend (contacts,
637 g_object_ref (contact));
639 g_array_append_val (new_handles, handle);
643 if (new_handles->len == 0) {
644 g_array_free (new_handles, TRUE);
648 /* Holds all handles we don't have yet.
649 * FIXME: We should release them at some point. */
650 if (!tp_conn_hold_handles (DBUS_G_PROXY (priv->tp_conn),
651 TP_HANDLE_TYPE_CONTACT,
652 new_handles, &error)) {
653 gossip_debug (DEBUG_DOMAIN,
654 "HoldHandles Error: %s",
655 error ? error->message : "No error given");
656 g_clear_error (&error);
657 g_array_free (new_handles, TRUE);
661 /* Get the IDs of all new handles */
662 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
663 TP_HANDLE_TYPE_CONTACT,
667 gossip_debug (DEBUG_DOMAIN,
668 "InspectHandle Error: %s",
669 error ? error->message : "No error given");
670 g_clear_error (&error);
671 g_array_free (new_handles, TRUE);
675 /* Create contact objects */
676 for (i = 0, id = handles_names; *id && i < new_handles->len; id++, i++) {
677 GossipContact *contact;
680 handle = g_array_index (new_handles, guint, i);
681 contact = g_object_new (GOSSIP_TYPE_CONTACT,
682 "account", priv->account,
687 if (!priv->presence_iface) {
688 GossipPresence *presence;
690 /* We have no presence iface, set default presence
692 presence = gossip_presence_new_full (MC_PRESENCE_AVAILABLE,
695 gossip_contact_set_presence (contact, presence);
696 g_object_unref (presence);
699 g_signal_connect (contact, "notify::groups",
700 G_CALLBACK (tp_contact_list_groups_updated_cb),
702 g_signal_connect (contact, "notify::subscription",
703 G_CALLBACK (tp_contact_list_subscription_updated_cb),
705 g_signal_connect (contact, "notify::name",
706 G_CALLBACK (tp_contact_list_name_updated_cb),
709 gossip_debug (DEBUG_DOMAIN, "new contact created: %s (%d)",
712 g_hash_table_insert (priv->contacts,
713 GUINT_TO_POINTER (handle),
716 contacts = g_list_prepend (contacts, g_object_ref (contact));
719 tp_contact_list_get_info (list, new_handles);
721 g_array_free (new_handles, TRUE);
722 g_strfreev (handles_names);
728 empathy_tp_contact_list_rename_group (EmpathyTpContactList *list,
729 const gchar *old_group,
730 const gchar *new_group)
732 EmpathyTpContactListPriv *priv;
733 GossipTelepathyGroup *group;
736 g_return_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list));
737 g_return_if_fail (old_group != NULL);
738 g_return_if_fail (new_group != NULL);
740 priv = GET_PRIV (list);
742 group = g_hash_table_find (priv->groups,
743 (GHRFunc) tp_contact_list_find_group,
746 /* The group doesn't exists on this account */
750 gossip_debug (DEBUG_DOMAIN, "rename group %s to %s", group, new_group);
752 /* Remove all members from the old group */
753 members = gossip_telepathy_group_get_members (group);
754 gossip_telepathy_group_remove_members (group, members, "");
755 tp_contact_list_group_members_removed_cb (group, members,
757 TP_CHANNEL_GROUP_CHANGE_REASON_NONE,
759 g_hash_table_remove (priv->groups,
760 gossip_telepathy_group_get_object_path (group));
762 /* Add all members to the new group */
763 group = tp_contact_list_get_group (list, new_group);
765 gossip_telepathy_group_add_members (group, members, "");
770 empathy_tp_contact_list_get_groups (EmpathyTpContactList *list)
772 EmpathyTpContactListPriv *priv;
773 GList *groups = NULL;
775 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_LIST (list), NULL);
777 priv = GET_PRIV (list);
779 g_hash_table_foreach (priv->groups,
780 (GHFunc) tp_contact_list_get_groups_foreach,
783 groups = g_list_sort (groups, (GCompareFunc) strcmp);
789 tp_contact_list_finalize_proxies (EmpathyTpContactList *list)
791 EmpathyTpContactListPriv *priv;
793 priv = GET_PRIV (list);
796 g_signal_handlers_disconnect_by_func (priv->tp_conn,
797 tp_contact_list_destroy_cb,
799 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->tp_conn), "NewChannel",
800 G_CALLBACK (tp_contact_list_newchannel_cb),
804 if (priv->aliasing_iface) {
805 dbus_g_proxy_disconnect_signal (priv->aliasing_iface,
807 G_CALLBACK (tp_contact_list_aliases_update_cb),
811 if (priv->avatars_iface) {
812 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
814 G_CALLBACK (tp_contact_list_avatar_update_cb),
818 if (priv->presence_iface) {
819 dbus_g_proxy_disconnect_signal (priv->presence_iface,
821 G_CALLBACK (tp_contact_list_presence_update_cb),
827 tp_contact_list_destroy_cb (DBusGProxy *proxy,
828 EmpathyTpContactList *list)
830 EmpathyTpContactListPriv *priv;
832 priv = GET_PRIV (list);
834 gossip_debug (DEBUG_DOMAIN, "Connection destroyed... "
835 "Account disconnected or CM crashed");
837 /* DBus proxies should NOT be used anymore */
838 g_object_unref (priv->tp_conn);
839 priv->tp_conn = NULL;
840 priv->aliasing_iface = NULL;
841 priv->avatars_iface = NULL;
842 priv->presence_iface = NULL;
844 /* Remove all contacts */
845 g_hash_table_foreach (priv->contacts,
846 (GHFunc) tp_contact_list_contact_removed_foreach,
848 g_hash_table_remove_all (priv->contacts);
850 /* Tell the world to not use us anymore */
851 g_signal_emit (list, signals[DESTROY], 0);
855 tp_contact_list_contact_removed_foreach (guint handle,
856 GossipContact *contact,
857 EmpathyTpContactList *list)
859 g_signal_handlers_disconnect_by_func (contact,
860 tp_contact_list_groups_updated_cb,
862 g_signal_handlers_disconnect_by_func (contact,
863 tp_contact_list_subscription_updated_cb,
865 g_signal_handlers_disconnect_by_func (contact,
866 tp_contact_list_name_updated_cb,
869 g_signal_emit_by_name (list, "contact-removed", contact);
873 tp_contact_list_block_contact (EmpathyTpContactList *list,
874 GossipContact *contact)
876 g_signal_handlers_block_by_func (contact,
877 tp_contact_list_groups_updated_cb,
879 g_signal_handlers_block_by_func (contact,
880 tp_contact_list_subscription_updated_cb,
882 g_signal_handlers_block_by_func (contact,
883 tp_contact_list_name_updated_cb,
888 tp_contact_list_unblock_contact (EmpathyTpContactList *list,
889 GossipContact *contact)
891 g_signal_handlers_unblock_by_func (contact,
892 tp_contact_list_groups_updated_cb,
894 g_signal_handlers_unblock_by_func (contact,
895 tp_contact_list_subscription_updated_cb,
897 g_signal_handlers_unblock_by_func (contact,
898 tp_contact_list_name_updated_cb,
903 tp_contact_list_find_foreach (guint handle,
904 GossipContact *contact,
907 if (strcmp (gossip_contact_get_id (contact), id) == 0) {
915 tp_contact_list_newchannel_cb (DBusGProxy *proxy,
916 const gchar *object_path,
917 const gchar *channel_type,
918 TelepathyHandleType handle_type,
919 guint channel_handle,
920 gboolean suppress_handle,
921 EmpathyTpContactList *list)
923 EmpathyTpContactListPriv *priv;
924 GossipTelepathyGroup *group;
926 const gchar *bus_name;
929 priv = GET_PRIV (list);
931 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST) != 0 ||
937 bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn));
938 new_chan = tp_chan_new (tp_get_bus (),
941 channel_type, handle_type, channel_handle);
943 if (handle_type == TP_HANDLE_TYPE_LIST) {
944 TpContactListType list_type;
946 list_type = tp_contact_list_get_type (list, new_chan);
947 if (list_type == TP_CONTACT_LIST_TYPE_UNKNOWN) {
948 gossip_debug (DEBUG_DOMAIN, "Unknown contact list channel");
949 g_object_unref (new_chan);
953 gossip_debug (DEBUG_DOMAIN, "New contact list channel of type: %d",
956 group = gossip_telepathy_group_new (new_chan, priv->tp_conn);
959 case TP_CONTACT_LIST_TYPE_KNOWN:
961 g_object_unref (priv->known);
965 case TP_CONTACT_LIST_TYPE_PUBLISH:
967 g_object_unref (priv->publish);
969 priv->publish = group;
971 case TP_CONTACT_LIST_TYPE_SUBSCRIBE:
972 if (priv->subscribe) {
973 g_object_unref (priv->subscribe);
975 priv->subscribe = group;
978 g_assert_not_reached ();
981 /* Connect and setup the new contact-list group */
982 if (list_type == TP_CONTACT_LIST_TYPE_KNOWN ||
983 list_type == TP_CONTACT_LIST_TYPE_SUBSCRIBE) {
984 g_signal_connect (group, "members-added",
985 G_CALLBACK (tp_contact_list_contact_added_cb),
987 g_signal_connect (group, "members-removed",
988 G_CALLBACK (tp_contact_list_contact_removed_cb),
991 members = gossip_telepathy_group_get_members (group);
992 tp_contact_list_contact_added_cb (group, members, 0,
993 TP_CHANNEL_GROUP_CHANGE_REASON_NONE,
995 g_array_free (members, TRUE);
997 if (list_type == TP_CONTACT_LIST_TYPE_PUBLISH) {
1001 g_signal_connect (group, "local-pending",
1002 G_CALLBACK (tp_contact_list_local_pending_cb),
1005 members = gossip_telepathy_group_get_local_pending_members_with_info (group);
1007 g_object_unref (new_chan);
1011 pending = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1);
1012 for (l = members; l; l = l->next) {
1013 GossipTpGroupInfo *info;
1017 g_array_insert_val (pending, 0, info->member);
1018 tp_contact_list_local_pending_cb (group, pending,
1025 gossip_telepathy_group_info_list_free (members);
1026 g_array_free (pending, TRUE);
1029 else if (handle_type == TP_HANDLE_TYPE_GROUP) {
1030 const gchar *object_path;
1032 object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (new_chan));
1033 if (g_hash_table_lookup (priv->groups, object_path)) {
1034 g_object_unref (new_chan);
1038 group = gossip_telepathy_group_new (new_chan, priv->tp_conn);
1040 gossip_debug (DEBUG_DOMAIN, "New server-side group channel: %s",
1041 gossip_telepathy_group_get_name (group));
1043 dbus_g_proxy_connect_signal (DBUS_G_PROXY (new_chan), "Closed",
1045 (tp_contact_list_group_channel_closed_cb),
1048 g_hash_table_insert (priv->groups, g_strdup (object_path), group);
1049 g_signal_connect (group, "members-added",
1050 G_CALLBACK (tp_contact_list_group_members_added_cb),
1052 g_signal_connect (group, "members-removed",
1053 G_CALLBACK (tp_contact_list_group_members_removed_cb),
1056 members = gossip_telepathy_group_get_members (group);
1057 tp_contact_list_group_members_added_cb (group, members, 0,
1058 TP_CHANNEL_GROUP_CHANGE_REASON_NONE,
1060 g_array_free (members, TRUE);
1063 g_object_unref (new_chan);
1066 static TpContactListType
1067 tp_contact_list_get_type (EmpathyTpContactList *list,
1070 EmpathyTpContactListPriv *priv;
1072 gchar **handle_name;
1073 TpContactListType list_type;
1074 GError *error = NULL;
1076 priv = GET_PRIV (list);
1078 handles = g_array_new (FALSE, FALSE, sizeof (guint));
1079 g_array_append_val (handles, list_chan->handle);
1081 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
1082 TP_HANDLE_TYPE_LIST,
1086 gossip_debug (DEBUG_DOMAIN,
1087 "InspectHandle Error: %s",
1088 error ? error->message : "No error given");
1089 g_clear_error (&error);
1090 g_array_free (handles, TRUE);
1091 return TP_CONTACT_LIST_TYPE_UNKNOWN;
1094 if (strcmp (*handle_name, "subscribe") == 0) {
1095 list_type = TP_CONTACT_LIST_TYPE_SUBSCRIBE;
1096 } else if (strcmp (*handle_name, "publish") == 0) {
1097 list_type = TP_CONTACT_LIST_TYPE_PUBLISH;
1098 } else if (strcmp (*handle_name, "known") == 0) {
1099 list_type = TP_CONTACT_LIST_TYPE_KNOWN;
1101 list_type = TP_CONTACT_LIST_TYPE_UNKNOWN;
1104 g_strfreev (handle_name);
1105 g_array_free (handles, TRUE);
1111 tp_contact_list_contact_added_cb (GossipTelepathyGroup *group,
1115 const gchar *message,
1116 EmpathyTpContactList *list)
1118 EmpathyTpContactListPriv *priv;
1119 GList *added_list, *l;
1121 priv = GET_PRIV (list);
1123 added_list = empathy_tp_contact_list_get_from_handles (list, handles);
1125 for (l = added_list; l; l = l->next) {
1126 GossipContact *contact;
1128 contact = GOSSIP_CONTACT (l->data);
1129 tp_contact_list_block_contact (list, contact);
1130 gossip_contact_set_subscription (contact, GOSSIP_SUBSCRIPTION_BOTH);
1131 tp_contact_list_unblock_contact (list, contact);
1133 g_signal_emit_by_name (list, "contact-added", contact);
1135 g_object_unref (contact);
1138 g_list_free (added_list);
1142 tp_contact_list_contact_removed_cb (GossipTelepathyGroup *group,
1146 const gchar *message,
1147 EmpathyTpContactList *list)
1149 EmpathyTpContactListPriv *priv;
1150 GList *removed_list, *l;
1152 priv = GET_PRIV (list);
1154 removed_list = empathy_tp_contact_list_get_from_handles (list, handles);
1156 for (l = removed_list; l; l = l->next) {
1157 GossipContact *contact;
1160 contact = GOSSIP_CONTACT (l->data);
1162 handle = gossip_contact_get_handle (contact);
1163 g_hash_table_remove (priv->contacts, GUINT_TO_POINTER (handle));
1165 g_signal_emit_by_name (list, "contact-removed", contact);
1167 g_object_unref (contact);
1170 g_list_free (removed_list);
1174 tp_contact_list_local_pending_cb (GossipTelepathyGroup *group,
1178 const gchar *message,
1179 EmpathyTpContactList *list)
1181 EmpathyTpContactListPriv *priv;
1182 GList *pending_list, *l;
1184 priv = GET_PRIV (list);
1186 pending_list = empathy_tp_contact_list_get_from_handles (list, handles);
1188 for (l = pending_list; l; l = l->next) {
1189 GossipContact *contact;
1191 contact = GOSSIP_CONTACT (l->data);
1193 /* FIXME: Is that the correct way ? */
1194 tp_contact_list_block_contact (list, contact);
1195 gossip_contact_set_subscription (contact, GOSSIP_SUBSCRIPTION_FROM);
1196 tp_contact_list_unblock_contact (list, contact);
1197 g_signal_emit_by_name (list, "contact-added", contact);
1199 g_object_unref (contact);
1202 g_list_free (pending_list);
1206 tp_contact_list_groups_updated_cb (GossipContact *contact,
1208 EmpathyTpContactList *list)
1210 EmpathyTpContactListPriv *priv;
1211 TpContactListData data;
1214 priv = GET_PRIV (list);
1216 /* Make sure all groups are created */
1217 groups = gossip_contact_get_groups (contact);
1218 for (l = groups; l; l = l->next) {
1219 tp_contact_list_get_group (list, l->data);
1222 data.handle = gossip_contact_get_handle (contact);
1223 data.new_groups = groups;
1225 g_hash_table_foreach (priv->groups,
1226 (GHFunc) tp_contact_list_update_groups_foreach,
1231 tp_contact_list_subscription_updated_cb (GossipContact *contact,
1233 EmpathyTpContactList *list)
1235 EmpathyTpContactListPriv *priv;
1236 GossipSubscription subscription;
1239 priv = GET_PRIV (list);
1241 subscription = gossip_contact_get_subscription (contact);
1242 handle = gossip_contact_get_handle (contact);
1244 /* FIXME: what to do here, I'm a bit lost... */
1246 gossip_telepathy_group_add_member (priv->publish, handle, "");
1248 gossip_telepathy_group_remove_member (priv->publish, handle, "");
1253 tp_contact_list_name_updated_cb (GossipContact *contact,
1255 EmpathyTpContactList *list)
1257 EmpathyTpContactListPriv *priv;
1258 GHashTable *new_alias;
1259 const gchar *new_name;
1261 GError *error = NULL;
1263 priv = GET_PRIV (list);
1265 handle = gossip_contact_get_handle (contact);
1266 new_name = gossip_contact_get_name (contact);
1268 gossip_debug (DEBUG_DOMAIN, "renaming handle %d to %s",
1271 new_alias = g_hash_table_new_full (g_direct_hash,
1276 g_hash_table_insert (new_alias,
1277 GUINT_TO_POINTER (handle),
1278 g_strdup (new_name));
1280 if (!tp_conn_iface_aliasing_set_aliases (priv->aliasing_iface,
1283 gossip_debug (DEBUG_DOMAIN,
1284 "Couldn't rename contact: %s",
1285 error ? error->message : "No error given");
1286 g_clear_error (&error);
1289 g_hash_table_destroy (new_alias);
1293 tp_contact_list_update_groups_foreach (gchar *object_path,
1294 GossipTelepathyGroup *group,
1295 TpContactListData *data)
1298 gboolean found = FALSE;
1299 const gchar *group_name;
1302 is_member = gossip_telepathy_group_is_member (group, data->handle);
1303 group_name = gossip_telepathy_group_get_name (group);
1305 for (l = data->new_groups; l; l = l->next) {
1306 if (strcmp (group_name, l->data) == 0) {
1312 if (is_member && !found) {
1313 /* We are no longer member of this group */
1314 gossip_debug (DEBUG_DOMAIN, "Contact %d removed from group '%s'",
1315 data->handle, group_name);
1316 gossip_telepathy_group_remove_member (group, data->handle, "");
1319 if (!is_member && found) {
1320 /* We are now member of this group */
1321 gossip_debug (DEBUG_DOMAIN, "Contact %d added to group '%s'",
1322 data->handle, group_name);
1323 gossip_telepathy_group_add_member (group, data->handle, "");
1327 static GossipTelepathyGroup *
1328 tp_contact_list_get_group (EmpathyTpContactList *list,
1331 EmpathyTpContactListPriv *priv;
1332 GossipTelepathyGroup *group;
1333 TpChan *group_channel;
1336 char *group_object_path;
1337 const char *names[2] = {name, NULL};
1338 GError *error = NULL;
1340 priv = GET_PRIV (list);
1342 group = g_hash_table_find (priv->groups,
1343 (GHRFunc) tp_contact_list_find_group,
1349 gossip_debug (DEBUG_DOMAIN, "creating new group: %s", name);
1351 if (!tp_conn_request_handles (DBUS_G_PROXY (priv->tp_conn),
1352 TP_HANDLE_TYPE_GROUP,
1356 gossip_debug (DEBUG_DOMAIN,
1357 "Couldn't request the creation of a new handle for group: %s",
1358 error ? error->message : "No error given");
1359 g_clear_error (&error);
1362 group_handle = g_array_index (handles, guint, 0);
1363 g_array_free (handles, TRUE);
1365 if (!tp_conn_request_channel (DBUS_G_PROXY (priv->tp_conn),
1366 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
1367 TP_HANDLE_TYPE_GROUP,
1372 gossip_debug (DEBUG_DOMAIN,
1373 "Couldn't request the creation of a new group channel: %s",
1374 error ? error->message : "No error given");
1375 g_clear_error (&error);
1379 group_channel = tp_chan_new (tp_get_bus (),
1380 dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->tp_conn)),
1382 TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
1383 TP_HANDLE_TYPE_GROUP,
1386 dbus_g_proxy_connect_signal (DBUS_G_PROXY (group_channel),
1389 (tp_contact_list_group_channel_closed_cb),
1393 group = gossip_telepathy_group_new (group_channel, priv->tp_conn);
1394 g_hash_table_insert (priv->groups, group_object_path, group);
1395 g_signal_connect (group, "members-added",
1396 G_CALLBACK (tp_contact_list_group_members_added_cb),
1398 g_signal_connect (group, "members-removed",
1399 G_CALLBACK (tp_contact_list_group_members_removed_cb),
1406 tp_contact_list_find_group (gchar *key,
1407 GossipTelepathyGroup *group,
1410 if (strcmp (group_name, gossip_telepathy_group_get_name (group)) == 0) {
1418 tp_contact_list_get_groups_foreach (gchar *key,
1419 GossipTelepathyGroup *group,
1424 name = gossip_telepathy_group_get_name (group);
1425 *groups = g_list_append (*groups, g_strdup (name));
1429 tp_contact_list_group_channel_closed_cb (TpChan *channel,
1430 EmpathyTpContactList *list)
1432 EmpathyTpContactListPriv *priv;
1434 priv = GET_PRIV (list);
1436 g_hash_table_remove (priv->groups,
1437 dbus_g_proxy_get_path (DBUS_G_PROXY (channel)));
1441 tp_contact_list_group_members_added_cb (GossipTelepathyGroup *group,
1445 const gchar *message,
1446 EmpathyTpContactList *list)
1448 EmpathyTpContactListPriv *priv;
1449 GList *added_list, *l;
1450 const gchar *group_name;
1452 priv = GET_PRIV (list);
1454 group_name = gossip_telepathy_group_get_name (group);
1455 added_list = empathy_tp_contact_list_get_from_handles (list, members);
1457 for (l = added_list; l; l = l->next) {
1458 GossipContact *contact;
1459 GList *contact_groups;
1461 contact = GOSSIP_CONTACT (l->data);
1462 contact_groups = gossip_contact_get_groups (contact);
1464 /* FIXME: this leaks */
1465 if (!g_list_find_custom (contact_groups,
1467 (GCompareFunc) strcmp)) {
1468 gossip_debug (DEBUG_DOMAIN, "Contact %s added to group '%s'",
1469 gossip_contact_get_name (contact),
1471 contact_groups = g_list_append (contact_groups,
1472 g_strdup (group_name));
1473 tp_contact_list_block_contact (list, contact);
1474 gossip_contact_set_groups (contact, contact_groups);
1475 tp_contact_list_unblock_contact (list, contact);
1478 g_object_unref (contact);
1481 g_list_free (added_list);
1485 tp_contact_list_group_members_removed_cb (GossipTelepathyGroup *group,
1489 const gchar *message,
1490 EmpathyTpContactList *list)
1492 EmpathyTpContactListPriv *priv;
1493 GList *removed_list, *l;
1494 const gchar *group_name;
1496 priv = GET_PRIV (list);
1498 group_name = gossip_telepathy_group_get_name (group);
1499 removed_list = empathy_tp_contact_list_get_from_handles (list, members);
1501 for (l = removed_list; l; l = l->next) {
1502 GossipContact *contact;
1503 GList *contact_groups;
1506 /* FIXME: Does it leak ? */
1507 contact = GOSSIP_CONTACT (l->data);
1508 contact_groups = gossip_contact_get_groups (contact);
1509 contact_groups = g_list_copy (contact_groups);
1511 to_remove = g_list_find_custom (contact_groups,
1513 (GCompareFunc) strcmp);
1515 gossip_debug (DEBUG_DOMAIN, "Contact %d removed from group '%s'",
1516 gossip_contact_get_handle (contact),
1518 contact_groups = g_list_remove_link (contact_groups,
1520 tp_contact_list_block_contact (list, contact);
1521 gossip_contact_set_groups (contact, contact_groups);
1522 tp_contact_list_unblock_contact (list, contact);
1525 g_list_free (contact_groups);
1527 g_object_unref (contact);
1530 g_list_free (removed_list);
1534 tp_contact_list_get_contacts_foreach (guint handle,
1535 GossipContact *contact,
1538 *contacts = g_list_append (*contacts, g_object_ref (contact));
1542 tp_contact_list_get_info (EmpathyTpContactList *list,
1545 EmpathyTpContactListPriv *priv;
1546 GError *error = NULL;
1548 priv = GET_PRIV (list);
1550 if (priv->presence_iface) {
1551 /* FIXME: We should use GetPresence instead */
1552 if (!tp_conn_iface_presence_request_presence (priv->presence_iface,
1554 gossip_debug (DEBUG_DOMAIN,
1555 "Could not request presences: %s",
1556 error ? error->message : "No error given");
1557 g_clear_error (&error);
1561 if (priv->aliasing_iface) {
1562 TpContactListAliasesRequestData *data;
1564 data = g_slice_new (TpContactListAliasesRequestData);
1566 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
1568 tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface,
1570 (tp_conn_iface_aliasing_request_aliases_reply)
1571 tp_contact_list_request_aliases_cb,
1575 if (priv->avatars_iface) {
1578 for (i = 0; i < handles->len; i++) {
1581 handle = g_array_index (handles, gint, i);
1582 tp_contact_list_request_avatar (list, handle);
1588 tp_contact_list_request_avatar (EmpathyTpContactList *list,
1591 EmpathyTpContactListPriv *priv;
1593 priv = GET_PRIV (list);
1595 /* We queue avatar requests to not send too many dbus async
1596 * calls at once. If we don't we reach the dbus's limit of
1598 priv->avatar_requests_queue = g_list_append (priv->avatar_requests_queue,
1599 GUINT_TO_POINTER (handle));
1600 tp_contact_list_start_avatar_requests (list);
1604 tp_contact_list_start_avatar_requests (EmpathyTpContactList *list)
1606 EmpathyTpContactListPriv *priv;
1607 TpContactListAvatarRequestData *data;
1609 priv = GET_PRIV (list);
1611 while (n_avatar_requests < MAX_AVATAR_REQUESTS &&
1612 priv->avatar_requests_queue) {
1613 data = g_slice_new (TpContactListAvatarRequestData);
1615 data->handle = GPOINTER_TO_UINT (priv->avatar_requests_queue->data);
1617 n_avatar_requests++;
1618 priv->avatar_requests_queue = g_list_remove (priv->avatar_requests_queue,
1619 priv->avatar_requests_queue->data);
1621 tp_conn_iface_avatars_request_avatar_async (priv->avatars_iface,
1623 (tp_conn_iface_avatars_request_avatar_reply)
1624 tp_contact_list_request_avatar_cb,
1630 tp_contact_list_avatar_update_cb (DBusGProxy *proxy,
1633 EmpathyTpContactList *list)
1635 EmpathyTpContactListPriv *priv;
1637 priv = GET_PRIV (list);
1639 if (!g_hash_table_lookup (priv->contacts, GUINT_TO_POINTER (handle))) {
1640 /* We don't know this contact, skip */
1644 gossip_debug (DEBUG_DOMAIN, "Changing avatar for %d to %s",
1647 tp_contact_list_request_avatar (list, handle);
1651 tp_contact_list_request_avatar_cb (DBusGProxy *proxy,
1652 GArray *avatar_data,
1655 TpContactListAvatarRequestData *data)
1657 GossipContact *contact;
1659 contact = empathy_tp_contact_list_get_from_handle (data->list, data->handle);
1662 gossip_debug (DEBUG_DOMAIN, "Error requesting avatar for %s: %s",
1663 gossip_contact_get_name (contact),
1664 error ? error->message : "No error given");
1666 GossipAvatar *avatar;
1668 avatar = gossip_avatar_new (avatar_data->data,
1671 tp_contact_list_block_contact (data->list, contact);
1672 gossip_contact_set_avatar (contact, avatar);
1673 tp_contact_list_unblock_contact (data->list, contact);
1674 gossip_avatar_unref (avatar);
1677 n_avatar_requests--;
1678 tp_contact_list_start_avatar_requests (data->list);
1680 g_object_unref (contact);
1681 g_slice_free (TpContactListAvatarRequestData, data);
1685 tp_contact_list_aliases_update_cb (DBusGProxy *proxy,
1686 GPtrArray *renamed_handlers,
1687 EmpathyTpContactList *list)
1689 EmpathyTpContactListPriv *priv;
1692 priv = GET_PRIV (list);
1694 for (i = 0; renamed_handlers->len > i; i++) {
1697 GValueArray *renamed_struct;
1698 GossipContact *contact;
1700 renamed_struct = g_ptr_array_index (renamed_handlers, i);
1701 handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0));
1702 alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1));
1704 if (!g_hash_table_lookup (priv->contacts, GUINT_TO_POINTER (handle))) {
1705 /* We don't know this contact, skip */
1709 if (G_STR_EMPTY (alias)) {
1713 contact = empathy_tp_contact_list_get_from_handle (list, handle);
1714 tp_contact_list_block_contact (list, contact);
1715 gossip_contact_set_name (contact, alias);
1716 tp_contact_list_unblock_contact (list, contact);
1717 g_object_unref (contact);
1719 gossip_debug (DEBUG_DOMAIN, "contact %d renamed to %s (update cb)",
1725 tp_contact_list_request_aliases_cb (DBusGProxy *proxy,
1726 gchar **contact_names,
1728 TpContactListAliasesRequestData *data)
1734 gossip_debug (DEBUG_DOMAIN, "Error requesting aliases: %s",
1738 for (name = contact_names; *name && !error; name++) {
1739 GossipContact *contact;
1741 contact = empathy_tp_contact_list_get_from_handle (data->list,
1743 tp_contact_list_block_contact (data->list, contact);
1744 gossip_contact_set_name (contact, *name);
1745 tp_contact_list_unblock_contact (data->list, contact);
1746 g_object_unref (contact);
1748 gossip_debug (DEBUG_DOMAIN, "contact %d renamed to %s (request cb)",
1749 data->handles[i], *name);
1754 g_free (data->handles);
1755 g_slice_free (TpContactListAliasesRequestData, data);
1759 tp_contact_list_presence_update_cb (DBusGProxy *proxy,
1760 GHashTable *handle_table,
1761 EmpathyTpContactList *list)
1763 g_hash_table_foreach (handle_table,
1764 (GHFunc) tp_contact_list_parse_presence_foreach,
1769 tp_contact_list_parse_presence_foreach (guint handle,
1770 GValueArray *presence_struct,
1771 EmpathyTpContactList *list)
1773 EmpathyTpContactListPriv *priv;
1774 GHashTable *presences_table;
1775 GossipContact *contact;
1776 GossipPresence *presence = NULL;
1778 priv = GET_PRIV (list);
1780 if (!g_hash_table_lookup (priv->contacts, GUINT_TO_POINTER (handle))) {
1781 /* We don't know this contact, skip */
1785 contact = empathy_tp_contact_list_get_from_handle (list, handle);
1786 presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1));
1788 g_hash_table_foreach (presences_table,
1789 (GHFunc) tp_contact_list_presences_table_foreach,
1792 gossip_debug (DEBUG_DOMAIN, "Presence changed for %s (%d) to %s (%d)",
1793 gossip_contact_get_name (contact),
1795 presence ? gossip_presence_get_status (presence) : "unset",
1796 presence ? gossip_presence_get_state (presence) : MC_PRESENCE_UNSET);
1798 tp_contact_list_block_contact (list, contact);
1799 gossip_contact_set_presence (contact, presence);
1800 tp_contact_list_unblock_contact (list, contact);
1802 g_object_unref (contact);
1806 tp_contact_list_presences_table_foreach (const gchar *state_str,
1807 GHashTable *presences_table,
1808 GossipPresence **presence)
1811 const GValue *message;
1813 state = gossip_presence_state_from_str (state_str);
1814 if ((state == MC_PRESENCE_UNSET) || (state == MC_PRESENCE_OFFLINE)) {
1819 g_object_unref (*presence);
1823 *presence = gossip_presence_new ();
1824 gossip_presence_set_state (*presence, state);
1826 message = g_hash_table_lookup (presences_table, "message");
1827 if (message != NULL) {
1828 gossip_presence_set_status (*presence,
1829 g_value_get_string (message));
1834 tp_contact_list_status_changed_cb (MissionControl *mc,
1835 TelepathyConnectionStatus status,
1836 McPresence presence,
1837 TelepathyConnectionStatusReason reason,
1838 const gchar *unique_name,
1839 EmpathyTpContactList *list)
1841 EmpathyTpContactListPriv *priv;
1844 priv = GET_PRIV (list);
1846 account = mc_account_lookup (unique_name);
1847 if (status != TP_CONN_STATUS_DISCONNECTED ||
1848 !gossip_account_equal (account, priv->account)) {
1849 g_object_unref (account);
1853 /* We are disconnected, do just like if the connection was destroyed */
1854 g_signal_handlers_disconnect_by_func (priv->tp_conn,
1855 tp_contact_list_destroy_cb,
1857 tp_contact_list_destroy_cb (DBUS_G_PROXY (priv->tp_conn), list);
1859 g_object_unref (account);