X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=libempathy%2Fempathy-tp-contact-factory.c;h=db019c9569c2d599433685013cf0ea62c9131ce3;hp=4621ba3940779176a9756edc48d4d95b5a9e56a0;hb=b409d1f2ca05bd2e7ebda4d42714b5511c227845;hpb=a7112593ab7be0dd2895834f06afe9bd47578fca diff --git a/libempathy/empathy-tp-contact-factory.c b/libempathy/empathy-tp-contact-factory.c index 4621ba39..db019c95 100644 --- a/libempathy/empathy-tp-contact-factory.c +++ b/libempathy/empathy-tp-contact-factory.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,44 +24,47 @@ #include #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; +#define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT +#include "empathy-debug.h" +#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpContactFactory) +typedef struct { + TpConnection *connection; GList *contacts; - guint self_handle; -}; -static void empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass); -static void empathy_tp_contact_factory_init (EmpathyTpContactFactory *factory); + gchar **avatar_mime_types; + guint avatar_min_width; + guint avatar_min_height; + guint avatar_max_width; + guint avatar_max_height; + guint avatar_max_size; + gboolean can_request_ft; +} EmpathyTpContactFactoryPriv; G_DEFINE_TYPE (EmpathyTpContactFactory, empathy_tp_contact_factory, G_TYPE_OBJECT); enum { PROP_0, - PROP_ACCOUNT, + PROP_CONNECTION, + + PROP_MIME_TYPES, + PROP_MIN_WIDTH, + PROP_MIN_HEIGHT, + PROP_MAX_WIDTH, + PROP_MAX_HEIGHT, + PROP_MAX_SIZE +}; + +static TpContactFeature contact_features[] = { + TP_CONTACT_FEATURE_ALIAS, + TP_CONTACT_FEATURE_PRESENCE, }; static EmpathyContact * @@ -81,14 +84,14 @@ tp_contact_factory_find_by_handle (EmpathyTpContactFactory *tp_factory, } static EmpathyContact * -tp_contact_factory_find_by_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) +tp_contact_factory_find_by_tp_contact (EmpathyTpContactFactory *tp_factory, + TpContact *tp_contact) { 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)) { + if (empathy_contact_get_tp_contact (l->data) == tp_contact) { return l->data; } } @@ -102,262 +105,82 @@ tp_contact_factory_weak_notify (gpointer data, { EmpathyTpContactFactoryPriv *priv = GET_PRIV (data); - empathy_debug (DEBUG_DOMAIN, "Remove finalized contact %p", - where_the_object_was); + DEBUG ("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, - EmpathyContact *contact) +tp_contact_factory_set_aliases_cb (TpConnection *connection, + const GError *error, + gpointer user_data, + GObject *tp_factory) { - const GValue *message; - - empathy_contact_set_presence (contact, - empathy_presence_from_str (state_str)); - - message = g_hash_table_lookup (presences_table, "message"); - if (message != NULL) { - empathy_contact_set_presence_message (contact, - g_value_get_string (message)); - } else { - empathy_contact_set_presence_message (contact, NULL); - } -} - -static void -tp_contact_factory_parse_presence_foreach (guint handle, - GValueArray *presence_struct, - EmpathyTpContactFactory *tp_factory) -{ - GHashTable *presences_table; - EmpathyContact *contact; - - 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, - contact); - - empathy_debug (DEBUG_DOMAIN, "Changing presence for contact %s (%d) to %s (%d)", - empathy_contact_get_id (contact), - handle, - empathy_contact_get_presence_message (contact), - empathy_contact_get_presence (contact)); -} - -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; + DEBUG ("Error: %s", error->message); } - - 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) +tp_contact_factory_set_avatar_cb (TpConnection *connection, + const gchar *token, + const GError *error, + gpointer user_data, + GObject *tp_factory) { - EmpathyTpContactFactory *tp_factory = user_data; - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error setting alias: %s", - error->message); + DEBUG ("Error: %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) +tp_contact_factory_clear_avatar_cb (TpConnection *connection, + const GError *error, + gpointer user_data, + GObject *tp_factory) { - 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); + DEBUG ("Error: %s", error->message); } } static void -tp_contact_factory_set_avatar_cb (DBusGProxy *proxy, - gchar *token, - GError *error, - gpointer user_data) +tp_contact_factory_avatar_retrieved_cb (TpConnection *connection, + guint handle, + const gchar *token, + const GArray *avatar_data, + const gchar *mime_type, + gpointer user_data, + GObject *tp_factory) { - 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; + EmpathyContact *contact; - contact = tp_contact_factory_find_by_handle (tp_factory, handle); + contact = tp_contact_factory_find_by_handle (EMPATHY_TP_CONTACT_FACTORY (tp_factory), + handle); if (!contact) { return; } - empathy_debug (DEBUG_DOMAIN, "Avatar retrieved for contact %s (%d)", - empathy_contact_get_id (contact), - handle); + DEBUG ("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); + empathy_contact_load_avatar_data (contact, + avatar_data->data, + avatar_data->len, + mime_type, + token); } static void -tp_contact_factory_request_avatars_cb (DBusGProxy *proxy, - GError *error, - gpointer user_data) +tp_contact_factory_request_avatars_cb (TpConnection *connection, + const GError *error, + gpointer user_data, + GObject *tp_factory) { - EmpathyTpContactFactory *tp_factory = user_data; - if (error) { - empathy_debug (DEBUG_DOMAIN, "Error requesting avatars: %s", - error->message); + DEBUG ("Error: %s", error->message); } - - g_object_unref (tp_factory); } static gboolean @@ -374,7 +197,7 @@ tp_contact_factory_avatar_maybe_update (EmpathyTpContactFactory *tp_factory, } /* Check if we have an avatar */ - if (G_STR_EMPTY (token)) { + if (EMP_STR_EMPTY (token)) { empathy_contact_set_avatar (contact, NULL); return TRUE; } @@ -386,11 +209,8 @@ tp_contact_factory_avatar_maybe_update (EmpathyTpContactFactory *tp_factory, } /* The avatar changed, search the new one in the cache */ - avatar = empathy_avatar_new_from_cache (token); - if (avatar) { + if (empathy_contact_load_avatar_cache (contact, token)) { /* Got from cache, use it */ - empathy_contact_set_avatar (contact, avatar); - empathy_avatar_unref (avatar); return TRUE; } @@ -419,20 +239,16 @@ tp_contact_factory_avatar_tokens_foreach (gpointer key, } static void -tp_contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy, - GHashTable *tokens, - GError *error, - gpointer user_data) +tp_contact_factory_got_known_avatar_tokens (EmpathyTpContactFactory *tp_factory, + GHashTable *tokens, + const GError *error) { - EmpathyTpContactFactory *tp_factory = user_data; EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - TokensData data; + TokensData data; if (error) { - empathy_debug (DEBUG_DOMAIN, - "Error getting known avatars tokens: %s", - error->message); - goto OUT; + DEBUG ("Error: %s", error->message); + return; } data.tp_factory = tp_factory; @@ -441,49 +257,49 @@ tp_contact_factory_get_known_avatar_tokens_cb (DBusGProxy *proxy, 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); + DEBUG ("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)); + tp_cli_connection_interface_avatars_call_request_avatars (priv->connection, + -1, + data.handles, + tp_contact_factory_request_avatars_cb, + NULL, NULL, + G_OBJECT (tp_factory)); } - g_hash_table_destroy (tokens); g_array_free (data.handles, TRUE); -OUT: - g_object_unref (tp_factory); + g_hash_table_destroy (tokens); } static void -tp_contact_factory_avatar_updated_cb (DBusGProxy *proxy, - guint handle, - gchar *new_token, - gpointer user_data) +tp_contact_factory_avatar_updated_cb (TpConnection *connection, + guint handle, + const gchar *new_token, + gpointer user_data, + GObject *tp_factory) { - EmpathyTpContactFactory *tp_factory = user_data; - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GArray *handles; + GArray *handles; - if (tp_contact_factory_avatar_maybe_update (tp_factory, handle, new_token)) { + if (tp_contact_factory_avatar_maybe_update (EMPATHY_TP_CONTACT_FACTORY (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); + DEBUG ("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)); + tp_cli_connection_interface_avatars_call_request_avatars (connection, + -1, + handles, + tp_contact_factory_request_avatars_cb, + NULL, NULL, + tp_factory); g_array_free (handles, TRUE); } @@ -516,29 +332,26 @@ tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory, } } - empathy_debug (DEBUG_DOMAIN, "Changing capabilities for contact %s (%d) to %d", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact), - capabilities); + DEBUG ("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) +tp_contact_factory_got_capabilities (EmpathyTpContactFactory *tp_factory, + GPtrArray *capabilities, + const GError *error) { - EmpathyTpContactFactory *tp_factory = user_data; - guint i; + guint i; if (error) { - empathy_debug (DEBUG_DOMAIN, "Error getting capabilities: %s", - error->message); + DEBUG ("Error: %s", error->message); /* FIXME Should set the capabilities of the contacts for which this request * originated to NONE */ - goto OUT; + return; } for (i = 0; i < capabilities->len; i++) { @@ -564,16 +377,15 @@ tp_contact_factory_get_capabilities_cb (DBusGProxy *proxy, } 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) +tp_contact_factory_capabilities_changed_cb (TpConnection *connection, + const GPtrArray *capabilities, + gpointer user_data, + GObject *weak_object) { - EmpathyTpContactFactory *tp_factory = user_data; + EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object); guint i; for (i = 0; i < capabilities->len; i++) { @@ -598,490 +410,294 @@ tp_contact_factory_capabilities_changed_cb (DBusGProxy *proxy, } static void -tp_contact_factory_request_everything (EmpathyTpContactFactory *tp_factory, - GArray *handles) +get_requestable_channel_classes_cb (TpProxy *connection, + const GValue *value, + const GError *error, + gpointer user_data, + GObject *weak_object) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + EmpathyTpContactFactory *self = EMPATHY_TP_CONTACT_FACTORY (weak_object); + EmpathyTpContactFactoryPriv *priv = GET_PRIV (self); + GPtrArray *classes; + guint i; - 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 (error != NULL) { + DEBUG ("Error: %s", error->message); + return; } - if (priv->aliasing_iface) { - RequestAliasesData *data; + classes = g_value_get_boxed (value); + for (i = 0; i < classes->len; i++) { + GValueArray *class_struct; + GHashTable *fixed_prop; + GValue *chan_type, *handle_type; + GList *l; + + class_struct = g_ptr_array_index (classes, i); + fixed_prop = g_value_get_boxed (g_value_array_get_nth (class_struct, 0)); + + chan_type = g_hash_table_lookup (fixed_prop, + TP_IFACE_CHANNEL ".ChannelType"); + if (chan_type == NULL || + tp_strdiff (g_value_get_string (chan_type), + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) { + continue; + } - data = g_slice_new (RequestAliasesData); - data->tp_factory = g_object_ref (tp_factory); - data->handles = g_memdup (handles->data, handles->len * sizeof (guint)); + handle_type = g_hash_table_lookup (fixed_prop, + TP_IFACE_CHANNEL ".TargetHandleType"); + if (handle_type == NULL || + g_value_get_uint (handle_type) != TP_HANDLE_TYPE_CONTACT) { + continue; + } - tp_conn_iface_aliasing_request_aliases_async (priv->aliasing_iface, - handles, - tp_contact_factory_request_aliases_cb, - data); - } + /* We can request file transfer channel to contacts. */ + priv->can_request_ft = TRUE; - 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)); - } + /* Update the capabilities of all contacts */ + for (l = priv->contacts; l != NULL; l = g_list_next (l)) { + EmpathyContact *contact = l->data; + EmpathyCapabilities caps; - 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)); + caps = empathy_contact_get_capabilities (contact); + empathy_contact_set_capabilities (contact, caps | + EMPATHY_CAPABILITIES_FT); + } + break; } } -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) +tp_contact_factory_got_avatar_requirements_cb (TpConnection *proxy, + const gchar **mime_types, + guint min_width, + guint min_height, + guint max_width, + guint max_height, + guint max_size, + const GError *error, + gpointer user_data, + GObject *tp_factory) { - 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++; + DEBUG ("Failed to get avatar requirements: %s", error->message); + /* We'll just leave avatar_mime_types as NULL; the + * avatar-setting code can use this as a signal that you can't + * set avatars. + */ + } else { + priv->avatar_mime_types = g_strdupv ((gchar **) mime_types); + priv->avatar_min_width = min_width; + priv->avatar_min_height = min_height; + priv->avatar_max_width = max_width; + priv->avatar_max_height = max_height; + priv->avatar_max_size = max_size; } - - 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, MC_PRESENCE_UNSET); - empathy_contact_set_handle (contact, 0); } static void -tp_contact_factory_destroy_cb (TpConn *tp_conn, - EmpathyTpContactFactory *tp_factory) +tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, + EmpathyContact *contact) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + TpHandle handle; + GArray handles = {(gchar*) &handle, 1}; + GHashTable *tokens; + GPtrArray *capabilities; + GError *error = NULL; - empathy_debug (DEBUG_DOMAIN, "Account disconnected or CM crashed"); + /* Keep a weak ref to that contact */ + g_object_weak_ref (G_OBJECT (contact), + tp_contact_factory_weak_notify, + tp_factory); + priv->contacts = g_list_prepend (priv->contacts, contact); - 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; + /* The contact keeps a ref to its factory */ + g_object_set_data_full (G_OBJECT (contact), "empathy-factory", + g_object_ref (tp_factory), + g_object_unref); - g_list_foreach (priv->contacts, - tp_contact_factory_disconnect_contact_foreach, - tp_factory); -} + /* Set the FT capability */ + if (priv->can_request_ft) { + EmpathyCapabilities caps; -static void -tp_contact_factory_disconnect (EmpathyTpContactFactory *tp_factory) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + caps = empathy_contact_get_capabilities (contact); + caps |= EMPATHY_CAPABILITIES_FT; - 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); + empathy_contact_set_capabilities (contact, caps); } + + /* FIXME: This should be done by TpContact */ + handle = empathy_contact_get_handle (contact); + tp_cli_connection_interface_avatars_run_get_known_avatar_tokens (priv->connection, + -1, + &handles, + &tokens, + &error, + NULL); + tp_contact_factory_got_known_avatar_tokens (tp_factory, tokens, error); + g_clear_error (&error); + + tp_cli_connection_interface_capabilities_run_get_capabilities (priv->connection, + -1, + &handles, + &capabilities, + &error, + NULL); + tp_contact_factory_got_capabilities (tp_factory, capabilities, error); + g_clear_error (&error); + + DEBUG ("Contact added: %s (%d)", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact)); } +typedef struct { + EmpathyTpContactFactory *tp_factory; + EmpathyTpContactFactoryGotContactsCb callback; + gpointer user_data; + GDestroyNotify destroy; +} GetContactsData; + static void -tp_contact_factory_update (EmpathyTpContactFactory *tp_factory) +get_contacts_data_free (gpointer user_data) { - 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; - } + GetContactsData *data = user_data; - /* 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 (data->destroy) { + data->destroy (data->user_data); } - 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++; - } + g_object_unref (data->tp_factory); - 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); - } + g_slice_free (GetContactsData, data); } static void -tp_contact_factory_status_changed_cb (MissionControl *mc, - TpConnectionStatus status, - McPresence presence, - TpConnectionStatusReason reason, - const gchar *unique_name, - EmpathyTpContactFactory *tp_factory) +got_contacts (GetContactsData *data, + GObject *weak_object, + guint n_contacts, + TpContact * const *contacts, + const GError *error) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - McAccount *account; + GList *ret = NULL; + guint i; - account = mc_account_lookup (unique_name); - if (account && empathy_account_equal (account, priv->account)) { - tp_contact_factory_update (tp_factory); + if (error) { + DEBUG ("Error: %s", error->message); } - g_object_unref (account); -} -static void -tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory, - EmpathyContact *contact) -{ - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + for (i = 0; i < n_contacts; i++) { + EmpathyContact *contact; - g_object_weak_ref (G_OBJECT (contact), - tp_contact_factory_weak_notify, - tp_factory); - priv->contacts = g_list_prepend (priv->contacts, contact); + contact = tp_contact_factory_find_by_tp_contact (data->tp_factory, + contacts[i]); - if (!priv->presence_iface) { - /* We have no presence iface, set default presence - * to available */ - empathy_contact_set_presence (contact, MC_PRESENCE_AVAILABLE); + if (contact != NULL) { + g_object_ref (contact); + } else { + contact = empathy_contact_new (contacts[i]); + tp_contact_factory_add_contact (data->tp_factory, contact); + } + ret = g_list_prepend (ret, contact); } - empathy_debug (DEBUG_DOMAIN, "Contact added: %s (%d)", - empathy_contact_get_id (contact), - empathy_contact_get_handle (contact)); + if (data->callback) + data->callback (data->tp_factory, ret, data->user_data, weak_object); + + g_list_foreach (ret, (GFunc) g_object_unref, NULL); + g_list_free (ret); } static void -tp_contact_factory_hold_handles_cb (DBusGProxy *proxy, - GError *error, - gpointer userdata) +get_contacts_by_handle_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object) { - if (error) { - empathy_debug (DEBUG_DOMAIN, "Failed to hold handles: %s", - error->message); - } + got_contacts (user_data, weak_object, + n_contacts, contacts, + error); } -EmpathyContact * -empathy_tp_contact_factory_get_user (EmpathyTpContactFactory *tp_factory) +static void +get_contacts_by_id_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) { - 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); + got_contacts (user_data, weak_object, + n_contacts, contacts, + error); } -EmpathyContact * -empathy_tp_contact_factory_get_from_id (EmpathyTpContactFactory *tp_factory, - const gchar *id) +void +empathy_tp_contact_factory_get_from_ids (EmpathyTpContactFactory *tp_factory, + guint n_ids, + const gchar * const *ids, + EmpathyTpContactFactoryGotContactsCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { 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; -} + GetContactsData *data; -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; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (ids != NULL); + + data = g_slice_new (GetContactsData); + data->callback = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_id (priv->connection, + n_ids, ids, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_id_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } -GList * +void empathy_tp_contact_factory_get_from_handles (EmpathyTpContactFactory *tp_factory, - GArray *handles) + guint n_handles, + const TpHandle *handles, + EmpathyTpContactFactoryGotContactsCb callback, + gpointer user_data, + GDestroyNotify destroy, + GObject *weak_object) { EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); - GList *contacts = NULL; - GArray *new_handles; - gchar **handles_names; - guint i; - GError *error = NULL; + GetContactsData *data; - 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; + g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory)); + g_return_if_fail (handles != NULL); + + data = g_slice_new (GetContactsData); + data->callback = callback; + data->user_data = user_data; + data->destroy = destroy; + data->tp_factory = g_object_ref (tp_factory); + tp_connection_get_contacts_by_handle (priv->connection, + n_handles, handles, + G_N_ELEMENTS (contact_features), + contact_features, + get_contacts_by_handle_cb, + data, + (GDestroyNotify) get_contacts_data_free, + weak_object); } void @@ -1095,18 +711,12 @@ empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, 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); + DEBUG ("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, @@ -1117,10 +727,12 @@ empathy_tp_contact_factory_set_alias (EmpathyTpContactFactory *tp_factory, 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)); + tp_cli_connection_interface_aliasing_call_set_aliases (priv->connection, + -1, + new_alias, + tp_contact_factory_set_aliases_cb, + NULL, NULL, + G_OBJECT (tp_factory)); g_hash_table_destroy (new_alias); } @@ -1135,30 +747,31 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *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)); + DEBUG ("Setting avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); - tp_conn_iface_avatars_set_avatar_async (priv->avatars_iface, - &avatar, - mime_type, - tp_contact_factory_set_avatar_cb, - g_object_ref (tp_factory)); + tp_cli_connection_interface_avatars_call_set_avatar (priv->connection, + -1, + &avatar, + mime_type, + tp_contact_factory_set_avatar_cb, + NULL, NULL, + G_OBJECT (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)); + DEBUG ("Clearing avatar on connection %s", + tp_proxy_get_object_path (TP_PROXY (priv->connection))); + + tp_cli_connection_interface_avatars_call_clear_avatar (priv->connection, + -1, + tp_contact_factory_clear_avatar_cb, + NULL, NULL, + G_OBJECT (tp_factory)); } } @@ -1171,8 +784,26 @@ tp_contact_factory_get_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); + case PROP_CONNECTION: + g_value_set_object (value, priv->connection); + break; + case PROP_MIME_TYPES: + g_value_set_boxed (value, priv->avatar_mime_types); + break; + case PROP_MIN_WIDTH: + g_value_set_uint (value, priv->avatar_min_width); + break; + case PROP_MIN_HEIGHT: + g_value_set_uint (value, priv->avatar_min_height); + break; + case PROP_MAX_WIDTH: + g_value_set_uint (value, priv->avatar_max_width); + break; + case PROP_MAX_HEIGHT: + g_value_set_uint (value, priv->avatar_max_height); + break; + case PROP_MAX_SIZE: + g_value_set_uint (value, priv->avatar_max_size); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -1189,8 +820,8 @@ tp_contact_factory_set_property (GObject *object, EmpathyTpContactFactoryPriv *priv = GET_PRIV (object); switch (param_id) { - case PROP_ACCOUNT: - priv->account = g_object_ref (g_value_get_object (value)); + case PROP_CONNECTION: + priv->connection = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); @@ -1204,15 +835,7 @@ 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); + DEBUG ("Finalized: %p", object); for (l = priv->contacts; l; l = l->next) { g_object_weak_unref (G_OBJECT (l->data), @@ -1221,12 +844,10 @@ tp_contact_factory_finalize (GObject *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_unref (priv->connection); + + g_strfreev (priv->avatar_mime_types); G_OBJECT_CLASS (empathy_tp_contact_factory_parent_class)->finalize (object); } @@ -1237,15 +858,44 @@ tp_contact_factory_constructor (GType type, GObjectConstructParam *props) { GObject *tp_factory; + EmpathyTpContactFactoryPriv *priv; 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)); + priv = GET_PRIV (tp_factory); + + /* FIXME: This should be moved to TpContact */ + tp_cli_connection_interface_avatars_connect_to_avatar_updated (priv->connection, + tp_contact_factory_avatar_updated_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_avatars_connect_to_avatar_retrieved (priv->connection, + tp_contact_factory_avatar_retrieved_cb, + NULL, NULL, + tp_factory, + NULL); + tp_cli_connection_interface_capabilities_connect_to_capabilities_changed (priv->connection, + tp_contact_factory_capabilities_changed_cb, + NULL, NULL, + tp_factory, + NULL); + + + /* FIXME: This should be moved to TpConnection */ + tp_cli_connection_interface_avatars_call_get_avatar_requirements (priv->connection, + -1, + tp_contact_factory_got_avatar_requirements_cb, + NULL, NULL, + tp_factory); + tp_cli_dbus_properties_call_get (priv->connection, -1, + TP_IFACE_CONNECTION_INTERFACE_REQUESTS, + "RequestableChannelClasses", + get_requestable_channel_classes_cb, NULL, NULL, + G_OBJECT (tp_factory)); return tp_factory; } - static void empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) { @@ -1256,15 +906,84 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) 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, + PROP_CONNECTION, + g_param_spec_object ("connection", + "Factory's Connection", + "The connection associated with the factory", + TP_TYPE_CONNECTION, G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_MIME_TYPES, + g_param_spec_boxed ("avatar-mime-types", + "Supported MIME types for avatars", + "Types of images that may be set as " + "avatars on this connection. Only valid " + "once 'ready' becomes TRUE.", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_MIN_WIDTH, + g_param_spec_uint ("avatar-min-width", + "Minimum width for avatars", + "Minimum width of avatar that may be set. " + "Only valid once 'ready' becomes TRUE.", + 0, + G_MAXUINT, + 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_MIN_HEIGHT, + g_param_spec_uint ("avatar-min-height", + "Minimum height for avatars", + "Minimum height of avatar that may be set. " + "Only valid once 'ready' becomes TRUE.", + 0, + G_MAXUINT, + 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_MAX_WIDTH, + g_param_spec_uint ("avatar-max-width", + "Maximum width for avatars", + "Maximum width of avatar that may be set " + "or 0 if there is no maximum. " + "Only valid once 'ready' becomes TRUE.", + 0, + G_MAXUINT, + 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_MAX_HEIGHT, + g_param_spec_uint ("avatar-max-height", + "Maximum height for avatars", + "Maximum height of avatar that may be set " + "or 0 if there is no maximum. " + "Only valid once 'ready' becomes TRUE.", + 0, + G_MAXUINT, + 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_MAX_SIZE, + g_param_spec_uint ("avatar-max-size", + "Maximum size for avatars in bytes", + "Maximum file size of avatar that may be " + "set or 0 if there is no maximum. " + "Only valid once 'ready' becomes TRUE.", + 0, + G_MAXUINT, + 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + g_type_class_add_private (object_class, sizeof (EmpathyTpContactFactoryPriv)); } @@ -1272,20 +991,72 @@ empathy_tp_contact_factory_class_init (EmpathyTpContactFactoryClass *klass) static void empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory) { - EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory); + EmpathyTpContactFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (tp_factory, + EMPATHY_TYPE_TP_CONTACT_FACTORY, EmpathyTpContactFactoryPriv); + + tp_factory->priv = priv; + priv->can_request_ft = FALSE; +} + +static GHashTable *factories = NULL; + +static void +tp_contact_factory_connection_invalidated_cb (TpProxy *connection, + guint domain, + gint code, + gchar *message, + gpointer user_data) +{ + DEBUG ("Message: %s", message); + g_hash_table_remove (factories, connection); +} - 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); +static void +tp_contact_factory_connection_weak_notify_cb (gpointer connection, + GObject *where_the_object_was) +{ + g_hash_table_remove (factories, connection); +} + +static void +tp_contact_factory_remove_connection (gpointer connection) +{ + g_signal_handlers_disconnect_by_func (connection, + tp_contact_factory_connection_invalidated_cb, NULL); + g_object_unref (connection); } EmpathyTpContactFactory * -empathy_tp_contact_factory_new (McAccount *account) +empathy_tp_contact_factory_dup_singleton (TpConnection *connection) { - return g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, - "account", account, - NULL); + EmpathyTpContactFactory *tp_factory; + + g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); + + if (factories == NULL) { + factories = g_hash_table_new_full (empathy_proxy_hash, + empathy_proxy_equal, + tp_contact_factory_remove_connection, + NULL); + } + + tp_factory = g_hash_table_lookup (factories, connection); + if (tp_factory == NULL) { + tp_factory = g_object_new (EMPATHY_TYPE_TP_CONTACT_FACTORY, + "connection", connection, + NULL); + g_hash_table_insert (factories, g_object_ref (connection), + tp_factory); + g_object_weak_ref (G_OBJECT (tp_factory), + tp_contact_factory_connection_weak_notify_cb, + connection); + g_signal_connect (connection, "invalidated", + G_CALLBACK (tp_contact_factory_connection_invalidated_cb), + NULL); + } else { + g_object_ref (tp_factory); + } + + return tp_factory; }