diff options
author | Will Thompson <will.thompson@collabora.co.uk> | 2012-03-23 08:53:21 +0000 |
---|---|---|
committer | Matúš Kukan <matus.kukan@gmail.com> | 2012-07-17 16:39:39 +0200 |
commit | e6a3874108e77d366085a4b275ac337cda5225ea (patch) | |
tree | 450026e4761086757d3f98747c8438cb800a40de | |
parent | 0b7f8fb6971ca1df6f94508e45c42cdb157e3dab (diff) |
tubes: implement receiving files.
-rw-r--r-- | tubes/inc/tubes/conference.hxx | 2 | ||||
-rw-r--r-- | tubes/inc/tubes/file-transfer-helper.h | 3 | ||||
-rw-r--r-- | tubes/inc/tubes/manager.hxx | 9 | ||||
-rw-r--r-- | tubes/qa/test_manager.cxx | 18 | ||||
-rw-r--r-- | tubes/source/conference.cxx | 5 | ||||
-rw-r--r-- | tubes/source/file-transfer-helper.c | 29 | ||||
-rw-r--r-- | tubes/source/manager.cxx | 144 |
7 files changed, 202 insertions, 8 deletions
diff --git a/tubes/inc/tubes/conference.hxx b/tubes/inc/tubes/conference.hxx index 7428bcb33a48..7c5fd30bd994 100644 --- a/tubes/inc/tubes/conference.hxx +++ b/tubes/inc/tubes/conference.hxx @@ -94,6 +94,8 @@ public: { return mbTubeChannelStateChangedHandlerInvoked; } void setTubeChannelState( TpTubeChannelState eState ) { meTubeChannelState = eState; } + static void FTReady( EmpathyFTHandler *handler, GError *error, gpointer user_data); + private: rtl::OString maSessionId; diff --git a/tubes/inc/tubes/file-transfer-helper.h b/tubes/inc/tubes/file-transfer-helper.h index fe0678f84eee..8960d147969b 100644 --- a/tubes/inc/tubes/file-transfer-helper.h +++ b/tubes/inc/tubes/file-transfer-helper.h @@ -90,6 +90,9 @@ void empathy_ft_handler_new_outgoing ( gint64 action_time, EmpathyFTHandlerReadyCallback callback, gpointer user_data); +void empathy_ft_handler_set_service_name ( + EmpathyFTHandler *self, + const gchar *service_name); void empathy_ft_handler_new_incoming (TpFileTransferChannel *channel, EmpathyFTHandlerReadyCallback callback, diff --git a/tubes/inc/tubes/manager.hxx b/tubes/inc/tubes/manager.hxx index 97f5de86fa19..0d2ef3eec745 100644 --- a/tubes/inc/tubes/manager.hxx +++ b/tubes/inc/tubes/manager.hxx @@ -140,6 +140,9 @@ public: void sendFile( rtl::OUString &localUri, TeleConference::FileSentCallback pCallback, void* pUserData); + typedef void (*FileReceivedCallback)( rtl::OUString &localUri, void* pUserData ); + void setFileReceivedCallback( FileReceivedCallback callback, void* pUserData ); + /// Only for use with MainLoopFlusher GMainLoop* getMainLoop() const; @@ -197,6 +200,9 @@ public: TpAccount* getAccount( const rtl::OString& rAccountID ); +/* Callbacks; not for use outside this class. */ + static void TransferDone( EmpathyFTHandler *handler, TpFileTransferChannel *, gpointer user_data); + private: TeleConferenceVector maConferences; @@ -207,6 +213,9 @@ private: static sal_uInt32 nRefCount; static rtl::OString aNameSuffix; + FileReceivedCallback mpFileReceivedCallback; + void *mpFileReceivedCallbackData; + friend class TeleManagerImpl; // access to mutex TUBES_DLLPRIVATE static ::osl::Mutex& GetMutex(); diff --git a/tubes/qa/test_manager.cxx b/tubes/qa/test_manager.cxx index d08190d56289..540728a5fa39 100644 --- a/tubes/qa/test_manager.cxx +++ b/tubes/qa/test_manager.cxx @@ -70,6 +70,7 @@ public: void spinMainLoop(); static void FileSent( bool success, void *user_data); + static void FileReceived( rtl::OUString& aUri, void *user_data); // Order is significant. CPPUNIT_TEST_SUITE( TestTeleTubes ); @@ -102,6 +103,7 @@ private: rtl::OString maAccepterIdentifier; bool maFileSentSuccess; + rtl::OUString maFileReceivedUri; }; // static, not members, so they actually survive cppunit test iteration @@ -299,17 +301,33 @@ void TestTeleTubes::FileSent( bool success, void *user_data) g_main_loop_quit (self->mpMainLoop); } +void TestTeleTubes::FileReceived( rtl::OUString& aUri, void *user_data) +{ + TestTeleTubes *self = reinterpret_cast<TestTeleTubes *>(user_data); + + self->maFileReceivedUri = aUri; + g_main_loop_quit (self->mpMainLoop); +} + void TestTeleTubes::testSendFile() { TpAccount *pAcc1 = mpManager1->getAccount(maOffererIdentifier); CPPUNIT_ASSERT( pAcc1 != 0); /* This has to run after testContactList has run successfully. */ CPPUNIT_ASSERT( mpAccepterContact != 0); + + mpManager1->setFileReceivedCallback(&TestTeleTubes::FileReceived, this); + mpManager1->sendFile( maTestConfigIniURL, &TestTeleTubes::FileSent, this); + /* Waiting for two events: FileSent and FileReceived both quit the mainloop */ + spinMainLoop(); spinMainLoop(); CPPUNIT_ASSERT( maFileSentSuccess); + CPPUNIT_ASSERT_MESSAGE( + OUStringToOString( maFileReceivedUri, RTL_TEXTENCODING_UTF8).getStr(), + maFileReceivedUri == "file:///tmp/fixme.ods"); } void TestTeleTubes::testFlushLoops() diff --git a/tubes/source/conference.cxx b/tubes/source/conference.cxx index 9a35c70e9a19..88ec817a3170 100644 --- a/tubes/source/conference.cxx +++ b/tubes/source/conference.cxx @@ -479,7 +479,7 @@ static void TeleConference_TransferError( EmpathyFTHandler *handler, const GErro g_object_unref (handler); } -static void TeleConference_FTReady( EmpathyFTHandler *handler, GError *error, gpointer user_data) +void TeleConference::FTReady( EmpathyFTHandler *handler, GError *error, gpointer user_data) { SendFileRequest *request = reinterpret_cast<SendFileRequest *>(user_data); @@ -495,6 +495,7 @@ static void TeleConference_FTReady( EmpathyFTHandler *handler, GError *error, gp G_CALLBACK (TeleConference_TransferDone), request); g_signal_connect(handler, "transfer-error", G_CALLBACK (TeleConference_TransferError), request); + empathy_ft_handler_set_service_name(handler, request->mpSelf->mpManager->getFullServiceName().getStr()); empathy_ft_handler_start_transfer(handler); } } @@ -517,7 +518,7 @@ void TeleConference::sendFile( rtl::OUString &localUri, FileSentCallback pCallba tp_channel_get_target_contact( mpChannel), pSource, 0, - &TeleConference_FTReady, pReq); + &TeleConference::FTReady, pReq); } diff --git a/tubes/source/file-transfer-helper.c b/tubes/source/file-transfer-helper.c index ca1a70bfc067..15e3dfdbb59d 100644 --- a/tubes/source/file-transfer-helper.c +++ b/tubes/source/file-transfer-helper.c @@ -134,6 +134,7 @@ struct _EmpathyFTHandlerPriv { guint64 mtime; gchar *content_hash; TpFileHashType content_hash_type; + gchar *service_name; gint64 user_action_time; @@ -260,6 +261,11 @@ do_dispose (GObject *object) priv->dispose_run = TRUE; + if (priv->account != NULL) { + g_object_unref (priv->account); + priv->account = NULL; + } + if (priv->contact != NULL) { g_object_unref (priv->contact); priv->contact = NULL; @@ -310,6 +316,9 @@ do_finalize (GObject *object) g_free (priv->content_hash); priv->content_hash = NULL; + g_free (priv->service_name); + priv->service_name = NULL; + G_OBJECT_CLASS (empathy_ft_handler_parent_class)->finalize (object); } @@ -907,6 +916,9 @@ ft_handler_populate_outgoing_request (EmpathyFTHandler *handler) TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_URI, G_TYPE_STRING, uri, NULL); + if (priv->service_name != NULL) + tp_asv_set_string (priv->request, TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME, priv->service_name); + g_free (uri); } @@ -1358,11 +1370,11 @@ channel_prepared_cb ( properties = tp_channel_borrow_immutable_properties (TP_CHANNEL (channel)); - priv->content_hash = g_value_dup_string ( - g_hash_table_lookup (properties, "ContentHash")); + priv->content_hash = g_strdup ( + tp_asv_get_string (properties, "ContentHash")); - priv->content_hash_type = g_value_get_uint ( - g_hash_table_lookup (properties, "ContentHashType")); + priv->content_hash_type = tp_asv_get_uint32 ( + properties, "ContentHashType", NULL); priv->contact = g_object_ref (tp_channel_get_target_contact (TP_CHANNEL (channel))); @@ -1426,6 +1438,15 @@ empathy_ft_handler_new_outgoing ( NULL, (GAsyncReadyCallback) ft_handler_gfile_ready_cb, data); } +void +empathy_ft_handler_set_service_name ( + EmpathyFTHandler *self, + const gchar *service_name) +{ + g_free (self->priv->service_name); + self->priv->service_name = g_strdup (service_name); +} + /** * empathy_ft_handler_new_incoming: * @channel: the #TpFileTransferChannel proxy to the incoming channel diff --git a/tubes/source/manager.cxx b/tubes/source/manager.cxx index 84032709045b..b479d5dc82d2 100644 --- a/tubes/source/manager.cxx +++ b/tubes/source/manager.cxx @@ -31,6 +31,7 @@ #include <rtl/strbuf.hxx> #include <rtl/uuid.h> #include <osl/mutex.hxx> +#include <cstring> #if defined SAL_LOG_INFO @@ -77,6 +78,7 @@ public: GMainLoop* mpLoop; TpDBusDaemon* mpDBus; TpBaseClient* mpClient; + TpBaseClient* mpFileTransferClient; TpAccountManager* mpAccountManager; TeleManager::AccountManagerStatus meAccountManagerStatus; bool mbAccountManagerReadyHandlerInvoked; @@ -172,6 +174,102 @@ static void TeleManager_DBusChannelHandler( } } +void TeleManager::TransferDone( EmpathyFTHandler *handler, TpFileTransferChannel *, gpointer pUserData) +{ + TeleManager* pManager = reinterpret_cast<TeleManager*>(pUserData); + + SAL_INFO( "tubes", "TeleConference_TransferDone: hooray!"); + GFile *gfile = empathy_ft_handler_get_gfile( handler); + char *uri = g_file_get_uri( gfile); + rtl::OUString aUri( uri, strlen( uri), RTL_TEXTENCODING_UTF8); + g_free( uri); + + pManager->mpFileReceivedCallback( aUri, pManager->mpFileReceivedCallbackData); + + //g_object_unref( handler); +} + +static void TeleManager_TransferError( EmpathyFTHandler *handler, const GError *error, void*) +{ + SAL_INFO( "tubes", "TeleConference_TransferError: " << error->message); + + //g_object_unref( handler); +} + +static void +TeleManager_IncomingHandlerReady ( + EmpathyFTHandler* pHandler, + GError* pError, + void* pUserData) +{ + TeleManager* pManager = reinterpret_cast<TeleManager*>(pUserData); + + if (pError) + { + SAL_INFO ("tubes", "failed to prepare incoming transfer: " << pError->message); + g_object_unref( pHandler); + return; + } + + GFile *pDestination = g_file_new_for_uri( "file:///tmp/fixme.ods"); + + empathy_ft_handler_incoming_set_destination( pHandler, pDestination); + g_object_unref( pDestination); + + g_signal_connect( pHandler, "transfer-done", G_CALLBACK (&TeleManager::TransferDone), pManager); + g_signal_connect( pHandler, "transfer-error", G_CALLBACK (TeleManager_TransferError), pManager); + empathy_ft_handler_start_transfer( pHandler); +} + +static void TeleManager_FileTransferHandler( + TpSimpleHandler* /*handler*/, + TpAccount* /*Account*/, + TpConnection* /*connection*/, + GList* pChannels, + GList* /*requests_satisfied*/, + gint64 /*user_action_time*/, + TpHandleChannelsContext* pContext, + gpointer pUserData) +{ + bool aAccepted = false; + INFO_LOGGER_F( "TeleManager_FileTransferHandler"); + + TeleManager* pManager = reinterpret_cast<TeleManager*>(pUserData); + SAL_WARN_IF( !pManager, "tubes", "TeleManager_FileTransferHandler: no manager"); + if (!pManager) + return; + + for (GList* p = pChannels; p; p = p->next) + { + TpChannel* pChannel = TP_CHANNEL(p->data); + + SAL_INFO( "tubes", "TeleManager_FileTransferHandler: incoming dbus channel: " + << tp_channel_get_identifier( pChannel)); + + if (TP_IS_FILE_TRANSFER_CHANNEL( pChannel)) + { + SAL_INFO( "tubes", "accepting file transfer"); + empathy_ft_handler_new_incoming( TP_FILE_TRANSFER_CHANNEL( pChannel), + TeleManager_IncomingHandlerReady, pManager); + aAccepted = true; + } + else + { + SAL_INFO( "tubes", "ignored"); + } + } + + if (aAccepted) + tp_handle_channels_context_accept( pContext); + else + { + GError *pError = g_error_new_literal( TP_ERRORS, TP_ERROR_CONFUSED, + "None of these channels were file transfers; " + "why did the Channel Dispatcher give them to us?"); + tp_handle_channels_context_fail( pContext, pError); + g_clear_error (&pError); + } +} static void TeleManager_ChannelReadyHandler( GObject* pSourceObject, @@ -296,13 +394,13 @@ bool TeleManager::connect() return false; } - TpSimpleClientFactory* pFactory = tp_simple_client_factory_new( pImpl->mpDBus); + TpAutomaticClientFactory* pFactory = tp_automatic_client_factory_new( pImpl->mpDBus); SAL_WARN_IF( !pFactory, "tubes", "TeleManager::connect: no client factory"); if (!pFactory) return false; pImpl->mpClient = tp_simple_handler_new_with_factory( - pFactory, // factory + TP_SIMPLE_CLIENT_FACTORY (pFactory), // factory FALSE, // bypass_approval FALSE, // requests getFullClientName().getStr(), // name @@ -346,6 +444,36 @@ bool TeleManager::connect() SAL_INFO( "tubes", "TeleManager::connect: bus name: " << tp_base_client_get_bus_name( pImpl->mpClient)); SAL_INFO( "tubes", "TeleManager::connect: object path: " << tp_base_client_get_object_path( pImpl->mpClient)); + /* Register a second "head" for incoming file transfers. This uses a more + * specific filter than Empathy's handler by matching on the file + * transfer's ServiceName property, and uses bypass_approval to ensure the + * user isn't prompted before the channel gets passed to us. + */ + pImpl->mpFileTransferClient = tp_simple_handler_new_with_factory ( + TP_SIMPLE_CLIENT_FACTORY( pFactory), // factory + TRUE, // bypass_approval + FALSE, // requests + getFullClientName().getStr(), // name + TRUE, // uniquify to get a different bus name to the main client, above + TeleManager_FileTransferHandler, // callback + this, // user_data + NULL // destroy + ); + tp_base_client_take_handler_filter( pImpl->mpFileTransferClient, + tp_asv_new( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, + TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME, G_TYPE_STRING, getFullServiceName().getStr(), + NULL)); + + if (!tp_base_client_register( pImpl->mpFileTransferClient, &pError)) + { + /* This shouldn't fail if registering the main handler succeeded */ + SAL_WARN( "tubes", "TeleManager::connect: error registering file transfer handler: " << pError->message); + g_error_free( pError); + return false; + } + return true; } @@ -603,6 +731,12 @@ void TeleManager::sendFile( rtl::OUString &localUri, TeleConference::FileSentCal } } +void TeleManager::setFileReceivedCallback( TeleManager::FileReceivedCallback callback, void* pUserData ) +{ + mpFileReceivedCallback = callback; + mpFileReceivedCallbackData = pUserData; +} + void TeleManager::unregisterConference( TeleConferencePtr pConference ) { INFO_LOGGER( "TeleManager::unregisterConference"); @@ -625,6 +759,9 @@ void TeleManager::disconnect() tp_base_client_unregister( pImpl->mpClient); pImpl->mpClient = NULL; + tp_base_client_unregister( pImpl->mpFileTransferClient); + pImpl->mpFileTransferClient = NULL; + size_t nSize = maConferences.size(); for (size_t i=0; i < nSize; /*nop*/) { @@ -798,6 +935,7 @@ TeleManagerImpl::TeleManagerImpl() mpLoop( NULL), mpDBus( NULL), mpClient( NULL), + mpFileTransferClient( NULL), mpAccountManager( NULL), meAccountManagerStatus( TeleManager::AMS_UNINITIALIZED), mbAccountManagerReadyHandlerInvoked( false) @@ -809,6 +947,8 @@ TeleManagerImpl::~TeleManagerImpl() { if (mpClient) g_object_unref( mpClient); + if (mpFileTransferClient) + g_object_unref( mpFileTransferClient); if (mpDBus) g_object_unref( mpDBus); if (mpAccountManager) |