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));
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",
541 for (i = 0; i < capabilities->len; i++) {
544 const gchar *channel_type;
548 values = g_ptr_array_index (capabilities, i);
549 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
550 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
551 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
552 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
554 tp_contact_factory_update_capabilities (tp_factory,
560 g_value_array_free (values);
563 g_ptr_array_free (capabilities, TRUE);
565 g_object_unref (tp_factory);
569 tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
570 GPtrArray *capabilities,
573 EmpathyTpContactFactory *tp_factory = user_data;
576 for (i = 0; i < capabilities->len; i++) {
579 const gchar *channel_type;
583 values = g_ptr_array_index (capabilities, i);
584 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
585 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
586 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
587 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
589 tp_contact_factory_update_capabilities (tp_factory,
598 tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory,
601 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
603 if (priv->presence_iface) {
604 tp_conn_iface_presence_get_presence_async (priv->presence_iface,
606 tp_contact_factory_get_presence_cb,
607 g_object_ref (tp_factory));
610 if (priv->aliasing_iface) {
611 RequestAliasesData *data;
613 data = g_slice_new (RequestAliasesData);
614 data->tp_factory = g_object_ref (tp_factory);
615 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
617 tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface,
619 tp_contact_factory_request_aliases_cb,
623 if (priv->avatars_iface) {
624 tp_conn_iface_avatars_get_known_avatar_tokens_async (priv->avatars_iface,
626 tp_contact_factory_get_known_avatar_tokens_cb,
627 g_object_ref (tp_factory));
630 if (priv->capabilities_iface) {
631 tp_conn_iface_capabilities_get_capabilities_async (priv->capabilities_iface,
633 tp_contact_factory_get_capabilities_cb,
634 g_object_ref (tp_factory));
639 EmpathyTpContactFactory *tp_factory;
641 } RequestHandlesData;
644 tp_contact_factory_request_handles_cb (DBusGProxy *proxy,
649 RequestHandlesData *data = user_data;
650 EmpathyTpContactFactory *tp_factory = data->tp_factory;
651 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
656 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
661 for (l = data->contacts; l; l = l->next) {
664 handle = g_array_index (handles, guint, i);
665 empathy_contact_set_handle (l->data, handle);
666 if (handle == priv->self_handle) {
667 empathy_contact_set_is_user (l->data, TRUE);
673 tp_contact_factory_request_everything (tp_factory, handles);
674 g_array_free (handles, TRUE);
677 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
678 g_list_free (data->contacts);
679 g_object_unref (tp_factory);
680 g_slice_free (RequestHandlesData, data);
684 tp_contact_factory_disconnect_contact_foreach (gpointer data,
687 EmpathyContact *contact = data;
689 empathy_contact_set_presence (contact, MC_PRESENCE_UNSET);
690 empathy_contact_set_handle (contact, 0);
694 tp_contact_factory_destroy_cb (TpConn *tp_conn,
695 EmpathyTpContactFactory *tp_factory)
697 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
699 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
701 g_object_unref (priv->tp_conn);
702 priv->tp_conn = NULL;
703 priv->aliasing_iface = NULL;
704 priv->avatars_iface = NULL;
705 priv->presence_iface = NULL;
706 priv->capabilities_iface = NULL;
708 g_list_foreach (priv->contacts,
709 tp_contact_factory_disconnect_contact_foreach,
714 tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory)
716 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
718 if (priv->aliasing_iface) {
719 dbus_g_proxy_disconnect_signal (priv->aliasing_iface,
721 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
724 if (priv->avatars_iface) {
725 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
727 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
729 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
731 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
734 if (priv->presence_iface) {
735 dbus_g_proxy_disconnect_signal (priv->presence_iface,
737 G_CALLBACK (tp_contact_factory_presence_update_cb),
740 if (priv->capabilities_iface) {
741 dbus_g_proxy_disconnect_signal (priv->capabilities_iface,
742 "CapabilitiesChanged",
743 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
747 g_signal_handlers_disconnect_by_func (priv->tp_conn,
748 tp_contact_factory_destroy_cb,
754 tp_contact_factory_update (EmpathyTpContactFactory *tp_factory)
756 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
757 TpConn *tp_conn = NULL;
758 RequestHandlesData *data;
759 const gchar **contact_ids;
762 GError *error = NULL;
767 /* status == 0 means the status is CONNECTED */
768 status = mission_control_get_connection_status (priv->mc,
772 tp_conn = mission_control_get_connection (priv->mc,
779 /* We are not connected anymore, remove the old connection */
780 tp_contact_factory_disconnect (tp_factory);
782 tp_contact_factory_destroy_cb (priv->tp_conn, tp_factory);
786 else if (priv->tp_conn) {
787 /* We were connected and we still are connected, nothing
788 * changed so nothing to do. */
789 g_object_unref (tp_conn);
793 /* We got a new connection */
794 priv->tp_conn = tp_conn;
795 priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn,
796 TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING);
797 priv->avatars_iface = tp_conn_get_interface (priv->tp_conn,
798 TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
799 priv->presence_iface = tp_conn_get_interface (priv->tp_conn,
800 TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE);
801 priv->capabilities_iface = tp_conn_get_interface (priv->tp_conn,
802 TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
804 /* Connect signals */
805 if (priv->aliasing_iface) {
806 dbus_g_proxy_connect_signal (priv->aliasing_iface,
808 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
811 if (priv->avatars_iface) {
812 dbus_g_proxy_connect_signal (priv->avatars_iface,
814 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
816 dbus_g_proxy_connect_signal (priv->avatars_iface,
818 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
821 if (priv->presence_iface) {
822 dbus_g_proxy_connect_signal (priv->presence_iface,
824 G_CALLBACK (tp_contact_factory_presence_update_cb),
827 if (priv->capabilities_iface) {
828 dbus_g_proxy_connect_signal (priv->capabilities_iface,
829 "CapabilitiesChanged",
830 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
833 g_signal_connect (priv->tp_conn, "destroy",
834 G_CALLBACK (tp_contact_factory_destroy_cb),
837 /* Get our own handle */
838 if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn),
841 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
842 error ? error->message : "No error given");
843 g_clear_error (&error);
846 /* Request new handles for all contacts */
847 if (priv->contacts) {
848 data = g_slice_new (RequestHandlesData);
849 data->tp_factory = g_object_ref (tp_factory);
850 data->contacts = g_list_copy (priv->contacts);
851 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
853 i = g_list_length (data->contacts);
854 contact_ids = g_new0 (const gchar*, i + 1);
856 for (l = data->contacts; l; l = l->next) {
857 contact_ids[i] = empathy_contact_get_id (l->data);
861 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
862 TP_HANDLE_TYPE_CONTACT,
864 tp_contact_factory_request_handles_cb,
866 g_free (contact_ids);
871 tp_contact_factory_status_changed_cb (MissionControl *mc,
872 TpConnectionStatus status,
874 TpConnectionStatusReason reason,
875 const gchar *unique_name,
876 EmpathyTpContactFactory *tp_factory)
878 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
881 account = mc_account_lookup (unique_name);
882 if (account && empathy_account_equal (account, priv->account)) {
883 tp_contact_factory_update (tp_factory);
885 g_object_unref (account);
889 tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
890 EmpathyContact *contact)
892 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
894 g_object_weak_ref (G_OBJECT (contact),
895 tp_contact_factory_weak_notify,
897 priv->contacts = g_list_prepend (priv->contacts, contact);
899 if (!priv->presence_iface) {
900 /* We have no presence iface, set default presence
902 empathy_contact_set_presence (contact, MC_PRESENCE_AVAILABLE);
905 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
906 empathy_contact_get_id (contact),
907 empathy_contact_get_handle (contact));
911 tp_contact_factory_hold_handles_cb (DBusGProxy *proxy,
916 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
922 empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory)
924 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
926 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
928 return empathy_tp_contact_factory_get_from_handle (tp_factory,
933 empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory,
936 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
937 EmpathyContact *contact;
939 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
940 g_return_val_if_fail (id != NULL, NULL);
942 /* Check if the contact already exists */
943 contact = tp_contact_factory_find_by_id (tp_factory, id);
945 return g_object_ref (contact);
948 /* Create new contact */
949 contact = g_object_new (EMPATHY_TYPE_CONTACT,
950 "account", priv->account,
953 tp_contact_factory_add_contact (tp_factory, contact);
955 /* If the account is connected, request contact's handle */
957 RequestHandlesData *data;
958 const gchar *contact_ids[] = {id, NULL};
960 data = g_slice_new (RequestHandlesData);
961 data->tp_factory = g_object_ref (tp_factory);
962 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
963 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
964 TP_HANDLE_TYPE_CONTACT,
966 tp_contact_factory_request_handles_cb,
974 empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory,
977 EmpathyContact *contact;
981 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
983 handles = g_array_new (FALSE, FALSE, sizeof (guint));
984 g_array_append_val (handles, handle);
986 contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles);
987 g_array_free (handles, TRUE);
989 contact = contacts ? contacts->data : NULL;
990 g_list_free (contacts);
996 empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory,
999 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1000 GList *contacts = NULL;
1001 GArray *new_handles;
1002 gchar **handles_names;
1004 GError *error = NULL;
1006 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
1007 g_return_val_if_fail (handles != NULL, NULL);
1009 /* Search all contacts we already have */
1010 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1011 for (i = 0; i < handles->len; i++) {
1012 EmpathyContact *contact;
1015 handle = g_array_index (handles, guint, i);
1020 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
1022 contacts = g_list_prepend (contacts, g_object_ref (contact));
1024 g_array_append_val (new_handles, handle);
1028 if (new_handles->len == 0) {
1029 g_array_free (new_handles, TRUE);
1033 /* Get the IDs of all new handles */
1034 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
1035 TP_HANDLE_TYPE_CONTACT,
1039 empathy_debug (DEBUG_DOMAIN,
1040 "Couldn't inspect contact: %s",
1041 error ? error->message : "No error given");
1042 g_clear_error (&error);
1043 g_array_free (new_handles, TRUE);
1047 /* Create new contacts */
1048 for (i = 0; i < new_handles->len; i++) {
1049 EmpathyContact *contact;
1054 id = handles_names[i];
1055 handle = g_array_index (new_handles, guint, i);
1057 is_user = (handle == priv->self_handle);
1058 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1059 "account", priv->account,
1064 tp_contact_factory_add_contact (tp_factory, contact);
1065 contacts = g_list_prepend (contacts, contact);
1068 g_free (handles_names);
1070 /* Hold all new handles. */
1071 tp_conn_hold_handles_async (DBUS_G_PROXY (priv->tp_conn),
1072 TP_HANDLE_TYPE_CONTACT,
1074 tp_contact_factory_hold_handles_cb,
1077 tp_contact_factory_request_everything (tp_factory, new_handles);
1079 g_array_free (new_handles, TRUE);
1085 empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory,
1086 EmpathyContact *contact,
1089 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1090 GHashTable *new_alias;
1093 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1094 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1095 g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact),
1098 if (!priv->aliasing_iface) {
1102 handle = empathy_contact_get_handle (contact);
1104 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1105 empathy_contact_get_id (contact),
1108 new_alias = g_hash_table_new_full (g_direct_hash,
1113 g_hash_table_insert (new_alias,
1114 GUINT_TO_POINTER (handle),
1117 tp_conn_iface_aliasing_set_aliases_async (priv->aliasing_iface,
1119 tp_contact_factory_set_aliases_cb,
1120 g_object_ref (tp_factory));
1122 g_hash_table_destroy (new_alias);
1126 empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory,
1129 const gchar *mime_type)
1131 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1133 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1135 if (!priv->avatars_iface) {
1139 if (data && size > 0 && size < G_MAXUINT) {
1142 avatar.data = (gchar*) data;
1145 empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s",
1146 mc_account_get_unique_name (priv->account));
1148 tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface,
1151 tp_contact_factory_set_avatar_cb,
1152 g_object_ref (tp_factory));
1154 empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s",
1155 mc_account_get_unique_name (priv->account));
1156 tp_conn_iface_avatars_clear_avatar_async (priv->avatars_iface,
1157 tp_contact_factory_clear_avatar_cb,
1158 g_object_ref (tp_factory));
1163 tp_contact_factory_get_property (GObject *object,
1168 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1172 g_value_set_object (value, priv->account);
1175 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1181 tp_contact_factory_set_property (GObject *object,
1183 const GValue *value,
1186 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1190 priv->account = g_object_ref (g_value_get_object (value));
1193 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1199 tp_contact_factory_finalize (GObject *object)
1201 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1204 empathy_debug (DEBUG_DOMAIN, "Finalized: %p (%s)",
1206 mc_account_get_normalized_name (priv->account));
1208 tp_contact_factory_disconnect (EMPATHY_TP_CONTACT_FACTORY (object));
1209 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1210 "AccountStatusChanged",
1211 G_CALLBACK (tp_contact_factory_status_changed_cb),
1214 for (l = priv->contacts; l; l = l->next) {
1215 g_object_weak_unref (G_OBJECT (l->data),
1216 tp_contact_factory_weak_notify,
1220 g_list_free (priv->contacts);
1221 g_object_unref (priv->mc);
1222 g_object_unref (priv->account);
1224 if (priv->tp_conn) {
1225 g_object_unref (priv->tp_conn);
1228 G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object);
1232 tp_contact_factory_constructor (GType type,
1234 GObjectConstructParam *props)
1236 GObject *tp_factory;
1238 tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props);
1240 tp_contact_factory_update (EMPATHY_TP_CONTACT_FACTORY (tp_factory));
1247 empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass)
1249 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1251 object_class->finalize = tp_contact_factory_finalize;
1252 object_class->constructor = tp_contact_factory_constructor;
1253 object_class->get_property = tp_contact_factory_get_property;
1254 object_class->set_property = tp_contact_factory_set_property;
1256 /* Construct-only properties */
1257 g_object_class_install_property (object_class,
1259 g_param_spec_object ("account",
1260 "Factory's Account",
1261 "The account associated with the factory",
1264 G_PARAM_CONSTRUCT_ONLY));
1266 g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv));
1270 empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory)
1272 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1274 priv->mc = empathy_mission_control_new ();
1275 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1276 "AccountStatusChanged",
1277 G_CALLBACK (tp_contact_factory_status_changed_cb),
1281 EmpathyTpContactFactory *
1282 empathy_tp_contact_factory_new (McAccount *account)
1284 return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY,