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-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;
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_disconnect (ContactFactoryAccountData *account_data);
132 contact_factory_weak_notify (gpointer data,
133 GObject *where_the_object_was)
135 ContactFactoryAccountData *account_data = data;
137 empathy_debug (DEBUG_DOMAIN, "Remove finalized contact %p",
138 where_the_object_was);
140 account_data->contacts = g_list_remove (account_data->contacts,
141 where_the_object_was);
142 if (!account_data->contacts) {
143 EmpathyContactFactoryPriv *priv = GET_PRIV (account_data->factory);
145 g_hash_table_remove (priv->accounts, account_data->account);
150 contact_factory_remove_foreach (gpointer data,
153 ContactFactoryAccountData *account_data = user_data;
154 EmpathyContact *contact = data;
156 g_object_weak_unref (G_OBJECT (contact),
157 contact_factory_weak_notify,
161 static ContactFactoryAccountData *
162 contact_factory_account_data_ref (ContactFactoryAccountData *account_data)
164 account_data->refcount++;
170 contact_factory_account_data_unref (ContactFactoryAccountData *account_data)
172 account_data->refcount--;
173 if (account_data->refcount > 0) {
177 empathy_debug (DEBUG_DOMAIN, "Account data finalized: %p (%s)",
179 mc_account_get_normalized_name (account_data->account));
181 contact_factory_account_data_disconnect (account_data);
183 if (account_data->contacts) {
184 g_list_foreach (account_data->contacts,
185 contact_factory_remove_foreach,
187 g_list_free (account_data->contacts);
190 if (account_data->account) {
191 g_object_unref (account_data->account);
194 if (account_data->tp_conn) {
195 g_object_unref (account_data->tp_conn);
198 g_slice_free (ContactFactoryAccountData, account_data);
202 contact_factory_presences_table_foreach (const gchar *state_str,
203 GHashTable *presences_table,
204 EmpathyPresence **presence)
207 const GValue *message;
209 state = empathy_presence_state_from_str (state_str);
210 if (state == MC_PRESENCE_UNSET) {
215 g_object_unref (*presence);
219 *presence = empathy_presence_new ();
220 empathy_presence_set_state (*presence, state);
222 message = g_hash_table_lookup (presences_table, "message");
223 if (message != NULL) {
224 empathy_presence_set_status (*presence,
225 g_value_get_string (message));
230 contact_factory_parse_presence_foreach (guint handle,
231 GValueArray *presence_struct,
232 ContactFactoryAccountData *account_data)
234 GHashTable *presences_table;
235 EmpathyContact *contact;
236 EmpathyPresence *presence = NULL;
238 contact = contact_factory_account_data_find_by_handle (account_data,
244 presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1));
246 g_hash_table_foreach (presences_table,
247 (GHFunc) contact_factory_presences_table_foreach,
250 empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)",
251 empathy_contact_get_id (contact),
253 presence ? empathy_presence_get_status (presence) : "unset",
254 presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET);
256 empathy_contact_set_presence (contact, presence);
257 g_object_unref (presence);
261 contact_factory_get_presence_cb (DBusGProxy *proxy,
262 GHashTable *handle_table,
266 ContactFactoryAccountData *account_data = user_data;
269 empathy_debug (DEBUG_DOMAIN, "Error getting presence: %s",
274 g_hash_table_foreach (handle_table,
275 (GHFunc) contact_factory_parse_presence_foreach,
278 g_hash_table_destroy (handle_table);
280 contact_factory_account_data_unref (account_data);
284 contact_factory_presence_update_cb (DBusGProxy *proxy,
285 GHashTable *handle_table,
286 ContactFactoryAccountData *account_data)
288 g_hash_table_foreach (handle_table,
289 (GHFunc) contact_factory_parse_presence_foreach,
294 contact_factory_set_aliases_cb (DBusGProxy *proxy,
298 ContactFactoryAccountData *account_data = user_data;
301 empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s",
305 contact_factory_account_data_unref (account_data);
309 contact_factory_request_aliases_cb (DBusGProxy *proxy,
310 gchar **contact_names,
314 RequestAliasesData *data = user_data;
319 empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s",
324 for (name = contact_names; *name; name++) {
325 EmpathyContact *contact;
327 contact = contact_factory_account_data_find_by_handle (data->account_data,
333 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)",
334 empathy_contact_get_id (contact),
335 data->handles[i], *name);
337 empathy_contact_set_name (contact, *name);
342 g_strfreev (contact_names);
344 contact_factory_account_data_unref (data->account_data);
345 g_free (data->handles);
346 g_slice_free (RequestAliasesData, data);
350 contact_factory_aliases_changed_cb (DBusGProxy *proxy,
351 GPtrArray *renamed_handlers,
354 ContactFactoryAccountData *account_data = user_data;
357 for (i = 0; renamed_handlers->len > i; i++) {
360 GValueArray *renamed_struct;
361 EmpathyContact *contact;
363 renamed_struct = g_ptr_array_index (renamed_handlers, i);
364 handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0));
365 alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1));
366 contact = contact_factory_account_data_find_by_handle (account_data, handle);
369 /* We don't know this contact, skip */
373 if (G_STR_EMPTY (alias)) {
377 empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)",
378 empathy_contact_get_id (contact),
381 empathy_contact_set_name (contact, alias);
386 contact_factory_set_avatar_cb (DBusGProxy *proxy,
391 ContactFactoryAccountData *account_data = user_data;
394 empathy_debug (DEBUG_DOMAIN, "Error setting avatar: %s",
398 contact_factory_account_data_unref (account_data);
403 contact_factory_clear_avatar_cb (DBusGProxy *proxy,
407 ContactFactoryAccountData *account_data = user_data;
410 empathy_debug (DEBUG_DOMAIN, "Error clearing avatar: %s",
414 contact_factory_account_data_unref (account_data);
418 contact_factory_avatar_retrieved_cb (DBusGProxy *proxy,
425 ContactFactoryAccountData *account_data = user_data;
426 EmpathyContact *contact;
427 EmpathyAvatar *avatar;
429 contact = contact_factory_account_data_find_by_handle (account_data,
435 empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)",
436 empathy_contact_get_id (contact),
439 avatar = empathy_avatar_new (avatar_data->data,
444 empathy_contact_set_avatar (contact, avatar);
445 empathy_avatar_unref (avatar);
449 contact_factory_request_avatars_cb (DBusGProxy *proxy,
453 ContactFactoryAccountData *account_data = user_data;
456 empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s",
460 contact_factory_account_data_unref (account_data);
464 ContactFactoryAccountData *account_data;
469 contact_factory_avatar_maybe_update (ContactFactoryAccountData *account_data,
473 EmpathyContact *contact;
474 EmpathyAvatar *avatar;
476 contact = contact_factory_account_data_find_by_handle (account_data,
482 /* Check if we have an avatar */
483 if (G_STR_EMPTY (token)) {
484 empathy_contact_set_avatar (contact, NULL);
488 /* Check if the avatar changed */
489 avatar = empathy_contact_get_avatar (contact);
490 if (avatar && !tp_strdiff (avatar->token, token)) {
494 /* The avatar changed, search the new one in the cache */
495 avatar = empathy_avatar_new_from_cache (token);
497 /* Got from cache, use it */
498 empathy_contact_set_avatar (contact, avatar);
499 empathy_avatar_unref (avatar);
503 /* Avatar is not up-to-date, we have to request it. */
508 contact_factory_avatar_tokens_foreach (gpointer key,
512 TokensData *data = user_data;
513 const gchar *token = value;
514 guint handle = GPOINTER_TO_UINT (key);
516 if (!contact_factory_avatar_maybe_update (data->account_data,
518 g_array_append_val (data->handles, handle);
523 contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy,
528 ContactFactoryAccountData *account_data = user_data;
532 empathy_debug (DEBUG_DOMAIN,
533 "Error getting known avatars tokens: %s",
538 data.account_data = account_data;
539 data.handles = g_array_new (FALSE, FALSE, sizeof (guint));
540 g_hash_table_foreach (tokens,
541 contact_factory_avatar_tokens_foreach,
544 empathy_debug (DEBUG_DOMAIN, "Got %d tokens, need to request %d avatars",
545 g_hash_table_size (tokens),
548 /* Request needed avatars */
549 if (data.handles->len > 0) {
550 tp_conn_iface_avatars_request_avatars_async (account_data->avatars_iface,
552 contact_factory_request_avatars_cb,
553 contact_factory_account_data_ref (account_data));
556 g_hash_table_destroy (tokens);
557 g_array_free (data.handles, TRUE);
559 contact_factory_account_data_unref (account_data);
563 contact_factory_avatar_updated_cb (DBusGProxy *proxy,
568 ContactFactoryAccountData *account_data = user_data;
571 if (contact_factory_avatar_maybe_update (account_data, handle, new_token)) {
572 /* Avatar was cached, nothing to do */
576 empathy_debug (DEBUG_DOMAIN, "Need to request avatar for token %s",
579 handles = g_array_new (FALSE, FALSE, sizeof (guint));
580 g_array_append_val (handles, handle);
582 tp_conn_iface_avatars_request_avatars_async (account_data->avatars_iface,
584 contact_factory_request_avatars_cb,
585 contact_factory_account_data_ref (account_data));
586 g_array_free (handles, TRUE);
590 contact_factory_update_capabilities (ContactFactoryAccountData *account_data,
592 const gchar *channel_type,
596 EmpathyContact *contact;
597 EmpathyCapabilities capabilities;
599 contact = contact_factory_account_data_find_by_handle (account_data,
605 capabilities = empathy_contact_get_capabilities (contact);
607 if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) {
608 capabilities &= ~EMPATHY_CAPABILITIES_AUDIO;
609 capabilities &= ~EMPATHY_CAPABILITIES_VIDEO;
610 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) {
611 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
613 if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) {
614 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
618 empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d",
619 empathy_contact_get_id (contact),
620 empathy_contact_get_handle (contact),
623 empathy_contact_set_capabilities (contact, capabilities);
627 contact_factory_get_capabilities_cb (DBusGProxy *proxy,
628 GPtrArray *capabilities,
632 ContactFactoryAccountData *account_data = user_data;
636 empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s",
641 for (i = 0; i < capabilities->len; i++) {
644 const gchar *channel_type;
648 values = g_ptr_array_index (capabilities, i);
649 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
650 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
651 generic = g_value_get_uint (g_value_array_get_nth (values, 2));
652 specific = g_value_get_uint (g_value_array_get_nth (values, 3));
654 contact_factory_update_capabilities (account_data,
660 g_value_array_free (values);
663 g_ptr_array_free (capabilities, TRUE);
665 contact_factory_account_data_unref (account_data);
669 contact_factory_capabilities_changed_cb (DBusGProxy *proxy,
670 GPtrArray *capabilities,
673 ContactFactoryAccountData *account_data = user_data;
676 for (i = 0; i < capabilities->len; i++) {
679 const gchar *channel_type;
683 values = g_ptr_array_index (capabilities, i);
684 handle = g_value_get_uint (g_value_array_get_nth (values, 0));
685 channel_type = g_value_get_string (g_value_array_get_nth (values, 1));
686 generic = g_value_get_uint (g_value_array_get_nth (values, 3));
687 specific = g_value_get_uint (g_value_array_get_nth (values, 5));
689 contact_factory_update_capabilities (account_data,
698 contact_factory_request_everything (ContactFactoryAccountData *account_data,
701 if (account_data->presence_iface) {
702 tp_conn_iface_presence_get_presence_async (account_data->presence_iface,
704 contact_factory_get_presence_cb,
705 contact_factory_account_data_ref (account_data));
708 if (account_data->aliasing_iface) {
709 RequestAliasesData *data;
711 data = g_slice_new (RequestAliasesData);
712 data->account_data = contact_factory_account_data_ref (account_data);
713 data->handles = g_memdup (handles->data, handles->len * sizeof (guint));
715 tp_conn_iface_aliasing_request_aliases_async (account_data->aliasing_iface,
717 contact_factory_request_aliases_cb,
721 if (account_data->avatars_iface) {
722 tp_conn_iface_avatars_get_known_avatar_tokens_async (account_data->avatars_iface,
724 contact_factory_get_known_avatar_tokens_cb,
725 contact_factory_account_data_ref (account_data));
728 if (account_data->capabilities_iface) {
729 tp_conn_iface_capabilities_get_capabilities_async (account_data->capabilities_iface,
731 contact_factory_get_capabilities_cb,
732 contact_factory_account_data_ref (account_data));
737 contact_factory_request_handles_cb (DBusGProxy *proxy,
742 RequestHandlesData *data = user_data;
747 empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s",
752 for (l = data->contacts; l; l = l->next) {
755 handle = g_array_index (handles, guint, i);
756 empathy_contact_set_handle (l->data, handle);
757 if (handle == data->account_data->self_handle) {
758 empathy_contact_set_is_user (l->data, TRUE);
764 contact_factory_request_everything (data->account_data, handles);
765 g_array_free (handles, TRUE);
768 g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL);
769 g_list_free (data->contacts);
770 contact_factory_account_data_unref (data->account_data);
771 g_slice_free (RequestHandlesData, data);
775 contact_factory_disconnect_contact_foreach (gpointer data,
778 EmpathyContact *contact = data;
780 empathy_contact_set_presence (contact, NULL);
781 empathy_contact_set_handle (contact, 0);
785 contact_factory_destroy_cb (TpConn *tp_conn,
786 ContactFactoryAccountData *account_data)
788 empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed");
790 g_object_unref (account_data->tp_conn);
791 account_data->tp_conn = NULL;
792 account_data->aliasing_iface = NULL;
793 account_data->avatars_iface = NULL;
794 account_data->presence_iface = NULL;
795 account_data->capabilities_iface = NULL;
797 g_list_foreach (account_data->contacts,
798 contact_factory_disconnect_contact_foreach,
803 contact_factory_account_data_disconnect (ContactFactoryAccountData *account_data)
805 if (account_data->aliasing_iface) {
806 dbus_g_proxy_disconnect_signal (account_data->aliasing_iface,
808 G_CALLBACK (contact_factory_aliases_changed_cb),
811 if (account_data->avatars_iface) {
812 dbus_g_proxy_disconnect_signal (account_data->avatars_iface,
814 G_CALLBACK (contact_factory_avatar_updated_cb),
816 dbus_g_proxy_disconnect_signal (account_data->avatars_iface,
818 G_CALLBACK (contact_factory_avatar_retrieved_cb),
821 if (account_data->presence_iface) {
822 dbus_g_proxy_disconnect_signal (account_data->presence_iface,
824 G_CALLBACK (contact_factory_presence_update_cb),
827 if (account_data->capabilities_iface) {
828 dbus_g_proxy_disconnect_signal (account_data->capabilities_iface,
829 "CapabilitiesChanged",
830 G_CALLBACK (contact_factory_capabilities_changed_cb),
833 if (account_data->tp_conn) {
834 g_signal_handlers_disconnect_by_func (account_data->tp_conn,
835 contact_factory_destroy_cb,
841 contact_factory_account_data_update (ContactFactoryAccountData *account_data)
843 EmpathyContactFactory *factory = account_data->factory;
844 EmpathyContactFactoryPriv *priv = GET_PRIV (factory);
845 McAccount *account = account_data->account;
846 TpConn *tp_conn = NULL;
847 RequestHandlesData *data;
848 const gchar **contact_ids;
851 GError *error = NULL;
853 if (account_data->account) {
856 /* status == 0 means the status is CONNECTED */
857 status = mission_control_get_connection_status (priv->mc,
860 tp_conn = mission_control_get_connection (priv->mc,
866 /* We are not connected anymore, remove the old connection */
867 contact_factory_account_data_disconnect (account_data);
868 if (account_data->tp_conn) {
869 contact_factory_destroy_cb (account_data->tp_conn,
874 else if (account_data->tp_conn) {
875 /* We were connected and we still are connected, nothing
876 * changed so nothing to do. */
877 g_object_unref (tp_conn);
881 /* We got a new connection */
882 account_data->tp_conn = tp_conn;
883 account_data->aliasing_iface = tp_conn_get_interface (tp_conn,
884 TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING);
885 account_data->avatars_iface = tp_conn_get_interface (tp_conn,
886 TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS);
887 account_data->presence_iface = tp_conn_get_interface (tp_conn,
888 TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE);
889 account_data->capabilities_iface = tp_conn_get_interface (tp_conn,
890 TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
892 /* Connect signals */
893 if (account_data->aliasing_iface) {
894 dbus_g_proxy_connect_signal (account_data->aliasing_iface,
896 G_CALLBACK (contact_factory_aliases_changed_cb),
899 if (account_data->avatars_iface) {
900 dbus_g_proxy_connect_signal (account_data->avatars_iface,
902 G_CALLBACK (contact_factory_avatar_updated_cb),
904 dbus_g_proxy_connect_signal (account_data->avatars_iface,
906 G_CALLBACK (contact_factory_avatar_retrieved_cb),
909 if (account_data->presence_iface) {
910 dbus_g_proxy_connect_signal (account_data->presence_iface,
912 G_CALLBACK (contact_factory_presence_update_cb),
915 if (account_data->capabilities_iface) {
916 dbus_g_proxy_connect_signal (account_data->capabilities_iface,
917 "CapabilitiesChanged",
918 G_CALLBACK (contact_factory_capabilities_changed_cb),
921 g_signal_connect (tp_conn, "destroy",
922 G_CALLBACK (contact_factory_destroy_cb),
925 /* Get our own handle */
926 if (!tp_conn_get_self_handle (DBUS_G_PROXY (account_data->tp_conn),
927 &account_data->self_handle,
929 empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s",
930 error ? error->message : "No error given");
931 g_clear_error (&error);
934 /* Request new handles for all contacts */
935 if (account_data->contacts) {
936 data = g_slice_new (RequestHandlesData);
937 data->account_data = contact_factory_account_data_ref (account_data);
938 data->contacts = g_list_copy (account_data->contacts);
939 g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL);
941 i = g_list_length (data->contacts);
942 contact_ids = g_new0 (const gchar*, i + 1);
944 for (l = data->contacts; l; l = l->next) {
945 contact_ids[i] = empathy_contact_get_id (l->data);
949 tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn),
950 TP_HANDLE_TYPE_CONTACT,
952 contact_factory_request_handles_cb,
954 g_free (contact_ids);
958 static ContactFactoryAccountData *
959 contact_factory_account_data_new (EmpathyContactFactory *factory,
962 ContactFactoryAccountData *account_data;
964 account_data = g_slice_new0 (ContactFactoryAccountData);
965 account_data->factory = factory;
966 account_data->account = g_object_ref (account);
967 account_data->refcount = 1;
969 contact_factory_account_data_update (account_data);
975 contact_factory_status_changed_cb (MissionControl *mc,
976 TpConnectionStatus status,
978 TpConnectionStatusReason reason,
979 const gchar *unique_name,
980 EmpathyContactFactory *factory)
982 EmpathyContactFactoryPriv *priv = GET_PRIV (factory);
983 ContactFactoryAccountData *account_data;
986 account = mc_account_lookup (unique_name);
987 account_data = g_hash_table_lookup (priv->accounts, account);
989 contact_factory_account_data_update (account_data);
991 g_object_unref (account);
994 static ContactFactoryAccountData *
995 contact_factory_account_data_get (EmpathyContactFactory *factory,
998 EmpathyContactFactoryPriv *priv = GET_PRIV (factory);
999 ContactFactoryAccountData *account_data;
1001 account_data = g_hash_table_lookup (priv->accounts, account);
1002 if (!account_data) {
1003 account_data = contact_factory_account_data_new (factory, account);
1004 g_hash_table_insert (priv->accounts,
1005 g_object_ref (account),
1009 return account_data;
1013 contact_factory_account_data_add_contact (ContactFactoryAccountData *account_data,
1014 EmpathyContact *contact)
1016 g_object_weak_ref (G_OBJECT (contact),
1017 contact_factory_weak_notify,
1019 account_data->contacts = g_list_prepend (account_data->contacts, contact);
1021 if (!account_data->presence_iface) {
1022 EmpathyPresence *presence;
1024 /* We have no presence iface, set default presence
1026 presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE,
1029 empathy_contact_set_presence (contact, presence);
1030 g_object_unref (presence);
1033 empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)",
1034 empathy_contact_get_id (contact),
1035 empathy_contact_get_handle (contact));
1039 contact_factory_hold_handles_cb (DBusGProxy *proxy,
1044 empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s",
1050 empathy_contact_factory_get_user (EmpathyContactFactory *factory,
1053 ContactFactoryAccountData *account_data;
1055 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
1056 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
1058 account_data = contact_factory_account_data_get (factory, account);
1060 return empathy_contact_factory_get_from_handle (factory, account,
1061 account_data->self_handle);
1065 empathy_contact_factory_get_from_id (EmpathyContactFactory *factory,
1069 ContactFactoryAccountData *account_data;
1070 EmpathyContact *contact;
1072 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
1073 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
1074 g_return_val_if_fail (id != NULL, NULL);
1076 /* Check if the contact already exists */
1077 account_data = contact_factory_account_data_get (factory, account);
1078 contact = contact_factory_account_data_find_by_id (account_data, id);
1080 return g_object_ref (contact);
1083 /* Create new contact */
1084 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1088 contact_factory_account_data_add_contact (account_data, contact);
1090 /* If the account is connected, request contact's handle */
1091 if (account_data->tp_conn) {
1092 RequestHandlesData *data;
1093 const gchar *contact_ids[] = {id, NULL};
1095 data = g_slice_new (RequestHandlesData);
1096 data->account_data = contact_factory_account_data_ref (account_data);
1097 data->contacts = g_list_prepend (NULL, g_object_ref (contact));
1098 tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn),
1099 TP_HANDLE_TYPE_CONTACT,
1101 contact_factory_request_handles_cb,
1109 empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory,
1113 EmpathyContact *contact;
1117 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
1118 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
1120 handles = g_array_new (FALSE, FALSE, sizeof (guint));
1121 g_array_append_val (handles, handle);
1123 contacts = empathy_contact_factory_get_from_handles (factory, account, handles);
1124 g_array_free (handles, TRUE);
1126 contact = contacts ? contacts->data : NULL;
1127 g_list_free (contacts);
1133 empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory,
1137 ContactFactoryAccountData *account_data;
1138 GList *contacts = NULL;
1139 GArray *new_handles;
1140 gchar **handles_names;
1142 GError *error = NULL;
1144 g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL);
1145 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
1146 g_return_val_if_fail (handles != NULL, NULL);
1148 /* Search all contacts we already have */
1149 account_data = contact_factory_account_data_get (factory, account);
1150 new_handles = g_array_new (FALSE, FALSE, sizeof (guint));
1151 for (i = 0; i < handles->len; i++) {
1152 EmpathyContact *contact;
1155 handle = g_array_index (handles, guint, i);
1160 contact = contact_factory_account_data_find_by_handle (account_data, handle);
1162 contacts = g_list_prepend (contacts, g_object_ref (contact));
1164 g_array_append_val (new_handles, handle);
1168 if (new_handles->len == 0) {
1169 g_array_free (new_handles, TRUE);
1173 /* Get the IDs of all new handles */
1174 if (!tp_conn_inspect_handles (DBUS_G_PROXY (account_data->tp_conn),
1175 TP_HANDLE_TYPE_CONTACT,
1179 empathy_debug (DEBUG_DOMAIN,
1180 "Couldn't inspect contact: %s",
1181 error ? error->message : "No error given");
1182 g_clear_error (&error);
1183 g_array_free (new_handles, TRUE);
1187 /* Create new contacts */
1188 for (i = 0; i < new_handles->len; i++) {
1189 EmpathyContact *contact;
1194 id = handles_names[i];
1195 handle = g_array_index (new_handles, guint, i);
1197 is_user = (handle == account_data->self_handle);
1198 contact = g_object_new (EMPATHY_TYPE_CONTACT,
1204 contact_factory_account_data_add_contact (account_data,
1206 contacts = g_list_prepend (contacts, contact);
1209 g_free (handles_names);
1211 /* Hold all new handles. */
1212 tp_conn_hold_handles_async (DBUS_G_PROXY (account_data->tp_conn),
1213 TP_HANDLE_TYPE_CONTACT,
1215 contact_factory_hold_handles_cb,
1218 contact_factory_request_everything (account_data, new_handles);
1220 g_array_free (new_handles, TRUE);
1226 empathy_contact_factory_set_alias (EmpathyContactFactory *factory,
1227 EmpathyContact *contact,
1230 ContactFactoryAccountData *account_data;
1232 GHashTable *new_alias;
1235 g_return_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory));
1236 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1238 account = empathy_contact_get_account (contact);
1239 account_data = contact_factory_account_data_get (factory, account);
1241 if (!account_data->aliasing_iface) {
1245 handle = empathy_contact_get_handle (contact);
1247 empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s",
1248 empathy_contact_get_id (contact),
1251 new_alias = g_hash_table_new_full (g_direct_hash,
1256 g_hash_table_insert (new_alias,
1257 GUINT_TO_POINTER (handle),
1260 tp_conn_iface_aliasing_set_aliases_async (account_data->aliasing_iface,
1262 contact_factory_set_aliases_cb,
1263 contact_factory_account_data_ref (account_data));
1265 g_hash_table_destroy (new_alias);
1269 empathy_contact_factory_set_avatar (EmpathyContactFactory *factory,
1273 const gchar *mime_type)
1275 ContactFactoryAccountData *account_data;
1277 g_return_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory));
1278 g_return_if_fail (MC_IS_ACCOUNT (account));
1280 account_data = contact_factory_account_data_get (factory, account);
1282 if (!account_data->avatars_iface) {
1286 if (data && size > 0 && size < G_MAXUINT) {
1289 avatar.data = (gchar*) data;
1292 empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s",
1293 mc_account_get_unique_name (account));
1295 tp_conn_iface_avatars_set_avatar_async (account_data->avatars_iface,
1298 contact_factory_set_avatar_cb,
1299 contact_factory_account_data_ref (account_data));
1301 empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s",
1302 mc_account_get_unique_name (account));
1303 tp_conn_iface_avatars_clear_avatar_async (account_data->avatars_iface,
1304 contact_factory_clear_avatar_cb,
1305 contact_factory_account_data_ref (account_data));
1310 contact_factory_finalize (GObject *object)
1312 EmpathyContactFactoryPriv *priv;
1314 priv = GET_PRIV (object);
1316 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
1317 "AccountStatusChanged",
1318 G_CALLBACK (contact_factory_status_changed_cb),
1321 g_hash_table_destroy (priv->accounts);
1322 g_object_unref (priv->mc);
1324 G_OBJECT_CLASS (empathy_contact_factory_parent_class)->finalize (object);
1328 empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass)
1330 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1332 object_class->finalize = contact_factory_finalize;
1334 g_type_class_add_private (object_class, sizeof (EmpathyContactFactoryPriv));
1338 empathy_contact_factory_init (EmpathyContactFactory *factory)
1340 EmpathyContactFactoryPriv *priv;
1342 priv = GET_PRIV (factory);
1344 priv->mc = empathy_mission_control_new ();
1345 priv->accounts = g_hash_table_new_full (empathy_account_hash,
1346 empathy_account_equal,
1348 (GDestroyNotify) contact_factory_account_data_unref);
1350 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
1351 "AccountStatusChanged",
1352 G_CALLBACK (contact_factory_status_changed_cb),
1356 EmpathyContactFactory *
1357 empathy_contact_factory_new (void)
1359 static EmpathyContactFactory *factory = NULL;
1362 factory = g_object_new (EMPATHY_TYPE_CONTACT_FACTORY, NULL);
1363 g_object_add_weak_pointer (G_OBJECT (factory), (gpointer) &factory);
1365 g_object_ref (factory);