X-Git-Url: https://git.0d.be/?p=empathy.git;a=blobdiff_plain;f=libempathy%2Fempathy-dispatcher.c;h=c8a0f9e60b043e5effd618a6ab3d71930267c841;hp=e8f7b8c7e9f1d2fc947e4a72f586aa9d5c3b916a;hb=5f6a57093aa93d8bcf4cee001adacaa91d4198c7;hpb=f2a0306b096a52d9f58b48c3c04a3a56cbd74a87 diff --git a/libempathy/empathy-dispatcher.c b/libempathy/empathy-dispatcher.c index e8f7b8c7..c8a0f9e6 100644 --- a/libempathy/empathy-dispatcher.c +++ b/libempathy/empathy-dispatcher.c @@ -28,9 +28,9 @@ #include #include #include +#include #include -#include #include @@ -38,7 +38,7 @@ #include "empathy-utils.h" #include "empathy-tube-handler.h" #include "empathy-account-manager.h" -#include "empathy-contact-factory.h" +#include "empathy-tp-contact-factory.h" #include "empathy-tp-file.h" #include "empathy-chatroom-manager.h" #include "empathy-utils.h" @@ -53,10 +53,11 @@ typedef struct MissionControl *mc; /* connection to connection data mapping */ GHashTable *connections; - /* accounts to connection mapping */ - GHashTable *accounts; gpointer token; GSList *tubes; + + /* channels which the dispatcher is listening "invalidated" */ + GList *channels; } EmpathyDispatcherPriv; G_DEFINE_TYPE (EmpathyDispatcher, empathy_dispatcher, G_TYPE_OBJECT); @@ -98,7 +99,6 @@ typedef struct typedef struct { - McAccount *account; /* ObjectPath => DispatchData.. */ GHashTable *dispatched_channels; /* ObjectPath -> EmpathyDispatchOperations */ @@ -107,6 +107,8 @@ typedef struct GHashTable *outstanding_channels; /* List of DispatcherRequestData */ GList *outstanding_requests; + /* List of requestable channel classes */ + GPtrArray *requestable_channels; } ConnectionData; static DispatchData * @@ -115,7 +117,8 @@ new_dispatch_data (TpChannel *channel, { 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; } @@ -124,7 +127,8 @@ 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); } @@ -142,7 +146,7 @@ new_dispatcher_request_data (EmpathyDispatcher *dispatcher, { 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); @@ -164,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); @@ -174,10 +181,9 @@ 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); @@ -195,14 +201,23 @@ 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 @@ -213,12 +228,8 @@ dispatcher_connection_invalidated_cb (TpConnection *connection, 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); } @@ -306,6 +317,8 @@ dispatcher_channel_invalidated_cb (TpProxy *proxy, 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) { @@ -340,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); @@ -384,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); @@ -409,6 +421,7 @@ dispatch_operation_ready_cb (EmpathyDispatchOperation *operation, g_signal_emit (dispatcher, signals[DISPATCH], 0, operation); } + g_object_unref (dispatcher); } static void @@ -487,7 +500,6 @@ dispatcher_connection_new_channel (EmpathyDispatcher *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 @@ -519,7 +531,7 @@ dispatcher_connection_new_channel (EmpathyDispatcher *dispatcher, * 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, EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) + && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) { DEBUG ("Ignoring incoming channel of type %s on %s", channel_type, object_path); @@ -549,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); @@ -674,22 +680,46 @@ dispatcher_connection_new_channels_cb (TpConnection *connection, } 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 @@ -736,26 +766,25 @@ dispatcher_connection_advertise_capabilities_cb (TpConnection *connection, } 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)) { @@ -763,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 { @@ -781,7 +810,6 @@ dispatcher_connection_ready_cb (TpConnection *connection, } /* Advertise VoIP capabilities */ - /* FIXME: Capabilities is leaked */ capabilities = g_ptr_array_sized_new (1); cap_type = dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID); @@ -799,44 +827,9 @@ 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_object_unref (connection); -} - -static void -dispatcher_account_connection_cb (EmpathyAccountManager *manager, - McAccount *account, - TpConnectionStatusReason reason, - TpConnectionStatus status, - TpConnectionStatus previous, - EmpathyDispatcher *dispatcher) -{ - dispatcher_update_account (dispatcher, account); + g_value_unset (&cap); + g_ptr_array_free (capabilities, TRUE); } static GObject* @@ -852,7 +845,7 @@ dispatcher_constructor (GType type, (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 { @@ -866,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); } @@ -922,7 +932,7 @@ 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); @@ -930,25 +940,22 @@ empathy_dispatcher_init (EmpathyDispatcher *dispatcher) 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) + connections = empathy_account_manager_dup_connections (priv->account_manager); + for (l = connections; l; l = l->next) { - dispatcher_update_account (dispatcher, l->data); + dispatcher_new_connection_cb (priv->account_manager, l->data, dispatcher); g_object_unref (l->data); } - g_list_free (accounts); + g_list_free (connections); } EmpathyDispatcher * @@ -1034,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); @@ -1049,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); @@ -1084,48 +1103,6 @@ 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, @@ -1133,51 +1110,84 @@ empathy_dispatcher_chat_with_contact (EmpathyContact *contact, { 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, +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 @@ -1214,7 +1224,7 @@ dispatcher_request_handles_cb (TpConnection *connection, } void -empathy_dispatcher_join_muc (McAccount *account, +empathy_dispatcher_join_muc (TpConnection *connection, const gchar *roomname, EmpathyDispatcherRequestCb *callback, gpointer user_data) @@ -1222,17 +1232,17 @@ empathy_dispatcher_join_muc (McAccount *account, 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, @@ -1264,30 +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, @@ -1295,25 +1318,6 @@ dispatcher_create_channel_with_contact_cb (EmpathyContact *contact, G_OBJECT (request_data->dispatcher)); } -static void -dispatcher_send_file_connection_ready_cb (TpConnection *connection, - const GError *error, - gpointer user_data) -{ - DispatcherRequestData *request_data = (DispatcherRequestData *) user_data; - - if (error != NULL) - { - dispatcher_request_failed (request_data->dispatcher, - request_data, error); - return; - } - - empathy_contact_call_when_ready (request_data->contact, - EMPATHY_CONTACT_READY_HANDLE, dispatcher_create_channel_with_contact_cb, - request_data, NULL, G_OBJECT (request_data->dispatcher)); -} - void empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, const gchar *filename, @@ -1325,8 +1329,7 @@ empathy_dispatcher_send_file_to_contact (EmpathyContact *contact, { 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; @@ -1334,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 */ @@ -1344,40 +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); - tp_connection_call_when_ready (connection, - dispatcher_send_file_connection_ready_cb, (gpointer) request_data); + 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; +} +