summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Thompson <will.thompson@collabora.co.uk>2012-03-23 08:53:21 +0000
committerMatúš Kukan <matus.kukan@gmail.com>2012-07-17 16:39:39 +0200
commite6a3874108e77d366085a4b275ac337cda5225ea (patch)
tree450026e4761086757d3f98747c8438cb800a40de
parent0b7f8fb6971ca1df6f94508e45c42cdb157e3dab (diff)
tubes: implement receiving files.
-rw-r--r--tubes/inc/tubes/conference.hxx2
-rw-r--r--tubes/inc/tubes/file-transfer-helper.h3
-rw-r--r--tubes/inc/tubes/manager.hxx9
-rw-r--r--tubes/qa/test_manager.cxx18
-rw-r--r--tubes/source/conference.cxx5
-rw-r--r--tubes/source/file-transfer-helper.c29
-rw-r--r--tubes/source/manager.cxx144
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)