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 EmpathyPresence **presence)
117 const GValue *message;
119 state = empathy_presence_state_from_str (state_str);
120 if (state == MC_PRESENCE_UNSET) {
125 g_object_unref (*presence);
129 *presence = empathy_presence_new ();
130 empathy_presence_set_state (*presence, state);
132 message = g_hash_table_lookup (presences_table, "message");
133 if (message != NULL) {
134 empathy_presence_set_status (*presence,
135 g_value_get_string (message));
140 tp_contact_factory_parse_presence_foreach (guint handle,
141 GValueArray *presence_struct,
142 EmpathyTpContactFactory *tp_factory)
144 GHashTable *presences_table;
145 EmpathyContact *contact;
146 EmpathyPresence *presence = NULL;
148 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
153 presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1));
155 g_hash_table_foreach (presences_table,
156 (GHFunc) tp_contact_factory_presences_table_foreach,
159 empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)",
160 empathy_contact_get_id (contact),
162 presence ? empathy_presence_get_status (presence) : "unset",
163 presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET);
165 empathy_contact_set_presence (contact, presence);
166 g_object_unref (presence);
170 tp_contact_factory_get_presence_cb (DBusGProxy *proxy,
171 GHashTable *handle_table,
175 EmpathyTpContactFactory *tp_factory = user_data;
178 empathy_debug (DEBUG_DOMAIN, "Error getting presence: %s",
183 g_hash_table_foreach (handle_table,
184 (GHFunc) tp_contact_factory_parse_presence_foreach,
187 g_hash_table_destroy (handle_table);
189 g_object_unref (tp_factory);
193 tp_contact_factory_presence_update_cb (DBusGProxy *proxy,
194 GHashTable *handle_table,
195 EmpathyTpContactFactory *tp_factory)
197 g_hash_table_foreach (handle_table,
198 (GHFunc) tp_contact_factory_parse_presence_foreach,
203 tp_contact_factory_set_aliases_cb (DBusGProxy *proxy,
207 EmpathyTpContactFactory *tp_factory = user_data;
210 empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s",
214 g_object_unref (tp_factory);
218 EmpathyTpContactFactory *tp_factory;
220 } RequestAliasesData;
223 tp_contact_factory_request_aliases_cb (DBusGProxy *proxy,
224 gchar **contact_names,
228 RequestAliasesData *data = user_data;
233 empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s",
238 for (name = contact_names; *name; name++) {
239 EmpathyContact *contact;
241 contact = tp_contact_factory_find_by_handle (data->tp_factory,
247 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)",
248 empathy_contact_get_id (contact),
249 data->handles[i], *name);
251 empathy_contact_set_name (contact, *name);
256 g_strfreev (contact_names);
258 g_object_unref (data->tp_factory);
259 g_free (data->handles);
260 g_slice_free (RequestAliasesData, data);
264 tp_contact_factory_aliases_changed_cb (DBusGProxy *proxy,
265 GPtrArray *renamed_handlers,
268 EmpathyTpContactFactory *tp_factory = user_data;
271 for (i = 0; renamed_handlers->len > i; i++) {
274 GValueArray *renamed_struct;
275 EmpathyContact *contact;
277 renamed_struct = g_ptr_array_index (renamed_handlers, i);
278 handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0));
279 alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1));
280 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
283 /* We don't know this contact, skip */
287 if (G_STR_EMPTY (alias)) {
291 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)",
292 empathy_contact_get_id (contact),
295 empathy_contact_set_name (contact, alias);
300 tp_contact_factory_set_avatar_cb (DBusGProxy *proxy,
305 EmpathyTpContactFactory *tp_factory = user_data;
308 empathy_debug (DEBUG_DOMAIN, "Error setting avatar: %s",
312 g_object_unref (tp_factory);
317 tp_contact_factory_clear_avatar_cb (DBusGProxy *proxy,
321 EmpathyTpContactFactory *tp_factory = user_data;
324 empathy_debug (DEBUG_DOMAIN, "Error clearing avatar: %s",
328 g_object_unref (tp_factory);
332 tp_contact_factory_avatar_retrieved_cb (DBusGProxy *proxy,
339 EmpathyTpContactFactory *tp_factory = user_data;
340 EmpathyContact *contact;
341 EmpathyAvatar *avatar;
343 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
348 empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)",
349 empathy_contact_get_id (contact),
352 avatar = empathy_avatar_new (avatar_data->data,
357 empathy_contact_set_avatar (contact, avatar);
358 empathy_avatar_unref (avatar);
362 tp_contact_factory_request_avatars_cb (DBusGProxy *proxy,
366 EmpathyTpContactFactory *tp_factory = user_data;
369 empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s",
373 g_object_unref (tp_factory);
377 tp_contact_factory_avatar_maybe_update (EmpathyTpContactFactory *tp_factory,
381 EmpathyContact *contact;
382 EmpathyAvatar *avatar;
384 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
389 /* Check if we have an avatar */
390 if (G_STR_EMPTY (token)) {
391 empathy_contact_set_avatar (contact, NULL);
395 /* Check if the avatar changed */
396 avatar = empathy_contact_get_avatar (contact);
397 if (avatar && !tp_strdiff (avatar->token, token)) {
401 /* The avatar changed, search the new one in the cache */
402 avatar = empathy_avatar_new_from_cache (token);
404 /* Got from cache, use it */
405 empathy_contact_set_avatar (contact, avatar);
406 empathy_avatar_unref (avatar);
410 /* Avatar is not up-to-date, we have to request it. */
415 EmpathyTpContactFactory *tp_factory;
420 tp_contact_factory_avatar_tokens_foreach (gpointer key,
424 TokensData *data = user_data;
425 const gchar *token = value;
426 guint handle = GPOINTER_TO_UINT (key);
428 if (!tp_contact_factory_avatar_maybe_update (data->tp_factory,
430 g_array_append_val (data->handles, handle);
435 tp_contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy,
440 EmpathyTpContactFactory *tp_factory = user_data;
441 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
445 empathy_debug (DEBUG_DOMAIN,
446 "Error getting known avatars tokens: %s",
451 data.tp_factory = tp_factory;
452 data.handles = g_array_new (FALSE, FALSE, sizeof (guint));
453 g_hash_table_foreach (tokens,
454 tp_contact_factory_avatar_tokens_foreach,
457 empathy_debug (DEBUG_DOMAIN, "Got %d tokens, need to request %d avatars",
458 g_hash_table_size (tokens),
461 /* Request needed avatars */
462 if (data.handles->len > 0) {
463 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
465 tp_contact_factory_request_avatars_cb,
466 g_object_ref (tp_factory));
469 g_hash_table_destroy (tokens);
470 g_array_free (data.handles, TRUE);
472 g_object_unref (tp_factory);
476 tp_contact_factory_avatar_updated_cb (DBusGProxy *proxy,
481 EmpathyTpContactFactory *tp_factory = user_data;
482 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
485 if (tp_contact_factory_avatar_maybe_update (tp_factory, handle, new_token)) {
486 /* Avatar was cached, nothing to do */
490 empathy_debug (DEBUG_DOMAIN, "Need to request avatar for token %s",
493 handles = g_array_new (FALSE, FALSE, sizeof (guint));
494 g_array_append_val (handles, handle);
496 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
498 tp_contact_factory_request_avatars_cb,
499 g_object_ref (tp_factory));
500 g_array_free (handles, TRUE);
504 tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory,
506 const gchar *channel_type,
510 EmpathyContact *contact;
511 EmpathyCapabilities capabilities;
513 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
518 capabilities = empathy_contact_get_capabilities (contact);
520 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) {
521 capabilities &= ~EMPATHY_CAPABILITIES_AUDIO;
522 capabilities &= ~EMPATHY_CAPABILITIES_VIDEO;
523 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) {
524 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
526 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) {
527 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
531 empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d",
532 empathy_contact_get_id (contact),
533 empathy_contact_get_handle (contact),
536 empathy_contact_set_capabilities (contact, capabilities);
540 tp_contact_factory_get_capabilities_cb (DBusGProxy *proxy,
541 GPtrArray *capabilities,
545 EmpathyTpContactFactory *tp_factory = user_data;
549 empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s",
554 for (i = 0; i < capabilities->len; i++) {
557 const gchar *channel_type;
561 values = g_ptr_array_index (capabilities, i);
562 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
563 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
564 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
565 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
567 tp_contact_factory_update_capabilities (tp_factory,
573 g_value_array_free (values);
576 g_ptr_array_free (capabilities, TRUE);
578 g_object_unref (tp_factory);
582 tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
583 GPtrArray *capabilities,
586 EmpathyTpContactFactory *tp_factory = user_data;
589 for (i = 0; i < capabilities->len; i++) {
592 const gchar *channel_type;
596 values = g_ptr_array_index (capabilities, i);
597 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
598 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
599 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
600 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
602 tp_contact_factory_update_capabilities (tp_factory,
611 tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory,
614 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
616 if (priv->presence_iface) {
617 tp_conn_iface_presence_get_presence_async (priv->presence_iface,
619 tp_contact_factory_get_presence_cb,
620 g_object_ref (tp_factory));
623 if (priv->aliasing_iface) {
624 RequestAliasesData *data;
626 data = g_slice_new (RequestAliasesData);
627 data->tp_factory = g_object_ref (tp_factory);
628 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
630 tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface,
632 tp_contact_factory_request_aliases_cb,
636 if (priv->avatars_iface) {
637 tp_conn_iface_avatars_get_known_avatar_tokens_async (priv->avatars_iface,
639 tp_contact_factory_get_known_avatar_tokens_cb,
640 g_object_ref (tp_factory));
643 if (priv->capabilities_iface) {
644 tp_conn_iface_capabilities_get_capabilities_async (priv->capabilities_iface,
646 tp_contact_factory_get_capabilities_cb,
647 g_object_ref (tp_factory));
652 EmpathyTpContactFactory *tp_factory;
654 } RequestHandlesData;
657 tp_contact_factory_request_handles_cb (DBusGProxy *proxy,
662 RequestHandlesData *data = user_data;
663 EmpathyTpContactFactory *tp_factory = data->tp_factory;
664 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
669 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
674 for (l = data->contacts; l; l = l->next) {
677 handle = g_array_index (handles, guint, i);
678 empathy_contact_set_handle (l->data, handle);
679 if (handle == priv->self_handle) {
680 empathy_contact_set_is_user (l->data, TRUE);
686 tp_contact_factory_request_everything (tp_factory, handles);
687 g_array_free (handles, TRUE);
690 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
691 g_list_free (data->contacts);
692 g_object_unref (tp_factory);
693 g_slice_free (RequestHandlesData, data);
697 tp_contact_factory_disconnect_contact_foreach (gpointer data,
700 EmpathyContact *contact = data;
702 empathy_contact_set_presence (contact, NULL);
703 empathy_contact_set_handle (contact, 0);
707 tp_contact_factory_destroy_cb (TpConn *tp_conn,
708 EmpathyTpContactFactory *tp_factory)
710 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
712 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
714 g_object_unref (priv->tp_conn);
715 priv->tp_conn = NULL;
716 priv->aliasing_iface = NULL;
717 priv->avatars_iface = NULL;
718 priv->presence_iface = NULL;
719 priv->capabilities_iface = NULL;
721 g_list_foreach (priv->contacts,
722 tp_contact_factory_disconnect_contact_foreach,
727 tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory)
729 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
731 if (priv->aliasing_iface) {
732 dbus_g_proxy_disconnect_signal (priv->aliasing_iface,
734 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
737 if (priv->avatars_iface) {
738 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
740 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
742 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
744 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
747 if (priv->presence_iface) {
748 dbus_g_proxy_disconnect_signal (priv->presence_iface,
750 G_CALLBACK (tp_contact_factory_presence_update_cb),
753 if (priv->capabilities_iface) {
754 dbus_g_proxy_disconnect_signal (priv->capabilities_iface,
755 "CapabilitiesChanged",
756 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
760 g_signal_handlers_disconnect_by_func (priv->tp_conn,
761 tp_contact_factory_destroy_cb,
767 tp_contact_factory_update (EmpathyTpContactFactory *tp_factory)
769 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
770 TpConn *tp_conn = NULL;
771 RequestHandlesData *data;
772 const gchar **contact_ids;
775 GError *error = NULL;
780 /* status == 0 means the status is CONNECTED */
781 status = mission_control_get_connection_status (priv->mc,
785 tp_conn = mission_control_get_connection (priv->mc,
792 /* We are not connected anymore, remove the old connection */
793 tp_contact_factory_disconnect (tp_factory);
795 tp_contact_factory_destroy_cb (priv->tp_conn, tp_factory);
799 else if (priv->tp_conn) {
800 /* We were connected and we still are connected, nothing
801 * changed so nothing to do. */
802 g_object_unref (tp_conn);
806 /* We got a new connection */
807 priv->tp_conn = tp_conn;
808 priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn,
809 TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING);
810 priv->avatars_iface = tp_conn_get_interface (priv->tp_conn,
811 TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
812 priv->presence_iface = tp_conn_get_interface (priv->tp_conn,
813 TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE);
814 priv->capabilities_iface = tp_conn_get_interface (priv->tp_conn,
815 TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
817 /* Connect signals */
818 if (priv->aliasing_iface) {
819 dbus_g_proxy_connect_signal (priv->aliasing_iface,
821 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
824 if (priv->avatars_iface) {
825 dbus_g_proxy_connect_signal (priv->avatars_iface,
827 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
829 dbus_g_proxy_connect_signal (priv->avatars_iface,
831 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
834 if (priv->presence_iface) {
835 dbus_g_proxy_connect_signal (priv->presence_iface,
837 G_CALLBACK (tp_contact_factory_presence_update_cb),
840 if (priv->capabilities_iface) {
841 dbus_g_proxy_connect_signal (priv->capabilities_iface,
842 "CapabilitiesChanged",
843 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
846 g_signal_connect (priv->tp_conn, "destroy",
847 G_CALLBACK (tp_contact_factory_destroy_cb),
850 /* Get our own handle */
851 if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn),
854 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
855 error ? error->message : "No error given");
856 g_clear_error (&error);
859 /* Request new handles for all contacts */
860 if (priv->contacts) {
861 data = g_slice_new (RequestHandlesData);
862 data->tp_factory = g_object_ref (tp_factory);
863 data->contacts = g_list_copy (priv->contacts);
864 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
866 i = g_list_length (data->contacts);
867 contact_ids = g_new0 (const gchar*, i + 1);
869 for (l = data->contacts; l; l = l->next) {
870 contact_ids[i] = empathy_contact_get_id (l->data);
874 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
875 TP_HANDLE_TYPE_CONTACT,
877 tp_contact_factory_request_handles_cb,
879 g_free (contact_ids);
884 tp_contact_factory_status_changed_cb (MissionControl *mc,
885 TpConnectionStatus status,
887 TpConnectionStatusReason reason,
888 const gchar *unique_name,
889 EmpathyTpContactFactory *tp_factory)
891 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
894 account = mc_account_lookup (unique_name);
895 if (account && empathy_account_equal (account, priv->account)) {
896 tp_contact_factory_update (tp_factory);
898 g_object_unref (account);
902 tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
903 EmpathyContact *contact)
905 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
907 g_object_weak_ref (G_OBJECT (contact),
908 tp_contact_factory_weak_notify,
910 priv->contacts = g_list_prepend (priv->contacts, contact);
912 if (!priv->presence_iface) {
913 EmpathyPresence *presence;
915 /* We have no presence iface, set default presence
917 presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE,
920 empathy_contact_set_presence (contact, presence);
921 g_object_unref (presence);
924 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
925 empathy_contact_get_id (contact),
926 empathy_contact_get_handle (contact));
930 tp_contact_factory_hold_handles_cb (DBusGProxy *proxy,
935 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
941 empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory)
943 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
945 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
947 return empathy_tp_contact_factory_get_from_handle (tp_factory,
952 empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory,
955 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
956 EmpathyContact *contact;
958 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
959 g_return_val_if_fail (id != NULL, NULL);
961 /* Check if the contact already exists */
962 contact = tp_contact_factory_find_by_id (tp_factory, id);
964 return g_object_ref (contact);
967 /* Create new contact */
968 contact = g_object_new (EMPATHY_TYPE_CONTACT,
969 "account", priv->account,
972 tp_contact_factory_add_contact (tp_factory, contact);
974 /* If the account is connected, request contact's handle */
976 RequestHandlesData *data;
977 const gchar *contact_ids[] = {id, NULL};
979 data = g_slice_new (RequestHandlesData);
980 data->tp_factory = g_object_ref (tp_factory);
981 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
982 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
983 TP_HANDLE_TYPE_CONTACT,
985 tp_contact_factory_request_handles_cb,
993 empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory,
996 EmpathyContact *contact;
1000 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
1002 handles = g_array_new (FALSE, FALSE, sizeof (guint));
1003 g_array_append_val (handles, handle);
1005 contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles);
1006 g_array_free (handles, TRUE);
1008 contact = contacts ? contacts->data : NULL;
1009 g_list_free (contacts);
1015 empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory,
1018 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1019 GList *contacts = NULL;
1020 GArray *new_handles;
1021 gchar **handles_names;
1023 GError *error = NULL;
1025 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
1026 g_return_val_if_fail (handles != NULL, NULL);
1028 /* Search all contacts we already have */
1029 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1030 for (i = 0; i < handles->len; i++) {
1031 EmpathyContact *contact;
1034 handle = g_array_index (handles, guint, i);
1039 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
1041 contacts = g_list_prepend (contacts, g_object_ref (contact));
1043 g_array_append_val (new_handles, handle);
1047 if (new_handles->len == 0) {
1048 g_array_free (new_handles, TRUE);
1052 /* Get the IDs of all new handles */
1053 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
1054 TP_HANDLE_TYPE_CONTACT,
1058 empathy_debug (DEBUG_DOMAIN,
1059 "Couldn't inspect contact: %s",
1060 error ? error->message : "No error given");
1061 g_clear_error (&error);
1062 g_array_free (new_handles, TRUE);
1066 /* Create new contacts */
1067 for (i = 0; i < new_handles->len; i++) {
1068 EmpathyContact *contact;
1073 id = handles_names[i];
1074 handle = g_array_index (new_handles, guint, i);
1076 is_user = (handle == priv->self_handle);
1077 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1078 "account", priv->account,
1083 tp_contact_factory_add_contact (tp_factory, contact);
1084 contacts = g_list_prepend (contacts, contact);
1087 g_free (handles_names);
1089 /* Hold all new handles. */
1090 tp_conn_hold_handles_async (DBUS_G_PROXY (priv->tp_conn),
1091 TP_HANDLE_TYPE_CONTACT,
1093 tp_contact_factory_hold_handles_cb,
1096 tp_contact_factory_request_everything (tp_factory, new_handles);
1098 g_array_free (new_handles, TRUE);
1104 empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory,
1105 EmpathyContact *contact,
1108 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1109 GHashTable *new_alias;
1112 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1113 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1114 g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact),
1117 if (!priv->aliasing_iface) {
1121 handle = empathy_contact_get_handle (contact);
1123 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1124 empathy_contact_get_id (contact),
1127 new_alias = g_hash_table_new_full (g_direct_hash,
1132 g_hash_table_insert (new_alias,
1133 GUINT_TO_POINTER (handle),
1136 tp_conn_iface_aliasing_set_aliases_async (priv->aliasing_iface,
1138 tp_contact_factory_set_aliases_cb,
1139 g_object_ref (tp_factory));
1141 g_hash_table_destroy (new_alias);
1145 empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory,
1148 const gchar *mime_type)
1150 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1152 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1154 if (!priv->avatars_iface) {
1158 if (data && size > 0 && size < G_MAXUINT) {
1161 avatar.data = (gchar*) data;
1164 empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s",
1165 mc_account_get_unique_name (priv->account));
1167 tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface,
1170 tp_contact_factory_set_avatar_cb,
1171 g_object_ref (tp_factory));
1173 empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s",
1174 mc_account_get_unique_name (priv->account));
1175 tp_conn_iface_avatars_clear_avatar_async (priv->avatars_iface,
1176 tp_contact_factory_clear_avatar_cb,
1177 g_object_ref (tp_factory));
1182 tp_contact_factory_get_property (GObject *object,
1187 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1191 g_value_set_object (value, priv->account);
1194 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1200 tp_contact_factory_set_property (GObject *object,
1202 const GValue *value,
1205 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1209 priv->account = g_object_ref (g_value_get_object (value));
1212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1218 tp_contact_factory_finalize (GObject *object)
1220 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1223 empathy_debug (DEBUG_DOMAIN, "Finalized: %p (%s)",
1225 mc_account_get_normalized_name (priv->account));
1227 tp_contact_factory_disconnect (EMPATHY_TP_CONTACT_FACTORY (object));
1228 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1229 "AccountStatusChanged",
1230 G_CALLBACK (tp_contact_factory_status_changed_cb),
1233 for (l = priv->contacts; l; l = l->next) {
1234 g_object_weak_unref (G_OBJECT (l->data),
1235 tp_contact_factory_weak_notify,
1239 g_list_free (priv->contacts);
1240 g_object_unref (priv->mc);
1241 g_object_unref (priv->account);
1243 if (priv->tp_conn) {
1244 g_object_unref (priv->tp_conn);
1247 G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object);
1251 tp_contact_factory_constructor (GType type,
1253 GObjectConstructParam *props)
1255 GObject *tp_factory;
1257 tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props);
1259 tp_contact_factory_update (EMPATHY_TP_CONTACT_FACTORY (tp_factory));
1266 empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass)
1268 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1270 object_class->finalize = tp_contact_factory_finalize;
1271 object_class->constructor = tp_contact_factory_constructor;
1272 object_class->get_property = tp_contact_factory_get_property;
1273 object_class->set_property = tp_contact_factory_set_property;
1275 /* Construct-only properties */
1276 g_object_class_install_property (object_class,
1278 g_param_spec_object ("account",
1279 "Factory's Account",
1280 "The account associated with the factory",
1283 G_PARAM_CONSTRUCT_ONLY));
1285 g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv));
1289 empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory)
1291 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1293 priv->mc = empathy_mission_control_new ();
1294 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1295 "AccountStatusChanged",
1296 G_CALLBACK (tp_contact_factory_status_changed_cb),
1300 EmpathyTpContactFactory *
1301 empathy_tp_contact_factory_new (McAccount *account)
1303 return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY,