1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 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));
129 tp_contact_factory_parse_presence_foreach (guint handle,
130 GValueArray *presence_struct,
131 EmpathyTpContactFactory *tp_factory)
133 GHashTable *presences_table;
134 EmpathyContact *contact;
136 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
141 presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1));
143 g_hash_table_foreach (presences_table,
144 (GHFunc) tp_contact_factory_presences_table_foreach,
147 empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)",
148 empathy_contact_get_id (contact),
150 empathy_contact_get_presence_message (contact),
151 empathy_contact_get_presence (contact));
155 tp_contact_factory_get_presence_cb (DBusGProxy *proxy,
156 GHashTable *handle_table,
160 EmpathyTpContactFactory *tp_factory = user_data;
163 empathy_debug (DEBUG_DOMAIN, "Error getting presence: %s",
168 g_hash_table_foreach (handle_table,
169 (GHFunc) tp_contact_factory_parse_presence_foreach,
172 g_hash_table_destroy (handle_table);
174 g_object_unref (tp_factory);
178 tp_contact_factory_presence_update_cb (DBusGProxy *proxy,
179 GHashTable *handle_table,
180 EmpathyTpContactFactory *tp_factory)
182 g_hash_table_foreach (handle_table,
183 (GHFunc) tp_contact_factory_parse_presence_foreach,
188 tp_contact_factory_set_aliases_cb (DBusGProxy *proxy,
192 EmpathyTpContactFactory *tp_factory = user_data;
195 empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s",
199 g_object_unref (tp_factory);
203 EmpathyTpContactFactory *tp_factory;
205 } RequestAliasesData;
208 tp_contact_factory_request_aliases_cb (DBusGProxy *proxy,
209 gchar **contact_names,
213 RequestAliasesData *data = user_data;
218 empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s",
223 for (name = contact_names; *name; name++) {
224 EmpathyContact *contact;
226 contact = tp_contact_factory_find_by_handle (data->tp_factory,
232 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)",
233 empathy_contact_get_id (contact),
234 data->handles[i], *name);
236 empathy_contact_set_name (contact, *name);
241 g_strfreev (contact_names);
243 g_object_unref (data->tp_factory);
244 g_free (data->handles);
245 g_slice_free (RequestAliasesData, data);
249 tp_contact_factory_aliases_changed_cb (DBusGProxy *proxy,
250 GPtrArray *renamed_handlers,
253 EmpathyTpContactFactory *tp_factory = user_data;
256 for (i = 0; renamed_handlers->len > i; i++) {
259 GValueArray *renamed_struct;
260 EmpathyContact *contact;
262 renamed_struct = g_ptr_array_index (renamed_handlers, i);
263 handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0));
264 alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1));
265 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
268 /* We don't know this contact, skip */
272 if (G_STR_EMPTY (alias)) {
276 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)",
277 empathy_contact_get_id (contact),
280 empathy_contact_set_name (contact, alias);
285 tp_contact_factory_set_avatar_cb (DBusGProxy *proxy,
290 EmpathyTpContactFactory *tp_factory = user_data;
293 empathy_debug (DEBUG_DOMAIN, "Error setting avatar: %s",
297 g_object_unref (tp_factory);
302 tp_contact_factory_clear_avatar_cb (DBusGProxy *proxy,
306 EmpathyTpContactFactory *tp_factory = user_data;
309 empathy_debug (DEBUG_DOMAIN, "Error clearing avatar: %s",
313 g_object_unref (tp_factory);
317 tp_contact_factory_avatar_retrieved_cb (DBusGProxy *proxy,
324 EmpathyTpContactFactory *tp_factory = user_data;
325 EmpathyContact *contact;
326 EmpathyAvatar *avatar;
328 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
333 empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)",
334 empathy_contact_get_id (contact),
337 avatar = empathy_avatar_new (avatar_data->data,
342 empathy_contact_set_avatar (contact, avatar);
343 empathy_avatar_unref (avatar);
347 tp_contact_factory_request_avatars_cb (DBusGProxy *proxy,
351 EmpathyTpContactFactory *tp_factory = user_data;
354 empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s",
358 g_object_unref (tp_factory);
362 tp_contact_factory_avatar_maybe_update (EmpathyTpContactFactory *tp_factory,
366 EmpathyContact *contact;
367 EmpathyAvatar *avatar;
369 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
374 /* Check if we have an avatar */
375 if (G_STR_EMPTY (token)) {
376 empathy_contact_set_avatar (contact, NULL);
380 /* Check if the avatar changed */
381 avatar = empathy_contact_get_avatar (contact);
382 if (avatar && !tp_strdiff (avatar->token, token)) {
386 /* The avatar changed, search the new one in the cache */
387 avatar = empathy_avatar_new_from_cache (token);
389 /* Got from cache, use it */
390 empathy_contact_set_avatar (contact, avatar);
391 empathy_avatar_unref (avatar);
395 /* Avatar is not up-to-date, we have to request it. */
400 EmpathyTpContactFactory *tp_factory;
405 tp_contact_factory_avatar_tokens_foreach (gpointer key,
409 TokensData *data = user_data;
410 const gchar *token = value;
411 guint handle = GPOINTER_TO_UINT (key);
413 if (!tp_contact_factory_avatar_maybe_update (data->tp_factory,
415 g_array_append_val (data->handles, handle);
420 tp_contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy,
425 EmpathyTpContactFactory *tp_factory = user_data;
426 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
430 empathy_debug (DEBUG_DOMAIN,
431 "Error getting known avatars tokens: %s",
436 data.tp_factory = tp_factory;
437 data.handles = g_array_new (FALSE, FALSE, sizeof (guint));
438 g_hash_table_foreach (tokens,
439 tp_contact_factory_avatar_tokens_foreach,
442 empathy_debug (DEBUG_DOMAIN, "Got %d tokens, need to request %d avatars",
443 g_hash_table_size (tokens),
446 /* Request needed avatars */
447 if (data.handles->len > 0) {
448 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
450 tp_contact_factory_request_avatars_cb,
451 g_object_ref (tp_factory));
454 g_hash_table_destroy (tokens);
455 g_array_free (data.handles, TRUE);
457 g_object_unref (tp_factory);
461 tp_contact_factory_avatar_updated_cb (DBusGProxy *proxy,
466 EmpathyTpContactFactory *tp_factory = user_data;
467 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
470 if (tp_contact_factory_avatar_maybe_update (tp_factory, handle, new_token)) {
471 /* Avatar was cached, nothing to do */
475 empathy_debug (DEBUG_DOMAIN, "Need to request avatar for token %s",
478 handles = g_array_new (FALSE, FALSE, sizeof (guint));
479 g_array_append_val (handles, handle);
481 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
483 tp_contact_factory_request_avatars_cb,
484 g_object_ref (tp_factory));
485 g_array_free (handles, TRUE);
489 tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory,
491 const gchar *channel_type,
495 EmpathyContact *contact;
496 EmpathyCapabilities capabilities;
498 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
503 capabilities = empathy_contact_get_capabilities (contact);
505 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) {
506 capabilities &= ~EMPATHY_CAPABILITIES_AUDIO;
507 capabilities &= ~EMPATHY_CAPABILITIES_VIDEO;
508 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) {
509 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
511 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) {
512 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
516 empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d",
517 empathy_contact_get_id (contact),
518 empathy_contact_get_handle (contact),
521 empathy_contact_set_capabilities (contact, capabilities);
525 tp_contact_factory_get_capabilities_cb (DBusGProxy *proxy,
526 GPtrArray *capabilities,
530 EmpathyTpContactFactory *tp_factory = user_data;
534 empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s",
539 for (i = 0; i < capabilities->len; i++) {
542 const gchar *channel_type;
546 values = g_ptr_array_index (capabilities, i);
547 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
548 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
549 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
550 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
552 tp_contact_factory_update_capabilities (tp_factory,
558 g_value_array_free (values);
561 g_ptr_array_free (capabilities, TRUE);
563 g_object_unref (tp_factory);
567 tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
568 GPtrArray *capabilities,
571 EmpathyTpContactFactory *tp_factory = user_data;
574 for (i = 0; i < capabilities->len; i++) {
577 const gchar *channel_type;
581 values = g_ptr_array_index (capabilities, i);
582 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
583 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
584 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
585 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
587 tp_contact_factory_update_capabilities (tp_factory,
596 tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory,
599 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
601 if (priv->presence_iface) {
602 tp_conn_iface_presence_get_presence_async (priv->presence_iface,
604 tp_contact_factory_get_presence_cb,
605 g_object_ref (tp_factory));
608 if (priv->aliasing_iface) {
609 RequestAliasesData *data;
611 data = g_slice_new (RequestAliasesData);
612 data->tp_factory = g_object_ref (tp_factory);
613 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
615 tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface,
617 tp_contact_factory_request_aliases_cb,
621 if (priv->avatars_iface) {
622 tp_conn_iface_avatars_get_known_avatar_tokens_async (priv->avatars_iface,
624 tp_contact_factory_get_known_avatar_tokens_cb,
625 g_object_ref (tp_factory));
628 if (priv->capabilities_iface) {
629 tp_conn_iface_capabilities_get_capabilities_async (priv->capabilities_iface,
631 tp_contact_factory_get_capabilities_cb,
632 g_object_ref (tp_factory));
637 EmpathyTpContactFactory *tp_factory;
639 } RequestHandlesData;
642 tp_contact_factory_request_handles_cb (DBusGProxy *proxy,
647 RequestHandlesData *data = user_data;
648 EmpathyTpContactFactory *tp_factory = data->tp_factory;
649 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
654 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
659 for (l = data->contacts; l; l = l->next) {
662 handle = g_array_index (handles, guint, i);
663 empathy_contact_set_handle (l->data, handle);
664 if (handle == priv->self_handle) {
665 empathy_contact_set_is_user (l->data, TRUE);
671 tp_contact_factory_request_everything (tp_factory, handles);
672 g_array_free (handles, TRUE);
675 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
676 g_list_free (data->contacts);
677 g_object_unref (tp_factory);
678 g_slice_free (RequestHandlesData, data);
682 tp_contact_factory_disconnect_contact_foreach (gpointer data,
685 EmpathyContact *contact = data;
687 empathy_contact_set_presence (contact, MC_PRESENCE_UNSET);
688 empathy_contact_set_handle (contact, 0);
692 tp_contact_factory_destroy_cb (TpConn *tp_conn,
693 EmpathyTpContactFactory *tp_factory)
695 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
697 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
699 g_object_unref (priv->tp_conn);
700 priv->tp_conn = NULL;
701 priv->aliasing_iface = NULL;
702 priv->avatars_iface = NULL;
703 priv->presence_iface = NULL;
704 priv->capabilities_iface = NULL;
706 g_list_foreach (priv->contacts,
707 tp_contact_factory_disconnect_contact_foreach,
712 tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory)
714 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
716 if (priv->aliasing_iface) {
717 dbus_g_proxy_disconnect_signal (priv->aliasing_iface,
719 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
722 if (priv->avatars_iface) {
723 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
725 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
727 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
729 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
732 if (priv->presence_iface) {
733 dbus_g_proxy_disconnect_signal (priv->presence_iface,
735 G_CALLBACK (tp_contact_factory_presence_update_cb),
738 if (priv->capabilities_iface) {
739 dbus_g_proxy_disconnect_signal (priv->capabilities_iface,
740 "CapabilitiesChanged",
741 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
745 g_signal_handlers_disconnect_by_func (priv->tp_conn,
746 tp_contact_factory_destroy_cb,
752 tp_contact_factory_update (EmpathyTpContactFactory *tp_factory)
754 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
755 TpConn *tp_conn = NULL;
756 RequestHandlesData *data;
757 const gchar **contact_ids;
760 GError *error = NULL;
765 /* status == 0 means the status is CONNECTED */
766 status = mission_control_get_connection_status (priv->mc,
770 tp_conn = mission_control_get_connection (priv->mc,
777 /* We are not connected anymore, remove the old connection */
778 tp_contact_factory_disconnect (tp_factory);
780 tp_contact_factory_destroy_cb (priv->tp_conn, tp_factory);
784 else if (priv->tp_conn) {
785 /* We were connected and we still are connected, nothing
786 * changed so nothing to do. */
787 g_object_unref (tp_conn);
791 /* We got a new connection */
792 priv->tp_conn = tp_conn;
793 priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn,
794 TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING);
795 priv->avatars_iface = tp_conn_get_interface (priv->tp_conn,
796 TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
797 priv->presence_iface = tp_conn_get_interface (priv->tp_conn,
798 TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE);
799 priv->capabilities_iface = tp_conn_get_interface (priv->tp_conn,
800 TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
802 /* Connect signals */
803 if (priv->aliasing_iface) {
804 dbus_g_proxy_connect_signal (priv->aliasing_iface,
806 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
809 if (priv->avatars_iface) {
810 dbus_g_proxy_connect_signal (priv->avatars_iface,
812 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
814 dbus_g_proxy_connect_signal (priv->avatars_iface,
816 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
819 if (priv->presence_iface) {
820 dbus_g_proxy_connect_signal (priv->presence_iface,
822 G_CALLBACK (tp_contact_factory_presence_update_cb),
825 if (priv->capabilities_iface) {
826 dbus_g_proxy_connect_signal (priv->capabilities_iface,
827 "CapabilitiesChanged",
828 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
831 g_signal_connect (priv->tp_conn, "destroy",
832 G_CALLBACK (tp_contact_factory_destroy_cb),
835 /* Get our own handle */
836 if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn),
839 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
840 error ? error->message : "No error given");
841 g_clear_error (&error);
844 /* Request new handles for all contacts */
845 if (priv->contacts) {
846 data = g_slice_new (RequestHandlesData);
847 data->tp_factory = g_object_ref (tp_factory);
848 data->contacts = g_list_copy (priv->contacts);
849 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
851 i = g_list_length (data->contacts);
852 contact_ids = g_new0 (const gchar*, i + 1);
854 for (l = data->contacts; l; l = l->next) {
855 contact_ids[i] = empathy_contact_get_id (l->data);
859 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
860 TP_HANDLE_TYPE_CONTACT,
862 tp_contact_factory_request_handles_cb,
864 g_free (contact_ids);
869 tp_contact_factory_status_changed_cb (MissionControl *mc,
870 TpConnectionStatus status,
872 TpConnectionStatusReason reason,
873 const gchar *unique_name,
874 EmpathyTpContactFactory *tp_factory)
876 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
879 account = mc_account_lookup (unique_name);
880 if (account && empathy_account_equal (account, priv->account)) {
881 tp_contact_factory_update (tp_factory);
883 g_object_unref (account);
887 tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
888 EmpathyContact *contact)
890 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
892 g_object_weak_ref (G_OBJECT (contact),
893 tp_contact_factory_weak_notify,
895 priv->contacts = g_list_prepend (priv->contacts, contact);
897 if (!priv->presence_iface) {
898 /* We have no presence iface, set default presence
900 empathy_contact_set_presence (contact, MC_PRESENCE_AVAILABLE);
903 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
904 empathy_contact_get_id (contact),
905 empathy_contact_get_handle (contact));
909 tp_contact_factory_hold_handles_cb (DBusGProxy *proxy,
914 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
920 empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory)
922 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
924 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
926 return empathy_tp_contact_factory_get_from_handle (tp_factory,
931 empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory,
934 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
935 EmpathyContact *contact;
937 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
938 g_return_val_if_fail (id != NULL, NULL);
940 /* Check if the contact already exists */
941 contact = tp_contact_factory_find_by_id (tp_factory, id);
943 return g_object_ref (contact);
946 /* Create new contact */
947 contact = g_object_new (EMPATHY_TYPE_CONTACT,
948 "account", priv->account,
951 tp_contact_factory_add_contact (tp_factory, contact);
953 /* If the account is connected, request contact's handle */
955 RequestHandlesData *data;
956 const gchar *contact_ids[] = {id, NULL};
958 data = g_slice_new (RequestHandlesData);
959 data->tp_factory = g_object_ref (tp_factory);
960 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
961 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
962 TP_HANDLE_TYPE_CONTACT,
964 tp_contact_factory_request_handles_cb,
972 empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory,
975 EmpathyContact *contact;
979 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
981 handles = g_array_new (FALSE, FALSE, sizeof (guint));
982 g_array_append_val (handles, handle);
984 contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles);
985 g_array_free (handles, TRUE);
987 contact = contacts ? contacts->data : NULL;
988 g_list_free (contacts);
994 empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory,
997 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
998 GList *contacts = NULL;
1000 gchar **handles_names;
1002 GError *error = NULL;
1004 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
1005 g_return_val_if_fail (handles != NULL, NULL);
1007 /* Search all contacts we already have */
1008 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1009 for (i = 0; i < handles->len; i++) {
1010 EmpathyContact *contact;
1013 handle = g_array_index (handles, guint, i);
1018 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
1020 contacts = g_list_prepend (contacts, g_object_ref (contact));
1022 g_array_append_val (new_handles, handle);
1026 if (new_handles->len == 0) {
1027 g_array_free (new_handles, TRUE);
1031 /* Get the IDs of all new handles */
1032 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
1033 TP_HANDLE_TYPE_CONTACT,
1037 empathy_debug (DEBUG_DOMAIN,
1038 "Couldn't inspect contact: %s",
1039 error ? error->message : "No error given");
1040 g_clear_error (&error);
1041 g_array_free (new_handles, TRUE);
1045 /* Create new contacts */
1046 for (i = 0; i < new_handles->len; i++) {
1047 EmpathyContact *contact;
1052 id = handles_names[i];
1053 handle = g_array_index (new_handles, guint, i);
1055 is_user = (handle == priv->self_handle);
1056 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1057 "account", priv->account,
1062 tp_contact_factory_add_contact (tp_factory, contact);
1063 contacts = g_list_prepend (contacts, contact);
1066 g_free (handles_names);
1068 /* Hold all new handles. */
1069 tp_conn_hold_handles_async (DBUS_G_PROXY (priv->tp_conn),
1070 TP_HANDLE_TYPE_CONTACT,
1072 tp_contact_factory_hold_handles_cb,
1075 tp_contact_factory_request_everything (tp_factory, new_handles);
1077 g_array_free (new_handles, TRUE);
1083 empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory,
1084 EmpathyContact *contact,
1087 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1088 GHashTable *new_alias;
1091 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1092 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1093 g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact),
1096 if (!priv->aliasing_iface) {
1100 handle = empathy_contact_get_handle (contact);
1102 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1103 empathy_contact_get_id (contact),
1106 new_alias = g_hash_table_new_full (g_direct_hash,
1111 g_hash_table_insert (new_alias,
1112 GUINT_TO_POINTER (handle),
1115 tp_conn_iface_aliasing_set_aliases_async (priv->aliasing_iface,
1117 tp_contact_factory_set_aliases_cb,
1118 g_object_ref (tp_factory));
1120 g_hash_table_destroy (new_alias);
1124 empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory,
1127 const gchar *mime_type)
1129 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1131 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1133 if (!priv->avatars_iface) {
1137 if (data && size > 0 && size < G_MAXUINT) {
1140 avatar.data = (gchar*) data;
1143 empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s",
1144 mc_account_get_unique_name (priv->account));
1146 tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface,
1149 tp_contact_factory_set_avatar_cb,
1150 g_object_ref (tp_factory));
1152 empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s",
1153 mc_account_get_unique_name (priv->account));
1154 tp_conn_iface_avatars_clear_avatar_async (priv->avatars_iface,
1155 tp_contact_factory_clear_avatar_cb,
1156 g_object_ref (tp_factory));
1161 tp_contact_factory_get_property (GObject *object,
1166 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1170 g_value_set_object (value, priv->account);
1173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1179 tp_contact_factory_set_property (GObject *object,
1181 const GValue *value,
1184 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1188 priv->account = g_object_ref (g_value_get_object (value));
1191 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1197 tp_contact_factory_finalize (GObject *object)
1199 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1202 empathy_debug (DEBUG_DOMAIN, "Finalized: %p (%s)",
1204 mc_account_get_normalized_name (priv->account));
1206 tp_contact_factory_disconnect (EMPATHY_TP_CONTACT_FACTORY (object));
1207 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1208 "AccountStatusChanged",
1209 G_CALLBACK (tp_contact_factory_status_changed_cb),
1212 for (l = priv->contacts; l; l = l->next) {
1213 g_object_weak_unref (G_OBJECT (l->data),
1214 tp_contact_factory_weak_notify,
1218 g_list_free (priv->contacts);
1219 g_object_unref (priv->mc);
1220 g_object_unref (priv->account);
1222 if (priv->tp_conn) {
1223 g_object_unref (priv->tp_conn);
1226 G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object);
1230 tp_contact_factory_constructor (GType type,
1232 GObjectConstructParam *props)
1234 GObject *tp_factory;
1236 tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props);
1238 tp_contact_factory_update (EMPATHY_TP_CONTACT_FACTORY (tp_factory));
1245 empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass)
1247 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1249 object_class->finalize = tp_contact_factory_finalize;
1250 object_class->constructor = tp_contact_factory_constructor;
1251 object_class->get_property = tp_contact_factory_get_property;
1252 object_class->set_property = tp_contact_factory_set_property;
1254 /* Construct-only properties */
1255 g_object_class_install_property (object_class,
1257 g_param_spec_object ("account",
1258 "Factory's Account",
1259 "The account associated with the factory",
1262 G_PARAM_CONSTRUCT_ONLY));
1264 g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv));
1268 empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory)
1270 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1272 priv->mc = empathy_mission_control_new ();
1273 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1274 "AccountStatusChanged",
1275 G_CALLBACK (tp_contact_factory_status_changed_cb),
1279 EmpathyTpContactFactory *
1280 empathy_tp_contact_factory_new (McAccount *account)
1282 return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY,