diff options
Diffstat (limited to 'libempathy/empathy-dispatcher.c')
-rw-r--r-- | libempathy/empathy-dispatcher.c | 656 |
1 files changed, 1 insertions, 655 deletions
diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 558767751..1f7d7f277 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -19,451 +19,21 @@ * Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> */ -#define DISPATCHER_BUS_NAME TP_CLIENT_BUS_NAME_BASE "Empathy" -#define DISPATCHER_OBJECT_PATH TP_CLIENT_OBJECT_PATH_BASE "Empathy" - #include <config.h> #include <string.h> #include <glib/gi18n-lib.h> -#include <telepathy-glib/account-manager.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/connection.h> -#include <telepathy-glib/util.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/proxy-subclass.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/defs.h> -#include <telepathy-glib/interfaces.h> - -#include <extensions/extensions.h> +#include <telepathy-glib/telepathy-glib.h> #include "empathy-dispatcher.h" #include "empathy-utils.h" -#include "empathy-tp-contact-factory.h" -#include "empathy-chatroom-manager.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER #include <libempathy/empathy-debug.h> -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyDispatcher) -typedef struct -{ - gboolean dispose_has_run; - - TpAccountManager *account_manager; - /* connection to connection data mapping */ - GHashTable *connections; - GHashTable *outstanding_classes_requests; - - /* reffed (TpAccount *) => gulong - * Signal handler ID of the "status-changed" signal */ - GHashTable *status_changed_handlers; -} EmpathyDispatcherPriv; - -G_DEFINE_TYPE (EmpathyDispatcher, empathy_dispatcher, G_TYPE_OBJECT); - -static EmpathyDispatcher *dispatcher = NULL; - -static void dispatcher_init_connection_if_needed ( - EmpathyDispatcher *dispatcher, - TpConnection *connection); - -static GList * empathy_dispatcher_find_channel_classes - (EmpathyDispatcher *dispatcher, TpConnection *connection, - const gchar *channel_type, guint handle_type, GArray *fixed_properties); - -typedef struct -{ - TpChannel *channel; - /* Channel type specific wrapper object */ - GObject *channel_wrapper; -} DispatchData; - -typedef struct -{ - /* List of requestable channel classes */ - GPtrArray *requestable_channels; -} ConnectionData; - -typedef struct -{ - EmpathyDispatcher *dispatcher; - TpConnection *connection; - char *channel_type; - guint handle_type; - GArray *properties; - EmpathyDispatcherFindChannelClassCb *callback; - gpointer user_data; -} FindChannelRequest; - -static ConnectionData * -new_connection_data (void) -{ - return g_slice_new0 (ConnectionData); -} - -static void -free_connection_data (ConnectionData *cd) -{ - guint i; - - if (cd->requestable_channels != NULL) - { - for (i = 0 ; i < cd->requestable_channels->len ; i++) - g_value_array_free ( - g_ptr_array_index (cd->requestable_channels, i)); - g_ptr_array_free (cd->requestable_channels, TRUE); - } -} - -static void -free_find_channel_request (FindChannelRequest *r) -{ - guint idx; - char *str; - - g_object_unref (r->dispatcher); - g_free (r->channel_type); - - if (r->properties != NULL) - { - for (idx = 0; idx < r->properties->len ; idx++) - { - str = g_array_index (r->properties, char *, idx); - g_free (str); - } - - g_array_free (r->properties, TRUE); - } - - g_slice_free (FindChannelRequest, r); -} - -static void -dispatcher_connection_invalidated_cb (TpConnection *connection, - guint domain, - gint code, - gchar *message, - EmpathyDispatcher *self) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (self); - - DEBUG ("Error: %s", message); - - g_hash_table_remove (priv->connections, connection); -} - -static void -got_connection_rcc (EmpathyDispatcher *self, - TpConnection *connection) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (self); - TpCapabilities *caps; - ConnectionData *cd; - GList *requests, *l; - FindChannelRequest *request; - GList *retval; - - caps = tp_connection_get_capabilities (connection); - g_assert (caps != NULL); - - cd = g_hash_table_lookup (priv->connections, connection); - g_assert (cd != NULL); - - cd->requestable_channels = g_boxed_copy ( - TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, - tp_capabilities_get_channel_classes (caps)); - - requests = g_hash_table_lookup (priv->outstanding_classes_requests, - connection); - - for (l = requests; l != NULL; l = l->next) - { - request = l->data; - - retval = empathy_dispatcher_find_channel_classes (self, - connection, request->channel_type, - request->handle_type, request->properties); - request->callback (retval, request->user_data); - - free_find_channel_request (request); - g_list_free (retval); - } - - g_list_free (requests); - - g_hash_table_remove (priv->outstanding_classes_requests, connection); -} - -static void -connection_prepare_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - EmpathyDispatcher *self = EMPATHY_DISPATCHER (user_data); - GError *error = NULL; - TpConnection *connection = (TpConnection *) source; - - if (!tp_proxy_prepare_finish (source, result, &error)) - { - DEBUG ("Error: %s", error->message); - - g_error_free (error); - goto out; - } - - got_connection_rcc (self, connection); - -out: - g_object_unref (self); -} - -static void -dispatcher_init_connection_if_needed (EmpathyDispatcher *self, - TpConnection *connection) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (self); - GQuark features[] = { TP_CONNECTION_FEATURE_CORE, - TP_CONNECTION_FEATURE_CAPABILITIES, - 0 }; - - if (g_hash_table_lookup (priv->connections, connection) != NULL) - return; - - g_hash_table_insert (priv->connections, g_object_ref (connection), - new_connection_data ()); - - g_signal_connect (connection, "invalidated", - G_CALLBACK (dispatcher_connection_invalidated_cb), self); - - /* Ensure to keep the self object alive while preparing the connection */ - g_object_ref (self); - - tp_proxy_prepare_async (connection, features, connection_prepare_cb, self); -} - -static void -dispatcher_status_changed_cb (TpAccount *account, - guint old_status, - guint new_status, - guint reason, - gchar *dbus_error_name, - GHashTable *details, - EmpathyDispatcher *self) -{ - TpConnection *conn = tp_account_get_connection (account); - - if (conn != NULL) - dispatcher_init_connection_if_needed (self, conn); -} - -static GObject * -dispatcher_constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) -{ - GObject *retval; - EmpathyDispatcherPriv *priv; - - if (dispatcher != NULL) - return g_object_ref (dispatcher); - - retval = G_OBJECT_CLASS (empathy_dispatcher_parent_class)->constructor - (type, n_construct_params, construct_params); - - dispatcher = EMPATHY_DISPATCHER (retval); - g_object_add_weak_pointer (retval, (gpointer) &dispatcher); - - priv = GET_PRIV (dispatcher); - - return retval; -} - -static void -dispatcher_dispose (GObject *object) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (object); - GHashTableIter iter; - gpointer connection; - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, &connection, NULL)) - { - g_signal_handlers_disconnect_by_func (connection, - dispatcher_connection_invalidated_cb, object); - } - - g_hash_table_destroy (priv->connections); - priv->connections = NULL; - - G_OBJECT_CLASS (empathy_dispatcher_parent_class)->dispose (object); -} - -static void -dispatcher_finalize (GObject *object) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (object); - GHashTableIter iter; - gpointer connection; - GList *list; - gpointer account, id; - - g_hash_table_iter_init (&iter, priv->outstanding_classes_requests); - while (g_hash_table_iter_next (&iter, &connection, (gpointer *) &list)) - { - g_list_foreach (list, (GFunc) free_find_channel_request, NULL); - g_list_free (list); - } - - g_hash_table_iter_init (&iter, priv->status_changed_handlers); - while (g_hash_table_iter_next (&iter, &account, &id)) - { - g_signal_handler_disconnect (account, GPOINTER_TO_UINT (id)); - } - g_hash_table_destroy (priv->status_changed_handlers); - - g_object_unref (priv->account_manager); - - g_hash_table_destroy (priv->outstanding_classes_requests); -} - -static void -empathy_dispatcher_class_init (EmpathyDispatcherClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = dispatcher_dispose; - object_class->finalize = dispatcher_finalize; - object_class->constructor = dispatcher_constructor; - - g_type_class_add_private (object_class, sizeof (EmpathyDispatcherPriv)); -} - -static void -connect_account (EmpathyDispatcher *self, - TpAccount *account) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (self); - TpConnection *conn = tp_account_get_connection (account); - gulong id; - - id = GPOINTER_TO_UINT (g_hash_table_lookup (priv->status_changed_handlers, - account)); - - if (id != 0) - return; - - if (conn != NULL) - dispatcher_status_changed_cb (account, 0, 0, 0, NULL, NULL, self); - - id = g_signal_connect (account, "status-changed", - G_CALLBACK (dispatcher_status_changed_cb), self); - - g_hash_table_insert (priv->status_changed_handlers, g_object_ref (account), - GUINT_TO_POINTER (id)); -} - -static void -account_manager_prepared_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - GList *accounts, *l; - EmpathyDispatcher *self = user_data; - TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object); - GError *error = NULL; - - if (!tp_account_manager_prepare_finish (account_manager, result, &error)) - { - DEBUG ("Failed to prepare account manager: %s", error->message); - g_error_free (error); - return; - } - - accounts = tp_account_manager_get_valid_accounts (account_manager); - for (l = accounts; l; l = l->next) - { - TpAccount *a = l->data; - - connect_account (self, a); - } - - g_list_foreach (accounts, (GFunc) g_object_ref, NULL); - g_list_free (accounts); -} - -static void -account_prepare_cb (GObject *source_object, - GAsyncResult *result, - gpointer user_data) -{ - EmpathyDispatcher *self = user_data; - TpAccount *account = TP_ACCOUNT (source_object); - GError *error = NULL; - - if (!tp_account_prepare_finish (account, result, &error)) - { - DEBUG ("Failed to prepare account: %s", error->message); - g_error_free (error); - return; - } - - connect_account (self, account); -} - -static void -account_validity_changed_cb (TpAccountManager *manager, - TpAccount *account, - gboolean valid, - gpointer user_data) -{ - if (!valid) - return; - - tp_account_prepare_async (account, NULL, account_prepare_cb, user_data); -} - -static void -empathy_dispatcher_init (EmpathyDispatcher *self) -{ - EmpathyDispatcherPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherPriv); - - self->priv = priv; - priv->account_manager = tp_account_manager_dup (); - - priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, - g_object_unref, (GDestroyNotify) free_connection_data); - - priv->outstanding_classes_requests = g_hash_table_new_full (g_direct_hash, - g_direct_equal, g_object_unref, NULL); - - tp_account_manager_prepare_async (priv->account_manager, NULL, - account_manager_prepared_cb, self); - - tp_g_signal_connect_object (priv->account_manager, - "account-validity-changed", G_CALLBACK (account_validity_changed_cb), - self, 0); - - priv->status_changed_handlers = g_hash_table_new_full (NULL, NULL, - (GDestroyNotify) g_object_unref, NULL); -} - -EmpathyDispatcher * -empathy_dispatcher_dup_singleton (void) -{ - return EMPATHY_DISPATCHER (g_object_new (EMPATHY_TYPE_DISPATCHER, NULL)); -} - void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, gint64 timestamp) @@ -535,227 +105,3 @@ empathy_dispatcher_join_muc (TpAccount *account, g_hash_table_unref (request); g_object_unref (req); } - -static gboolean -channel_class_matches (GValueArray *class, - const char *channel_type, - guint handle_type, - GArray *fixed_properties) -{ - GHashTable *fprops; - GValue *v; - const char *c_type; - guint h_type; - gboolean valid; - - v = g_value_array_get_nth (class, 0); - - /* if the class doesn't match channel type discard it. */ - fprops = g_value_get_boxed (v); - c_type = tp_asv_get_string (fprops, TP_IFACE_CHANNEL ".ChannelType"); - - if (tp_strdiff (channel_type, c_type)) - return FALSE; - - /* we have the right channel type, see if the handle type matches */ - h_type = tp_asv_get_uint32 (fprops, - TP_IFACE_CHANNEL ".TargetHandleType", &valid); - - if (!valid || (handle_type != h_type && handle_type != TP_UNKNOWN_HANDLE_TYPE)) - return FALSE; - - if (fixed_properties != NULL) - { - gpointer h_key, h_val; - guint idx; - GHashTableIter iter; - gboolean found; - - g_hash_table_iter_init (&iter, fprops); - - while (g_hash_table_iter_next (&iter, &h_key, &h_val)) - { - /* discard ChannelType and TargetHandleType, as we already - * checked them. - */ - if (!tp_strdiff ((char *) h_key, TP_IFACE_CHANNEL ".ChannelType") || - !tp_strdiff - ((char *) h_key, TP_IFACE_CHANNEL ".TargetHandleType")) - continue; - - found = FALSE; - - for (idx = 0; idx < fixed_properties->len; idx++) - { - /* if |key| doesn't exist in |fixed_properties|, discard - * the class. - */ - if (!tp_strdiff - ((char *) h_key, - g_array_index (fixed_properties, char *, idx))) - { - found = TRUE; - /* exit the for() loop */ - break; - } - } - - if (!found) - return FALSE; - } - } - else - { - /* if no fixed_properties are specified, discard the classes - * with some fixed properties other than the two we already - * checked. - */ - if (g_hash_table_size (fprops) > 2) - return FALSE; - } - - return TRUE; -} - -static GList * -empathy_dispatcher_find_channel_classes (EmpathyDispatcher *self, - TpConnection *connection, - const gchar *channel_type, - guint handle_type, - GArray *fixed_properties) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (self); - GValueArray *class; - GPtrArray *classes; - GList *matching_classes; - guint i; - ConnectionData *cd; - - g_return_val_if_fail (channel_type != NULL, NULL); - - cd = g_hash_table_lookup (priv->connections, connection); - - if (cd == NULL) - return NULL; - - classes = cd->requestable_channels; - if (classes == NULL) - return NULL; - - matching_classes = NULL; - - for (i = 0; i < classes->len; i++) - { - class = g_ptr_array_index (classes, i); - - if (!channel_class_matches - (class, channel_type, handle_type, fixed_properties)) - continue; - - matching_classes = g_list_prepend (matching_classes, class); - } - - return matching_classes; -} - -static GArray * -setup_varargs (va_list var_args, - const char *channel_namespace, - const char *first_property_name) -{ - const char *name; - char *name_full; - GArray *properties; - - if (first_property_name == NULL) - return NULL; - - name = first_property_name; - properties = g_array_new (TRUE, TRUE, sizeof (char *)); - - while (name != NULL) - { - name_full = g_strdup (name); - properties = g_array_append_val (properties, name_full); - name = va_arg (var_args, char *); - } - - return properties; -} - -/** - * empathy_dispatcher_find_requestable_channel_classes: - * @dispatcher: an #EmpathyDispatcher - * @connection: a #TpConnection - * @channel_type: a string identifying the type of the channel to lookup - * @handle_type: the handle type for the channel, or %TP_UNKNOWN_HANDLE_TYPE - * if you don't care about the channel's target handle type - * @first_property_name: %NULL, or the name of the first fixed property, - * followed optionally by more names, followed by %NULL. - * - * Returns all the channel classes that a client can request for the connection - * @connection, of the type identified by @channel_type, @handle_type and the - * fixed properties list. - * The classes which are compatible with a fixed properties list (i.e. those - * that will be returned by this function) are intended as those that do not - * contain any fixed property other than those in the list; note that this - * doesn't guarantee that all the classes compatible with the list will contain - * all the requested fixed properties, so the clients will have to filter - * the returned list themselves. - * If @first_property_name is %NULL, only the classes with no other fixed - * properties than ChannelType and TargetHandleType will be returned. - * Note that this function may return %NULL without performing any lookup if - * @connection is not ready. To ensure that @connection is always ready, - * use the empathy_dispatcher_find_requestable_channel_classes_async() variant. - * - * Return value: a #GList of #GValueArray objects, where the first element in - * the array is a #GHashTable of the fixed properties, and the second is - * a #GStrv of the allowed properties for the class. The list should be free'd - * with g_list_free() when done, but the objects inside the list are owned - * by the #EmpathyDispatcher and must not be modified. - */ -GList * -empathy_dispatcher_find_requestable_channel_classes - (EmpathyDispatcher *self, - TpConnection *connection, - const gchar *channel_type, - guint handle_type, - const char *first_property_name, - ...) -{ - va_list var_args; - GArray *properties; - EmpathyDispatcherPriv *priv; - GList *retval; - guint idx; - char *str; - - g_return_val_if_fail (EMPATHY_IS_DISPATCHER (self), NULL); - g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (channel_type != NULL, NULL); - - priv = GET_PRIV (self); - - va_start (var_args, first_property_name); - - properties = setup_varargs (var_args, channel_type, first_property_name); - - va_end (var_args); - - retval = empathy_dispatcher_find_channel_classes (self, connection, - channel_type, handle_type, properties); - - if (properties != NULL) - { - /* free the properties array */ - for (idx = 0; idx < properties->len ; idx++) - { - str = g_array_index (properties, char *, idx); - g_free (str); - } - - g_array_free (properties, TRUE); - } - - return retval; -} |