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 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)",
275 empathy_contact_get_id (contact),
278 empathy_contact_set_name (contact, alias);
283 tp_contact_factory_set_avatar_cb (DBusGProxy *proxy,
288 EmpathyTpContactFactory *tp_factory = user_data;
291 empathy_debug (DEBUG_DOMAIN, "Error setting avatar: %s",
295 g_object_unref (tp_factory);
300 tp_contact_factory_clear_avatar_cb (DBusGProxy *proxy,
304 EmpathyTpContactFactory *tp_factory = user_data;
307 empathy_debug (DEBUG_DOMAIN, "Error clearing avatar: %s",
311 g_object_unref (tp_factory);
315 tp_contact_factory_avatar_retrieved_cb (DBusGProxy *proxy,
322 EmpathyTpContactFactory *tp_factory = user_data;
323 EmpathyContact *contact;
324 EmpathyAvatar *avatar;
326 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
331 empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)",
332 empathy_contact_get_id (contact),
335 avatar = empathy_avatar_new (avatar_data->data,
340 empathy_contact_set_avatar (contact, avatar);
341 empathy_avatar_unref (avatar);
345 tp_contact_factory_request_avatars_cb (DBusGProxy *proxy,
349 EmpathyTpContactFactory *tp_factory = user_data;
352 empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s",
356 g_object_unref (tp_factory);
360 tp_contact_factory_avatar_maybe_update (EmpathyTpContactFactory *tp_factory,
364 EmpathyContact *contact;
365 EmpathyAvatar *avatar;
367 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
372 /* Check if we have an avatar */
373 if (G_STR_EMPTY (token)) {
374 empathy_contact_set_avatar (contact, NULL);
378 /* Check if the avatar changed */
379 avatar = empathy_contact_get_avatar (contact);
380 if (avatar && !tp_strdiff (avatar->token, token)) {
384 /* The avatar changed, search the new one in the cache */
385 avatar = empathy_avatar_new_from_cache (token);
387 /* Got from cache, use it */
388 empathy_contact_set_avatar (contact, avatar);
389 empathy_avatar_unref (avatar);
393 /* Avatar is not up-to-date, we have to request it. */
398 EmpathyTpContactFactory *tp_factory;
403 tp_contact_factory_avatar_tokens_foreach (gpointer key,
407 TokensData *data = user_data;
408 const gchar *token = value;
409 guint handle = GPOINTER_TO_UINT (key);
411 if (!tp_contact_factory_avatar_maybe_update (data->tp_factory,
413 g_array_append_val (data->handles, handle);
418 tp_contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy,
423 EmpathyTpContactFactory *tp_factory = user_data;
424 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
428 empathy_debug (DEBUG_DOMAIN,
429 "Error getting known avatars tokens: %s",
434 data.tp_factory = tp_factory;
435 data.handles = g_array_new (FALSE, FALSE, sizeof (guint));
436 g_hash_table_foreach (tokens,
437 tp_contact_factory_avatar_tokens_foreach,
440 empathy_debug (DEBUG_DOMAIN, "Got %d tokens, need to request %d avatars",
441 g_hash_table_size (tokens),
444 /* Request needed avatars */
445 if (data.handles->len > 0) {
446 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
448 tp_contact_factory_request_avatars_cb,
449 g_object_ref (tp_factory));
452 g_hash_table_destroy (tokens);
453 g_array_free (data.handles, TRUE);
455 g_object_unref (tp_factory);
459 tp_contact_factory_avatar_updated_cb (DBusGProxy *proxy,
464 EmpathyTpContactFactory *tp_factory = user_data;
465 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
468 if (tp_contact_factory_avatar_maybe_update (tp_factory, handle, new_token)) {
469 /* Avatar was cached, nothing to do */
473 empathy_debug (DEBUG_DOMAIN, "Need to request avatar for token %s",
476 handles = g_array_new (FALSE, FALSE, sizeof (guint));
477 g_array_append_val (handles, handle);
479 tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface,
481 tp_contact_factory_request_avatars_cb,
482 g_object_ref (tp_factory));
483 g_array_free (handles, TRUE);
487 tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory,
489 const gchar *channel_type,
493 EmpathyContact *contact;
494 EmpathyCapabilities capabilities;
496 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
501 capabilities = empathy_contact_get_capabilities (contact);
502 capabilities &= ~EMPATHY_CAPABILITIES_UNKNOWN;
504 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) {
505 capabilities &= ~EMPATHY_CAPABILITIES_AUDIO;
506 capabilities &= ~EMPATHY_CAPABILITIES_VIDEO;
507 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) {
508 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
510 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) {
511 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
515 empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d",
516 empathy_contact_get_id (contact),
517 empathy_contact_get_handle (contact),
520 empathy_contact_set_capabilities (contact, capabilities);
524 tp_contact_factory_get_capabilities_cb (DBusGProxy *proxy,
525 GPtrArray *capabilities,
529 EmpathyTpContactFactory *tp_factory = user_data;
533 empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s",
535 /* FIXME Should set the capabilities of the contacts for which this request
536 * originated to NONE */
540 for (i = 0; i < capabilities->len; i++) {
543 const gchar *channel_type;
547 values = g_ptr_array_index (capabilities, i);
548 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
549 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
550 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
551 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
553 tp_contact_factory_update_capabilities (tp_factory,
559 g_value_array_free (values);
562 g_ptr_array_free (capabilities, TRUE);
564 g_object_unref (tp_factory);
568 tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
569 GPtrArray *capabilities,
572 EmpathyTpContactFactory *tp_factory = user_data;
575 for (i = 0; i < capabilities->len; i++) {
578 const gchar *channel_type;
582 values = g_ptr_array_index (capabilities, i);
583 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
584 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
585 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
586 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
588 tp_contact_factory_update_capabilities (tp_factory,
597 tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory,
600 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
602 if (priv->presence_iface) {
603 tp_conn_iface_presence_get_presence_async (priv->presence_iface,
605 tp_contact_factory_get_presence_cb,
606 g_object_ref (tp_factory));
609 if (priv->aliasing_iface) {
610 RequestAliasesData *data;
612 data = g_slice_new (RequestAliasesData);
613 data->tp_factory = g_object_ref (tp_factory);
614 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
616 tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface,
618 tp_contact_factory_request_aliases_cb,
622 if (priv->avatars_iface) {
623 tp_conn_iface_avatars_get_known_avatar_tokens_async (priv->avatars_iface,
625 tp_contact_factory_get_known_avatar_tokens_cb,
626 g_object_ref (tp_factory));
629 if (priv->capabilities_iface) {
630 tp_conn_iface_capabilities_get_capabilities_async (priv->capabilities_iface,
632 tp_contact_factory_get_capabilities_cb,
633 g_object_ref (tp_factory));
638 EmpathyTpContactFactory *tp_factory;
640 } RequestHandlesData;
643 tp_contact_factory_request_handles_cb (DBusGProxy *proxy,
648 RequestHandlesData *data = user_data;
649 EmpathyTpContactFactory *tp_factory = data->tp_factory;
650 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
655 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
660 for (l = data->contacts; l; l = l->next) {
663 handle = g_array_index (handles, guint, i);
664 empathy_contact_set_handle (l->data, handle);
665 if (handle == priv->self_handle) {
666 empathy_contact_set_is_user (l->data, TRUE);
672 tp_contact_factory_request_everything (tp_factory, handles);
673 g_array_free (handles, TRUE);
676 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
677 g_list_free (data->contacts);
678 g_object_unref (tp_factory);
679 g_slice_free (RequestHandlesData, data);
683 tp_contact_factory_disconnect_contact_foreach (gpointer data,
686 EmpathyContact *contact = data;
688 empathy_contact_set_presence (contact, MC_PRESENCE_UNSET);
689 empathy_contact_set_handle (contact, 0);
693 tp_contact_factory_destroy_cb (TpConn *tp_conn,
694 EmpathyTpContactFactory *tp_factory)
696 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
698 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
700 g_object_unref (priv->tp_conn);
701 priv->tp_conn = NULL;
702 priv->aliasing_iface = NULL;
703 priv->avatars_iface = NULL;
704 priv->presence_iface = NULL;
705 priv->capabilities_iface = NULL;
707 g_list_foreach (priv->contacts,
708 tp_contact_factory_disconnect_contact_foreach,
713 tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory)
715 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
717 if (priv->aliasing_iface) {
718 dbus_g_proxy_disconnect_signal (priv->aliasing_iface,
720 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
723 if (priv->avatars_iface) {
724 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
726 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
728 dbus_g_proxy_disconnect_signal (priv->avatars_iface,
730 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
733 if (priv->presence_iface) {
734 dbus_g_proxy_disconnect_signal (priv->presence_iface,
736 G_CALLBACK (tp_contact_factory_presence_update_cb),
739 if (priv->capabilities_iface) {
740 dbus_g_proxy_disconnect_signal (priv->capabilities_iface,
741 "CapabilitiesChanged",
742 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
746 g_signal_handlers_disconnect_by_func (priv->tp_conn,
747 tp_contact_factory_destroy_cb,
753 tp_contact_factory_update (EmpathyTpContactFactory *tp_factory)
755 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
756 TpConn *tp_conn = NULL;
757 RequestHandlesData *data;
758 const gchar **contact_ids;
761 GError *error = NULL;
766 /* status == 0 means the status is CONNECTED */
767 status = mission_control_get_connection_status (priv->mc,
771 tp_conn = mission_control_get_connection (priv->mc,
778 /* We are not connected anymore, remove the old connection */
779 tp_contact_factory_disconnect (tp_factory);
781 tp_contact_factory_destroy_cb (priv->tp_conn, tp_factory);
785 else if (priv->tp_conn) {
786 /* We were connected and we still are connected, nothing
787 * changed so nothing to do. */
788 g_object_unref (tp_conn);
792 /* We got a new connection */
793 priv->tp_conn = tp_conn;
794 priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn,
795 TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING);
796 priv->avatars_iface = tp_conn_get_interface (priv->tp_conn,
797 TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
798 priv->presence_iface = tp_conn_get_interface (priv->tp_conn,
799 TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE);
800 priv->capabilities_iface = tp_conn_get_interface (priv->tp_conn,
801 TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
803 /* Connect signals */
804 if (priv->aliasing_iface) {
805 dbus_g_proxy_connect_signal (priv->aliasing_iface,
807 G_CALLBACK (tp_contact_factory_aliases_changed_cb),
810 if (priv->avatars_iface) {
811 dbus_g_proxy_connect_signal (priv->avatars_iface,
813 G_CALLBACK (tp_contact_factory_avatar_updated_cb),
815 dbus_g_proxy_connect_signal (priv->avatars_iface,
817 G_CALLBACK (tp_contact_factory_avatar_retrieved_cb),
820 if (priv->presence_iface) {
821 dbus_g_proxy_connect_signal (priv->presence_iface,
823 G_CALLBACK (tp_contact_factory_presence_update_cb),
826 if (priv->capabilities_iface) {
827 dbus_g_proxy_connect_signal (priv->capabilities_iface,
828 "CapabilitiesChanged",
829 G_CALLBACK (tp_contact_factory_capabilities_changed_cb),
832 g_signal_connect (priv->tp_conn, "destroy",
833 G_CALLBACK (tp_contact_factory_destroy_cb),
836 /* Get our own handle */
837 if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn),
840 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
841 error ? error->message : "No error given");
842 g_clear_error (&error);
845 /* Request new handles for all contacts */
846 if (priv->contacts) {
847 data = g_slice_new (RequestHandlesData);
848 data->tp_factory = g_object_ref (tp_factory);
849 data->contacts = g_list_copy (priv->contacts);
850 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
852 i = g_list_length (data->contacts);
853 contact_ids = g_new0 (const gchar*, i + 1);
855 for (l = data->contacts; l; l = l->next) {
856 contact_ids[i] = empathy_contact_get_id (l->data);
860 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
861 TP_HANDLE_TYPE_CONTACT,
863 tp_contact_factory_request_handles_cb,
865 g_free (contact_ids);
870 tp_contact_factory_status_changed_cb (MissionControl *mc,
871 TpConnectionStatus status,
873 TpConnectionStatusReason reason,
874 const gchar *unique_name,
875 EmpathyTpContactFactory *tp_factory)
877 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
880 account = mc_account_lookup (unique_name);
881 if (account && empathy_account_equal (account, priv->account)) {
882 tp_contact_factory_update (tp_factory);
884 g_object_unref (account);
888 tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
889 EmpathyContact *contact)
891 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
893 g_object_weak_ref (G_OBJECT (contact),
894 tp_contact_factory_weak_notify,
896 priv->contacts = g_list_prepend (priv->contacts, contact);
898 if (!priv->presence_iface) {
899 /* We have no presence iface, set default presence
901 empathy_contact_set_presence (contact, MC_PRESENCE_AVAILABLE);
904 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
905 empathy_contact_get_id (contact),
906 empathy_contact_get_handle (contact));
910 tp_contact_factory_hold_handles_cb (DBusGProxy *proxy,
915 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
921 empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory)
923 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
925 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
927 return empathy_tp_contact_factory_get_from_handle (tp_factory,
932 empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory,
935 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
936 EmpathyContact *contact;
938 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
939 g_return_val_if_fail (id != NULL, NULL);
941 /* Check if the contact already exists */
942 contact = tp_contact_factory_find_by_id (tp_factory, id);
944 return g_object_ref (contact);
947 /* Create new contact */
948 contact = g_object_new (EMPATHY_TYPE_CONTACT,
949 "account", priv->account,
952 tp_contact_factory_add_contact (tp_factory, contact);
954 /* If the account is connected, request contact's handle */
956 RequestHandlesData *data;
957 const gchar *contact_ids[] = {id, NULL};
959 data = g_slice_new (RequestHandlesData);
960 data->tp_factory = g_object_ref (tp_factory);
961 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
962 tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn),
963 TP_HANDLE_TYPE_CONTACT,
965 tp_contact_factory_request_handles_cb,
973 empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory,
976 EmpathyContact *contact;
980 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
982 handles = g_array_new (FALSE, FALSE, sizeof (guint));
983 g_array_append_val (handles, handle);
985 contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles);
986 g_array_free (handles, TRUE);
988 contact = contacts ? contacts->data : NULL;
989 g_list_free (contacts);
995 empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory,
998 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
999 GList *contacts = NULL;
1000 GArray *new_handles;
1001 gchar **handles_names;
1003 GError *error = NULL;
1005 g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL);
1006 g_return_val_if_fail (handles != NULL, NULL);
1008 /* Search all contacts we already have */
1009 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1010 for (i = 0; i < handles->len; i++) {
1011 EmpathyContact *contact;
1014 handle = g_array_index (handles, guint, i);
1019 contact = tp_contact_factory_find_by_handle (tp_factory, handle);
1021 contacts = g_list_prepend (contacts, g_object_ref (contact));
1023 g_array_append_val (new_handles, handle);
1027 if (new_handles->len == 0) {
1028 g_array_free (new_handles, TRUE);
1032 /* Get the IDs of all new handles */
1033 if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
1034 TP_HANDLE_TYPE_CONTACT,
1038 empathy_debug (DEBUG_DOMAIN,
1039 "Couldn't inspect contact: %s",
1040 error ? error->message : "No error given");
1041 g_clear_error (&error);
1042 g_array_free (new_handles, TRUE);
1046 /* Create new contacts */
1047 for (i = 0; i < new_handles->len; i++) {
1048 EmpathyContact *contact;
1053 id = handles_names[i];
1054 handle = g_array_index (new_handles, guint, i);
1056 is_user = (handle == priv->self_handle);
1057 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1058 "account", priv->account,
1063 tp_contact_factory_add_contact (tp_factory, contact);
1064 contacts = g_list_prepend (contacts, contact);
1067 g_free (handles_names);
1069 /* Hold all new handles. */
1070 tp_conn_hold_handles_async (DBUS_G_PROXY (priv->tp_conn),
1071 TP_HANDLE_TYPE_CONTACT,
1073 tp_contact_factory_hold_handles_cb,
1076 tp_contact_factory_request_everything (tp_factory, new_handles);
1078 g_array_free (new_handles, TRUE);
1084 empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory,
1085 EmpathyContact *contact,
1088 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1089 GHashTable *new_alias;
1092 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1093 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1094 g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact),
1097 if (!priv->aliasing_iface) {
1101 handle = empathy_contact_get_handle (contact);
1103 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1104 empathy_contact_get_id (contact),
1107 new_alias = g_hash_table_new_full (g_direct_hash,
1112 g_hash_table_insert (new_alias,
1113 GUINT_TO_POINTER (handle),
1116 tp_conn_iface_aliasing_set_aliases_async (priv->aliasing_iface,
1118 tp_contact_factory_set_aliases_cb,
1119 g_object_ref (tp_factory));
1121 g_hash_table_destroy (new_alias);
1125 empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory,
1128 const gchar *mime_type)
1130 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1132 g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
1134 if (!priv->avatars_iface) {
1138 if (data && size > 0 && size < G_MAXUINT) {
1141 avatar.data = (gchar*) data;
1144 empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s",
1145 mc_account_get_unique_name (priv->account));
1147 tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface,
1150 tp_contact_factory_set_avatar_cb,
1151 g_object_ref (tp_factory));
1153 empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s",
1154 mc_account_get_unique_name (priv->account));
1155 tp_conn_iface_avatars_clear_avatar_async (priv->avatars_iface,
1156 tp_contact_factory_clear_avatar_cb,
1157 g_object_ref (tp_factory));
1162 tp_contact_factory_get_property (GObject *object,
1167 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1171 g_value_set_object (value, priv->account);
1174 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1180 tp_contact_factory_set_property (GObject *object,
1182 const GValue *value,
1185 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1189 priv->account = g_object_ref (g_value_get_object (value));
1192 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1198 tp_contact_factory_finalize (GObject *object)
1200 EmpathyTpContactFactoryPriv *priv = GET_PRIV (object);
1203 empathy_debug (DEBUG_DOMAIN, "Finalized: %p (%s)",
1205 mc_account_get_normalized_name (priv->account));
1207 tp_contact_factory_disconnect (EMPATHY_TP_CONTACT_FACTORY (object));
1208 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1209 "AccountStatusChanged",
1210 G_CALLBACK (tp_contact_factory_status_changed_cb),
1213 for (l = priv->contacts; l; l = l->next) {
1214 g_object_weak_unref (G_OBJECT (l->data),
1215 tp_contact_factory_weak_notify,
1219 g_list_free (priv->contacts);
1220 g_object_unref (priv->mc);
1221 g_object_unref (priv->account);
1223 if (priv->tp_conn) {
1224 g_object_unref (priv->tp_conn);
1227 G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object);
1231 tp_contact_factory_constructor (GType type,
1233 GObjectConstructParam *props)
1235 GObject *tp_factory;
1237 tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props);
1239 tp_contact_factory_update (EMPATHY_TP_CONTACT_FACTORY (tp_factory));
1246 empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass)
1248 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1250 object_class->finalize = tp_contact_factory_finalize;
1251 object_class->constructor = tp_contact_factory_constructor;
1252 object_class->get_property = tp_contact_factory_get_property;
1253 object_class->set_property = tp_contact_factory_set_property;
1255 /* Construct-only properties */
1256 g_object_class_install_property (object_class,
1258 g_param_spec_object ("account",
1259 "Factory's Account",
1260 "The account associated with the factory",
1263 G_PARAM_CONSTRUCT_ONLY));
1265 g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv));
1269 empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory)
1271 EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
1273 priv->mc = empathy_mission_control_new ();
1274 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1275 "AccountStatusChanged",
1276 G_CALLBACK (tp_contact_factory_status_changed_cb),
1280 EmpathyTpContactFactory *
1281 empathy_tp_contact_factory_new (McAccount *account)
1283 return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY,