X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=libempathy%2Fempathy-dispatcher.c;h=c8a0f9e60b043e5effd618a6ab3d71930267c841;hp=711d7c854bea429a82229dd8be2558e8e3263eac;hb=5f6a57093aa93d8bcf4cee001adacaa91d4198c7;hpb=53a5ccde2a29a81a34e2624d44d798bd765a921e diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index 711d7c85..c8a0f9e6 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -28,9 +28,9 @@ #include #include #include +#include #include -#include #include @@ -38,8 +38,7 @@ #include "empathy-utils.h" #include "empathy-tube-handler.h" #include "empathy-account-manager.h" -#include "empathy-contact-factory.h" -#include "empathy-tp-group.h" +#include "empathy-tp-contact-factory.h" #include "empathy-tp-file.h" #include "empathy-chatroom-manager.h" #include "empathy-utils.h" @@ -48,20 +47,23 @@ #include #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyDispatcher) -typedef struct { +typedef struct +{ EmpathyAccountManager *account_manager; MissionControl *mc; /* connection to connection data mapping */ - GHashTable *connections; - /* accounts to connection mapping */ - GHashTable *accounts; - gpointer token; - GSList *tubes; + GHashTable *connections; + gpointer token; + GSList *tubes; + + /* channels which the dispatcher is listening "invalidated" */ + GList *channels; } EmpathyDispatcherPriv; G_DEFINE_TYPE (EmpathyDispatcher, empathy_dispatcher, G_TYPE_OBJECT); -enum { +enum +{ OBSERVE, APPROVE, DISPATCH, @@ -71,7 +73,8 @@ enum { static guint signals[LAST_SIGNAL]; static EmpathyDispatcher *dispatcher = NULL; -typedef struct { +typedef struct +{ EmpathyDispatcher *dispatcher; EmpathyDispatchOperation *operation; TpConnection *connection; @@ -87,14 +90,15 @@ typedef struct { gpointer *request_data; } DispatcherRequestData; -typedef struct { +typedef struct +{ TpChannel *channel; /* Channel type specific wrapper object */ GObject *channel_wrapper; } DispatchData; -typedef struct { - McAccount *account; +typedef struct +{ /* ObjectPath => DispatchData.. */ GHashTable *dispatched_channels; /* ObjectPath -> EmpathyDispatchOperations */ @@ -103,14 +107,18 @@ typedef struct { GHashTable *outstanding_channels; /* List of DispatcherRequestData */ GList *outstanding_requests; + /* List of requestable channel classes */ + GPtrArray *requestable_channels; } ConnectionData; static DispatchData * -new_dispatch_data (TpChannel *channel, GObject *channel_wrapper) +new_dispatch_data (TpChannel *channel, + GObject *channel_wrapper) { DispatchData *d = g_slice_new0 (DispatchData); d->channel = g_object_ref (channel); - d->channel_wrapper = g_object_ref (channel_wrapper); + if (channel_wrapper != NULL) + d->channel_wrapper = g_object_ref (channel_wrapper); return d; } @@ -119,21 +127,26 @@ static void free_dispatch_data (DispatchData *data) { g_object_unref (data->channel); - g_object_unref (data->channel_wrapper); + if (data->channel_wrapper != NULL) + g_object_unref (data->channel_wrapper); g_slice_free (DispatchData, data); } - static DispatcherRequestData * new_dispatcher_request_data (EmpathyDispatcher *dispatcher, - TpConnection *connection, const gchar *channel_type, guint handle_type, - guint handle, GHashTable *request, - EmpathyContact *contact, EmpathyDispatcherRequestCb *cb, gpointer user_data) + TpConnection *connection, + const gchar *channel_type, + guint handle_type, + guint handle, + GHashTable *request, + EmpathyContact *contact, + EmpathyDispatcherRequestCb *cb, + gpointer user_data) { DispatcherRequestData *result = g_slice_new0 (DispatcherRequestData); - result->dispatcher = dispatcher; + result->dispatcher = g_object_ref (dispatcher); result->connection = connection; result->channel_type = g_strdup (channel_type); @@ -155,6 +168,9 @@ free_dispatcher_request_data (DispatcherRequestData *r) { g_free (r->channel_type); + if (r->dispatcher != NULL) + g_object_unref (r->dispatcher); + if (r->contact != NULL) g_object_unref (r->contact); @@ -165,19 +181,18 @@ free_dispatcher_request_data (DispatcherRequestData *r) } static ConnectionData * -new_connection_data (McAccount *account) +new_connection_data (void) { ConnectionData *cd = g_slice_new0 (ConnectionData); - cd->account = g_object_ref (account); cd->dispatched_channels = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) free_dispatch_data); + g_free, (GDestroyNotify) free_dispatch_data); cd->dispatching_channels = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); + g_free, g_object_unref); cd->outstanding_channels = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); + g_free, NULL); return cd; } @@ -186,34 +201,42 @@ static void free_connection_data (ConnectionData *cd) { GList *l; - g_object_unref (cd->account); + g_hash_table_destroy (cd->dispatched_channels); g_hash_table_destroy (cd->dispatching_channels); + int i; for (l = cd->outstanding_requests ; l != NULL; l = g_list_delete_link (l,l)) { free_dispatcher_request_data (l->data); } + + 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 -dispatcher_connection_invalidated_cb (TpConnection *connection, - guint domain, gint code, gchar *message, - EmpathyDispatcher *dispatcher) +dispatcher_connection_invalidated_cb (TpConnection *connection, + guint domain, + gint code, + gchar *message, + EmpathyDispatcher *dispatcher) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - ConnectionData *cd; DEBUG ("Error: %s", message); - cd = g_hash_table_lookup (priv->connections, connection); - - g_hash_table_remove (priv->accounts, cd->account); g_hash_table_remove (priv->connections, connection); } static gboolean dispatcher_operation_can_start (EmpathyDispatcher *self, - EmpathyDispatchOperation *operation, ConnectionData *cd) + EmpathyDispatchOperation *operation, + ConnectionData *cd) { GList *l; const gchar *channel_type = @@ -234,7 +257,9 @@ dispatcher_operation_can_start (EmpathyDispatcher *self, static void dispatch_operation_flush_requests (EmpathyDispatcher *dispatcher, - EmpathyDispatchOperation *operation, GError *error, ConnectionData *cd) + EmpathyDispatchOperation *operation, + GError *error, + ConnectionData *cd) { GList *l; @@ -265,8 +290,11 @@ dispatch_operation_flush_requests (EmpathyDispatcher *dispatcher, } static void -dispatcher_channel_invalidated_cb (TpProxy *proxy, guint domain, gint code, - gchar *message, EmpathyDispatcher *dispatcher) +dispatcher_channel_invalidated_cb (TpProxy *proxy, + guint domain, + gint code, + gchar *message, + EmpathyDispatcher *dispatcher) { /* Channel went away... */ EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); @@ -275,7 +303,7 @@ dispatcher_channel_invalidated_cb (TpProxy *proxy, guint domain, gint code, ConnectionData *cd; const gchar *object_path; - g_object_get (G_OBJECT (proxy), "connection", &connection, NULL); + connection = tp_channel_borrow_connection (TP_CHANNEL (proxy)); cd = g_hash_table_lookup (priv->connections, connection); /* Connection itself invalidated? */ @@ -289,6 +317,8 @@ dispatcher_channel_invalidated_cb (TpProxy *proxy, guint domain, gint code, g_hash_table_remove (cd->dispatched_channels, object_path); g_hash_table_remove (cd->dispatching_channels, object_path); + priv->channels = g_list_remove (priv->channels, proxy); + operation = g_hash_table_lookup (cd->outstanding_channels, object_path); if (operation != NULL) { @@ -301,7 +331,7 @@ dispatcher_channel_invalidated_cb (TpProxy *proxy, guint domain, gint code, static void dispatch_operation_approved_cb (EmpathyDispatchOperation *operation, - EmpathyDispatcher *dispatcher) + EmpathyDispatcher *dispatcher) { g_assert (empathy_dispatch_operation_is_incoming (operation)); DEBUG ("Send of for dispatching: %s", @@ -311,7 +341,7 @@ dispatch_operation_approved_cb (EmpathyDispatchOperation *operation, static void dispatch_operation_claimed_cb (EmpathyDispatchOperation *operation, - EmpathyDispatcher *dispatcher) + EmpathyDispatcher *dispatcher) { /* Our job is done, remove the dispatch operation and mark the channel as * dispatched */ @@ -323,7 +353,6 @@ dispatch_operation_claimed_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); object_path = empathy_dispatch_operation_get_object_path (operation); @@ -343,7 +372,7 @@ dispatch_operation_claimed_cb (EmpathyDispatchOperation *operation, static void dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, - EmpathyDispatcher *dispatcher) + EmpathyDispatcher *dispatcher) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); TpConnection *connection; @@ -367,9 +396,9 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, connection = empathy_dispatch_operation_get_tp_connection (operation); cd = g_hash_table_lookup (priv->connections, connection); g_assert (cd != NULL); - g_object_unref (G_OBJECT (connection)); g_object_ref (operation); + g_object_ref (dispatcher); dispatch_operation_flush_requests (dispatcher, operation, NULL, cd); status = empathy_dispatch_operation_get_status (operation); @@ -392,11 +421,13 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, g_signal_emit (dispatcher, signals[DISPATCH], 0, operation); } + g_object_unref (dispatcher); } static void dispatcher_start_dispatching (EmpathyDispatcher *self, - EmpathyDispatchOperation *operation, ConnectionData *cd) + EmpathyDispatchOperation *operation, + ConnectionData *cd) { const gchar *object_path = empathy_dispatch_operation_get_object_path (operation); @@ -435,10 +466,9 @@ dispatcher_start_dispatching (EmpathyDispatcher *self, } } - static void dispatcher_flush_outstanding_operations (EmpathyDispatcher *self, - ConnectionData *cd) + ConnectionData *cd) { GHashTableIter iter; gpointer value; @@ -456,19 +486,20 @@ dispatcher_flush_outstanding_operations (EmpathyDispatcher *self, } } - static void dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, - TpConnection *connection, - const gchar *object_path, const gchar *channel_type, - guint handle_type, guint handle, GHashTable *properties, - gboolean incoming) + TpConnection *connection, + const gchar *object_path, + const gchar *channel_type, + guint handle_type, + guint handle, + GHashTable *properties, + gboolean incoming) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); TpChannel *channel; ConnectionData *cd; EmpathyDispatchOperation *operation; - EmpathyContact *contact = NULL; int i; /* Channel types we never want to dispatch because they're either deprecated * or can't sensibly be dispatch (e.g. channels that should always be @@ -496,10 +527,11 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, if (g_hash_table_lookup (cd->outstanding_channels, object_path) != NULL) return; - /* Only pick up non-requested text channels. For all other it doesn't make - * sense to handle it if we didn't request it. The same goes for channels we - * discovered by the Channels property or ListChannels */ - if (!incoming && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) + /* Only pick up non-requested text and file channels. For all other it + * doesn't make sense to handle it if we didn't request it. The same goes + * for channels we discovered by the Channels property or ListChannels */ + if (!incoming && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT) + && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) { DEBUG ("Ignoring incoming channel of type %s on %s", channel_type, object_path); @@ -529,15 +561,9 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, G_CALLBACK (dispatcher_channel_invalidated_cb), dispatcher); - if (handle_type == TP_CONN_HANDLE_TYPE_CONTACT) - { - EmpathyContactFactory *factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_handle (factory, - cd->account, handle); - g_object_unref (factory); - } + priv->channels = g_list_prepend (priv->channels, channel); - operation = empathy_dispatch_operation_new (connection, channel, contact, + operation = empathy_dispatch_operation_new (connection, channel, NULL, incoming); g_object_unref (channel); @@ -561,10 +587,13 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, static void dispatcher_connection_new_channel_cb (TpConnection *connection, - const gchar *object_path, const gchar *channel_type, - guint handle_type, guint handle, - gboolean suppress_handler, gpointer user_data, - GObject *object) + const gchar *object_path, + const gchar *channel_type, + guint handle_type, + guint handle, + gboolean suppress_handler, + gpointer user_data, + GObject *object) { EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (object); @@ -577,9 +606,10 @@ dispatcher_connection_new_channel_cb (TpConnection *connection, } static void -dispatcher_connection_new_channel_with_properties ( - EmpathyDispatcher *dispatcher, TpConnection *connection, - const gchar *object_path, GHashTable *properties) +dispatcher_connection_new_channel_with_properties (EmpathyDispatcher *dispatcher, + TpConnection *connection, + const gchar *object_path, + GHashTable *properties) { const gchar *channel_type; guint handle_type; @@ -626,11 +656,11 @@ dispatcher_connection_new_channel_with_properties ( object_path, channel_type, handle_type, handle, properties, !requested); } - static void -dispatcher_connection_new_channels_cb ( - TpConnection *connection, const GPtrArray *channels, gpointer user_data, - GObject *object) +dispatcher_connection_new_channels_cb (TpConnection *connection, + const GPtrArray *channels, + gpointer user_data, + GObject *object) { EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (object); int i; @@ -650,84 +680,111 @@ dispatcher_connection_new_channels_cb ( } static void -dispatcher_connection_got_channels_property (TpProxy *proxy, - const GValue *channels_prop, const GError *error, gpointer user_data, - GObject *object) +dispatcher_connection_got_all (TpProxy *proxy, + GHashTable *properties, + const GError *error, + gpointer user_data, + GObject *object) { + EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (object); + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); GPtrArray *channels; + GPtrArray *requestable_channels; if (error) { DEBUG ("Error: %s", error->message); return; } - channels = g_value_get_boxed (channels_prop); - dispatcher_connection_new_channels_cb (TP_CONNECTION (proxy), - channels, NULL, object); + channels = tp_asv_get_boxed (properties, "Channels", + TP_ARRAY_TYPE_CHANNEL_DETAILS_LIST); + + if (channels == NULL) + DEBUG ("No Channels property !?! on connection"); + else + dispatcher_connection_new_channels_cb (TP_CONNECTION (proxy), + channels, NULL, object); + + requestable_channels = tp_asv_get_boxed (properties, + "RequestableChannelClasses", TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST); + + if (requestable_channels == NULL) + DEBUG ("No RequestableChannelClasses property !?! on connection"); + else + { + ConnectionData *cd; + + cd = g_hash_table_lookup (priv->connections, proxy); + g_assert (cd != NULL); + + cd->requestable_channels = g_boxed_copy ( + TP_ARRAY_TYPE_REQUESTABLE_CHANNEL_CLASS_LIST, requestable_channels); + } } static void dispatcher_connection_list_channels_cb (TpConnection *connection, - const GPtrArray *channels, - const GError *error, - gpointer user_data, - GObject *dispatcher) + const GPtrArray *channels, + const GError *error, + gpointer user_data, + GObject *dispatcher) { - int i; - - if (error) { - DEBUG ("Error: %s", error->message); - return; - } - - for (i = 0; i < channels->len; i++) { - GValueArray *values; - - values = g_ptr_array_index (channels, i); - /* We don't have any extra info, so assume already existing channels are - * incoming... */ - dispatcher_connection_new_channel (EMPATHY_DISPATCHER (dispatcher), - connection, - g_value_get_boxed (g_value_array_get_nth (values, 0)), - g_value_get_string (g_value_array_get_nth (values, 1)), - g_value_get_uint (g_value_array_get_nth (values, 2)), - g_value_get_uint (g_value_array_get_nth (values, 3)), - NULL, TRUE); - } + int i; + + if (error) + { + DEBUG ("Error: %s", error->message); + return; + } + + for (i = 0; i < channels->len; i++) + { + GValueArray *values; + + values = g_ptr_array_index (channels, i); + /* We don't have any extra info, so assume already existing channels are + * incoming... */ + dispatcher_connection_new_channel (EMPATHY_DISPATCHER (dispatcher), + connection, + g_value_get_boxed (g_value_array_get_nth (values, 0)), + g_value_get_string (g_value_array_get_nth (values, 1)), + g_value_get_uint (g_value_array_get_nth (values, 2)), + g_value_get_uint (g_value_array_get_nth (values, 3)), + NULL, TRUE); + } } static void dispatcher_connection_advertise_capabilities_cb (TpConnection *connection, - const GPtrArray *capabilities, - const GError *error, - gpointer user_data, - GObject *dispatcher) + const GPtrArray *capabilities, + const GError *error, + gpointer user_data, + GObject *dispatcher) { - if (error) { - DEBUG ("Error: %s", error->message); - } + if (error) + DEBUG ("Error: %s", error->message); } static void -dispatcher_connection_ready_cb (TpConnection *connection, - const GError *error, gpointer dispatcher) +dispatcher_new_connection_cb (EmpathyAccountManager *manager, + TpConnection *connection, + EmpathyDispatcher *dispatcher) { + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); GPtrArray *capabilities; GType cap_type; GValue cap = {0, }; const gchar *remove = NULL; - if (error) - { - dispatcher_connection_invalidated_cb (connection, error->domain, - error->code, error->message, dispatcher); - return; - } + 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), dispatcher); - if (tp_proxy_has_interface_by_id (TP_PROXY (connection), TP_IFACE_QUARK_CONNECTION_INTERFACE_REQUESTS)) { @@ -735,10 +792,10 @@ dispatcher_connection_ready_cb (TpConnection *connection, dispatcher_connection_new_channels_cb, NULL, NULL, G_OBJECT (dispatcher), NULL); - tp_cli_dbus_properties_call_get (connection, -1, - TP_IFACE_CONNECTION_INTERFACE_REQUESTS, "Channels", - dispatcher_connection_got_channels_property, - NULL, NULL, dispatcher); + tp_cli_dbus_properties_call_get_all (connection, -1, + TP_IFACE_CONNECTION_INTERFACE_REQUESTS, + dispatcher_connection_got_all, + NULL, NULL, G_OBJECT (dispatcher)); } else { @@ -770,45 +827,15 @@ dispatcher_connection_ready_cb (TpConnection *connection, connection, -1, capabilities, &remove, dispatcher_connection_advertise_capabilities_cb, NULL, NULL, G_OBJECT (dispatcher)); -} - -static void -dispatcher_update_account (EmpathyDispatcher *dispatcher, McAccount *account) -{ - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - TpConnection *connection; - - connection = g_hash_table_lookup (priv->accounts, account); - if (connection != NULL) - return; - - connection = mission_control_get_tpconnection (priv->mc, account, NULL); - if (connection == NULL) - return; - g_hash_table_insert (priv->connections, g_object_ref (connection), - new_connection_data (account)); - - g_hash_table_insert (priv->accounts, g_object_ref (account), - g_object_ref (connection)); - - tp_connection_call_when_ready (connection, dispatcher_connection_ready_cb, - dispatcher); + g_value_unset (&cap); + g_ptr_array_free (capabilities, TRUE); } -static void -dispatcher_account_connection_cb (EmpathyAccountManager *manager, - McAccount *account, TpConnectionStatusReason reason, - TpConnectionStatus status, TpConnectionStatus previous, - EmpathyDispatcher *dispatcher) -{ - dispatcher_update_account (dispatcher, account); -} - - static GObject* -dispatcher_constructor (GType type, guint n_construct_params, - GObjectConstructParam *construct_params) +dispatcher_constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) { GObject *retval; @@ -818,7 +845,7 @@ dispatcher_constructor (GType type, guint n_construct_params, (type, n_construct_params, construct_params); dispatcher = EMPATHY_DISPATCHER (retval); - g_object_add_weak_pointer (retval, (gpointer *) &dispatcher); + g_object_add_weak_pointer (retval, (gpointer) &dispatcher); } else { @@ -832,14 +859,31 @@ static void dispatcher_finalize (GObject *object) { EmpathyDispatcherPriv *priv = GET_PRIV (object); + GList *l; + GHashTableIter iter; + gpointer connection; g_signal_handlers_disconnect_by_func (priv->account_manager, - dispatcher_account_connection_cb, object); + dispatcher_new_connection_cb, object); + + for (l = priv->channels; l; l = l->next) + { + g_signal_handlers_disconnect_by_func (l->data, + dispatcher_channel_invalidated_cb, object); + } + + g_list_free (priv->channels); + + 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_object_unref (priv->account_manager); g_object_unref (priv->mc); - g_hash_table_destroy (priv->accounts); g_hash_table_destroy (priv->connections); } @@ -888,32 +932,30 @@ empathy_dispatcher_class_init (EmpathyDispatcherClass *klass) static void empathy_dispatcher_init (EmpathyDispatcher *dispatcher) { - GList *accounts, *l; + GList *connections, *l; EmpathyDispatcherPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (dispatcher, EMPATHY_TYPE_DISPATCHER, EmpathyDispatcherPriv); dispatcher->priv = priv; - priv->mc = empathy_mission_control_new (); + priv->mc = empathy_mission_control_dup_singleton (); priv->account_manager = empathy_account_manager_dup_singleton (); - g_signal_connect (priv->account_manager, - "account-connection-changed", - G_CALLBACK (dispatcher_account_connection_cb), + g_signal_connect (priv->account_manager, "new-connection", + G_CALLBACK (dispatcher_new_connection_cb), dispatcher); - priv->accounts = g_hash_table_new_full (empathy_account_hash, - empathy_account_equal, g_object_unref, g_object_unref); - priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) free_connection_data); - accounts = mc_accounts_list_by_enabled (TRUE); + priv->channels = NULL; - for (l = accounts; l; l = l->next) { - dispatcher_update_account (dispatcher, l->data); - g_object_unref (l->data); - } - g_list_free (accounts); + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) + { + dispatcher_new_connection_cb (priv->account_manager, l->data, dispatcher); + g_object_unref (l->data); + } + g_list_free (connections); } EmpathyDispatcher * @@ -924,7 +966,8 @@ empathy_dispatcher_dup_singleton (void) static void dispatcher_request_failed (EmpathyDispatcher *dispatcher, - DispatcherRequestData *request_data, const GError *error) + DispatcherRequestData *request_data, + const GError *error) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); ConnectionData *conn_data; @@ -940,8 +983,10 @@ dispatcher_request_failed (EmpathyDispatcher *dispatcher, static void dispatcher_connection_new_requested_channel (EmpathyDispatcher *dispatcher, - DispatcherRequestData *request_data, const gchar *object_path, - GHashTable *properties, const GError *error) + DispatcherRequestData *request_data, + const gchar *object_path, + GHashTable *properties, + const GError *error) { EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); EmpathyDispatchOperation *operation = NULL; @@ -957,7 +1002,7 @@ dispatcher_connection_new_requested_channel (EmpathyDispatcher *dispatcher, dispatcher_request_failed (dispatcher, request_data, error); goto out; - } + } operation = g_hash_table_lookup (conn_data->outstanding_channels, object_path); @@ -996,6 +1041,8 @@ dispatcher_connection_new_requested_channel (EmpathyDispatcher *dispatcher, G_CALLBACK (dispatcher_channel_invalidated_cb), request_data->dispatcher); + priv->channels = g_list_prepend (priv->channels, channel); + operation = empathy_dispatch_operation_new (request_data->connection, channel, request_data->contact, FALSE); g_object_unref (channel); @@ -1011,11 +1058,21 @@ dispatcher_connection_new_requested_channel (EmpathyDispatcher *dispatcher, request_data->operation = operation; - /* (pre)-approve this right away as we requested it */ + /* (pre)-approve this right away as we requested it + * This might cause the channel to be claimed, in which case the operation + * will disappear. So ref it, and check the status before starting the + * dispatching */ + + g_object_ref (operation); empathy_dispatch_operation_approve (operation); - dispatcher_start_dispatching (request_data->dispatcher, operation, - conn_data); + if (empathy_dispatch_operation_get_status (operation) < + EMPATHY_DISPATCHER_OPERATION_STATE_APPROVING) + dispatcher_start_dispatching (request_data->dispatcher, operation, + conn_data); + + g_object_unref (operation); + out: dispatcher_flush_outstanding_operations (request_data->dispatcher, conn_data); @@ -1023,8 +1080,10 @@ out: static void dispatcher_request_channel_cb (TpConnection *connection, - const gchar *object_path, const GError *error, - gpointer user_data, GObject *weak_object) + const gchar *object_path, + const GError *error, + gpointer user_data, + GObject *weak_object) { EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (weak_object); DispatcherRequestData *request_data = (DispatcherRequestData*) user_data; @@ -1044,102 +1103,99 @@ dispatcher_request_channel (DispatcherRequestData *request_data) request_data, NULL, G_OBJECT (request_data->dispatcher)); } -void -empathy_dispatcher_call_with_contact ( EmpathyContact *contact, - EmpathyDispatcherRequestCb *callback, gpointer user_data) -{ - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); - EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account; - TpConnection *connection; - ConnectionData *cd; - DispatcherRequestData *request_data; - - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); - - g_assert (connection != NULL); - cd = g_hash_table_lookup (priv->connections, connection); - request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_NONE, 0, NULL, - contact, callback, user_data); - - cd->outstanding_requests = g_list_prepend - (cd->outstanding_requests, request_data); - - dispatcher_request_channel (request_data); - - g_object_unref (dispatcher); -} - - -static void -dispatcher_chat_with_contact_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - request_data->handle = empathy_contact_get_handle (contact); - - dispatcher_request_channel (request_data); -} - void empathy_dispatcher_chat_with_contact (EmpathyContact *contact, - EmpathyDispatcherRequestCb *callback, gpointer user_data) + EmpathyDispatcherRequestCb *callback, + gpointer user_data) { EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; - McAccount *account; TpConnection *connection; ConnectionData *connection_data; DispatcherRequestData *request_data; + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - account = empathy_contact_get_account (contact); - connection = g_hash_table_lookup (priv->accounts, account); + connection = empathy_contact_get_connection (contact); connection_data = g_hash_table_lookup (priv->connections, connection); /* The contact handle might not be known yet */ request_data = new_dispatcher_request_data (dispatcher, connection, - TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, 0, NULL, - contact, callback, user_data); + TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), NULL, contact, callback, user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_chat_with_contact_cb, - request_data, NULL, G_OBJECT (dispatcher)); + dispatcher_request_channel (request_data); g_object_unref (dispatcher); } +typedef struct +{ + EmpathyDispatcher *dispatcher; + EmpathyDispatcherRequestCb *callback; + gpointer user_data; +} ChatWithContactIdData; + +static void +dispatcher_chat_with_contact_id_cb (EmpathyTpContactFactory *factory, + EmpathyContact *contact, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + ChatWithContactIdData *data = user_data; + + if (error) + { + /* FIXME: Should call data->callback with the error */ + DEBUG ("Error: %s", error->message); + } + else + { + empathy_dispatcher_chat_with_contact (contact, data->callback, data->user_data); + } + + g_object_unref (data->dispatcher); + g_slice_free (ChatWithContactIdData, data); +} + void -empathy_dispatcher_chat_with_contact_id (McAccount *account, const gchar - *contact_id, EmpathyDispatcherRequestCb *callback, gpointer user_data) +empathy_dispatcher_chat_with_contact_id (TpConnection *connection, + const gchar *contact_id, + EmpathyDispatcherRequestCb *callback, + gpointer user_data) { - EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton (); - EmpathyContactFactory *factory; - EmpathyContact *contact; + EmpathyDispatcher *dispatcher; + EmpathyTpContactFactory *factory; + ChatWithContactIdData *data; - factory = empathy_contact_factory_dup_singleton (); - contact = empathy_contact_factory_get_from_id (factory, account, contact_id); + g_return_if_fail (TP_IS_CONNECTION (connection)); + g_return_if_fail (!EMP_STR_EMPTY (contact_id)); - empathy_dispatcher_chat_with_contact (contact, callback, user_data); + dispatcher = empathy_dispatcher_dup_singleton (); + factory = empathy_tp_contact_factory_dup_singleton (connection); + data = g_slice_new0 (ChatWithContactIdData); + data->dispatcher = dispatcher; + data->callback = callback; + data->user_data = user_data; + empathy_tp_contact_factory_get_from_id (factory, contact_id, + dispatcher_chat_with_contact_id_cb, data, NULL, NULL); - g_object_unref (contact); g_object_unref (factory); - g_object_unref (dispatcher); } - static void dispatcher_request_handles_cb (TpConnection *connection, - const GArray *handles, const GError *error, gpointer user_data, - GObject *object) + const GArray *handles, + const GError *error, + gpointer user_data, + GObject *object) { DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; @@ -1168,23 +1224,25 @@ dispatcher_request_handles_cb (TpConnection *connection, } void -empathy_dispatcher_join_muc (McAccount *account, const gchar *roomname, - EmpathyDispatcherRequestCb *callback, gpointer user_data) +empathy_dispatcher_join_muc (TpConnection *connection, + const gchar *roomname, + EmpathyDispatcherRequestCb *callback, + gpointer user_data) { EmpathyDispatcher *dispatcher; EmpathyDispatcherPriv *priv; DispatcherRequestData *request_data; - TpConnection *connection; ConnectionData *connection_data; const gchar *names[] = { roomname, NULL }; + g_return_if_fail (TP_IS_CONNECTION (connection)); + g_return_if_fail (!EMP_STR_EMPTY (roomname)); + dispatcher = empathy_dispatcher_dup_singleton(); priv = GET_PRIV (dispatcher); - connection = g_hash_table_lookup (priv->accounts, account); connection_data = g_hash_table_lookup (priv->connections, connection); - /* Don't know the room handle yet */ request_data = new_dispatcher_request_data (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_TEXT, TP_HANDLE_TYPE_ROOM, 0, NULL, @@ -1203,8 +1261,11 @@ empathy_dispatcher_join_muc (McAccount *account, const gchar *roomname, static void dispatcher_create_channel_cb (TpConnection *connect, - const gchar *object_path, GHashTable *properties, const GError *error, - gpointer user_data, GObject *weak_object) + const gchar *object_path, + GHashTable *properties, + const GError *error, + gpointer user_data, + GObject *weak_object) { EmpathyDispatcher *dispatcher = EMPATHY_DISPATCHER (weak_object); DispatcherRequestData *request_data = (DispatcherRequestData*) user_data; @@ -1213,29 +1274,43 @@ dispatcher_create_channel_cb (TpConnection *connect, request_data, object_path, properties, error); } - -static void -dispatcher_create_channel_with_contact_cb (EmpathyContact *contact, - const GError *error, gpointer user_data, GObject *object) +void +empathy_dispatcher_create_channel (EmpathyDispatcher *dispatcher, + TpConnection *connection, + GHashTable *request, + EmpathyDispatcherRequestCb *callback, + gpointer user_data) { - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - GValue *target_handle; + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + ConnectionData *connection_data; + DispatcherRequestData *request_data; + const gchar *channel_type; + guint handle_type; + guint handle; + gboolean valid; - g_assert (request_data->request); + g_return_if_fail (EMPATHY_IS_DISPATCHER (dispatcher)); + g_return_if_fail (TP_IS_CONNECTION (connection)); + g_return_if_fail (request != NULL); - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } + connection_data = g_hash_table_lookup (priv->connections, connection); + g_assert (connection_data != NULL); + + channel_type = tp_asv_get_string (request, TP_IFACE_CHANNEL ".ChannelType"); + + handle_type = tp_asv_get_uint32 (request, + TP_IFACE_CHANNEL ".TargetHandleType", &valid); + if (!valid) + handle_type = TP_UNKNOWN_HANDLE_TYPE; + + handle = tp_asv_get_uint32 (request, TP_IFACE_CHANNEL ".TargetHandle", NULL); - request_data->handle = empathy_contact_get_handle (contact); + request_data = new_dispatcher_request_data (dispatcher, connection, + channel_type, handle_type, handle, request, + NULL, callback, user_data); - target_handle = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (target_handle, request_data->handle); - g_hash_table_insert (request_data->request, - TP_IFACE_CHANNEL ".TargetHandle", target_handle); + connection_data->outstanding_requests = g_list_prepend + (connection_data->outstanding_requests, request_data); tp_cli_connection_interface_requests_call_create_channel ( request_data->connection, -1, @@ -1245,14 +1320,16 @@ dispatcher_create_channel_with_contact_cb (EmpathyContact *contact, void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, - const gchar *filename, guint64 size, guint64 date, - const gchar *content_type, EmpathyDispatcherRequestCb *callback, - gpointer user_data) + const gchar *filename, + guint64 size, + guint64 date, + const gchar *content_type, + EmpathyDispatcherRequestCb *callback, + gpointer user_data) { EmpathyDispatcher *dispatcher = empathy_dispatcher_dup_singleton(); EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); - McAccount *account = empathy_contact_get_account (contact); - TpConnection *connection = g_hash_table_lookup (priv->accounts, account); + TpConnection *connection = empathy_contact_get_connection (contact); ConnectionData *connection_data = g_hash_table_lookup (priv->connections, connection); DispatcherRequestData *request_data; @@ -1260,9 +1337,13 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, GHashTable *request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); + g_return_if_fail (EMPATHY_IS_CONTACT (contact)); + g_return_if_fail (!EMP_STR_EMPTY (filename)); + g_return_if_fail (!EMP_STR_EMPTY (content_type)); + /* org.freedesktop.Telepathy.Channel.ChannelType */ value = tp_g_value_slice_new (G_TYPE_STRING); - g_value_set_string (value, EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER); + g_value_set_string (value, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER); g_hash_table_insert (request, TP_IFACE_CHANNEL ".ChannelType", value); /* org.freedesktop.Telepathy.Channel.TargetHandleType */ @@ -1270,41 +1351,103 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandleType", value); + /* org.freedesktop.Telepathy.Channel.TargetHandle */ + value = tp_g_value_slice_new (G_TYPE_UINT); + g_value_set_uint (value, empathy_contact_get_handle (contact)); + g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value); + /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentType */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, content_type); g_hash_table_insert (request, - EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentType", value); + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentType", value); /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Filename */ value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (value, filename); g_hash_table_insert (request, - EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Filename", value); + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Filename", value); /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Size */ value = tp_g_value_slice_new (G_TYPE_UINT64); g_value_set_uint64 (value, size); g_hash_table_insert (request, - EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Size", value); + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Size", value); /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Date */ value = tp_g_value_slice_new (G_TYPE_UINT64); g_value_set_uint64 (value, date); g_hash_table_insert (request, - EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value); + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value); - - /* The contact handle might not be known yet */ - request_data = new_dispatcher_request_data (dispatcher, connection, - EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, 0, request, - contact, callback, user_data); + request_data = new_dispatcher_request_data (dispatcher, connection, + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT, + empathy_contact_get_handle (contact), request, contact, callback, + user_data); connection_data->outstanding_requests = g_list_prepend (connection_data->outstanding_requests, request_data); - empathy_contact_call_when_ready (contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_create_channel_with_contact_cb, - request_data, NULL, G_OBJECT (dispatcher)); + tp_cli_connection_interface_requests_call_create_channel ( + request_data->connection, -1, + request_data->request, dispatcher_create_channel_cb, request_data, NULL, + G_OBJECT (request_data->dispatcher)); g_object_unref (dispatcher); } + +GStrv +empathy_dispatcher_find_channel_class (EmpathyDispatcher *dispatcher, + TpConnection *connection, + const gchar *channel_type, + guint handle_type) +{ + EmpathyDispatcherPriv *priv = GET_PRIV (dispatcher); + ConnectionData *cd; + int i; + GPtrArray *classes; + + g_return_val_if_fail (channel_type != NULL, NULL); + g_return_val_if_fail (handle_type != 0, NULL); + + cd = g_hash_table_lookup (priv->connections, connection); + + if (cd == NULL) + return NULL; + + classes = cd->requestable_channels; + if (classes == NULL) + return NULL; + + for (i = 0; i < classes->len; i++) + { + GValueArray *class; + GValue *fixed; + GValue *allowed; + GHashTable *fprops; + const gchar *c_type; + guint32 h_type; + gboolean valid; + + class = g_ptr_array_index (classes, i); + fixed = g_value_array_get_nth (class, 0); + + fprops = g_value_get_boxed (fixed); + c_type = tp_asv_get_string (fprops, TP_IFACE_CHANNEL ".ChannelType"); + + if (tp_strdiff (channel_type, c_type)) + continue; + + h_type = tp_asv_get_uint32 (fprops, + TP_IFACE_CHANNEL ".TargetHandleType", &valid); + + if (!valid || handle_type != h_type) + continue; + + allowed = g_value_array_get_nth (class, 1); + + return g_value_get_boxed (allowed); + } + + return NULL; +} +