1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Collabora Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program 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 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
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-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_CONTACT_FACTORY, EmpathyContactFactoryPriv))
41 #define DEBUG_DOMAIN "ContactFactory"
43 struct _EmpathyContactFactoryPriv {
49 EmpathyContactFactory *factory;
51 guint nb_pending_calls;
54 DBusGProxy *aliasing_iface;
55 DBusGProxy *avatars_iface;
56 DBusGProxy *presence_iface;
57 DBusGProxy *capabilities_iface;
61 } ContactFactoryAccountData;
64 ContactFactoryAccountData *account_data;
69 ContactFactoryAccountData *account_data;
73 static void empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass);
74 static void empathy_contact_factory_init (EmpathyContactFactory *factory);
76 G_DEFINE_TYPE (EmpathyContactFactory, empathy_contact_factory, G_TYPE_OBJECT);
79 contact_factory_find_by_handle (gconstpointer a,
82 EmpathyContact *contact;
85 contact = EMPATHY_CONTACT (a);
86 handle = GPOINTER_TO_UINT (b);
88 return handle - empathy_contact_get_handle (contact);
91 static EmpathyContact *
92 contact_factory_account_data_find_by_handle (ContactFactoryAccountData *account_data,
97 l = g_list_find_custom (account_data->contacts,
98 GUINT_TO_POINTER (handle),
99 contact_factory_find_by_handle);
101 return l ? l->data : NULL;
105 contact_factory_find_by_id (gconstpointer a,
108 EmpathyContact *contact;
111 contact = EMPATHY_CONTACT (a);
113 return strcmp (id, empathy_contact_get_id (contact));
116 static EmpathyContact *
117 contact_factory_account_data_find_by_id (ContactFactoryAccountData *account_data,
122 l = g_list_find_custom (account_data->contacts,
124 contact_factory_find_by_id);
126 return l ? l->data : NULL;
129 static void contact_factory_account_data_free (gpointer data);
132 contact_factory_account_data_return_call (ContactFactoryAccountData *account_data)
134 if (--account_data->nb_pending_calls == 0 &&
135 account_data->contacts == NULL) {
136 contact_factory_account_data_free (account_data);
141 contact_factory_presences_table_foreach (const gchar *state_str,
142 GHashTable *presences_table,
143 EmpathyPresence **presence)
146 const GValue *message;
148 state = empathy_presence_state_from_str (state_str);
149 if (state == MC_PRESENCE_UNSET) {
154 g_object_unref (*presence);
158 *presence = empathy_presence_new ();
159 empathy_presence_set_state (*presence, state);
161 message = g_hash_table_lookup (presences_table, "message");
162 if (message != NULL) {
163 empathy_presence_set_status (*presence,
164 g_value_get_string (message));
169 contact_factory_parse_presence_foreach (guint handle,
170 GValueArray *presence_struct,
171 ContactFactoryAccountData *account_data)
173 GHashTable *presences_table;
174 EmpathyContact *contact;
175 EmpathyPresence *presence = NULL;
177 contact = contact_factory_account_data_find_by_handle (account_data,
183 presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1));
185 g_hash_table_foreach (presences_table,
186 (GHFunc) contact_factory_presences_table_foreach,
189 empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)",
190 empathy_contact_get_id (contact),
192 presence ? empathy_presence_get_status (presence) : "unset",
193 presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET);
195 empathy_contact_set_presence (contact, presence);
199 contact_factory_get_presence_cb (DBusGProxy *proxy,
200 GHashTable *handle_table,
204 ContactFactoryAccountData *account_data = user_data;
207 empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s",
212 g_hash_table_foreach (handle_table,
213 (GHFunc) contact_factory_parse_presence_foreach,
216 contact_factory_account_data_return_call (account_data);
220 contact_factory_presence_update_cb (DBusGProxy *proxy,
221 GHashTable *handle_table,
222 ContactFactoryAccountData *account_data)
224 g_hash_table_foreach (handle_table,
225 (GHFunc) contact_factory_parse_presence_foreach,
230 contact_factory_set_aliases_cb (DBusGProxy *proxy,
234 ContactFactoryAccountData *account_data = user_data;
237 empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s",
241 contact_factory_account_data_return_call (account_data);
245 contact_factory_request_aliases_cb (DBusGProxy *proxy,
246 gchar **contact_names,
250 RequestAliasesData *data = user_data;
255 empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s",
260 for (name = contact_names; *name; name++) {
261 EmpathyContact *contact;
263 contact = contact_factory_account_data_find_by_handle (data->account_data,
269 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)",
270 empathy_contact_get_id (contact),
271 data->handles[i], *name);
273 empathy_contact_set_name (contact, *name);
279 contact_factory_account_data_return_call (data->account_data);
280 g_free (data->handles);
281 g_slice_free (RequestAliasesData, data);
285 contact_factory_aliases_changed_cb (DBusGProxy *proxy,
286 GPtrArray *renamed_handlers,
289 ContactFactoryAccountData *account_data = user_data;
292 for (i = 0; renamed_handlers->len > i; i++) {
295 GValueArray *renamed_struct;
296 EmpathyContact *contact;
298 renamed_struct = g_ptr_array_index (renamed_handlers, i);
299 handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0));
300 alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1));
301 contact = contact_factory_account_data_find_by_handle (account_data, handle);
304 /* We don't know this contact, skip */
308 if (G_STR_EMPTY (alias)) {
312 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)",
313 empathy_contact_get_id (contact),
316 empathy_contact_set_name (contact, alias);
321 contact_factory_request_avatars_cb (DBusGProxy *proxy,
325 ContactFactoryAccountData *account_data = user_data;
328 empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s",
332 contact_factory_account_data_return_call (account_data);
336 contact_factory_avatar_updated_cb (DBusGProxy *proxy,
341 ContactFactoryAccountData *account_data = user_data;
344 handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1);
345 g_array_insert_val (handles, 0, handle);
347 account_data->nb_pending_calls++;
348 tp_conn_iface_avatars_request_avatars_async (account_data->avatars_iface,
350 contact_factory_request_avatars_cb,
352 g_array_free (handles, TRUE);
356 contact_factory_avatar_retrieved_cb (DBusGProxy *proxy,
363 ContactFactoryAccountData *account_data = user_data;
364 EmpathyContact *contact;
365 EmpathyAvatar *avatar;
367 contact = contact_factory_account_data_find_by_handle (account_data,
373 avatar = empathy_avatar_new (avatar_data->data,
376 empathy_contact_set_avatar (contact, avatar);
377 empathy_avatar_unref (avatar);
381 contact_factory_update_capabilities (ContactFactoryAccountData *account_data,
383 const gchar *channel_type,
387 EmpathyContact *contact;
388 EmpathyCapabilities capabilities;
390 contact = contact_factory_account_data_find_by_handle (account_data,
396 capabilities = empathy_contact_get_capabilities (contact);
398 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) {
399 capabilities &= !(EMPATHY_CAPABILITIES_AUDIO);
400 capabilities &= !(EMPATHY_CAPABILITIES_VIDEO);
401 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) {
402 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
404 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) {
405 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
409 empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d",
410 empathy_contact_get_id (contact),
411 empathy_contact_get_handle (contact),
414 empathy_contact_set_capabilities (contact, capabilities);
418 contact_factory_get_capabilities_cb (DBusGProxy *proxy,
419 GPtrArray *capabilities,
423 ContactFactoryAccountData *account_data = user_data;
427 empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s",
432 for (i = 0; i < capabilities->len; i++) {
435 const gchar *channel_type;
439 values = g_ptr_array_index (capabilities, i);
440 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
441 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
442 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
443 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
445 contact_factory_update_capabilities (account_data,
454 contact_factory_account_data_return_call (account_data);
458 contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
459 GPtrArray *capabilities,
462 ContactFactoryAccountData *account_data = user_data;
465 for (i = 0; i < capabilities->len; i++) {
468 const gchar *channel_type;
472 values = g_ptr_array_index (capabilities, i);
473 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
474 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
475 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
476 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
478 contact_factory_update_capabilities (account_data,
487 contact_factory_request_everything (ContactFactoryAccountData *account_data,
490 if (account_data->presence_iface) {
491 account_data->nb_pending_calls++;
492 tp_conn_iface_presence_get_presence_async (account_data->presence_iface,
494 contact_factory_get_presence_cb,
498 if (account_data->aliasing_iface) {
499 RequestAliasesData *data;
501 account_data->nb_pending_calls++;
502 data = g_slice_new (RequestAliasesData);
503 data->account_data = account_data;
504 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
506 tp_conn_iface_aliasing_request_aliases_async (account_data->aliasing_iface,
508 contact_factory_request_aliases_cb,
512 if (account_data->avatars_iface) {
513 account_data->nb_pending_calls++;
514 tp_conn_iface_avatars_request_avatars_async (account_data->avatars_iface,
516 contact_factory_request_avatars_cb,
520 if (account_data->capabilities_iface) {
521 account_data->nb_pending_calls++;
522 tp_conn_iface_capabilities_get_capabilities_async (account_data->capabilities_iface,
524 contact_factory_get_capabilities_cb,
530 contact_factory_request_handles_cb (DBusGProxy *proxy,
535 RequestHandlesData *data = user_data;
540 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
545 for (l = data->contacts; l; l = l->next) {
548 handle = g_array_index (handles, guint, i);
549 empathy_contact_set_handle (l->data, handle);
550 if (handle == data->account_data->self_handle) {
551 empathy_contact_set_is_user (l->data, TRUE);
557 contact_factory_request_everything (data->account_data, handles);
560 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
561 g_list_free (data->contacts);
562 contact_factory_account_data_return_call (data->account_data);
563 g_slice_free (RequestHandlesData, data);
567 contact_factory_disconnect_contact_foreach (gpointer data,
570 EmpathyContact *contact = data;
572 empathy_contact_set_presence (contact, NULL);
573 empathy_contact_set_handle (contact, 0);
577 contact_factory_destroy_cb (TpConn *tp_conn,
578 ContactFactoryAccountData *account_data)
580 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
582 g_object_unref (account_data->tp_conn);
583 account_data->tp_conn = NULL;
584 account_data->aliasing_iface = NULL;
585 account_data->avatars_iface = NULL;
586 account_data->presence_iface = NULL;
587 account_data->capabilities_iface = NULL;
589 g_list_foreach (account_data->contacts,
590 contact_factory_disconnect_contact_foreach,
595 contact_factory_account_data_disconnect (ContactFactoryAccountData *account_data)
597 if (account_data->aliasing_iface) {
598 dbus_g_proxy_disconnect_signal (account_data->aliasing_iface,
600 G_CALLBACK (contact_factory_aliases_changed_cb),
603 if (account_data->avatars_iface) {
604 dbus_g_proxy_disconnect_signal (account_data->avatars_iface,
606 G_CALLBACK (contact_factory_avatar_updated_cb),
608 dbus_g_proxy_disconnect_signal (account_data->avatars_iface,
610 G_CALLBACK (contact_factory_avatar_retrieved_cb),
613 if (account_data->presence_iface) {
614 dbus_g_proxy_disconnect_signal (account_data->presence_iface,
616 G_CALLBACK (contact_factory_presence_update_cb),
619 if (account_data->capabilities_iface) {
620 dbus_g_proxy_disconnect_signal (account_data->capabilities_iface,
621 "CapabilitiesChanged",
622 G_CALLBACK (contact_factory_capabilities_changed_cb),
625 if (account_data->tp_conn) {
626 g_signal_handlers_disconnect_by_func (account_data->tp_conn,
627 contact_factory_destroy_cb,
633 contact_factory_account_data_update (ContactFactoryAccountData *account_data)
635 EmpathyContactFactory *factory = account_data->factory;
636 EmpathyContactFactoryPriv *priv = GET_PRIV (factory);
637 McAccount *account = account_data->account;
638 TpConn *tp_conn = NULL;
639 RequestHandlesData *data;
640 const gchar **contact_ids;
645 if (account_data->account) {
648 /* status == 0 means the status is CONNECTED */
649 status = mission_control_get_connection_status (priv->mc,
652 tp_conn = mission_control_get_connection (priv->mc,
658 /* We are not connected anymore, remove the old connection */
659 contact_factory_account_data_disconnect (account_data);
660 if (account_data->tp_conn) {
661 contact_factory_destroy_cb (account_data->tp_conn,
666 else if (account_data->tp_conn) {
667 /* We were connected and we still are connected, nothing
668 * changed so nothing to do. */
669 g_object_unref (tp_conn);
673 /* We got a new connection */
674 account_data->tp_conn = tp_conn;
675 account_data->aliasing_iface = tp_conn_get_interface (tp_conn,
676 TELEPATHY_CONN_IFACE_ALIASING_QUARK);
677 account_data->avatars_iface = tp_conn_get_interface (tp_conn,
678 TELEPATHY_CONN_IFACE_AVATARS_QUARK);
679 account_data->presence_iface = tp_conn_get_interface (tp_conn,
680 TELEPATHY_CONN_IFACE_PRESENCE_QUARK);
681 account_data->capabilities_iface = tp_conn_get_interface (tp_conn,
682 TELEPATHY_CONN_IFACE_CAPABILITIES_QUARK);
684 /* Connect signals */
685 if (account_data->aliasing_iface) {
686 dbus_g_proxy_connect_signal (account_data->aliasing_iface,
688 G_CALLBACK (contact_factory_aliases_changed_cb),
691 if (account_data->avatars_iface) {
692 dbus_g_proxy_connect_signal (account_data->avatars_iface,
694 G_CALLBACK (contact_factory_avatar_updated_cb),
696 dbus_g_proxy_connect_signal (account_data->avatars_iface,
698 G_CALLBACK (contact_factory_avatar_retrieved_cb),
701 if (account_data->presence_iface) {
702 dbus_g_proxy_connect_signal (account_data->presence_iface,
704 G_CALLBACK (contact_factory_presence_update_cb),
707 if (account_data->capabilities_iface) {
708 dbus_g_proxy_connect_signal (account_data->capabilities_iface,
709 "CapabilitiesChanged",
710 G_CALLBACK (contact_factory_capabilities_changed_cb),
713 g_signal_connect (tp_conn, "destroy",
714 G_CALLBACK (contact_factory_destroy_cb),
717 /* Get our own handle */
718 if (!tp_conn_get_self_handle (DBUS_G_PROXY (account_data->tp_conn),
719 &account_data->self_handle,
721 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
722 error ? error->message : "No error given");
723 g_clear_error (&error);
726 /* Request new handles for all contacts */
727 if (account_data->contacts) {
728 data = g_slice_new (RequestHandlesData);
729 data->account_data = account_data;
730 data->contacts = g_list_copy (account_data->contacts);
731 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
733 i = g_list_length (data->contacts);
734 contact_ids = g_new0 (const gchar*, i + 1);
736 for (l = data->contacts; l; l = l->next) {
737 contact_ids[i] = empathy_contact_get_id (l->data);
741 account_data->nb_pending_calls++;
742 tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn),
743 TP_HANDLE_TYPE_CONTACT,
745 contact_factory_request_handles_cb,
747 g_free (contact_ids);
752 contact_factory_weak_notify (gpointer data,
753 GObject *where_the_object_was)
755 ContactFactoryAccountData *account_data = data;
757 empathy_debug (DEBUG_DOMAIN, "Remove finalized contact %p",
758 where_the_object_was);
760 account_data->contacts = g_list_remove (account_data->contacts,
761 where_the_object_was);
762 if (!account_data->contacts) {
763 EmpathyContactFactoryPriv *priv;
765 priv = GET_PRIV (account_data->factory);
767 g_hash_table_remove (priv->accounts, account_data->account);
772 contact_factory_remove_foreach (gpointer data,
775 ContactFactoryAccountData *account_data = user_data;
776 EmpathyContact *contact = data;
778 g_object_weak_unref (G_OBJECT (contact),
779 contact_factory_weak_notify,
783 static ContactFactoryAccountData *
784 contact_factory_account_data_new (EmpathyContactFactory *factory,
787 ContactFactoryAccountData *account_data;
789 account_data = g_slice_new0 (ContactFactoryAccountData);
790 account_data->factory = factory;
791 account_data->account = g_object_ref (account);
793 contact_factory_account_data_update (account_data);
799 contact_factory_account_data_free (gpointer data)
801 ContactFactoryAccountData *account_data = data;
803 contact_factory_account_data_disconnect (account_data);
805 if (account_data->contacts) {
806 g_list_foreach (account_data->contacts,
807 contact_factory_remove_foreach,
809 g_list_free (account_data->contacts);
810 account_data->contacts = NULL;
813 if (account_data->account) {
814 g_object_unref (account_data->account);
815 account_data->account = NULL;
818 if (account_data->tp_conn) {
819 g_object_unref (account_data->tp_conn);
820 account_data->tp_conn = NULL;
821 account_data->aliasing_iface = NULL;
822 account_data->avatars_iface = NULL;
823 account_data->presence_iface = NULL;
824 account_data->capabilities_iface = NULL;
827 /* Keep the struct alive if we have calls in flight, it will be
828 * destroyed once all calls returned. */
829 if (account_data->nb_pending_calls == 0) {
830 g_slice_free (ContactFactoryAccountData, account_data);
835 contact_factory_status_changed_cb (MissionControl *mc,
836 TelepathyConnectionStatus status,
838 TelepathyConnectionStatusReason reason,
839 const gchar *unique_name,
840 EmpathyContactFactory *factory)
842 EmpathyContactFactoryPriv *priv = GET_PRIV (factory);
843 ContactFactoryAccountData *account_data;
846 account = mc_account_lookup (unique_name);
847 account_data = g_hash_table_lookup (priv->accounts, account);
849 contact_factory_account_data_update (account_data);
851 g_object_unref (account);
854 static ContactFactoryAccountData *
855 contact_factory_account_data_get (EmpathyContactFactory *factory,
858 EmpathyContactFactoryPriv *priv = GET_PRIV (factory);
859 ContactFactoryAccountData *account_data;
861 account_data = g_hash_table_lookup (priv->accounts, account);
863 account_data = contact_factory_account_data_new (factory, account);
864 g_hash_table_insert (priv->accounts,
865 g_object_ref (account),
873 contact_factory_account_data_add_contact (ContactFactoryAccountData *account_data,
874 EmpathyContact *contact)
876 g_object_weak_ref (G_OBJECT (contact),
877 contact_factory_weak_notify,
879 account_data->contacts = g_list_prepend (account_data->contacts, contact);
881 if (!account_data->presence_iface) {
882 EmpathyPresence *presence;
884 /* We have no presence iface, set default presence
886 presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE,
889 empathy_contact_set_presence (contact, presence);
890 g_object_unref (presence);
893 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
894 empathy_contact_get_id (contact),
895 empathy_contact_get_handle (contact));
899 contact_factory_hold_handles_cb (DBusGProxy *proxy,
904 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
910 empathy_contact_factory_get_user (EmpathyContactFactory *factory,
913 ContactFactoryAccountData *account_data;
915 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
916 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
918 account_data = contact_factory_account_data_get (factory, account);
920 return empathy_contact_factory_get_from_handle (factory, account,
921 account_data->self_handle);
925 empathy_contact_factory_get_from_id (EmpathyContactFactory *factory,
929 ContactFactoryAccountData *account_data;
930 EmpathyContact *contact;
932 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
933 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
934 g_return_val_if_fail (id != NULL, NULL);
936 /* Check if the contact already exists */
937 account_data = contact_factory_account_data_get (factory, account);
938 contact = contact_factory_account_data_find_by_id (account_data, id);
940 return g_object_ref (contact);
943 /* Create new contact */
944 contact = g_object_new (EMPATHY_TYPE_CONTACT,
948 contact_factory_account_data_add_contact (account_data, contact);
950 /* If the account is connected, request contact's handle */
951 if (account_data->tp_conn) {
952 RequestHandlesData *data;
953 const gchar *contact_ids[] = {id, NULL};
955 account_data->nb_pending_calls++;
956 data = g_slice_new (RequestHandlesData);
957 data->account_data = account_data;
958 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
959 tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn),
960 TP_HANDLE_TYPE_CONTACT,
962 contact_factory_request_handles_cb,
970 empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory,
974 EmpathyContact *contact;
978 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
979 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
981 handles = g_array_new (FALSE, FALSE, sizeof (guint));
982 g_array_append_val (handles, handle);
984 contacts = empathy_contact_factory_get_from_handles (factory, account, handles);
985 g_array_free (handles, TRUE);
987 contact = contacts ? contacts->data : NULL;
988 g_list_free (contacts);
994 empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory,
998 ContactFactoryAccountData *account_data;
999 GList *contacts = NULL;
1000 GArray *new_handles;
1001 gchar **handles_names;
1003 GError *error = NULL;
1005 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
1006 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
1007 g_return_val_if_fail (handles != NULL, NULL);
1009 /* Search all contacts we already have */
1010 account_data = contact_factory_account_data_get (factory, account);
1011 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1012 for (i = 0; i < handles->len; i++) {
1013 EmpathyContact *contact;
1016 handle = g_array_index (handles, guint, i);
1021 contact = contact_factory_account_data_find_by_handle (account_data, handle);
1023 contacts = g_list_prepend (contacts, g_object_ref (contact));
1025 g_array_append_val (new_handles, handle);
1029 if (new_handles->len == 0) {
1030 g_array_free (new_handles, TRUE);
1034 /* Get the IDs of all new handles */
1035 if (!tp_conn_inspect_handles (DBUS_G_PROXY (account_data->tp_conn),
1036 TP_HANDLE_TYPE_CONTACT,
1040 empathy_debug (DEBUG_DOMAIN,
1041 "Couldn't inspect contact: %s",
1042 error ? error->message : "No error given");
1043 g_clear_error (&error);
1044 g_array_free (new_handles, TRUE);
1048 /* Create new contacts */
1049 for (i = 0; i < new_handles->len; i++) {
1050 EmpathyContact *contact;
1055 id = handles_names[i];
1056 handle = g_array_index (new_handles, guint, i);
1058 is_user = (handle == account_data->self_handle);
1059 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1065 contact_factory_account_data_add_contact (account_data,
1067 contacts = g_list_prepend (contacts, contact);
1070 g_free (handles_names);
1072 /* Hold all new handles. */
1073 tp_conn_hold_handles_async (DBUS_G_PROXY (account_data->tp_conn),
1074 TP_HANDLE_TYPE_CONTACT,
1076 contact_factory_hold_handles_cb,
1079 contact_factory_request_everything (account_data, new_handles);
1081 g_array_free (new_handles, TRUE);
1087 empathy_contact_factory_set_name (EmpathyContactFactory *factory,
1088 EmpathyContact *contact,
1091 ContactFactoryAccountData *account_data;
1093 GHashTable *new_alias;
1096 g_return_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory));
1097 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1099 account = empathy_contact_get_account (contact);
1100 account_data = contact_factory_account_data_get (factory, account);
1102 if (!account_data->aliasing_iface) {
1106 handle = empathy_contact_get_handle (contact);
1108 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1109 empathy_contact_get_id (contact),
1112 new_alias = g_hash_table_new_full (g_direct_hash,
1117 g_hash_table_insert (new_alias,
1118 GUINT_TO_POINTER (handle),
1121 account_data->nb_pending_calls++;
1122 tp_conn_iface_aliasing_set_aliases_async (account_data->aliasing_iface,
1124 contact_factory_set_aliases_cb,
1127 g_hash_table_destroy (new_alias);
1131 contact_factory_finalize (GObject *object)
1133 EmpathyContactFactoryPriv *priv;
1135 priv = GET_PRIV (object);
1137 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1138 "AccountStatusChanged",
1139 G_CALLBACK (contact_factory_status_changed_cb),
1142 g_hash_table_destroy (priv->accounts);
1143 g_object_unref (priv->mc);
1145 G_OBJECT_CLASS (empathy_contact_factory_parent_class)->finalize (object);
1149 empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass)
1151 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1153 object_class->finalize = contact_factory_finalize;
1155 g_type_class_add_private (object_class, sizeof (EmpathyContactFactoryPriv));
1159 empathy_contact_factory_init (EmpathyContactFactory *factory)
1161 EmpathyContactFactoryPriv *priv;
1163 priv = GET_PRIV (factory);
1165 priv->mc = empathy_mission_control_new ();
1166 priv->accounts = g_hash_table_new_full (empathy_account_hash,
1167 empathy_account_equal,
1169 contact_factory_account_data_free);
1171 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1172 "AccountStatusChanged",
1173 G_CALLBACK (contact_factory_status_changed_cb),
1177 EmpathyContactFactory *
1178 empathy_contact_factory_new (void)
1180 static EmpathyContactFactory *factory = NULL;
1183 factory = g_object_new (EMPATHY_TYPE_CONTACT_FACTORY, NULL);
1184 g_object_add_weak_pointer (G_OBJECT (factory), (gpointer) &factory);
1186 g_object_ref (factory);