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);
506 capabilities &= ~EMPATHY_CAPABILITIES_UNKNOWN;
508 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) {
509 capabilities &= ~EMPATHY_CAPABILITIES_AUDIO;
510 capabilities &= ~EMPATHY_CAPABILITIES_VIDEO;
511 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) {
512 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
514 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) {
515 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
519 empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d",
520 empathy_contact_get_id (contact),
521 empathy_contact_get_handle (contact),
524 empathy_contact_set_capabilities (contact, capabilities);
528 tp_contact_factory_get_capabilities_cb (DBusGProxy *proxy,
529 GPtrArray *capabilities,
533 EmpathyTpContactFactory *tp_factory = user_data;
537 empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s",
539 /* FIXME Should set the capabilities of the contacts for which this request
540 * originated to NONE */
544 for (i = 0; i < capabilities->len; i++) {
547 const gchar *channel_type;
551 values = g_ptr_array_index (capabilities, i);
552 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
553 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
554 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
555 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
557 tp_contact_factory_update_capabilities (tp_factory,
563 g_value_array_free (values);
566 g_ptr_array_free (capabilities, TRUE);
568 g_object_unref (tp_factory);
572 tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
573 GPtrArray *capabilities,
576 EmpathyTpContactFactory *tp_factory = user_data;
579 for (i = 0; i < capabilities->len; i++) {
582 const gchar *channel_type;
586 values = g_ptr_array_index (capabilities, i);
587 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
588 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
589 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
590 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
592 tp_contact_factory_update_capabilities (tp_factory,
601 tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory,
604 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
606 if (priv->presence_iface) {
607 tp_conn_iface_presence_get_presence_async (priv->presence_iface,
609 tp_contact_factory_get_presence_cb,
610 g_object_ref (tp_factory));
613 if (priv->aliasing_iface) {
614 RequestAliasesData *data;
616 data = g_slice_new (RequestAliasesData);
617 data->tp_factory = g_object_ref (tp_factory);
618 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
620 tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface,
622 tp_contact_factory_request_aliases_cb,
626 if (priv->avatars_iface) {
627 tp_conn_iface_avatars_get_known_avatar_tokens_async (priv->avatars_iface,
629 tp_contact_factory_get_known_avatar_tokens_cb,
630 g_object_ref (tp_factory));
633 if (priv->capabilities_iface) {
634 tp_conn_iface_capabilities_get_capabilities_async (priv->capabilities_iface,
636 tp_contact_factory_get_capabilities_cb,
637 g_object_ref (tp_factory));
642 EmpathyTpContactFactory *tp_factory;
644 } RequestHandlesData;
647 tp_contact_factory_request_handles_cb (DBusGProxy *proxy,
652 RequestHandlesData *data = user_data;
653 EmpathyTpContactFactory *tp_factory = data->tp_factory;
654 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
659 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
664 for (l = data->contacts; l; l = l->next) {
667 handle = g_array_index (handles, guint, i);
668 empathy_contact_set_handle (l->data, handle);
669 if (handle == priv->self_handle) {
670 empathy_contact_set_is_user (l->data, TRUE);
676 tp_contact_factory_request_everything (tp_factory, handles);
677 g_array_free (handles, TRUE);
680 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
681 g_list_free (data->contacts);
682 g_object_unref (tp_factory);
683 g_slice_free (RequestHandlesData, data);
687 tp_contact_factory_disconnect_contact_foreach (gpointer data,
690 EmpathyContact *contact = data;
692 empathy_contact_set_presence (contact, MC_PRESENCE_UNSET);
693 empathy_contact_set_handle (contact, 0);
697 tp_contact_factory_destroy_cb (TpConn *tp_conn,
698 EmpathyTpContactFactory *tp_factory)
700 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
702 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
704 g_object_unref (priv->tp_conn);
705 priv->tp_conn = NULL;
706 priv->aliasing_iface = NULL;
707 priv->avatars_iface = NULL;
708 priv->presence_iface = NULL;
709 priv->capabilities_iface = NULL;
711 g_list_foreach (priv->contacts,
712 tp_contact_factory_disconnect_contact_foreach,
717 tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory)
719 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
721 if (priv->aliasing_iface) {
722 dbus_g_proxy_disconnect_signal (priv->aliasing_iface,
724 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
727 if (priv->avatars_iface) {
728 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
730 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
732 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
734 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
737 if (priv->presence_iface) {
738 dbus_g_proxy_disconnect_signal (priv->presence_iface,
740 G_CALLBACK (tp_contact_factory_presence_update_cb),
743 if (priv->capabilities_iface) {
744 dbus_g_proxy_disconnect_signal (priv->capabilities_iface,
745 "CapabilitiesChanged",
746 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
750 g_signal_handlers_disconnect_by_func (priv->tp_conn,
751 tp_contact_factory_destroy_cb,
757 tp_contact_factory_update (EmpathyTpContactFactory *tp_factory)
759 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
760 TpConn *tp_conn = NULL;
761 RequestHandlesData *data;
762 const gchar **contact_ids;
765 GError *error = NULL;
770 /* status == 0 means the status is CONNECTED */
771 status = mission_control_get_connection_status (priv->mc,
775 tp_conn = mission_control_get_connection (priv->mc,
782 /* We are not connected anymore, remove the old connection */
783 tp_contact_factory_disconnect (tp_factory);
785 tp_contact_factory_destroy_cb (priv->tp_conn, tp_factory);
789 else if (priv->tp_conn) {
790 /* We were connected and we still are connected, nothing
791 * changed so nothing to do. */
792 g_object_unref (tp_conn);
796 /* We got a new connection */
797 priv->tp_conn = tp_conn;
798 priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn,
799 TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING);
800 priv->avatars_iface = tp_conn_get_interface (priv->tp_conn,
801 TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
802 priv->presence_iface = tp_conn_get_interface (priv->tp_conn,
803 TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE);
804 priv->capabilities_iface = tp_conn_get_interface (priv->tp_conn,
805 TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
807 /* Connect signals */
808 if (priv->aliasing_iface) {
809 dbus_g_proxy_connect_signal (priv->aliasing_iface,
811 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
814 if (priv->avatars_iface) {
815 dbus_g_proxy_connect_signal (priv->avatars_iface,
817 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
819 dbus_g_proxy_connect_signal (priv->avatars_iface,
821 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
824 if (priv->presence_iface) {
825 dbus_g_proxy_connect_signal (priv->presence_iface,
827 G_CALLBACK (tp_contact_factory_presence_update_cb),
830 if (priv->capabilities_iface) {
831 dbus_g_proxy_connect_signal (priv->capabilities_iface,
832 "CapabilitiesChanged",
833 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
836 g_signal_connect (priv->tp_conn, "destroy",
837 G_CALLBACK (tp_contact_factory_destroy_cb),
840 /* Get our own handle */
841 if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn),
844 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
845 error ? error->message : "No error given");
846 g_clear_error (&error);
849 /* Request new handles for all contacts */
850 if (priv->contacts) {
851 data = g_slice_new (RequestHandlesData);
852 data->tp_factory = g_object_ref (tp_factory);
853 data->contacts = g_list_copy (priv->contacts);
854 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
856 i = g_list_length (data->contacts);
857 contact_ids = g_new0 (const gchar*, i + 1);
859 for (l = data->contacts; l; l = l->next) {
860 contact_ids[i] = empathy_contact_get_id (l->data);
864 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
865 TP_HANDLE_TYPE_CONTACT,
867 tp_contact_factory_request_handles_cb,
869 g_free (contact_ids);
874 tp_contact_factory_status_changed_cb (MissionControl *mc,
875 TpConnectionStatus status,
877 TpConnectionStatusReason reason,
878 const gchar *unique_name,
879 EmpathyTpContactFactory *tp_factory)
881 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
884 account = mc_account_lookup (unique_name);
885 if (account && empathy_account_equal (account, priv->account)) {
886 tp_contact_factory_update (tp_factory);
888 g_object_unref (account);
892 tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
893 EmpathyContact *contact)
895 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
897 g_object_weak_ref (G_OBJECT (contact),
898 tp_contact_factory_weak_notify,
900 priv->contacts = g_list_prepend (priv->contacts, contact);
902 if (!priv->presence_iface) {
903 /* We have no presence iface, set default presence
905 empathy_contact_set_presence (contact, MC_PRESENCE_AVAILABLE);
908 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
909 empathy_contact_get_id (contact),
910 empathy_contact_get_handle (contact));
914 tp_contact_factory_hold_handles_cb (DBusGProxy *proxy,
919 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
925 empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory)
927 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
929 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
931 return empathy_tp_contact_factory_get_from_handle (tp_factory,
936 empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory,
939 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
940 EmpathyContact *contact;
942 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
943 g_return_val_if_fail (id != NULL, NULL);
945 /* Check if the contact already exists */
946 contact = tp_contact_factory_find_by_id (tp_factory, id);
948 return g_object_ref (contact);
951 /* Create new contact */
952 contact = g_object_new (EMPATHY_TYPE_CONTACT,
953 "account", priv->account,
956 tp_contact_factory_add_contact (tp_factory, contact);
958 /* If the account is connected, request contact's handle */
960 RequestHandlesData *data;
961 const gchar *contact_ids[] = {id, NULL};
963 data = g_slice_new (RequestHandlesData);
964 data->tp_factory = g_object_ref (tp_factory);
965 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
966 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
967 TP_HANDLE_TYPE_CONTACT,
969 tp_contact_factory_request_handles_cb,
977 empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory,
980 EmpathyContact *contact;
984 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
986 handles = g_array_new (FALSE, FALSE, sizeof (guint));
987 g_array_append_val (handles, handle);
989 contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles);
990 g_array_free (handles, TRUE);
992 contact = contacts ? contacts->data : NULL;
993 g_list_free (contacts);
999 empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory,
1002 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1003 GList *contacts = NULL;
1004 GArray *new_handles;
1005 gchar **handles_names;
1007 GError *error = NULL;
1009 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
1010 g_return_val_if_fail (handles != NULL, NULL);
1012 /* Search all contacts we already have */
1013 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1014 for (i = 0; i < handles->len; i++) {
1015 EmpathyContact *contact;
1018 handle = g_array_index (handles, guint, i);
1023 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
1025 contacts = g_list_prepend (contacts, g_object_ref (contact));
1027 g_array_append_val (new_handles, handle);
1031 if (new_handles->len == 0) {
1032 g_array_free (new_handles, TRUE);
1036 /* Get the IDs of all new handles */
1037 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
1038 TP_HANDLE_TYPE_CONTACT,
1042 empathy_debug (DEBUG_DOMAIN,
1043 "Couldn't inspect contact: %s",
1044 error ? error->message : "No error given");
1045 g_clear_error (&error);
1046 g_array_free (new_handles, TRUE);
1050 /* Create new contacts */
1051 for (i = 0; i < new_handles->len; i++) {
1052 EmpathyContact *contact;
1057 id = handles_names[i];
1058 handle = g_array_index (new_handles, guint, i);
1060 is_user = (handle == priv->self_handle);
1061 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1062 "account", priv->account,
1067 tp_contact_factory_add_contact (tp_factory, contact);
1068 contacts = g_list_prepend (contacts, contact);
1071 g_free (handles_names);
1073 /* Hold all new handles. */
1074 tp_conn_hold_handles_async (DBUS_G_PROXY (priv->tp_conn),
1075 TP_HANDLE_TYPE_CONTACT,
1077 tp_contact_factory_hold_handles_cb,
1080 tp_contact_factory_request_everything (tp_factory, new_handles);
1082 g_array_free (new_handles, TRUE);
1088 empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory,
1089 EmpathyContact *contact,
1092 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1093 GHashTable *new_alias;
1096 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1097 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1098 g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact),
1101 if (!priv->aliasing_iface) {
1105 handle = empathy_contact_get_handle (contact);
1107 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1108 empathy_contact_get_id (contact),
1111 new_alias = g_hash_table_new_full (g_direct_hash,
1116 g_hash_table_insert (new_alias,
1117 GUINT_TO_POINTER (handle),
1120 tp_conn_iface_aliasing_set_aliases_async (priv->aliasing_iface,
1122 tp_contact_factory_set_aliases_cb,
1123 g_object_ref (tp_factory));
1125 g_hash_table_destroy (new_alias);
1129 empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory,
1132 const gchar *mime_type)
1134 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1136 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1138 if (!priv->avatars_iface) {
1142 if (data && size > 0 && size < G_MAXUINT) {
1145 avatar.data = (gchar*) data;
1148 empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s",
1149 mc_account_get_unique_name (priv->account));
1151 tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface,
1154 tp_contact_factory_set_avatar_cb,
1155 g_object_ref (tp_factory));
1157 empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s",
1158 mc_account_get_unique_name (priv->account));
1159 tp_conn_iface_avatars_clear_avatar_async (priv->avatars_iface,
1160 tp_contact_factory_clear_avatar_cb,
1161 g_object_ref (tp_factory));
1166 tp_contact_factory_get_property (GObject *object,
1171 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1175 g_value_set_object (value, priv->account);
1178 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1184 tp_contact_factory_set_property (GObject *object,
1186 const GValue *value,
1189 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1193 priv->account = g_object_ref (g_value_get_object (value));
1196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1202 tp_contact_factory_finalize (GObject *object)
1204 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1207 empathy_debug (DEBUG_DOMAIN, "Finalized: %p (%s)",
1209 mc_account_get_normalized_name (priv->account));
1211 tp_contact_factory_disconnect (EMPATHY_TP_CONTACT_FACTORY (object));
1212 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1213 "AccountStatusChanged",
1214 G_CALLBACK (tp_contact_factory_status_changed_cb),
1217 for (l = priv->contacts; l; l = l->next) {
1218 g_object_weak_unref (G_OBJECT (l->data),
1219 tp_contact_factory_weak_notify,
1223 g_list_free (priv->contacts);
1224 g_object_unref (priv->mc);
1225 g_object_unref (priv->account);
1227 if (priv->tp_conn) {
1228 g_object_unref (priv->tp_conn);
1231 G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object);
1235 tp_contact_factory_constructor (GType type,
1237 GObjectConstructParam *props)
1239 GObject *tp_factory;
1241 tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props);
1243 tp_contact_factory_update (EMPATHY_TP_CONTACT_FACTORY (tp_factory));
1250 empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass)
1252 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1254 object_class->finalize = tp_contact_factory_finalize;
1255 object_class->constructor = tp_contact_factory_constructor;
1256 object_class->get_property = tp_contact_factory_get_property;
1257 object_class->set_property = tp_contact_factory_set_property;
1259 /* Construct-only properties */
1260 g_object_class_install_property (object_class,
1262 g_param_spec_object ("account",
1263 "Factory's Account",
1264 "The account associated with the factory",
1267 G_PARAM_CONSTRUCT_ONLY));
1269 g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv));
1273 empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory)
1275 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1277 priv->mc = empathy_mission_control_new ();
1278 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1279 "AccountStatusChanged",
1280 G_CALLBACK (tp_contact_factory_status_changed_cb),
1284 EmpathyTpContactFactory *
1285 empathy_tp_contact_factory_new (McAccount *account)
1287 return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY,