1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007-2008 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
26 #include <telepathy-glib/util.h>
27 #include <libtelepathy/tp-conn.h>
28 #include <libtelepathy/tp-conn-iface-aliasing-gen.h>
29 #include <libtelepathy/tp-conn-iface-presence-gen.h>
30 #include <libtelepathy/tp-conn-iface-avatars-gen.h>
31 #include <libtelepathy/tp-conn-iface-capabilities-gen.h>
32 #include <libmissioncontrol/mission-control.h>
34 #include "empathy-tp-contact-factory.h"
35 #include "empathy-utils.h"
36 #include "empathy-debug.h"
38 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
39 EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryPriv))
41 #define DEBUG_DOMAIN "TpContactFactory"
43 struct _EmpathyTpContactFactoryPriv {
48 DBusGProxy *aliasing_iface;
49 DBusGProxy *avatars_iface;
50 DBusGProxy *presence_iface;
51 DBusGProxy *capabilities_iface;
57 static void empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass);
58 static void empathy_tp_contact_factory_init (EmpathyTpContactFactory *factory);
60 G_DEFINE_TYPE (EmpathyTpContactFactory, empathy_tp_contact_factory, G_TYPE_OBJECT);
67 static EmpathyContact *
68 tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory,
71 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
74 for (l = priv->contacts; l; l = l->next) {
75 if (empathy_contact_get_handle (l->data) == handle) {
83 static EmpathyContact *
84 tp_contact_factory_find_by_id (EmpathyTpContactFactory *tp_factory,
87 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
90 for (l = priv->contacts; l; l = l->next) {
91 if (!tp_strdiff (empathy_contact_get_id (l->data), id)) {
100 tp_contact_factory_weak_notify (gpointer data,
101 GObject *where_the_object_was)
103 EmpathyTpContactFactoryPriv *priv = GET_PRIV (data);
105 empathy_debug (DEBUG_DOMAIN, "Remove finalized contact %p",
106 where_the_object_was);
108 priv->contacts = g_list_remove (priv->contacts, where_the_object_was);
112 tp_contact_factory_presences_table_foreach (const gchar *state_str,
113 GHashTable *presences_table,
114 EmpathyContact *contact)
116 const GValue *message;
118 empathy_contact_set_presence (contact,
119 empathy_presence_from_str (state_str));
121 message = g_hash_table_lookup (presences_table, "message");
122 if (message != NULL) {
123 empathy_contact_set_presence_message (contact,
124 g_value_get_string (message));
126 empathy_contact_set_presence_message (contact, NULL);
131 tp_contact_factory_parse_presence_foreach (guint handle,
132 GValueArray *presence_struct,
133 EmpathyTpContactFactory *tp_factory)
135 GHashTable *presences_table;
136 EmpathyContact *contact;
138 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
143 presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1));
145 g_hash_table_foreach (presences_table,
146 (GHFunc) tp_contact_factory_presences_table_foreach,
149 empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)",
150 empathy_contact_get_id (contact),
152 empathy_contact_get_presence_message (contact),
153 empathy_contact_get_presence (contact));
157 tp_contact_factory_get_presence_cb (DBusGProxy *proxy,
158 GHashTable *handle_table,
162 EmpathyTpContactFactory *tp_factory = user_data;
165 empathy_debug (DEBUG_DOMAIN, "Error getting presence: %s",
170 g_hash_table_foreach (handle_table,
171 (GHFunc) tp_contact_factory_parse_presence_foreach,
174 g_hash_table_destroy (handle_table);
176 g_object_unref (tp_factory);
180 tp_contact_factory_presence_update_cb (DBusGProxy *proxy,
181 GHashTable *handle_table,
182 EmpathyTpContactFactory *tp_factory)
184 g_hash_table_foreach (handle_table,
185 (GHFunc) tp_contact_factory_parse_presence_foreach,
190 tp_contact_factory_set_aliases_cb (DBusGProxy *proxy,
194 EmpathyTpContactFactory *tp_factory = user_data;
197 empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s",
201 g_object_unref (tp_factory);
205 EmpathyTpContactFactory *tp_factory;
207 } RequestAliasesData;
210 tp_contact_factory_request_aliases_cb (DBusGProxy *proxy,
211 gchar **contact_names,
215 RequestAliasesData *data = user_data;
220 empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s",
225 for (name = contact_names; *name; name++) {
226 EmpathyContact *contact;
228 contact = tp_contact_factory_find_by_handle (data->tp_factory,
234 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)",
235 empathy_contact_get_id (contact),
236 data->handles[i], *name);
238 empathy_contact_set_name (contact, *name);
243 g_strfreev (contact_names);
245 g_object_unref (data->tp_factory);
246 g_free (data->handles);
247 g_slice_free (RequestAliasesData, data);
251 tp_contact_factory_aliases_changed_cb (DBusGProxy *proxy,
252 GPtrArray *renamed_handlers,
255 EmpathyTpContactFactory *tp_factory = user_data;
258 for (i = 0; renamed_handlers->len > i; i++) {
261 GValueArray *renamed_struct;
262 EmpathyContact *contact;
264 renamed_struct = g_ptr_array_index (renamed_handlers, i);
265 handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0));
266 alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1));
267 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
270 /* We don't know this contact, skip */
274 if (G_STR_EMPTY (alias)) {
278 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)",
279 empathy_contact_get_id (contact),
282 empathy_contact_set_name (contact, alias);
287 tp_contact_factory_set_avatar_cb (DBusGProxy *proxy,
292 EmpathyTpContactFactory *tp_factory = user_data;
295 empathy_debug (DEBUG_DOMAIN, "Error setting avatar: %s",
299 g_object_unref (tp_factory);
304 tp_contact_factory_clear_avatar_cb (DBusGProxy *proxy,
308 EmpathyTpContactFactory *tp_factory = user_data;
311 empathy_debug (DEBUG_DOMAIN, "Error clearing avatar: %s",
315 g_object_unref (tp_factory);
319 tp_contact_factory_avatar_retrieved_cb (DBusGProxy *proxy,
326 EmpathyTpContactFactory *tp_factory = user_data;
327 EmpathyContact *contact;
328 EmpathyAvatar *avatar;
330 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
335 empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)",
336 empathy_contact_get_id (contact),
339 avatar = empathy_avatar_new (avatar_data->data,
344 empathy_contact_set_avatar (contact, avatar);
345 empathy_avatar_unref (avatar);
349 tp_contact_factory_request_avatars_cb (DBusGProxy *proxy,
353 EmpathyTpContactFactory *tp_factory = user_data;
356 empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s",
360 g_object_unref (tp_factory);
364 tp_contact_factory_avatar_maybe_update (EmpathyTpContactFactory *tp_factory,
368 EmpathyContact *contact;
369 EmpathyAvatar *avatar;
371 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
376 /* Check if we have an avatar */
377 if (G_STR_EMPTY (token)) {
378 empathy_contact_set_avatar (contact, NULL);
382 /* Check if the avatar changed */
383 avatar = empathy_contact_get_avatar (contact);
384 if (avatar && !tp_strdiff (avatar->token, token)) {
388 /* The avatar changed, search the new one in the cache */
389 avatar = empathy_avatar_new_from_cache (token);
391 /* Got from cache, use it */
392 empathy_contact_set_avatar (contact, avatar);
393 empathy_avatar_unref (avatar);
397 /* Avatar is not up-to-date, we have to request it. */
402 EmpathyTpContactFactory *tp_factory;
407 tp_contact_factory_avatar_tokens_foreach (gpointer key,
411 TokensData *data = user_data;
412 const gchar *token = value;
413 guint handle = GPOINTER_TO_UINT (key);
415 if (!tp_contact_factory_avatar_maybe_update (data->tp_factory,
417 g_array_append_val (data->handles, handle);
422 tp_contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy,
427 EmpathyTpContactFactory *tp_factory = user_data;
428 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
432 empathy_debug (DEBUG_DOMAIN,
433 "Error getting known avatars tokens: %s",
438 data.tp_factory = tp_factory;
439 data.handles = g_array_new (FALSE, FALSE, sizeof (guint));
440 g_hash_table_foreach (tokens,
441 tp_contact_factory_avatar_tokens_foreach,
444 empathy_debug (DEBUG_DOMAIN, "Got %d tokens, need to request %d avatars",
445 g_hash_table_size (tokens),
448 /* Request needed avatars */
449 if (data.handles->len > 0) {
450 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
452 tp_contact_factory_request_avatars_cb,
453 g_object_ref (tp_factory));
456 g_hash_table_destroy (tokens);
457 g_array_free (data.handles, TRUE);
459 g_object_unref (tp_factory);
463 tp_contact_factory_avatar_updated_cb (DBusGProxy *proxy,
468 EmpathyTpContactFactory *tp_factory = user_data;
469 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
472 if (tp_contact_factory_avatar_maybe_update (tp_factory, handle, new_token)) {
473 /* Avatar was cached, nothing to do */
477 empathy_debug (DEBUG_DOMAIN, "Need to request avatar for token %s",
480 handles = g_array_new (FALSE, FALSE, sizeof (guint));
481 g_array_append_val (handles, handle);
483 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
485 tp_contact_factory_request_avatars_cb,
486 g_object_ref (tp_factory));
487 g_array_free (handles, TRUE);
491 tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory,
493 const gchar *channel_type,
497 EmpathyContact *contact;
498 EmpathyCapabilities capabilities;
500 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
505 capabilities = empathy_contact_get_capabilities (contact);
507 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) {
508 capabilities &= ~EMPATHY_CAPABILITIES_AUDIO;
509 capabilities &= ~EMPATHY_CAPABILITIES_VIDEO;
510 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) {
511 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
513 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) {
514 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
518 empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d",
519 empathy_contact_get_id (contact),
520 empathy_contact_get_handle (contact),
523 empathy_contact_set_capabilities (contact, capabilities);
527 tp_contact_factory_get_capabilities_cb (DBusGProxy *proxy,
528 GPtrArray *capabilities,
532 EmpathyTpContactFactory *tp_factory = user_data;
536 empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s",
538 /* FIXME Should set the capabilities of the contacts for which this request
539 * originated to NONE */
543 for (i = 0; i < capabilities->len; i++) {
546 const gchar *channel_type;
550 values = g_ptr_array_index (capabilities, i);
551 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
552 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
553 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
554 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
556 tp_contact_factory_update_capabilities (tp_factory,
562 g_value_array_free (values);
565 g_ptr_array_free (capabilities, TRUE);
567 g_object_unref (tp_factory);
571 tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
572 GPtrArray *capabilities,
575 EmpathyTpContactFactory *tp_factory = user_data;
578 for (i = 0; i < capabilities->len; i++) {
581 const gchar *channel_type;
585 values = g_ptr_array_index (capabilities, i);
586 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
587 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
588 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
589 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
591 tp_contact_factory_update_capabilities (tp_factory,
600 tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory,
603 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
605 if (priv->presence_iface) {
606 tp_conn_iface_presence_get_presence_async (priv->presence_iface,
608 tp_contact_factory_get_presence_cb,
609 g_object_ref (tp_factory));
612 if (priv->aliasing_iface) {
613 RequestAliasesData *data;
615 data = g_slice_new (RequestAliasesData);
616 data->tp_factory = g_object_ref (tp_factory);
617 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
619 tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface,
621 tp_contact_factory_request_aliases_cb,
625 if (priv->avatars_iface) {
626 tp_conn_iface_avatars_get_known_avatar_tokens_async (priv->avatars_iface,
628 tp_contact_factory_get_known_avatar_tokens_cb,
629 g_object_ref (tp_factory));
632 if (priv->capabilities_iface) {
633 tp_conn_iface_capabilities_get_capabilities_async (priv->capabilities_iface,
635 tp_contact_factory_get_capabilities_cb,
636 g_object_ref (tp_factory));
641 EmpathyTpContactFactory *tp_factory;
643 } RequestHandlesData;
646 tp_contact_factory_request_handles_cb (DBusGProxy *proxy,
651 RequestHandlesData *data = user_data;
652 EmpathyTpContactFactory *tp_factory = data->tp_factory;
653 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
658 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
663 for (l = data->contacts; l; l = l->next) {
666 handle = g_array_index (handles, guint, i);
667 empathy_contact_set_handle (l->data, handle);
668 if (handle == priv->self_handle) {
669 empathy_contact_set_is_user (l->data, TRUE);
675 tp_contact_factory_request_everything (tp_factory, handles);
676 g_array_free (handles, TRUE);
679 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
680 g_list_free (data->contacts);
681 g_object_unref (tp_factory);
682 g_slice_free (RequestHandlesData, data);
686 tp_contact_factory_disconnect_contact_foreach (gpointer data,
689 EmpathyContact *contact = data;
691 empathy_contact_set_presence (contact, MC_PRESENCE_UNSET);
692 empathy_contact_set_handle (contact, 0);
696 tp_contact_factory_destroy_cb (TpConn *tp_conn,
697 EmpathyTpContactFactory *tp_factory)
699 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
701 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
703 g_object_unref (priv->tp_conn);
704 priv->tp_conn = NULL;
705 priv->aliasing_iface = NULL;
706 priv->avatars_iface = NULL;
707 priv->presence_iface = NULL;
708 priv->capabilities_iface = NULL;
710 g_list_foreach (priv->contacts,
711 tp_contact_factory_disconnect_contact_foreach,
716 tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory)
718 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
720 if (priv->aliasing_iface) {
721 dbus_g_proxy_disconnect_signal (priv->aliasing_iface,
723 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
726 if (priv->avatars_iface) {
727 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
729 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
731 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
733 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
736 if (priv->presence_iface) {
737 dbus_g_proxy_disconnect_signal (priv->presence_iface,
739 G_CALLBACK (tp_contact_factory_presence_update_cb),
742 if (priv->capabilities_iface) {
743 dbus_g_proxy_disconnect_signal (priv->capabilities_iface,
744 "CapabilitiesChanged",
745 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
749 g_signal_handlers_disconnect_by_func (priv->tp_conn,
750 tp_contact_factory_destroy_cb,
756 tp_contact_factory_update (EmpathyTpContactFactory *tp_factory)
758 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
759 TpConn *tp_conn = NULL;
760 RequestHandlesData *data;
761 const gchar **contact_ids;
764 GError *error = NULL;
769 /* status == 0 means the status is CONNECTED */
770 status = mission_control_get_connection_status (priv->mc,
774 tp_conn = mission_control_get_connection (priv->mc,
781 /* We are not connected anymore, remove the old connection */
782 tp_contact_factory_disconnect (tp_factory);
784 tp_contact_factory_destroy_cb (priv->tp_conn, tp_factory);
788 else if (priv->tp_conn) {
789 /* We were connected and we still are connected, nothing
790 * changed so nothing to do. */
791 g_object_unref (tp_conn);
795 /* We got a new connection */
796 priv->tp_conn = tp_conn;
797 priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn,
798 TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING);
799 priv->avatars_iface = tp_conn_get_interface (priv->tp_conn,
800 TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
801 priv->presence_iface = tp_conn_get_interface (priv->tp_conn,
802 TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE);
803 priv->capabilities_iface = tp_conn_get_interface (priv->tp_conn,
804 TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
806 /* Connect signals */
807 if (priv->aliasing_iface) {
808 dbus_g_proxy_connect_signal (priv->aliasing_iface,
810 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
813 if (priv->avatars_iface) {
814 dbus_g_proxy_connect_signal (priv->avatars_iface,
816 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
818 dbus_g_proxy_connect_signal (priv->avatars_iface,
820 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
823 if (priv->presence_iface) {
824 dbus_g_proxy_connect_signal (priv->presence_iface,
826 G_CALLBACK (tp_contact_factory_presence_update_cb),
829 if (priv->capabilities_iface) {
830 dbus_g_proxy_connect_signal (priv->capabilities_iface,
831 "CapabilitiesChanged",
832 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
835 g_signal_connect (priv->tp_conn, "destroy",
836 G_CALLBACK (tp_contact_factory_destroy_cb),
839 /* Get our own handle */
840 if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn),
843 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
844 error ? error->message : "No error given");
845 g_clear_error (&error);
848 /* Request new handles for all contacts */
849 if (priv->contacts) {
850 data = g_slice_new (RequestHandlesData);
851 data->tp_factory = g_object_ref (tp_factory);
852 data->contacts = g_list_copy (priv->contacts);
853 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
855 i = g_list_length (data->contacts);
856 contact_ids = g_new0 (const gchar*, i + 1);
858 for (l = data->contacts; l; l = l->next) {
859 contact_ids[i] = empathy_contact_get_id (l->data);
863 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
864 TP_HANDLE_TYPE_CONTACT,
866 tp_contact_factory_request_handles_cb,
868 g_free (contact_ids);
873 tp_contact_factory_status_changed_cb (MissionControl *mc,
874 TpConnectionStatus status,
876 TpConnectionStatusReason reason,
877 const gchar *unique_name,
878 EmpathyTpContactFactory *tp_factory)
880 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
883 account = mc_account_lookup (unique_name);
884 if (account && empathy_account_equal (account, priv->account)) {
885 tp_contact_factory_update (tp_factory);
887 g_object_unref (account);
891 tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
892 EmpathyContact *contact)
894 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
896 g_object_weak_ref (G_OBJECT (contact),
897 tp_contact_factory_weak_notify,
899 priv->contacts = g_list_prepend (priv->contacts, contact);
901 if (!priv->presence_iface) {
902 /* We have no presence iface, set default presence
904 empathy_contact_set_presence (contact, MC_PRESENCE_AVAILABLE);
907 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
908 empathy_contact_get_id (contact),
909 empathy_contact_get_handle (contact));
913 tp_contact_factory_hold_handles_cb (DBusGProxy *proxy,
918 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
924 empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory)
926 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
928 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
930 return empathy_tp_contact_factory_get_from_handle (tp_factory,
935 empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory,
938 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
939 EmpathyContact *contact;
941 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
942 g_return_val_if_fail (id != NULL, NULL);
944 /* Check if the contact already exists */
945 contact = tp_contact_factory_find_by_id (tp_factory, id);
947 return g_object_ref (contact);
950 /* Create new contact */
951 contact = g_object_new (EMPATHY_TYPE_CONTACT,
952 "account", priv->account,
955 tp_contact_factory_add_contact (tp_factory, contact);
957 /* If the account is connected, request contact's handle */
959 RequestHandlesData *data;
960 const gchar *contact_ids[] = {id, NULL};
962 data = g_slice_new (RequestHandlesData);
963 data->tp_factory = g_object_ref (tp_factory);
964 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
965 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
966 TP_HANDLE_TYPE_CONTACT,
968 tp_contact_factory_request_handles_cb,
976 empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory,
979 EmpathyContact *contact;
983 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
985 handles = g_array_new (FALSE, FALSE, sizeof (guint));
986 g_array_append_val (handles, handle);
988 contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles);
989 g_array_free (handles, TRUE);
991 contact = contacts ? contacts->data : NULL;
992 g_list_free (contacts);
998 empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory,
1001 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1002 GList *contacts = NULL;
1003 GArray *new_handles;
1004 gchar **handles_names;
1006 GError *error = NULL;
1008 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
1009 g_return_val_if_fail (handles != NULL, NULL);
1011 /* Search all contacts we already have */
1012 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1013 for (i = 0; i < handles->len; i++) {
1014 EmpathyContact *contact;
1017 handle = g_array_index (handles, guint, i);
1022 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
1024 contacts = g_list_prepend (contacts, g_object_ref (contact));
1026 g_array_append_val (new_handles, handle);
1030 if (new_handles->len == 0) {
1031 g_array_free (new_handles, TRUE);
1035 /* Get the IDs of all new handles */
1036 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
1037 TP_HANDLE_TYPE_CONTACT,
1041 empathy_debug (DEBUG_DOMAIN,
1042 "Couldn't inspect contact: %s",
1043 error ? error->message : "No error given");
1044 g_clear_error (&error);
1045 g_array_free (new_handles, TRUE);
1049 /* Create new contacts */
1050 for (i = 0; i < new_handles->len; i++) {
1051 EmpathyContact *contact;
1056 id = handles_names[i];
1057 handle = g_array_index (new_handles, guint, i);
1059 is_user = (handle == priv->self_handle);
1060 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1061 "account", priv->account,
1066 tp_contact_factory_add_contact (tp_factory, contact);
1067 contacts = g_list_prepend (contacts, contact);
1070 g_free (handles_names);
1072 /* Hold all new handles. */
1073 tp_conn_hold_handles_async (DBUS_G_PROXY (priv->tp_conn),
1074 TP_HANDLE_TYPE_CONTACT,
1076 tp_contact_factory_hold_handles_cb,
1079 tp_contact_factory_request_everything (tp_factory, new_handles);
1081 g_array_free (new_handles, TRUE);
1087 empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory,
1088 EmpathyContact *contact,
1091 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1092 GHashTable *new_alias;
1095 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1096 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1097 g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact),
1100 if (!priv->aliasing_iface) {
1104 handle = empathy_contact_get_handle (contact);
1106 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1107 empathy_contact_get_id (contact),
1110 new_alias = g_hash_table_new_full (g_direct_hash,
1115 g_hash_table_insert (new_alias,
1116 GUINT_TO_POINTER (handle),
1119 tp_conn_iface_aliasing_set_aliases_async (priv->aliasing_iface,
1121 tp_contact_factory_set_aliases_cb,
1122 g_object_ref (tp_factory));
1124 g_hash_table_destroy (new_alias);
1128 empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory,
1131 const gchar *mime_type)
1133 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1135 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1137 if (!priv->avatars_iface) {
1141 if (data && size > 0 && size < G_MAXUINT) {
1144 avatar.data = (gchar*) data;
1147 empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s",
1148 mc_account_get_unique_name (priv->account));
1150 tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface,
1153 tp_contact_factory_set_avatar_cb,
1154 g_object_ref (tp_factory));
1156 empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s",
1157 mc_account_get_unique_name (priv->account));
1158 tp_conn_iface_avatars_clear_avatar_async (priv->avatars_iface,
1159 tp_contact_factory_clear_avatar_cb,
1160 g_object_ref (tp_factory));
1165 tp_contact_factory_get_property (GObject *object,
1170 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1174 g_value_set_object (value, priv->account);
1177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1183 tp_contact_factory_set_property (GObject *object,
1185 const GValue *value,
1188 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1192 priv->account = g_object_ref (g_value_get_object (value));
1195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1201 tp_contact_factory_finalize (GObject *object)
1203 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1206 empathy_debug (DEBUG_DOMAIN, "Finalized: %p (%s)",
1208 mc_account_get_normalized_name (priv->account));
1210 tp_contact_factory_disconnect (EMPATHY_TP_CONTACT_FACTORY (object));
1211 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1212 "AccountStatusChanged",
1213 G_CALLBACK (tp_contact_factory_status_changed_cb),
1216 for (l = priv->contacts; l; l = l->next) {
1217 g_object_weak_unref (G_OBJECT (l->data),
1218 tp_contact_factory_weak_notify,
1222 g_list_free (priv->contacts);
1223 g_object_unref (priv->mc);
1224 g_object_unref (priv->account);
1226 if (priv->tp_conn) {
1227 g_object_unref (priv->tp_conn);
1230 G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object);
1234 tp_contact_factory_constructor (GType type,
1236 GObjectConstructParam *props)
1238 GObject *tp_factory;
1240 tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props);
1242 tp_contact_factory_update (EMPATHY_TP_CONTACT_FACTORY (tp_factory));
1249 empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass)
1251 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1253 object_class->finalize = tp_contact_factory_finalize;
1254 object_class->constructor = tp_contact_factory_constructor;
1255 object_class->get_property = tp_contact_factory_get_property;
1256 object_class->set_property = tp_contact_factory_set_property;
1258 /* Construct-only properties */
1259 g_object_class_install_property (object_class,
1261 g_param_spec_object ("account",
1262 "Factory's Account",
1263 "The account associated with the factory",
1266 G_PARAM_CONSTRUCT_ONLY));
1268 g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv));
1272 empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory)
1274 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1276 priv->mc = empathy_mission_control_new ();
1277 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1278 "AccountStatusChanged",
1279 G_CALLBACK (tp_contact_factory_status_changed_cb),
1283 EmpathyTpContactFactory *
1284 empathy_tp_contact_factory_new (McAccount *account)
1286 return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY,