From 0b4abd3ca3f42267963cf570a7161c4f5dced537 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 12 Dec 2007 15:38:10 +0000 Subject: Split EmpathyContactFactory to have one EmpathyTpContactFactory per account svn path=/trunk/; revision=472 --- libempathy/Makefile.am | 2 + libempathy/empathy-contact-factory.c | 1259 +---------------------------- libempathy/empathy-tp-contact-factory.c | 1307 +++++++++++++++++++++++++++++++ libempathy/empathy-tp-contact-factory.h | 71 ++ 4 files changed, 1414 insertions(+), 1225 deletions(-) create mode 100644 libempathy/empathy-tp-contact-factory.c create mode 100644 libempathy/empathy-tp-contact-factory.h (limited to 'libempathy') diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index 6d66c9321..733289f51 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -29,6 +29,7 @@ libempathy_la_SOURCES = \ empathy-contact-list.c \ empathy-contact-manager.c \ empathy-contact-factory.c \ + empathy-tp-contact-factory.c \ empathy-tp-group.c \ empathy-tp-contact-list.c \ empathy-tp-chat.c \ @@ -64,6 +65,7 @@ libempathy_headers = \ empathy-contact-list.h \ empathy-contact-manager.h \ empathy-contact-factory.h \ + empathy-tp-contact-factory.h \ empathy-tp-group.h \ empathy-tp-contact-list.h \ empathy-tp-chat.h \ diff --git a/libempathy/empathy-contact-factory.c b/libempathy/empathy-contact-factory.c index 3365f1710..125afdb62 100644 --- a/libempathy/empathy-contact-factory.c +++ b/libempathy/empathy-contact-factory.c @@ -21,1044 +21,49 @@ #include -#include - -#include -#include -#include -#include -#include -#include -#include - #include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-utils.h" -#include "empathy-debug.h" #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ EMPATHY_TYPE_CONTACT_FACTORY, EmpathyContactFactoryPriv)) -#define DEBUG_DOMAIN "ContactFactory" - struct _EmpathyContactFactoryPriv { - MissionControl *mc; - GHashTable *accounts; + GHashTable *accounts; }; -typedef struct { - EmpathyContactFactory *factory; - McAccount *account; - guint refcount; - - TpConn *tp_conn; - DBusGProxy *aliasing_iface; - DBusGProxy *avatars_iface; - DBusGProxy *presence_iface; - DBusGProxy *capabilities_iface; - - GList *contacts; - guint self_handle; -} ContactFactoryAccountData; - -typedef struct { - ContactFactoryAccountData *account_data; - GList *contacts; -} RequestHandlesData; - -typedef struct { - ContactFactoryAccountData *account_data; - guint *handles; -} RequestAliasesData; - static void empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass); static void empathy_contact_factory_init (EmpathyContactFactory *factory); G_DEFINE_TYPE (EmpathyContactFactory, empathy_contact_factory, G_TYPE_OBJECT); -static gint -contact_factory_find_by_handle (gconstpointer a, - gconstpointer b) -{ - EmpathyContact *contact; - guint handle; - - contact = EMPATHY_CONTACT (a); - handle = GPOINTER_TO_UINT (b); - - return handle - empathy_contact_get_handle (contact); -} - -static EmpathyContact * -contact_factory_account_data_find_by_handle (ContactFactoryAccountData *account_data, - guint handle) -{ - GList *l; - - l = g_list_find_custom (account_data->contacts, - GUINT_TO_POINTER (handle), - contact_factory_find_by_handle); - - return l ? l->data : NULL; -} - -static gint -contact_factory_find_by_id (gconstpointer a, - gconstpointer b) -{ - EmpathyContact *contact; - const gchar *id = b; - - contact = EMPATHY_CONTACT (a); - - return strcmp (id, empathy_contact_get_id (contact)); -} - -static EmpathyContact * -contact_factory_account_data_find_by_id (ContactFactoryAccountData *account_data, - const gchar *id) -{ - GList *l; - - l = g_list_find_custom (account_data->contacts, - id, - contact_factory_find_by_id); - - return l ? l->data : NULL; -} - -static void contact_factory_account_data_disconnect (ContactFactoryAccountData *account_data); - -static void -contact_factory_weak_notify (gpointer data, - GObject *where_the_object_was) -{ - ContactFactoryAccountData *account_data = data; - - empathy_debug (DEBUG_DOMAIN, "Remove finalized contact %p", - where_the_object_was); - - account_data->contacts = g_list_remove (account_data->contacts, - where_the_object_was); - if (!account_data->contacts) { - EmpathyContactFactoryPriv *priv = GET_PRIV (account_data->factory); - - g_hash_table_remove (priv->accounts, account_data->account); - } -} - -static void -contact_factory_remove_foreach (gpointer data, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - EmpathyContact *contact = data; - - g_object_weak_unref (G_OBJECT (contact), - contact_factory_weak_notify, - account_data); -} - -static ContactFactoryAccountData * -contact_factory_account_data_ref (ContactFactoryAccountData *account_data) -{ - account_data->refcount++; - - return account_data; -} - -static void -contact_factory_account_data_unref (ContactFactoryAccountData *account_data) -{ - account_data->refcount--; - if (account_data->refcount > 0) { - return; - } - - empathy_debug (DEBUG_DOMAIN, "Account data finalized: %p (%s)", - account_data, - mc_account_get_normalized_name (account_data->account)); - - contact_factory_account_data_disconnect (account_data); - - if (account_data->contacts) { - g_list_foreach (account_data->contacts, - contact_factory_remove_foreach, - account_data); - g_list_free (account_data->contacts); - } - - if (account_data->account) { - g_object_unref (account_data->account); - } - - if (account_data->tp_conn) { - g_object_unref (account_data->tp_conn); - } - - g_slice_free (ContactFactoryAccountData, account_data); -} - -static void -contact_factory_presences_table_foreach (const gchar *state_str, - GHashTable *presences_table, - EmpathyPresence **presence) -{ - McPresence state; - const GValue *message; - - state = empathy_presence_state_from_str (state_str); - if (state == MC_PRESENCE_UNSET) { - return; - } - - if (*presence) { - g_object_unref (*presence); - *presence = NULL; - } - - *presence = empathy_presence_new (); - empathy_presence_set_state (*presence, state); - - message = g_hash_table_lookup (presences_table, "message"); - if (message != NULL) { - empathy_presence_set_status (*presence, - g_value_get_string (message)); - } -} - -static void -contact_factory_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - ContactFactoryAccountData *account_data) -{ - GHashTable *presences_table; - EmpathyContact *contact; - EmpathyPresence *presence = NULL; - - contact = contact_factory_account_data_find_by_handle (account_data, - handle); - if (!contact) { - return; - } - - presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1)); - - g_hash_table_foreach (presences_table, - (GHFunc) contact_factory_presences_table_foreach, - &presence); - - empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)", - empathy_contact_get_id (contact), - handle, - presence ? empathy_presence_get_status (presence) : "unset", - presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET); - - empathy_contact_set_presence (contact, presence); - g_object_unref (presence); -} - -static void -contact_factory_get_presence_cb (DBusGProxy *proxy, - GHashTable *handle_table, - GError *error, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error getting presence: %s", - error->message); - goto OUT; - } - - g_hash_table_foreach (handle_table, - (GHFunc) contact_factory_parse_presence_foreach, - account_data); - - g_hash_table_destroy (handle_table); -OUT: - contact_factory_account_data_unref (account_data); -} - -static void -contact_factory_presence_update_cb (DBusGProxy *proxy, - GHashTable *handle_table, - ContactFactoryAccountData *account_data) -{ - g_hash_table_foreach (handle_table, - (GHFunc) contact_factory_parse_presence_foreach, - account_data); -} - -static void -contact_factory_set_aliases_cb (DBusGProxy *proxy, - GError *error, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s", - error->message); - } - - contact_factory_account_data_unref (account_data); -} - -static void -contact_factory_request_aliases_cb (DBusGProxy *proxy, - gchar **contact_names, - GError *error, - gpointer user_data) -{ - RequestAliasesData *data = user_data; - guint i = 0; - gchar **name; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s", - error->message); - goto OUT; - } - - for (name = contact_names; *name; name++) { - EmpathyContact *contact; - - contact = contact_factory_account_data_find_by_handle (data->account_data, - data->handles[i]); - if (!contact) { - continue; - } - - empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)", - empathy_contact_get_id (contact), - data->handles[i], *name); - - empathy_contact_set_name (contact, *name); - - i++; - } - - g_strfreev (contact_names); -OUT: - contact_factory_account_data_unref (data->account_data); - g_free (data->handles); - g_slice_free (RequestAliasesData, data); -} - -static void -contact_factory_aliases_changed_cb (DBusGProxy *proxy, - GPtrArray *renamed_handlers, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - guint i; - - for (i = 0; renamed_handlers->len > i; i++) { - guint handle; - const gchar *alias; - GValueArray *renamed_struct; - EmpathyContact *contact; - - renamed_struct = g_ptr_array_index (renamed_handlers, i); - handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0)); - alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1)); - contact = contact_factory_account_data_find_by_handle (account_data, handle); - - if (!contact) { - /* We don't know this contact, skip */ - continue; - } - - if (G_STR_EMPTY (alias)) { - alias = NULL; - } - - empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)", - empathy_contact_get_id (contact), - handle, alias); - - empathy_contact_set_name (contact, alias); - } -} - -static void -contact_factory_set_avatar_cb (DBusGProxy *proxy, - gchar *token, - GError *error, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error setting avatar: %s", - error->message); - } - - contact_factory_account_data_unref (account_data); - g_free (token); -} - -static void -contact_factory_clear_avatar_cb (DBusGProxy *proxy, - GError *error, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error clearing avatar: %s", - error->message); - } - - contact_factory_account_data_unref (account_data); -} - -static void -contact_factory_avatar_retrieved_cb (DBusGProxy *proxy, - guint handle, - gchar *token, - GArray *avatar_data, - gchar *mime_type, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - EmpathyContact *contact; - EmpathyAvatar *avatar; - - contact = contact_factory_account_data_find_by_handle (account_data, - handle); - if (!contact) { - return; - } - - empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)", - empathy_contact_get_id (contact), - handle); - - avatar = empathy_avatar_new (avatar_data->data, - avatar_data->len, - mime_type, - token); - - empathy_contact_set_avatar (contact, avatar); - empathy_avatar_unref (avatar); -} - -static void -contact_factory_request_avatars_cb (DBusGProxy *proxy, - GError *error, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s", - error->message); - } - - contact_factory_account_data_unref (account_data); -} - -typedef struct { - ContactFactoryAccountData *account_data; - GArray *handles; -} TokensData; - -static gboolean -contact_factory_avatar_maybe_update (ContactFactoryAccountData *account_data, - guint handle, - const gchar *token) -{ - EmpathyContact *contact; - EmpathyAvatar *avatar; - - contact = contact_factory_account_data_find_by_handle (account_data, - handle); - if (!contact) { - return TRUE; - } - - /* Check if we have an avatar */ - if (G_STR_EMPTY (token)) { - empathy_contact_set_avatar (contact, NULL); - return TRUE; - } - - /* Check if the avatar changed */ - avatar = empathy_contact_get_avatar (contact); - if (avatar && !tp_strdiff (avatar->token, token)) { - return TRUE; - } - - /* The avatar changed, search the new one in the cache */ - avatar = empathy_avatar_new_from_cache (token); - if (avatar) { - /* Got from cache, use it */ - empathy_contact_set_avatar (contact, avatar); - empathy_avatar_unref (avatar); - return TRUE; - } - - /* Avatar is not up-to-date, we have to request it. */ - return FALSE; -} - -static void -contact_factory_avatar_tokens_foreach (gpointer key, - gpointer value, - gpointer user_data) -{ - TokensData *data = user_data; - const gchar *token = value; - guint handle = GPOINTER_TO_UINT (key); - - if (!contact_factory_avatar_maybe_update (data->account_data, - handle, token)) { - g_array_append_val (data->handles, handle); - } -} - -static void -contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy, - GHashTable *tokens, - GError *error, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - TokensData data; - - if (error) { - empathy_debug (DEBUG_DOMAIN, - "Error getting known avatars tokens: %s", - error->message); - goto OUT; - } - - data.account_data = account_data; - data.handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_hash_table_foreach (tokens, - contact_factory_avatar_tokens_foreach, - &data); - - empathy_debug (DEBUG_DOMAIN, "Got %d tokens, need to request %d avatars", - g_hash_table_size (tokens), - data.handles->len); - - /* Request needed avatars */ - if (data.handles->len > 0) { - tp_conn_iface_avatars_request_avatars_async (account_data->avatars_iface, - data.handles, - contact_factory_request_avatars_cb, - contact_factory_account_data_ref (account_data)); - } - - g_hash_table_destroy (tokens); - g_array_free (data.handles, TRUE); -OUT: - contact_factory_account_data_unref (account_data); -} - -static void -contact_factory_avatar_updated_cb (DBusGProxy *proxy, - guint handle, - gchar *new_token, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - GArray *handles; - - if (contact_factory_avatar_maybe_update (account_data, handle, new_token)) { - /* Avatar was cached, nothing to do */ - return; - } - - empathy_debug (DEBUG_DOMAIN, "Need to request avatar for token %s", - new_token); - - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - tp_conn_iface_avatars_request_avatars_async (account_data->avatars_iface, - handles, - contact_factory_request_avatars_cb, - contact_factory_account_data_ref (account_data)); - g_array_free (handles, TRUE); -} - -static void -contact_factory_update_capabilities (ContactFactoryAccountData *account_data, - guint handle, - const gchar *channel_type, - guint generic, - guint specific) -{ - EmpathyContact *contact; - EmpathyCapabilities capabilities; - - contact = contact_factory_account_data_find_by_handle (account_data, - handle); - if (!contact) { - return; - } - - capabilities = empathy_contact_get_capabilities (contact); - - if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) { - capabilities &= ~EMPATHY_CAPABILITIES_AUDIO; - capabilities &= ~EMPATHY_CAPABILITIES_VIDEO; - if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) { - capabilities |= EMPATHY_CAPABILITIES_AUDIO; - } - if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) { - capabilities |= EMPATHY_CAPABILITIES_VIDEO; - } - } - - empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - capabilities); - - empathy_contact_set_capabilities (contact, capabilities); -} - -static void -contact_factory_get_capabilities_cb (DBusGProxy *proxy, - GPtrArray *capabilities, - GError *error, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - guint i; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s", - error->message); - goto OUT; - } - - for (i = 0; i < capabilities->len; i++) { - GValueArray *values; - guint handle; - const gchar *channel_type; - guint generic; - guint specific; - - values = g_ptr_array_index (capabilities, i); - handle = g_value_get_uint (g_value_array_get_nth (values, 0)); - channel_type = g_value_get_string (g_value_array_get_nth (values, 1)); - generic = g_value_get_uint (g_value_array_get_nth (values, 2)); - specific = g_value_get_uint (g_value_array_get_nth (values, 3)); - - contact_factory_update_capabilities (account_data, - handle, - channel_type, - generic, - specific); - - g_value_array_free (values); - } - - g_ptr_array_free (capabilities, TRUE); -OUT: - contact_factory_account_data_unref (account_data); -} - -static void -contact_factory_capabilities_changed_cb (DBusGProxy *proxy, - GPtrArray *capabilities, - gpointer user_data) -{ - ContactFactoryAccountData *account_data = user_data; - guint i; - - for (i = 0; i < capabilities->len; i++) { - GValueArray *values; - guint handle; - const gchar *channel_type; - guint generic; - guint specific; - - values = g_ptr_array_index (capabilities, i); - handle = g_value_get_uint (g_value_array_get_nth (values, 0)); - channel_type = g_value_get_string (g_value_array_get_nth (values, 1)); - generic = g_value_get_uint (g_value_array_get_nth (values, 3)); - specific = g_value_get_uint (g_value_array_get_nth (values, 5)); - - contact_factory_update_capabilities (account_data, - handle, - channel_type, - generic, - specific); - } -} - -static void -contact_factory_request_everything (ContactFactoryAccountData *account_data, - GArray *handles) -{ - if (account_data->presence_iface) { - tp_conn_iface_presence_get_presence_async (account_data->presence_iface, - handles, - contact_factory_get_presence_cb, - contact_factory_account_data_ref (account_data)); - } - - if (account_data->aliasing_iface) { - RequestAliasesData *data; - - data = g_slice_new (RequestAliasesData); - data->account_data = contact_factory_account_data_ref (account_data); - data->handles = g_memdup (handles->data, handles->len * sizeof (guint)); - - tp_conn_iface_aliasing_request_aliases_async (account_data->aliasing_iface, - handles, - contact_factory_request_aliases_cb, - data); - } - - if (account_data->avatars_iface) { - tp_conn_iface_avatars_get_known_avatar_tokens_async (account_data->avatars_iface, - handles, - contact_factory_get_known_avatar_tokens_cb, - contact_factory_account_data_ref (account_data)); - } - - if (account_data->capabilities_iface) { - tp_conn_iface_capabilities_get_capabilities_async (account_data->capabilities_iface, - handles, - contact_factory_get_capabilities_cb, - contact_factory_account_data_ref (account_data)); - } -} - -static void -contact_factory_request_handles_cb (DBusGProxy *proxy, - GArray *handles, - GError *error, - gpointer user_data) -{ - RequestHandlesData *data = user_data; - GList *l; - guint i = 0; - - if (error) { - empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s", - error->message); - goto OUT; - } - - for (l = data->contacts; l; l = l->next) { - guint handle; - - handle = g_array_index (handles, guint, i); - empathy_contact_set_handle (l->data, handle); - if (handle == data->account_data->self_handle) { - empathy_contact_set_is_user (l->data, TRUE); - } - - i++; - } - - contact_factory_request_everything (data->account_data, handles); - g_array_free (handles, TRUE); - -OUT: - g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL); - g_list_free (data->contacts); - contact_factory_account_data_unref (data->account_data); - g_slice_free (RequestHandlesData, data); -} - -static void -contact_factory_disconnect_contact_foreach (gpointer data, - gpointer user_data) -{ - EmpathyContact *contact = data; - - empathy_contact_set_presence (contact, NULL); - empathy_contact_set_handle (contact, 0); -} - -static void -contact_factory_destroy_cb (TpConn *tp_conn, - ContactFactoryAccountData *account_data) -{ - empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed"); - - g_object_unref (account_data->tp_conn); - account_data->tp_conn = NULL; - account_data->aliasing_iface = NULL; - account_data->avatars_iface = NULL; - account_data->presence_iface = NULL; - account_data->capabilities_iface = NULL; - - g_list_foreach (account_data->contacts, - contact_factory_disconnect_contact_foreach, - account_data); -} - -static void -contact_factory_account_data_disconnect (ContactFactoryAccountData *account_data) -{ - if (account_data->aliasing_iface) { - dbus_g_proxy_disconnect_signal (account_data->aliasing_iface, - "AliasesChanged", - G_CALLBACK (contact_factory_aliases_changed_cb), - account_data); - } - if (account_data->avatars_iface) { - dbus_g_proxy_disconnect_signal (account_data->avatars_iface, - "AvatarUpdated", - G_CALLBACK (contact_factory_avatar_updated_cb), - account_data); - dbus_g_proxy_disconnect_signal (account_data->avatars_iface, - "AvatarRetrieved", - G_CALLBACK (contact_factory_avatar_retrieved_cb), - account_data); - } - if (account_data->presence_iface) { - dbus_g_proxy_disconnect_signal (account_data->presence_iface, - "PresenceUpdate", - G_CALLBACK (contact_factory_presence_update_cb), - account_data); - } - if (account_data->capabilities_iface) { - dbus_g_proxy_disconnect_signal (account_data->capabilities_iface, - "CapabilitiesChanged", - G_CALLBACK (contact_factory_capabilities_changed_cb), - account_data); - } - if (account_data->tp_conn) { - g_signal_handlers_disconnect_by_func (account_data->tp_conn, - contact_factory_destroy_cb, - account_data); - } -} - -static void -contact_factory_account_data_update (ContactFactoryAccountData *account_data) -{ - EmpathyContactFactory *factory = account_data->factory; - EmpathyContactFactoryPriv *priv = GET_PRIV (factory); - McAccount *account = account_data->account; - TpConn *tp_conn = NULL; - RequestHandlesData *data; - const gchar **contact_ids; - guint i; - GList *l; - GError *error = NULL; - - if (account_data->account) { - guint status; - - /* status == 0 means the status is CONNECTED */ - status = mission_control_get_connection_status (priv->mc, - account, NULL); - if (status == 0) { - tp_conn = mission_control_get_connection (priv->mc, - account, NULL); - } - } - - if (!tp_conn) { - /* We are not connected anymore, remove the old connection */ - contact_factory_account_data_disconnect (account_data); - if (account_data->tp_conn) { - contact_factory_destroy_cb (account_data->tp_conn, - account_data); - } - return; - } - else if (account_data->tp_conn) { - /* We were connected and we still are connected, nothing - * changed so nothing to do. */ - g_object_unref (tp_conn); - return; - } - - /* We got a new connection */ - account_data->tp_conn = tp_conn; - account_data->aliasing_iface = tp_conn_get_interface (tp_conn, - TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING); - account_data->avatars_iface = tp_conn_get_interface (tp_conn, - TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS); - account_data->presence_iface = tp_conn_get_interface (tp_conn, - TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE); - account_data->capabilities_iface = tp_conn_get_interface (tp_conn, - TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES); - - /* Connect signals */ - if (account_data->aliasing_iface) { - dbus_g_proxy_connect_signal (account_data->aliasing_iface, - "AliasesChanged", - G_CALLBACK (contact_factory_aliases_changed_cb), - account_data, NULL); - } - if (account_data->avatars_iface) { - dbus_g_proxy_connect_signal (account_data->avatars_iface, - "AvatarUpdated", - G_CALLBACK (contact_factory_avatar_updated_cb), - account_data, NULL); - dbus_g_proxy_connect_signal (account_data->avatars_iface, - "AvatarRetrieved", - G_CALLBACK (contact_factory_avatar_retrieved_cb), - account_data, NULL); - } - if (account_data->presence_iface) { - dbus_g_proxy_connect_signal (account_data->presence_iface, - "PresenceUpdate", - G_CALLBACK (contact_factory_presence_update_cb), - account_data, NULL); - } - if (account_data->capabilities_iface) { - dbus_g_proxy_connect_signal (account_data->capabilities_iface, - "CapabilitiesChanged", - G_CALLBACK (contact_factory_capabilities_changed_cb), - account_data, NULL); - } - g_signal_connect (tp_conn, "destroy", - G_CALLBACK (contact_factory_destroy_cb), - account_data); - - /* Get our own handle */ - if (!tp_conn_get_self_handle (DBUS_G_PROXY (account_data->tp_conn), - &account_data->self_handle, - &error)) { - empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - } - - /* Request new handles for all contacts */ - if (account_data->contacts) { - data = g_slice_new (RequestHandlesData); - data->account_data = contact_factory_account_data_ref (account_data); - data->contacts = g_list_copy (account_data->contacts); - g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL); - - i = g_list_length (data->contacts); - contact_ids = g_new0 (const gchar*, i + 1); - i = 0; - for (l = data->contacts; l; l = l->next) { - contact_ids[i] = empathy_contact_get_id (l->data); - i++; - } - - tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn), - TP_HANDLE_TYPE_CONTACT, - contact_ids, - contact_factory_request_handles_cb, - data); - g_free (contact_ids); - } -} - -static ContactFactoryAccountData * -contact_factory_account_data_new (EmpathyContactFactory *factory, - McAccount *account) -{ - ContactFactoryAccountData *account_data; - - account_data = g_slice_new0 (ContactFactoryAccountData); - account_data->factory = factory; - account_data->account = g_object_ref (account); - account_data->refcount = 1; - - contact_factory_account_data_update (account_data); - - return account_data; -} - -static void -contact_factory_status_changed_cb (MissionControl *mc, - TpConnectionStatus status, - McPresence presence, - TpConnectionStatusReason reason, - const gchar *unique_name, - EmpathyContactFactory *factory) -{ - EmpathyContactFactoryPriv *priv = GET_PRIV (factory); - ContactFactoryAccountData *account_data; - McAccount *account; - - account = mc_account_lookup (unique_name); - account_data = g_hash_table_lookup (priv->accounts, account); - if (account_data) { - contact_factory_account_data_update (account_data); - } - g_object_unref (account); -} - -static ContactFactoryAccountData * -contact_factory_account_data_get (EmpathyContactFactory *factory, - McAccount *account) +static EmpathyTpContactFactory * +contact_factory_get_tp_factory (EmpathyContactFactory *factory, + McAccount *account) { EmpathyContactFactoryPriv *priv = GET_PRIV (factory); - ContactFactoryAccountData *account_data; + EmpathyTpContactFactory *tp_factory; - account_data = g_hash_table_lookup (priv->accounts, account); - if (!account_data) { - account_data = contact_factory_account_data_new (factory, account); + tp_factory = g_hash_table_lookup (priv->accounts, account); + if (!tp_factory) { + tp_factory = empathy_tp_contact_factory_new (account); g_hash_table_insert (priv->accounts, g_object_ref (account), - account_data); + tp_factory); } - return account_data; -} - -static void -contact_factory_account_data_add_contact (ContactFactoryAccountData *account_data, - EmpathyContact *contact) -{ - g_object_weak_ref (G_OBJECT (contact), - contact_factory_weak_notify, - account_data); - account_data->contacts = g_list_prepend (account_data->contacts, contact); - - if (!account_data->presence_iface) { - EmpathyPresence *presence; - - /* We have no presence iface, set default presence - * to available */ - presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE, - NULL); - - empathy_contact_set_presence (contact, presence); - g_object_unref (presence); - } - - empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact)); -} - -static void -contact_factory_hold_handles_cb (DBusGProxy *proxy, - GError *error, - gpointer userdata) -{ - if (error) { - empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s", - error->message); - } + return tp_factory; } EmpathyContact * empathy_contact_factory_get_user (EmpathyContactFactory *factory, McAccount *account) { - ContactFactoryAccountData *account_data; + EmpathyTpContactFactory *tp_factory; - g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + tp_factory = contact_factory_get_tp_factory (factory, account); - account_data = contact_factory_account_data_get (factory, account); - - return empathy_contact_factory_get_from_handle (factory, account, - account_data->self_handle); + return empathy_tp_contact_factory_get_user (tp_factory); } EmpathyContact * @@ -1066,43 +71,11 @@ empathy_contact_factory_get_from_id (EmpathyContactFactory *factory, McAccount *account, const gchar *id) { - ContactFactoryAccountData *account_data; - EmpathyContact *contact; - - g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (id != NULL, NULL); - - /* Check if the contact already exists */ - account_data = contact_factory_account_data_get (factory, account); - contact = contact_factory_account_data_find_by_id (account_data, id); - if (contact) { - return g_object_ref (contact); - } - - /* Create new contact */ - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", account, - "id", id, - NULL); - contact_factory_account_data_add_contact (account_data, contact); + EmpathyTpContactFactory *tp_factory; - /* If the account is connected, request contact's handle */ - if (account_data->tp_conn) { - RequestHandlesData *data; - const gchar *contact_ids[] = {id, NULL}; - - data = g_slice_new (RequestHandlesData); - data->account_data = contact_factory_account_data_ref (account_data); - data->contacts = g_list_prepend (NULL, g_object_ref (contact)); - tp_conn_request_handles_async (DBUS_G_PROXY (account_data->tp_conn), - TP_HANDLE_TYPE_CONTACT, - contact_ids, - contact_factory_request_handles_cb, - data); - } + tp_factory = contact_factory_get_tp_factory (factory, account); - return contact; + return empathy_tp_contact_factory_get_from_id (tp_factory, id); } EmpathyContact * @@ -1110,23 +83,11 @@ empathy_contact_factory_get_from_handle (EmpathyContactFactory *factory, McAccount *account, guint handle) { - EmpathyContact *contact; - GArray *handles; - GList *contacts; + EmpathyTpContactFactory *tp_factory; - g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); + tp_factory = contact_factory_get_tp_factory (factory, account); - handles = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (handles, handle); - - contacts = empathy_contact_factory_get_from_handles (factory, account, handles); - g_array_free (handles, TRUE); - - contact = contacts ? contacts->data : NULL; - g_list_free (contacts); - - return contact; + return empathy_tp_contact_factory_get_from_handle (tp_factory, handle); } GList * @@ -1134,92 +95,11 @@ empathy_contact_factory_get_from_handles (EmpathyContactFactory *factory, McAccount *account, GArray *handles) { - ContactFactoryAccountData *account_data; - GList *contacts = NULL; - GArray *new_handles; - gchar **handles_names; - guint i; - GError *error = NULL; - - g_return_val_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory), NULL); - g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL); - g_return_val_if_fail (handles != NULL, NULL); - - /* Search all contacts we already have */ - account_data = contact_factory_account_data_get (factory, account); - new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); - for (i = 0; i < handles->len; i++) { - EmpathyContact *contact; - guint handle; - - handle = g_array_index (handles, guint, i); - if (handle == 0) { - continue; - } - - contact = contact_factory_account_data_find_by_handle (account_data, handle); - if (contact) { - contacts = g_list_prepend (contacts, g_object_ref (contact)); - } else { - g_array_append_val (new_handles, handle); - } - } - - if (new_handles->len == 0) { - g_array_free (new_handles, TRUE); - return contacts; - } - - /* Get the IDs of all new handles */ - if (!tp_conn_inspect_handles (DBUS_G_PROXY (account_data->tp_conn), - TP_HANDLE_TYPE_CONTACT, - new_handles, - &handles_names, - &error)) { - empathy_debug (DEBUG_DOMAIN, - "Couldn't inspect contact: %s", - error ? error->message : "No error given"); - g_clear_error (&error); - g_array_free (new_handles, TRUE); - return contacts; - } - - /* Create new contacts */ - for (i = 0; i < new_handles->len; i++) { - EmpathyContact *contact; - gchar *id; - guint handle; - gboolean is_user; - - id = handles_names[i]; - handle = g_array_index (new_handles, guint, i); - - is_user = (handle == account_data->self_handle); - contact = g_object_new (EMPATHY_TYPE_CONTACT, - "account", account, - "handle", handle, - "id", id, - "is-user", is_user, - NULL); - contact_factory_account_data_add_contact (account_data, - contact); - contacts = g_list_prepend (contacts, contact); - g_free (id); - } - g_free (handles_names); - - /* Hold all new handles. */ - tp_conn_hold_handles_async (DBUS_G_PROXY (account_data->tp_conn), - TP_HANDLE_TYPE_CONTACT, - new_handles, - contact_factory_hold_handles_cb, - NULL); + EmpathyTpContactFactory *tp_factory; - contact_factory_request_everything (account_data, new_handles); + tp_factory = contact_factory_get_tp_factory (factory, account); - g_array_free (new_handles, TRUE); - - return contacts; + return empathy_tp_contact_factory_get_from_handles (tp_factory, handles); } void @@ -1227,42 +107,13 @@ empathy_contact_factory_set_alias (EmpathyContactFactory *factory, EmpathyContact *contact, const gchar *alias) { - ContactFactoryAccountData *account_data; - McAccount *account; - GHashTable *new_alias; - guint handle; - - g_return_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory)); - g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + EmpathyTpContactFactory *tp_factory; + McAccount *account; account = empathy_contact_get_account (contact); - account_data = contact_factory_account_data_get (factory, account); - - if (!account_data->aliasing_iface) { - return; - } - - handle = empathy_contact_get_handle (contact); - - empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s", - empathy_contact_get_id (contact), - handle, alias); + tp_factory = contact_factory_get_tp_factory (factory, account); - new_alias = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - g_free); - - g_hash_table_insert (new_alias, - GUINT_TO_POINTER (handle), - g_strdup (alias)); - - tp_conn_iface_aliasing_set_aliases_async (account_data->aliasing_iface, - new_alias, - contact_factory_set_aliases_cb, - contact_factory_account_data_ref (account_data)); - - g_hash_table_destroy (new_alias); + return empathy_tp_contact_factory_set_alias (tp_factory, contact, alias); } void @@ -1272,54 +123,20 @@ empathy_contact_factory_set_avatar (EmpathyContactFactory *factory, gsize size, const gchar *mime_type) { - ContactFactoryAccountData *account_data; - - g_return_if_fail (EMPATHY_IS_CONTACT_FACTORY (factory)); - g_return_if_fail (MC_IS_ACCOUNT (account)); - - account_data = contact_factory_account_data_get (factory, account); + EmpathyTpContactFactory *tp_factory; - if (!account_data->avatars_iface) { - return; - } - - if (data && size > 0 && size < G_MAXUINT) { - GArray avatar; - - avatar.data = (gchar*) data; - avatar.len = size; + tp_factory = contact_factory_get_tp_factory (factory, account); - empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s", - mc_account_get_unique_name (account)); - - tp_conn_iface_avatars_set_avatar_async (account_data->avatars_iface, - &avatar, - mime_type, - contact_factory_set_avatar_cb, - contact_factory_account_data_ref (account_data)); - } else { - empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s", - mc_account_get_unique_name (account)); - tp_conn_iface_avatars_clear_avatar_async (account_data->avatars_iface, - contact_factory_clear_avatar_cb, - contact_factory_account_data_ref (account_data)); - } + return empathy_tp_contact_factory_set_avatar (tp_factory, + data, size, mime_type); } static void contact_factory_finalize (GObject *object) { - EmpathyContactFactoryPriv *priv; - - priv = GET_PRIV (object); - - dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), - "AccountStatusChanged", - G_CALLBACK (contact_factory_status_changed_cb), - object); + EmpathyContactFactoryPriv *priv = GET_PRIV (object); g_hash_table_destroy (priv->accounts); - g_object_unref (priv->mc); G_OBJECT_CLASS (empathy_contact_factory_parent_class)->finalize (object); } @@ -1337,20 +154,12 @@ empathy_contact_factory_class_init (EmpathyContactFactoryClass *klass) static void empathy_contact_factory_init (EmpathyContactFactory *factory) { - EmpathyContactFactoryPriv *priv; - - priv = GET_PRIV (factory); + EmpathyContactFactoryPriv *priv = GET_PRIV (factory); - priv->mc = empathy_mission_control_new (); priv->accounts = g_hash_table_new_full (empathy_account_hash, empathy_account_equal, g_object_unref, - (GDestroyNotify) contact_factory_account_data_unref); - - dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), - "AccountStatusChanged", - G_CALLBACK (contact_factory_status_changed_cb), - factory, NULL); + g_object_unref); } EmpathyContactFactory * diff --git a/libempathy/empathy-tp-contact-factory.c b/libempathy/empathy-tp-contact-factory.c new file mode 100644 index 000000000..f71a91014 --- /dev/null +++ b/libempathy/empathy-tp-contact-factory.c @@ -0,0 +1,1307 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Xavier Claessens + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "empathy-tp-contact-factory.h" +#include "empathy-utils.h" +#include "empathy-debug.h" + +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryPriv)) + +#define DEBUG_DOMAIN "TpContactFactory" + +struct _EmpathyTpContactFactoryPriv { + MissionControl *mc; + McAccount *account; + + TpConn *tp_conn; + DBusGProxy *aliasing_iface; + DBusGProxy *avatars_iface; + DBusGProxy *presence_iface; + DBusGProxy *capabilities_iface; + + GList *contacts; + guint self_handle; +}; + +static void empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass); +static void empathy_tp_contact_factory_init (EmpathyTpContactFactory *factory); + +G_DEFINE_TYPE (EmpathyTpContactFactory, empathy_tp_contact_factory, G_TYPE_OBJECT); + +enum { + PROP_0, + PROP_ACCOUNT, +}; + +static EmpathyContact * +tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, + guint handle) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GList *l; + + for (l = priv->contacts; l; l = l->next) { + if (empathy_contact_get_handle (l->data) == handle) { + return l->data; + } + } + + return NULL; +} + +static EmpathyContact * +tp_contact_factory_find_by_id (EmpathyTpContactFactory *tp_factory, + const gchar *id) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GList *l; + + for (l = priv->contacts; l; l = l->next) { + if (!tp_strdiff (empathy_contact_get_id (l->data), id)) { + return l->data; + } + } + + return NULL; +} + +static void +tp_contact_factory_weak_notify (gpointer data, + GObject *where_the_object_was) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (data); + + empathy_debug (DEBUG_DOMAIN, "Remove finalized contact %p", + where_the_object_was); + + priv->contacts = g_list_remove (priv->contacts, where_the_object_was); +} + +static void +tp_contact_factory_presences_table_foreach (const gchar *state_str, + GHashTable *presences_table, + EmpathyPresence **presence) +{ + McPresence state; + const GValue *message; + + state = empathy_presence_state_from_str (state_str); + if (state == MC_PRESENCE_UNSET) { + return; + } + + if (*presence) { + g_object_unref (*presence); + *presence = NULL; + } + + *presence = empathy_presence_new (); + empathy_presence_set_state (*presence, state); + + message = g_hash_table_lookup (presences_table, "message"); + if (message != NULL) { + empathy_presence_set_status (*presence, + g_value_get_string (message)); + } +} + +static void +tp_contact_factory_parse_presence_foreach (guint handle, + GValueArray *presence_struct, + EmpathyTpContactFactory *tp_factory) +{ + GHashTable *presences_table; + EmpathyContact *contact; + EmpathyPresence *presence = NULL; + + contact = tp_contact_factory_find_by_handle (tp_factory, handle); + if (!contact) { + return; + } + + presences_table = g_value_get_boxed (g_value_array_get_nth (presence_struct, 1)); + + g_hash_table_foreach (presences_table, + (GHFunc) tp_contact_factory_presences_table_foreach, + &presence); + + empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)", + empathy_contact_get_id (contact), + handle, + presence ? empathy_presence_get_status (presence) : "unset", + presence ? empathy_presence_get_state (presence) : MC_PRESENCE_UNSET); + + empathy_contact_set_presence (contact, presence); + g_object_unref (presence); +} + +static void +tp_contact_factory_get_presence_cb (DBusGProxy *proxy, + GHashTable *handle_table, + GError *error, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error getting presence: %s", + error->message); + goto OUT; + } + + g_hash_table_foreach (handle_table, + (GHFunc) tp_contact_factory_parse_presence_foreach, + tp_factory); + + g_hash_table_destroy (handle_table); +OUT: + g_object_unref (tp_factory); +} + +static void +tp_contact_factory_presence_update_cb (DBusGProxy *proxy, + GHashTable *handle_table, + EmpathyTpContactFactory *tp_factory) +{ + g_hash_table_foreach (handle_table, + (GHFunc) tp_contact_factory_parse_presence_foreach, + tp_factory); +} + +static void +tp_contact_factory_set_aliases_cb (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s", + error->message); + } + + g_object_unref (tp_factory); +} + +typedef struct { + EmpathyTpContactFactory *tp_factory; + guint *handles; +} RequestAliasesData; + +static void +tp_contact_factory_request_aliases_cb (DBusGProxy *proxy, + gchar **contact_names, + GError *error, + gpointer user_data) +{ + RequestAliasesData *data = user_data; + guint i = 0; + gchar **name; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error requesting aliases: %s", + error->message); + goto OUT; + } + + for (name = contact_names; *name; name++) { + EmpathyContact *contact; + + contact = tp_contact_factory_find_by_handle (data->tp_factory, + data->handles[i]); + if (!contact) { + continue; + } + + empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (request cb)", + empathy_contact_get_id (contact), + data->handles[i], *name); + + empathy_contact_set_name (contact, *name); + + i++; + } + + g_strfreev (contact_names); +OUT: + g_object_unref (data->tp_factory); + g_free (data->handles); + g_slice_free (RequestAliasesData, data); +} + +static void +tp_contact_factory_aliases_changed_cb (DBusGProxy *proxy, + GPtrArray *renamed_handlers, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + guint i; + + for (i = 0; renamed_handlers->len > i; i++) { + guint handle; + const gchar *alias; + GValueArray *renamed_struct; + EmpathyContact *contact; + + renamed_struct = g_ptr_array_index (renamed_handlers, i); + handle = g_value_get_uint(g_value_array_get_nth (renamed_struct, 0)); + alias = g_value_get_string(g_value_array_get_nth (renamed_struct, 1)); + contact = tp_contact_factory_find_by_handle (tp_factory, handle); + + if (!contact) { + /* We don't know this contact, skip */ + continue; + } + + if (G_STR_EMPTY (alias)) { + alias = NULL; + } + + empathy_debug (DEBUG_DOMAIN, "Renaming contact %s (%d) to %s (changed cb)", + empathy_contact_get_id (contact), + handle, alias); + + empathy_contact_set_name (contact, alias); + } +} + +static void +tp_contact_factory_set_avatar_cb (DBusGProxy *proxy, + gchar *token, + GError *error, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error setting avatar: %s", + error->message); + } + + g_object_unref (tp_factory); + g_free (token); +} + +static void +tp_contact_factory_clear_avatar_cb (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error clearing avatar: %s", + error->message); + } + + g_object_unref (tp_factory); +} + +static void +tp_contact_factory_avatar_retrieved_cb (DBusGProxy *proxy, + guint handle, + gchar *token, + GArray *avatar_data, + gchar *mime_type, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + EmpathyContact *contact; + EmpathyAvatar *avatar; + + contact = tp_contact_factory_find_by_handle (tp_factory, handle); + if (!contact) { + return; + } + + empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)", + empathy_contact_get_id (contact), + handle); + + avatar = empathy_avatar_new (avatar_data->data, + avatar_data->len, + mime_type, + token); + + empathy_contact_set_avatar (contact, avatar); + empathy_avatar_unref (avatar); +} + +static void +tp_contact_factory_request_avatars_cb (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s", + error->message); + } + + g_object_unref (tp_factory); +} + +static gboolean +tp_contact_factory_avatar_maybe_update (EmpathyTpContactFactory *tp_factory, + guint handle, + const gchar *token) +{ + EmpathyContact *contact; + EmpathyAvatar *avatar; + + contact = tp_contact_factory_find_by_handle (tp_factory, handle); + if (!contact) { + return TRUE; + } + + /* Check if we have an avatar */ + if (G_STR_EMPTY (token)) { + empathy_contact_set_avatar (contact, NULL); + return TRUE; + } + + /* Check if the avatar changed */ + avatar = empathy_contact_get_avatar (contact); + if (avatar && !tp_strdiff (avatar->token, token)) { + return TRUE; + } + + /* The avatar changed, search the new one in the cache */ + avatar = empathy_avatar_new_from_cache (token); + if (avatar) { + /* Got from cache, use it */ + empathy_contact_set_avatar (contact, avatar); + empathy_avatar_unref (avatar); + return TRUE; + } + + /* Avatar is not up-to-date, we have to request it. */ + return FALSE; +} + +typedef struct { + EmpathyTpContactFactory *tp_factory; + GArray *handles; +} TokensData; + +static void +tp_contact_factory_avatar_tokens_foreach (gpointer key, + gpointer value, + gpointer user_data) +{ + TokensData *data = user_data; + const gchar *token = value; + guint handle = GPOINTER_TO_UINT (key); + + if (!tp_contact_factory_avatar_maybe_update (data->tp_factory, + handle, token)) { + g_array_append_val (data->handles, handle); + } +} + +static void +tp_contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy, + GHashTable *tokens, + GError *error, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + TokensData data; + + if (error) { + empathy_debug (DEBUG_DOMAIN, + "Error getting known avatars tokens: %s", + error->message); + goto OUT; + } + + data.tp_factory = tp_factory; + data.handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_hash_table_foreach (tokens, + tp_contact_factory_avatar_tokens_foreach, + &data); + + empathy_debug (DEBUG_DOMAIN, "Got %d tokens, need to request %d avatars", + g_hash_table_size (tokens), + data.handles->len); + + /* Request needed avatars */ + if (data.handles->len > 0) { + tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface, + data.handles, + tp_contact_factory_request_avatars_cb, + g_object_ref (tp_factory)); + } + + g_hash_table_destroy (tokens); + g_array_free (data.handles, TRUE); +OUT: + g_object_unref (tp_factory); +} + +static void +tp_contact_factory_avatar_updated_cb (DBusGProxy *proxy, + guint handle, + gchar *new_token, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GArray *handles; + + if (tp_contact_factory_avatar_maybe_update (tp_factory, handle, new_token)) { + /* Avatar was cached, nothing to do */ + return; + } + + empathy_debug (DEBUG_DOMAIN, "Need to request avatar for token %s", + new_token); + + handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (handles, handle); + + tp_conn_iface_avatars_request_avatars_async (priv->avatars_iface, + handles, + tp_contact_factory_request_avatars_cb, + g_object_ref (tp_factory)); + g_array_free (handles, TRUE); +} + +static void +tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory, + guint handle, + const gchar *channel_type, + guint generic, + guint specific) +{ + EmpathyContact *contact; + EmpathyCapabilities capabilities; + + contact = tp_contact_factory_find_by_handle (tp_factory, handle); + if (!contact) { + return; + } + + capabilities = empathy_contact_get_capabilities (contact); + + if (strcmp (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) == 0) { + capabilities &= ~EMPATHY_CAPABILITIES_AUDIO; + capabilities &= ~EMPATHY_CAPABILITIES_VIDEO; + if (specific & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) { + capabilities |= EMPATHY_CAPABILITIES_AUDIO; + } + if (specific & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) { + capabilities |= EMPATHY_CAPABILITIES_VIDEO; + } + } + + empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + capabilities); + + empathy_contact_set_capabilities (contact, capabilities); +} + +static void +tp_contact_factory_get_capabilities_cb (DBusGProxy *proxy, + GPtrArray *capabilities, + GError *error, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + guint i; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s", + error->message); + goto OUT; + } + + for (i = 0; i < capabilities->len; i++) { + GValueArray *values; + guint handle; + const gchar *channel_type; + guint generic; + guint specific; + + values = g_ptr_array_index (capabilities, i); + handle = g_value_get_uint (g_value_array_get_nth (values, 0)); + channel_type = g_value_get_string (g_value_array_get_nth (values, 1)); + generic = g_value_get_uint (g_value_array_get_nth (values, 2)); + specific = g_value_get_uint (g_value_array_get_nth (values, 3)); + + tp_contact_factory_update_capabilities (tp_factory, + handle, + channel_type, + generic, + specific); + + g_value_array_free (values); + } + + g_ptr_array_free (capabilities, TRUE); +OUT: + g_object_unref (tp_factory); +} + +static void +tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy, + GPtrArray *capabilities, + gpointer user_data) +{ + EmpathyTpContactFactory *tp_factory = user_data; + guint i; + + for (i = 0; i < capabilities->len; i++) { + GValueArray *values; + guint handle; + const gchar *channel_type; + guint generic; + guint specific; + + values = g_ptr_array_index (capabilities, i); + handle = g_value_get_uint (g_value_array_get_nth (values, 0)); + channel_type = g_value_get_string (g_value_array_get_nth (values, 1)); + generic = g_value_get_uint (g_value_array_get_nth (values, 3)); + specific = g_value_get_uint (g_value_array_get_nth (values, 5)); + + tp_contact_factory_update_capabilities (tp_factory, + handle, + channel_type, + generic, + specific); + } +} + +static void +tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory, + GArray *handles) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + + if (priv->presence_iface) { + tp_conn_iface_presence_get_presence_async (priv->presence_iface, + handles, + tp_contact_factory_get_presence_cb, + g_object_ref (tp_factory)); + } + + if (priv->aliasing_iface) { + RequestAliasesData *data; + + data = g_slice_new (RequestAliasesData); + data->tp_factory = g_object_ref (tp_factory); + data->handles = g_memdup (handles->data, handles->len * sizeof (guint)); + + tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface, + handles, + tp_contact_factory_request_aliases_cb, + data); + } + + if (priv->avatars_iface) { + tp_conn_iface_avatars_get_known_avatar_tokens_async (priv->avatars_iface, + handles, + tp_contact_factory_get_known_avatar_tokens_cb, + g_object_ref (tp_factory)); + } + + if (priv->capabilities_iface) { + tp_conn_iface_capabilities_get_capabilities_async (priv->capabilities_iface, + handles, + tp_contact_factory_get_capabilities_cb, + g_object_ref (tp_factory)); + } +} + +typedef struct { + EmpathyTpContactFactory *tp_factory; + GList *contacts; +} RequestHandlesData; + +static void +tp_contact_factory_request_handles_cb (DBusGProxy *proxy, + GArray *handles, + GError *error, + gpointer user_data) +{ + RequestHandlesData *data = user_data; + EmpathyTpContactFactory *tp_factory = data->tp_factory; + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GList *l; + guint i = 0; + + if (error) { + empathy_debug (DEBUG_DOMAIN, "Failed to request handles: %s", + error->message); + goto OUT; + } + + for (l = data->contacts; l; l = l->next) { + guint handle; + + handle = g_array_index (handles, guint, i); + empathy_contact_set_handle (l->data, handle); + if (handle == priv->self_handle) { + empathy_contact_set_is_user (l->data, TRUE); + } + + i++; + } + + tp_contact_factory_request_everything (tp_factory, handles); + g_array_free (handles, TRUE); + +OUT: + g_list_foreach (data->contacts, (GFunc) g_object_unref, NULL); + g_list_free (data->contacts); + g_object_unref (tp_factory); + g_slice_free (RequestHandlesData, data); +} + +static void +tp_contact_factory_disconnect_contact_foreach (gpointer data, + gpointer user_data) +{ + EmpathyContact *contact = data; + + empathy_contact_set_presence (contact, NULL); + empathy_contact_set_handle (contact, 0); +} + +static void +tp_contact_factory_destroy_cb (TpConn *tp_conn, + EmpathyTpContactFactory *tp_factory) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + + empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed"); + + g_object_unref (priv->tp_conn); + priv->tp_conn = NULL; + priv->aliasing_iface = NULL; + priv->avatars_iface = NULL; + priv->presence_iface = NULL; + priv->capabilities_iface = NULL; + + g_list_foreach (priv->contacts, + tp_contact_factory_disconnect_contact_foreach, + tp_factory); +} + +static void +tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + + if (priv->aliasing_iface) { + dbus_g_proxy_disconnect_signal (priv->aliasing_iface, + "AliasesChanged", + G_CALLBACK (tp_contact_factory_aliases_changed_cb), + tp_factory); + } + if (priv->avatars_iface) { + dbus_g_proxy_disconnect_signal (priv->avatars_iface, + "AvatarUpdated", + G_CALLBACK (tp_contact_factory_avatar_updated_cb), + tp_factory); + dbus_g_proxy_disconnect_signal (priv->avatars_iface, + "AvatarRetrieved", + G_CALLBACK (tp_contact_factory_avatar_retrieved_cb), + tp_factory); + } + if (priv->presence_iface) { + dbus_g_proxy_disconnect_signal (priv->presence_iface, + "PresenceUpdate", + G_CALLBACK (tp_contact_factory_presence_update_cb), + tp_factory); + } + if (priv->capabilities_iface) { + dbus_g_proxy_disconnect_signal (priv->capabilities_iface, + "CapabilitiesChanged", + G_CALLBACK (tp_contact_factory_capabilities_changed_cb), + tp_factory); + } + if (priv->tp_conn) { + g_signal_handlers_disconnect_by_func (priv->tp_conn, + tp_contact_factory_destroy_cb, + tp_factory); + } +} + +static void +tp_contact_factory_update (EmpathyTpContactFactory *tp_factory) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + TpConn *tp_conn = NULL; + RequestHandlesData *data; + const gchar **contact_ids; + guint i; + GList *l; + GError *error = NULL; + + if (priv->account) { + guint status; + + /* status == 0 means the status is CONNECTED */ + status = mission_control_get_connection_status (priv->mc, + priv->account, + NULL); + if (status == 0) { + tp_conn = mission_control_get_connection (priv->mc, + priv->account, + NULL); + } + } + + if (!tp_conn) { + /* We are not connected anymore, remove the old connection */ + tp_contact_factory_disconnect (tp_factory); + if (priv->tp_conn) { + tp_contact_factory_destroy_cb (priv->tp_conn, tp_factory); + } + return; + } + else if (priv->tp_conn) { + /* We were connected and we still are connected, nothing + * changed so nothing to do. */ + g_object_unref (tp_conn); + return; + } + + /* We got a new connection */ + priv->tp_conn = tp_conn; + priv->aliasing_iface = tp_conn_get_interface (priv->tp_conn, + TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING); + priv->avatars_iface = tp_conn_get_interface (priv->tp_conn, + TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS); + priv->presence_iface = tp_conn_get_interface (priv->tp_conn, + TP_IFACE_QUARK_CONNECTION_INTERFACE_PRESENCE); + priv->capabilities_iface = tp_conn_get_interface (priv->tp_conn, + TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES); + + /* Connect signals */ + if (priv->aliasing_iface) { + dbus_g_proxy_connect_signal (priv->aliasing_iface, + "AliasesChanged", + G_CALLBACK (tp_contact_factory_aliases_changed_cb), + tp_factory, NULL); + } + if (priv->avatars_iface) { + dbus_g_proxy_connect_signal (priv->avatars_iface, + "AvatarUpdated", + G_CALLBACK (tp_contact_factory_avatar_updated_cb), + tp_factory, NULL); + dbus_g_proxy_connect_signal (priv->avatars_iface, + "AvatarRetrieved", + G_CALLBACK (tp_contact_factory_avatar_retrieved_cb), + tp_factory, NULL); + } + if (priv->presence_iface) { + dbus_g_proxy_connect_signal (priv->presence_iface, + "PresenceUpdate", + G_CALLBACK (tp_contact_factory_presence_update_cb), + tp_factory, NULL); + } + if (priv->capabilities_iface) { + dbus_g_proxy_connect_signal (priv->capabilities_iface, + "CapabilitiesChanged", + G_CALLBACK (tp_contact_factory_capabilities_changed_cb), + tp_factory, NULL); + } + g_signal_connect (priv->tp_conn, "destroy", + G_CALLBACK (tp_contact_factory_destroy_cb), + tp_factory); + + /* Get our own handle */ + if (!tp_conn_get_self_handle (DBUS_G_PROXY (priv->tp_conn), + &priv->self_handle, + &error)) { + empathy_debug (DEBUG_DOMAIN, "GetSelfHandle Error: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + } + + /* Request new handles for all contacts */ + if (priv->contacts) { + data = g_slice_new (RequestHandlesData); + data->tp_factory = g_object_ref (tp_factory); + data->contacts = g_list_copy (priv->contacts); + g_list_foreach (data->contacts, (GFunc) g_object_ref, NULL); + + i = g_list_length (data->contacts); + contact_ids = g_new0 (const gchar*, i + 1); + i = 0; + for (l = data->contacts; l; l = l->next) { + contact_ids[i] = empathy_contact_get_id (l->data); + i++; + } + + tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn), + TP_HANDLE_TYPE_CONTACT, + contact_ids, + tp_contact_factory_request_handles_cb, + data); + g_free (contact_ids); + } +} + +static void +tp_contact_factory_status_changed_cb (MissionControl *mc, + TpConnectionStatus status, + McPresence presence, + TpConnectionStatusReason reason, + const gchar *unique_name, + EmpathyTpContactFactory *tp_factory) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + McAccount *account; + + account = mc_account_lookup (unique_name); + if (account && empathy_account_equal (account, priv->account)) { + tp_contact_factory_update (tp_factory); + } + g_object_unref (account); +} + +static void +tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, + EmpathyContact *contact) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + + g_object_weak_ref (G_OBJECT (contact), + tp_contact_factory_weak_notify, + tp_factory); + priv->contacts = g_list_prepend (priv->contacts, contact); + + if (!priv->presence_iface) { + EmpathyPresence *presence; + + /* We have no presence iface, set default presence + * to available */ + presence = empathy_presence_new_full (MC_PRESENCE_AVAILABLE, + NULL); + + empathy_contact_set_presence (contact, presence); + g_object_unref (presence); + } + + empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact)); +} + +static void +tp_contact_factory_hold_handles_cb (DBusGProxy *proxy, + GError *error, + gpointer userdata) +{ + if (error) { + empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s", + error->message); + } +} + +EmpathyContact * +empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); + + return empathy_tp_contact_factory_get_from_handle (tp_factory, + priv->self_handle); +} + +EmpathyContact * +empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, + const gchar *id) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + EmpathyContact *contact; + + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); + g_return_val_if_fail (id != NULL, NULL); + + /* Check if the contact already exists */ + contact = tp_contact_factory_find_by_id (tp_factory, id); + if (contact) { + return g_object_ref (contact); + } + + /* Create new contact */ + contact = g_object_new (EMPATHY_TYPE_CONTACT, + "account", priv->account, + "id", id, + NULL); + tp_contact_factory_add_contact (tp_factory, contact); + + /* If the account is connected, request contact's handle */ + if (priv->tp_conn) { + RequestHandlesData *data; + const gchar *contact_ids[] = {id, NULL}; + + data = g_slice_new (RequestHandlesData); + data->tp_factory = g_object_ref (tp_factory); + data->contacts = g_list_prepend (NULL, g_object_ref (contact)); + tp_conn_request_handles_async (DBUS_G_PROXY (priv->tp_conn), + TP_HANDLE_TYPE_CONTACT, + contact_ids, + tp_contact_factory_request_handles_cb, + data); + } + + return contact; +} + +EmpathyContact * +empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + guint handle) +{ + EmpathyContact *contact; + GArray *handles; + GList *contacts; + + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); + + handles = g_array_new (FALSE, FALSE, sizeof (guint)); + g_array_append_val (handles, handle); + + contacts = empathy_tp_contact_factory_get_from_handles (tp_factory, handles); + g_array_free (handles, TRUE); + + contact = contacts ? contacts->data : NULL; + g_list_free (contacts); + + return contact; +} + +GList * +empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, + GArray *handles) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GList *contacts = NULL; + GArray *new_handles; + gchar **handles_names; + guint i; + GError *error = NULL; + + g_return_val_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory), NULL); + g_return_val_if_fail (handles != NULL, NULL); + + /* Search all contacts we already have */ + new_handles = g_array_new (FALSE, FALSE, sizeof (guint)); + for (i = 0; i < handles->len; i++) { + EmpathyContact *contact; + guint handle; + + handle = g_array_index (handles, guint, i); + if (handle == 0) { + continue; + } + + contact = tp_contact_factory_find_by_handle (tp_factory, handle); + if (contact) { + contacts = g_list_prepend (contacts, g_object_ref (contact)); + } else { + g_array_append_val (new_handles, handle); + } + } + + if (new_handles->len == 0) { + g_array_free (new_handles, TRUE); + return contacts; + } + + /* Get the IDs of all new handles */ + if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn), + TP_HANDLE_TYPE_CONTACT, + new_handles, + &handles_names, + &error)) { + empathy_debug (DEBUG_DOMAIN, + "Couldn't inspect contact: %s", + error ? error->message : "No error given"); + g_clear_error (&error); + g_array_free (new_handles, TRUE); + return contacts; + } + + /* Create new contacts */ + for (i = 0; i < new_handles->len; i++) { + EmpathyContact *contact; + gchar *id; + guint handle; + gboolean is_user; + + id = handles_names[i]; + handle = g_array_index (new_handles, guint, i); + + is_user = (handle == priv->self_handle); + contact = g_object_new (EMPATHY_TYPE_CONTACT, + "account", priv->account, + "handle", handle, + "id", id, + "is-user", is_user, + NULL); + tp_contact_factory_add_contact (tp_factory, contact); + contacts = g_list_prepend (contacts, contact); + g_free (id); + } + g_free (handles_names); + + /* Hold all new handles. */ + tp_conn_hold_handles_async (DBUS_G_PROXY (priv->tp_conn), + TP_HANDLE_TYPE_CONTACT, + new_handles, + tp_contact_factory_hold_handles_cb, + NULL); + + tp_contact_factory_request_everything (tp_factory, new_handles); + + g_array_free (new_handles, TRUE); + + return contacts; +} + +void +empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, + EmpathyContact *contact, + const gchar *alias) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + GHashTable *new_alias; + guint handle; + + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (empathy_account_equal (empathy_contact_get_account (contact), + priv->account)); + + if (!priv->aliasing_iface) { + return; + } + + handle = empathy_contact_get_handle (contact); + + empathy_debug (DEBUG_DOMAIN, "Setting alias for contact %s (%d) to %s", + empathy_contact_get_id (contact), + handle, alias); + + new_alias = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + g_free); + + g_hash_table_insert (new_alias, + GUINT_TO_POINTER (handle), + g_strdup (alias)); + + tp_conn_iface_aliasing_set_aliases_async (priv->aliasing_iface, + new_alias, + tp_contact_factory_set_aliases_cb, + g_object_ref (tp_factory)); + + g_hash_table_destroy (new_alias); +} + +void +empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, + const gchar *data, + gsize size, + const gchar *mime_type) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + + if (!priv->avatars_iface) { + return; + } + + if (data && size > 0 && size < G_MAXUINT) { + GArray avatar; + + avatar.data = (gchar*) data; + avatar.len = size; + + empathy_debug (DEBUG_DOMAIN, "Setting avatar on account %s", + mc_account_get_unique_name (priv->account)); + + tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface, + &avatar, + mime_type, + tp_contact_factory_set_avatar_cb, + g_object_ref (tp_factory)); + } else { + empathy_debug (DEBUG_DOMAIN, "Clearing avatar on account %s", + mc_account_get_unique_name (priv->account)); + tp_conn_iface_avatars_clear_avatar_async (priv->avatars_iface, + tp_contact_factory_clear_avatar_cb, + g_object_ref (tp_factory)); + } +} + +static void +tp_contact_factory_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); + + switch (param_id) { + case PROP_ACCOUNT: + g_value_set_object (value, priv->account); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +tp_contact_factory_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); + + switch (param_id) { + case PROP_ACCOUNT: + priv->account = g_object_ref (g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +tp_contact_factory_finalize (GObject *object) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); + GList *l; + + empathy_debug (DEBUG_DOMAIN, "Finalized: %p (%s)", + object, + mc_account_get_normalized_name (priv->account)); + + tp_contact_factory_disconnect (EMPATHY_TP_CONTACT_FACTORY (object)); + dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), + "AccountStatusChanged", + G_CALLBACK (tp_contact_factory_status_changed_cb), + object); + + for (l = priv->contacts; l; l = l->next) { + g_object_weak_unref (G_OBJECT (l->data), + tp_contact_factory_weak_notify, + object); + } + + g_list_free (priv->contacts); + g_object_unref (priv->mc); + g_object_unref (priv->account); + + if (priv->tp_conn) { + g_object_unref (priv->tp_conn); + } + + G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object); +} + +static GObject * +tp_contact_factory_constructor (GType type, + guint n_props, + GObjectConstructParam *props) +{ + GObject *tp_factory; + + tp_factory = G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->constructor (type, n_props, props); + + tp_contact_factory_update (EMPATHY_TP_CONTACT_FACTORY (tp_factory)); + + return tp_factory; +} + + +static void +empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = tp_contact_factory_finalize; + object_class->constructor = tp_contact_factory_constructor; + object_class->get_property = tp_contact_factory_get_property; + object_class->set_property = tp_contact_factory_set_property; + + /* Construct-only properties */ + g_object_class_install_property (object_class, + PROP_ACCOUNT, + g_param_spec_object ("account", + "Factory's Account", + "The account associated with the factory", + MC_TYPE_ACCOUNT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv)); +} + +static void +empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory) +{ + EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + + priv->mc = empathy_mission_control_new (); + dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), + "AccountStatusChanged", + G_CALLBACK (tp_contact_factory_status_changed_cb), + tp_factory, NULL); +} + +EmpathyTpContactFactory * +empathy_tp_contact_factory_new (McAccount *account) +{ + return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, + "account", account, + NULL); +} + diff --git a/libempathy/empathy-tp-contact-factory.h b/libempathy/empathy-tp-contact-factory.h new file mode 100644 index 000000000..43d30bdbf --- /dev/null +++ b/libempathy/empathy-tp-contact-factory.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2007 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Xavier Claessens + */ + +#ifndef __EMPATHY_TP_CONTACT_FACTORY_H__ +#define __EMPATHY_TP_CONTACT_FACTORY_H__ + +#include + +#include + +#include "empathy-contact.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_TP_CONTACT_FACTORY (empathy_tp_contact_factory_get_type ()) +#define EMPATHY_TP_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactory)) +#define EMPATHY_TP_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryClass)) +#define EMPATHY_IS_TP_CONTACT_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_TP_CONTACT_FACTORY)) +#define EMPATHY_IS_TP_CONTACT_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_TP_CONTACT_FACTORY)) +#define EMPATHY_TP_CONTACT_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryClass)) + +typedef struct _EmpathyTpContactFactory EmpathyTpContactFactory; +typedef struct _EmpathyTpContactFactoryClass EmpathyTpContactFactoryClass; +typedef struct _EmpathyTpContactFactoryPriv EmpathyTpContactFactoryPriv; + +struct _EmpathyTpContactFactory { + GObject parent; +}; + +struct _EmpathyTpContactFactoryClass { + GObjectClass parent_class; +}; + +GType empathy_tp_contact_factory_get_type (void) G_GNUC_CONST; +EmpathyTpContactFactory *empathy_tp_contact_factory_new (McAccount *account); +EmpathyContact * empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory); +EmpathyContact * empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, + const gchar *id); +EmpathyContact * empathy_tp_contact_factory_get_from_handle (EmpathyTpContactFactory *tp_factory, + guint handle); +GList * empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, + GArray *handles); +void empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, + EmpathyContact *contact, + const gchar *alias); +void empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory, + const gchar *data, + gsize size, + const gchar *mime_type); + +G_END_DECLS + +#endif /* __EMPATHY_TP_CONTACT_FACTORY_H__ */ -- cgit v1.2.3