diff options
author | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2017-04-14 02:44:20 +0200 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2017-04-14 03:32:37 +0200 |
commit | b7b159d79c2b4ec53915e0b9c3e28912c289a5ba (patch) | |
tree | 2510d25832202cfbc79378473b497540dd5a5500 /tubes | |
parent | 6f12914ddfb4d69c0267b206be654c875da17426 (diff) |
remove the old collaboration feature based on telepathy
Change-Id: I1f08d6ef43b76e7bae41ac33bb954f506ae7c485
Reviewed-on: https://gerrit.libreoffice.org/36542
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
Diffstat (limited to 'tubes')
24 files changed, 0 insertions, 4724 deletions
diff --git a/tubes/CppunitTest_tubes_test.mk b/tubes/CppunitTest_tubes_test.mk deleted file mode 100644 index eada4f0de92e..000000000000 --- a/tubes/CppunitTest_tubes_test.mk +++ /dev/null @@ -1,29 +0,0 @@ -# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- -# -# This file is part of the LibreOffice project. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# - -$(eval $(call gb_CppunitTest_CppunitTest,tubes_test)) - -$(eval $(call gb_CppunitTest_add_exception_objects,tubes_test, \ - tubes/qa/test_manager \ -)) - -$(eval $(call gb_CppunitTest_use_libraries,tubes_test, \ - sal \ - tubes \ - utl \ - $(gb_UWINAPI) \ -)) - -$(eval $(call gb_CppunitTest_use_externals,tubes_test,\ - telepathy \ -)) - -$(eval $(call gb_CppunitTest_use_udk_api,tubes_test)) - -# vim: set noet sw=4 ts=4: diff --git a/tubes/Executable_liboapprover.mk b/tubes/Executable_liboapprover.mk deleted file mode 100644 index 57d785099180..000000000000 --- a/tubes/Executable_liboapprover.mk +++ /dev/null @@ -1,21 +0,0 @@ -# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- -# -# This file is part of the LibreOffice project. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# - -$(eval $(call gb_Executable_Executable,liboapprover)) - -$(eval $(call gb_Executable_use_externals,liboapprover,\ - gtk \ - telepathy \ -)) - -$(eval $(call gb_Executable_add_cobjects,liboapprover,\ - tubes/source/approver \ -)) - -# vim: set ts=4 sw=4 et: diff --git a/tubes/Library_tubes.mk b/tubes/Library_tubes.mk deleted file mode 100644 index 96e93563d1f3..000000000000 --- a/tubes/Library_tubes.mk +++ /dev/null @@ -1,47 +0,0 @@ -# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- -# -# -# This file is part of the LibreOffice project. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# - -$(eval $(call gb_Library_Library,tubes)) - -$(eval $(call gb_Library_use_sdk_api,tubes)) - -$(eval $(call gb_Library_add_defs,tubes,\ - -DTUBES_DLLIMPLEMENTATION \ -)) - -$(eval $(call gb_Library_use_libraries,tubes,\ - comphelper \ - cppu \ - sal \ - svt \ - svxcore \ - tl \ - vcl \ - $(gb_UWINAPI) \ -)) - -$(eval $(call gb_Library_use_externals,tubes,\ - boost_headers \ - gtk \ - telepathy \ -)) - -$(eval $(call gb_Library_add_exception_objects,tubes,\ - tubes/source/collaboration \ - tubes/source/conference \ - tubes/source/contacts \ - tubes/source/manager \ -)) - -$(eval $(call gb_Library_add_cobjects,tubes,\ - tubes/source/file-transfer-helper \ -)) - -# vim:set shiftwidth=4 tabstop=4 noexpandtab: */ diff --git a/tubes/LibreOffice.client b/tubes/LibreOffice.client deleted file mode 100644 index 8c3356fd30d2..000000000000 --- a/tubes/LibreOffice.client +++ /dev/null @@ -1,11 +0,0 @@ -[org.freedesktop.Telepathy.Client] -Interfaces = org.freedesktop.Telepathy.Client.Handler; - -[org.freedesktop.Telepathy.Client.Handler] -BypassApproval = false - -[org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0] -org.freedesktop.Telepathy.Channel.TargetHandleType u = 1 -org.freedesktop.Telepathy.Channel.ChannelType s = org.freedesktop.Telepathy.Channel.Type.DBusTube -org.freedesktop.Telepathy.Channel.Type.DBusTube.ServiceName s = org.libreoffice.calc - diff --git a/tubes/LibreOfficeApprover.client b/tubes/LibreOfficeApprover.client deleted file mode 100644 index 035e02255d84..000000000000 --- a/tubes/LibreOfficeApprover.client +++ /dev/null @@ -1,8 +0,0 @@ -[org.freedesktop.Telepathy.Client] -Interfaces = org.freedesktop.Telepathy.Client.Approver; - -[org.freedesktop.Telepathy.Client.Approver.ApproverChannelFilter 0] -org.freedesktop.Telepathy.Channel.TargetHandleType u = 1 -org.freedesktop.Telepathy.Channel.ChannelType s = org.freedesktop.Telepathy.Channel.Type.DBusTube -org.freedesktop.Telepathy.Channel.Type.DBusTube.ServiceName s = org.libreoffice.calc - diff --git a/tubes/Makefile b/tubes/Makefile deleted file mode 100644 index ccb1c85a04da..000000000000 --- a/tubes/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- - -module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) - -include $(module_directory)/../solenv/gbuild/partial_build.mk - -# vim: set noet sw=4 ts=4: diff --git a/tubes/Module_tubes.mk b/tubes/Module_tubes.mk deleted file mode 100644 index abccf51b2cbc..000000000000 --- a/tubes/Module_tubes.mk +++ /dev/null @@ -1,30 +0,0 @@ -# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- -# -# -# This file is part of the LibreOffice project. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# - -$(eval $(call gb_Module_Module,tubes)) - -ifeq ($(ENABLE_TELEPATHY),TRUE) - -$(eval $(call gb_Module_add_targets,tubes,\ - Executable_liboapprover \ - Library_tubes \ -)) - -$(eval $(call gb_Module_add_l10n_targets,tubes,\ - UIConfig_tubes \ -)) - -$(eval $(call gb_Module_add_subsequentcheck_targets,tubes,\ - CppunitTest_tubes_test \ -)) - -endif - -# vim:set shiftwidth=4 tabstop=4 noexpandtab: */ diff --git a/tubes/README b/tubes/README deleted file mode 100644 index 8619a1a72ca3..000000000000 --- a/tubes/README +++ /dev/null @@ -1,82 +0,0 @@ -Interface to Telepathy Tubes. - -The idea is to provide 1-1 collaboration between contacts and many-many -collaboration via MUCs, using Telepathy DBus Tubes over Jabber/XMPP. - -To enable configure LibO with --enable-telepathy - -Currently (2012-04-14) at least telepathy-glib 0.18 is needed, which doesn't -come with distributions. Download it from -http://telepathy.freedesktop.org/releases/telepathy-glib/ -and make install it locally, e.g. with --prefix=$HOME/usr -For LibO configure then use PKG_CONFIG_PATH="$HOME/usr/lib/pkgconfig -To not have tubes and sc cppunittests stumble (LD_LIBRARY_PATH is not evaluated -in unit tests and thus not a solution) copy the libs to the solver, i.e. -cp -p $HOME/usr/lib/libtelepathy-glib.* $SRCDIR/solver/$INPATH/lib/ - -If you have a Telepathy-enabled LibreOffice installed to /usr (including -liboapprover) you may also want to install the .service and .client files to -make everything service-activatable. Currently this does not seem to work. - - mkdir -p $HOME/.local/share/telepathy/clients - ln -s $PWD/tubes/LibreOffice.client \ - $PWD/tubes/LibreOfficeApprover.client \ - $HOME/.local/share/telepathy/clients - - mkdir -p $HOME/.local/share/dbus-1/services - ln -s $PWD/tubes/org.freedesktop.Telepathy.Client.LibreOfficeApprover.service \ - $PWD/tubes/org.freedesktop.Telepathy.Client.LibreOffice.service \ - $HOME/.local/share/dbus-1/services - - -* liboapprover - -You may run it in the background. When someone wants to collaborate with you, -you then get a confirmation dialog. - -* Demo modes - -To play with the interposing without having an online account connected, create -a bit of a document, go to File -> Collaboration -> startDemoSession and bingo. - - -* To do interesting things with this code build and run calc thus: - - SAL_LOG=1 ./soffice --calc - - Now type simple strings into cells, rename sheets, or go to - File -> Collaboration; Listen; startBuddySession; - to transfer your document as-is to the other side ... - - -* for the cppunittest needed: - * Configure two Jabber accounts in Empathy - * Both must be online and on each other's contact list - * Copy qa/test-config.ini.example to qa/test-config.ini, and specify those - two accounts' JIDs in it. - - -* TODOs: - -* TeleConference is not deleted anywhere -* dialog to pick own account -* dialog to pick contact or MUC to work with -* dialog to accept/reject collaboration requests -* make the .service and .client files work reliably - - -In applications, e.g. Calc: - -* stricter model,view,controller -* disable all actions we cannot process collaboratively -* separate input from view -* preprocess input to determine data type (text, number, date, ...) -* send typed/categorized data over wire before actually processing in model -* process serialized input as received -* Calc specific: - * use existing shared document feature with change-tracking enabled to - visualize changes - * may have the benefit of having already only a subset of trackable change - actions available - * let ScDocFunc handle also received changes -* have dialogs send their result item sets over the wire diff --git a/tubes/UIConfig_tubes.mk b/tubes/UIConfig_tubes.mk deleted file mode 100644 index 43a0febe52f4..000000000000 --- a/tubes/UIConfig_tubes.mk +++ /dev/null @@ -1,16 +0,0 @@ -# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- -# -# This file is part of the LibreOffice project. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# - -$(eval $(call gb_UIConfig_UIConfig,tubes)) - -$(eval $(call gb_UIConfig_add_uifiles,tubes,\ - tubes/uiconfig/ui/contacts \ -)) - -# vim: set noet sw=4 ts=4: diff --git a/tubes/org.freedesktop.Telepathy.Client.LibreOffice.service b/tubes/org.freedesktop.Telepathy.Client.LibreOffice.service deleted file mode 100644 index d1257242ab17..000000000000 --- a/tubes/org.freedesktop.Telepathy.Client.LibreOffice.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=org.freedesktop.Telepathy.Client.LibreOffice -Exec=/usr/bin/libreoffice --calc diff --git a/tubes/org.freedesktop.Telepathy.Client.LibreOfficeApprover.service b/tubes/org.freedesktop.Telepathy.Client.LibreOfficeApprover.service deleted file mode 100644 index 89e4acf668fb..000000000000 --- a/tubes/org.freedesktop.Telepathy.Client.LibreOfficeApprover.service +++ /dev/null @@ -1,3 +0,0 @@ -[D-BUS Service] -Name=org.freedesktop.Telepathy.Client.LibreOfficeApprover -Exec=/usr/bin/liboapprover diff --git a/tubes/qa/test-config.ini.example b/tubes/qa/test-config.ini.example deleted file mode 100644 index 2d03ca8f3bb1..000000000000 --- a/tubes/qa/test-config.ini.example +++ /dev/null @@ -1,5 +0,0 @@ -# Locally-configured Jabber accounts used by Tubes test suite. These accounts -# must both be signed in and on each others' contact lists for the tests to -# work. -offerer=libo1@localhost.localdomain -accepter=libo2@localhost.localdomain diff --git a/tubes/qa/test_manager.cxx b/tubes/qa/test_manager.cxx deleted file mode 100644 index 11b653eb0ce1..000000000000 --- a/tubes/qa/test_manager.cxx +++ /dev/null @@ -1,192 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <sal/types.h> - -#include <cppunit/TestFixture.h> -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/plugin/TestPlugIn.h> - -#include <rtl/bootstrap.hxx> -#include <rtl/string.hxx> -#include <rtl/ustring.hxx> -#include <tubes/collaboration.hxx> -#include <tubes/manager.hxx> -#include <unotools/localfilehelper.hxx> - -#include <telepathy-glib/telepathy-glib.h> - -class TeleConference; - -namespace { - -class TestTeleTubes: public CppUnit::TestFixture -{ -public: - - virtual void setUp() override; - virtual void tearDown() override; - - void testSession(); - - // There is only one method because the code in setUp - // and tearDown is expected to be executed only once. - CPPUNIT_TEST_SUITE( TestTeleTubes ); - CPPUNIT_TEST( testSession ); - CPPUNIT_TEST_SUITE_END(); -}; - -class TestCollaboration; -// static, not members, so they actually survive cppunit test iteration -static TestCollaboration* mpCollaboration1 = nullptr; -static TestCollaboration* mpCollaboration2 = nullptr; -//static bool mbFileSentSuccess = false; -static bool mbPacketReceived = false; -static OUString maTestConfigIniURL; -static OString maOffererIdentifier; -static OString maAccepterIdentifier; - -class TestCollaboration : public Collaboration -{ - virtual void EndCollaboration() const override {} - virtual void PacketReceived( const OString& rPacket ) const override - { - CPPUNIT_ASSERT( rPacket == "from 1 to 2"); - mbPacketReceived = true; - } - virtual void SaveAndSendFile( TpContact* ) const override {} - virtual void StartCollaboration( TeleConference* ) override {} -}; - -gboolean timed_out( void * ) -{ - CPPUNIT_ASSERT_MESSAGE( "Test took longer than ten seconds!", false); - - return FALSE; -} - -void TestTeleTubes::setUp() -{ - g_timeout_add_seconds (10, timed_out, nullptr); - maTestConfigIniURL = "file://" + - OUString::createFromAscii( getenv("SRCDIR") ) + "/tubes/qa/test-config.ini"; - rtl::Bootstrap aTestConfig( maTestConfigIniURL ); - - TeleManager::addSuffixToNames( "TeleTest"); - - OUString aOffererIdentifier; - CPPUNIT_ASSERT_MESSAGE( "See README for how to set up test-config.ini", - aTestConfig.getFrom("offerer", aOffererIdentifier)); - maOffererIdentifier = OUStringToOString( aOffererIdentifier, RTL_TEXTENCODING_UTF8); - - OUString aAccepterIdentifier; - CPPUNIT_ASSERT_MESSAGE( "See README for how to set up test-config.ini", - aTestConfig.getFrom("accepter", aAccepterIdentifier)); - maAccepterIdentifier = OUStringToOString( aAccepterIdentifier, RTL_TEXTENCODING_UTF8); - - mpCollaboration1 = new TestCollaboration(); - mpCollaboration2 = new TestCollaboration(); - - CPPUNIT_ASSERT( TeleManager::init( true)); -} - -/* FIXME: do we need the possibility to pass function to Collaboration::SendFile() ? -static void lcl_FileSent( bool success, void * ) -{ - mbFileSentSuccess = success; -} -*/ - -void TestTeleTubes::testSession() -{ - // First try to get account and contact - AccountContactPairV pairs = TeleManager::getContacts(); - /* Both our accounts are meant to be signed in, and they both should be - * capable of LibreOffice tubes because this test runs after we register - * our handler. */ - CPPUNIT_ASSERT_MESSAGE( - "Make sure both your test accounts are signed in " - "and are on each other's contact lists", - pairs.size() > 0 ); - - TpAccount* mpOffererAccount = nullptr; - TpContact* mpAccepterContact = nullptr; - - for (AccountContactPairV::size_type i = 0; i < pairs.size(); i++) - { - AccountContactPair pair = pairs[i]; - - if (tp_account_get_normalized_name (pair.first) == maOffererIdentifier && - tp_contact_get_identifier (pair.second) == maAccepterIdentifier) - { - mpOffererAccount = pair.first; - g_object_ref (mpOffererAccount); - mpAccepterContact = pair.second; - g_object_ref (mpAccepterContact); - } - g_object_unref (pair.first); - g_object_unref (pair.second); - } - - CPPUNIT_ASSERT_MESSAGE( - "Couldn't find offerer account. " - "Make sure both your test accounts are signed in " - "and are on each other's contact lists", - mpOffererAccount); - CPPUNIT_ASSERT_MESSAGE( - "Couldn't find accepter contact. " - "Make sure both your test accounts are signed in " - "and are on each other's contact lists", - mpAccepterContact); - - // Now we can start session - TeleConference* pConference = nullptr; - pConference = TeleManager::startBuddySession( mpOffererAccount, mpAccepterContact); - CPPUNIT_ASSERT( pConference != nullptr); - mpCollaboration1->SetConference( pConference ); - mpCollaboration1->SendFile( mpAccepterContact, maTestConfigIniURL ); - - g_object_unref(mpOffererAccount); - mpOffererAccount = nullptr; - g_object_unref(mpAccepterContact); - mpAccepterContact = nullptr; - - //while (!mbFileSentSuccess) - // g_main_context_iteration( NULL, TRUE); - - // This checks that the file was received and msCurrentUUID set (see manager.cxx) - while (!TeleManager::hasWaitingConference()) - g_main_context_iteration( nullptr, TRUE); - - pConference = TeleManager::getConference(); - CPPUNIT_ASSERT( pConference != nullptr); - mpCollaboration2->SetConference( pConference ); - - mpCollaboration1->SendPacket( "from 1 to 2"); - - while (!mbPacketReceived) - g_main_context_iteration( nullptr, TRUE); -} - -void TestTeleTubes::tearDown() -{ - // Closes the TeleConference in destructor: - delete mpCollaboration1; - delete mpCollaboration2; - - TeleManager::finalize(); -} - -CPPUNIT_TEST_SUITE_REGISTRATION( TestTeleTubes); - -} - -CPPUNIT_PLUGIN_IMPLEMENT(); - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/approver.c b/tubes/source/approver.c deleted file mode 100644 index 6d6e28050d71..000000000000 --- a/tubes/source/approver.c +++ /dev/null @@ -1,235 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <glib.h> -#include <stdio.h> - -#include <gtk/gtk.h> - -#include <telepathy-glib/telepathy-glib.h> -#include <telepathy-glib/debug.h> -#include <telepathy-glib/simple-approver.h> - -#include <constants.h> - -GMainLoop *mainloop = NULL; - -static void -handle_with_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - TpChannelDispatchOperation *cdo = TP_CHANNEL_DISPATCH_OPERATION (source); - GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (user_data); - GError *error = NULL; - - if (!tp_channel_dispatch_operation_handle_with_finish (cdo, result, &error)) - { - g_print ("HandleWith() failed: %s\n", error->message); - gtk_message_dialog_format_secondary_markup (dialog, - "<b>Error</b>\n\nAsking LibreOffice to accept the session failed: <i>%s</i>", - error->message); - g_error_free (error); - return; - } - - g_print ("HandleWith() succeeded\n"); - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -static void -close_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) - -{ - TpChannelDispatchOperation *cdo = TP_CHANNEL_DISPATCH_OPERATION (source); - GError *error = NULL; - - (void)user_data; /* suppress unused-parameter warning */ - - if (!tp_channel_dispatch_operation_close_channels_finish (cdo, result, &error)) - { - g_print ("Rejecting channels failed: %s\n", error->message); - g_error_free (error); - return; - } - - g_print ("Rejected all the things!\n"); -} - -static void -dialog_response_cb ( - GtkWidget *dialog, - gint response_id, - gpointer user_data) -{ - TpSimpleApprover *self = TP_SIMPLE_APPROVER (g_object_get_data (G_OBJECT (dialog), "client")); - TpChannelDispatchOperation *cdo = TP_CHANNEL_DISPATCH_OPERATION (user_data); - - (void)self; /* suppress unused-parameter warning (could remove TP_SIMPLE_APPROVER above?) */ - - if (response_id == GTK_RESPONSE_ACCEPT) - { - g_print ("Approve channels\n"); - - tp_channel_dispatch_operation_handle_with_async (cdo, NULL, - handle_with_cb, dialog); - - gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, FALSE); - gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT, FALSE); - } - else - { - g_print ("Reject channels\n"); - - tp_channel_dispatch_operation_close_channels_async (cdo, close_cb, dialog); - gtk_widget_destroy (dialog); - } - - g_object_unref (cdo); -} - -static void -show_dialog ( - TpSimpleApprover *self, - TpChannelDispatchOperation *cdo, - TpContact *target) -{ - GFile *avatar_file = tp_contact_get_avatar_file (target); - GtkWidget *dialog = gtk_message_dialog_new_with_markup (NULL, - 0, /* flags */ - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - "<b>%s</b> (<i>%s</i>) would like to edit a spreadsheet in LibreOffice " - "with you.", - tp_contact_get_alias (target), - tp_contact_get_identifier (target)); - - if (avatar_file != NULL) - { - GtkWidget *avatar = gtk_image_new_from_file (g_file_get_path (avatar_file)); - - gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), avatar); - } - - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - "_Reject", GTK_RESPONSE_REJECT, - "_Accept", GTK_RESPONSE_ACCEPT, - NULL); - - g_object_set_data_full (G_OBJECT (dialog), "client", g_object_ref (self), g_object_unref); - g_signal_connect (dialog, "response", G_CALLBACK (dialog_response_cb), g_object_ref (cdo)); - - gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE); - - gtk_widget_show_all (dialog); -} - -static void -add_dispatch_operation_cb (TpSimpleApprover *self, - TpAccount *account, - TpConnection *connection, - GList *channels, - TpChannelDispatchOperation *cdo, - TpAddDispatchOperationContext *context, - gpointer user_data) -{ - TpContact *target = NULL; - GList *l; - - (void)account; /* suppress unused-parameter warning */ - (void)connection; /* suppress unused-parameter warning */ - (void)user_data; /* suppress unused-parameter warning */ - - g_print ("Approving this batch of channels:\n"); - - for (l = channels; l != NULL; l = g_list_next (l)) - { - TpChannel *channel = l->data; - - if (TP_IS_DBUS_TUBE_CHANNEL (channel)) - { - target = tp_channel_get_target_contact (channel); - break; - } - } - - if (target == NULL) - { - g_critical ("Hmm. No 1-1 D-Bus tube in cdo %s, so why did we get it?", - tp_proxy_get_object_path (cdo)); - g_return_if_reached (); - } - - tp_add_dispatch_operation_context_accept (context); - show_dialog (self, cdo, target); -} - -int -main (int argc, - char **argv) -{ - TpAccountManager *manager; - TpSimpleClientFactory *factory; - TpBaseClient *approver; - GError *error = NULL; - - gtk_init (&argc, &argv); - tp_debug_set_flags (g_getenv ("LIBO_APPROVER_DEBUG")); - - manager = tp_account_manager_dup (); - - factory = tp_proxy_get_factory (manager); - /* We want the target contact on channels to be available... */ - tp_simple_client_factory_add_channel_features_varargs (factory, - TP_CHANNEL_FEATURE_CONTACTS, - 0); - /* ...and for it to have its alias and avatar available */ - tp_simple_client_factory_add_contact_features_varargs (factory, - TP_CONTACT_FEATURE_ALIAS, - TP_CONTACT_FEATURE_AVATAR_DATA, - TP_CONTACT_FEATURE_INVALID); - - approver = tp_simple_approver_new_with_am (manager, "LibreOfficeApprover", - FALSE, add_dispatch_operation_cb, NULL, NULL); - - tp_base_client_take_approver_filter (approver, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, - LIBO_DTUBE_SERVICE, - NULL)); - - if (!tp_base_client_register (approver, &error)) - { - g_warning ("Failed to register Approver: %s\n", error->message); - g_error_free (error); - goto out; - } - - g_print ("Start approving\n"); - - mainloop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (mainloop); - /* TODO: time out after 5 seconds of inactivity? */ - - if (mainloop != NULL) - g_main_loop_unref (mainloop); - -out: - g_object_unref (manager); - g_object_unref (approver); - - return 0; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/collaboration.cxx b/tubes/source/collaboration.cxx deleted file mode 100644 index fe397f8381fd..000000000000 --- a/tubes/source/collaboration.cxx +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <tubes/collaboration.hxx> -#include <tubes/manager.hxx> - -#include <conference.hxx> -#include <contacts.hxx> - -Collaboration::Collaboration() : - mpConference( nullptr ) -{ - TeleManager::registerCollaboration( this ); -} - -Collaboration::~Collaboration() -{ - TeleManager::unregisterCollaboration( this ); - if (mpConference) - mpConference->close(); -} - -sal_uInt64 Collaboration::GetId() const -{ - return reinterpret_cast<sal_uInt64> (this); -} - -void Collaboration::Invite( TpContact* pContact ) const -{ - if (mpConference) - { - mpConference->invite( pContact ); - SaveAndSendFile( pContact ); - } -} - -void Collaboration::DisplayContacts() -{ - if (!mpContacts) - mpContacts = VclPtr<tubes::TubeContacts>::Create( this ); - mpContacts->Populate(); -} - -void Collaboration::SendFile( TpContact* pContact, const OUString& rURL ) const -{ - if (mpConference) - mpConference->sendFile( pContact, rURL, nullptr, nullptr ); -} - -void Collaboration::SendPacket( const OString& rPacket ) const -{ - if (mpConference) - mpConference->sendPacket( rPacket ); -} - -void Collaboration::SetConference( TeleConference* pConference ) -{ - mpConference = pConference; - mpConference->setCollaboration( this ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/conference.cxx b/tubes/source/conference.cxx deleted file mode 100644 index 373a564692b0..000000000000 --- a/tubes/source/conference.cxx +++ /dev/null @@ -1,574 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <tubes/collaboration.hxx> -#include <tubes/manager.hxx> - -#include <conference.hxx> -#include <constants.h> -#include <file-transfer-helper.h> - -#include <gtk/gtk.h> -#include <telepathy-glib/telepathy-glib.h> - -#if defined SAL_LOG_INFO -namespace -{ -struct InfoLogger -{ - const void* mpThat; - const char* mpMethod; - explicit InfoLogger( const void* pThat, const char* pMethod ) - : - mpThat( pThat), - mpMethod( pMethod) - { - SAL_INFO( "tubes.method", mpThat << " entering " << mpMethod); - } - ~InfoLogger() - { - SAL_INFO( "tubes.method", mpThat << " leaving " << mpMethod); - } -}; -} -#define INFO_LOGGER_F(s) InfoLogger aLogger(nullptr,(s)) -#define INFO_LOGGER(s) InfoLogger aLogger(this,(s)) -#else -#define INFO_LOGGER_F(s) -#define INFO_LOGGER(s) -#endif // SAL_LOG_INFO - -class TeleConferenceImpl -{ -public: - guint maObjectRegistrationId; - GDBusConnection* mpTube; - bool mbTubeOfferedHandlerInvoked : 1; - - TeleConferenceImpl() : - mpTube( nullptr ), - mbTubeOfferedHandlerInvoked( false ) - {} - - ~TeleConferenceImpl() {} -}; - -static void TeleConference_MethodCallHandler( - GDBusConnection* /*pConnection*/, - const gchar* pSender, - const gchar* /*pObjectPath*/, - const gchar* pInterfaceName, - const gchar* pMethodName, - GVariant* pParameters, - GDBusMethodInvocation* pInvocation, - void* pUserData) -{ - INFO_LOGGER_F( "TeleConference_MethodCallHandler"); - - TeleConference* pConference = static_cast<TeleConference*>(pUserData); - SAL_WARN_IF( !pConference, "tubes", "TeleConference_MethodCallHandler: no conference"); - if (!pConference) - return; - - if (tp_strdiff (pMethodName, LIBO_TUBES_DBUS_MSG_METHOD)) - { - g_dbus_method_invocation_return_error ( pInvocation, - G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method '%s' on interface %s", - pMethodName, pInterfaceName ); - return; - } - - if (!g_variant_is_of_type ( pParameters, G_VARIANT_TYPE ("(ay)"))) - { - g_dbus_method_invocation_return_error ( pInvocation, - G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "'%s' takes an array of bytes, not %s", - pMethodName, - g_variant_get_type_string (pParameters)); - return; - } - - GVariant *ay; - g_variant_get( pParameters, "(@ay)", &ay); - const char* pPacketData = static_cast<const char*>( g_variant_get_data( ay)); - gsize nPacketSize = g_variant_get_size( ay); - - SAL_WARN_IF( !pPacketData, "tubes", "TeleConference_MethodCallHandler: couldn't get packet data"); - if (!pPacketData) - return; - - SAL_INFO( "tubes", "TeleConference_MethodCallHandler: received packet from sender " - << (pSender ? pSender : "(null)") << " with size " << nPacketSize); - OString aPacket( pPacketData, nPacketSize ); - if (pConference->getCollaboration()) - pConference->getCollaboration()->PacketReceived( aPacket ); - // Master needs to send the packet back to impose ordering, - // so the slave can execute his command. - if (pConference->isMaster()) - pConference->sendPacket( aPacket ); - - g_dbus_method_invocation_return_value( pInvocation, nullptr ); - - g_variant_unref( ay); -} - - -static void TeleConference_ChannelCloseHandler( - TpChannel* /*proxy*/, - const GError* pError, - gpointer pUserData, - GObject* /*weak_object*/ - ) -{ - INFO_LOGGER_F( "TeleConference_ChannelCloseHandler"); - - TeleConference* pConference = static_cast<TeleConference*>(pUserData); - SAL_WARN_IF( !pConference, "tubes", "TeleConference_ChannelCloseHandler: no conference"); - if (!pConference) - return; - - if (pError) - { - SAL_WARN( "tubes", "TeleConference_ChannelCloseHandler: entered with error: " << pError->message); - pConference->finalize(); - return; - } - - pConference->finalize(); -} - - -static void TeleConference_TubeOfferedHandler( - GObject* pSource, - GAsyncResult* pResult, - gpointer pUserData) -{ - INFO_LOGGER_F( "TeleConference_TubeOfferedHandler"); - - TeleConference* pConference = static_cast<TeleConference*>(pUserData); - SAL_WARN_IF( !pConference, "tubes", "TeleConference_TubeOfferedHandler: no conference"); - if (!pConference) - return; - - pConference->setTubeOfferedHandlerInvoked( true); - - TpDBusTubeChannel* pChannel = TP_DBUS_TUBE_CHANNEL( pSource); - GError* pError = nullptr; - GDBusConnection* pTube = tp_dbus_tube_channel_offer_finish( - pChannel, pResult, &pError); - - // "can't find contact ... presence" means contact is not a contact. - /* FIXME: detect and handle */ - SAL_WARN_IF( !pTube, "tubes", "TeleConference_TubeOfferedHandler: entered with error: " << pError->message); - if (pError) { - g_error_free( pError); - return; - } - - pConference->setTube( pTube); -} - - -static void TeleConference_TubeAcceptedHandler( - GObject* pSource, - GAsyncResult* pResult, - gpointer pUserData) -{ - INFO_LOGGER_F( "TeleConference_TubeAcceptedHandler"); - - TeleConference* pConference = static_cast<TeleConference*>(pUserData); - SAL_WARN_IF( !pConference, "tubes", "TeleConference_TubeAcceptedHandler: no conference"); - if (!pConference) - return; - - pConference->setTubeOfferedHandlerInvoked( true); - - TpDBusTubeChannel* pChannel = TP_DBUS_TUBE_CHANNEL( pSource); - GError* pError = nullptr; - GDBusConnection* pTube = tp_dbus_tube_channel_accept_finish( - pChannel, pResult, &pError); - - SAL_WARN_IF( !pTube, "tubes", "TeleConference_TubeAcceptedHandler: entered with error: " << pError->message); - if (pError) { - g_error_free( pError); - return; - } - GHashTable* pParameters = tp_dbus_tube_channel_get_parameters( pChannel); - const char* sUuid = tp_asv_get_string( pParameters, LIBO_TUBES_UUID); - pConference->setUuid( OString( sUuid)); - - pConference->setTube( pTube); -} - - -TeleConference::TeleConference( TpAccount* pAccount, - TpDBusTubeChannel* pChannel, const OString & sUuid, bool bMaster ) - : - mpCollaboration( nullptr ), - mpAccount( nullptr ), - mpChannel( nullptr ), - msUuid( sUuid ), - mbMaster( bMaster ), - pImpl( new TeleConferenceImpl() ) -{ - setChannel( pAccount, pChannel ); -} - - -TeleConference::~TeleConference() -{ - // We're destructed from finalize() - delete pImpl; -} - -static void channel_closed_cb( TpChannel *channel, gpointer user_data, GObject * /* weak_object */ ) -{ - Collaboration* pCollaboration = static_cast<Collaboration*> (user_data); - if (TeleManager::existsCollaboration( pCollaboration )) - { - GtkWidget *dialog = gtk_message_dialog_new( nullptr, static_cast<GtkDialogFlags> (0), - GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, - "Contact %s lost, you'll now be working locally.", - tp_contact_get_alias (tp_channel_get_target_contact (channel)) ); - g_signal_connect_swapped (dialog, "response", - G_CALLBACK (gtk_widget_destroy), dialog); - gtk_widget_show_all (dialog); - - pCollaboration->EndCollaboration(); - } -} - - -void TeleConference::setChannel( TpAccount *pAccount, TpDBusTubeChannel* pChannel ) -{ - SAL_WARN_IF( mpChannel, "tubes", "TeleConference::setChannel: already have channel"); - if (mpChannel) - g_object_unref( mpChannel); - if (mpAccount) - g_object_unref( mpAccount); - - mpChannel = pChannel; - if (mpChannel) - g_object_ref( mpChannel); - - mpAccount = pAccount; - if (mpAccount) - g_object_ref( mpAccount); -} - - -bool TeleConference::spinUntilTubeEstablished() -{ - while (!isTubeOfferedHandlerInvoked()) - { - g_main_context_iteration( nullptr, TRUE ); - } - - bool bOpen = pImpl->mpTube != nullptr; - SAL_INFO( "tubes", "TeleConference::spinUntilTubeEstablished: tube open: " << bOpen); - return bOpen; -} - - -bool TeleConference::acceptTube() -{ - INFO_LOGGER( "TeleConference::acceptTube"); - - SAL_WARN_IF( !mpChannel, "tubes", "TeleConference::acceptTube: no channel setup"); - SAL_WARN_IF( pImpl->mpTube, "tubes", "TeleConference::acceptTube: already tubed"); - if (!mpChannel || pImpl->mpTube) - return false; - - tp_dbus_tube_channel_accept_async( mpChannel, - TeleConference_TubeAcceptedHandler, - this); - return spinUntilTubeEstablished(); -} - - -bool TeleConference::offerTube() -{ - INFO_LOGGER( "TeleConference::offerTube"); - - SAL_WARN_IF( !mpChannel, "tubes", "TeleConference::offerTube: no channel"); - if (!mpChannel) - return false; - - GHashTable* pParameters = tp_asv_new ( - LIBO_TUBES_UUID, G_TYPE_STRING, msUuid.getStr(), - nullptr); - - tp_dbus_tube_channel_offer_async( - mpChannel, - pParameters, - TeleConference_TubeOfferedHandler, - this); - - return spinUntilTubeEstablished(); -} - - -bool TeleConference::setTube( GDBusConnection* pTube) -{ - INFO_LOGGER( "TeleConference::setTube"); - - SAL_WARN_IF( pImpl->mpTube, "tubes", "TeleConference::setTube: already tubed"); - - pImpl->mpTube = pTube; - - GDBusNodeInfo *introspection_data; - static const GDBusInterfaceVTable interface_vtable = - { - TeleConference_MethodCallHandler, - nullptr, - nullptr, - { nullptr }, - }; - static const gchar introspection_xml[] = - "<node>" - " <interface name='" LIBO_TUBES_DBUS_INTERFACE "'>" - " <method name='" LIBO_TUBES_DBUS_MSG_METHOD "'>" - " <arg type='ay' name='packet' direction='in'/>" - " </method>" - " </interface>" - "</node>"; - - introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, nullptr); - g_assert (introspection_data != nullptr); - - pImpl->maObjectRegistrationId = g_dbus_connection_register_object( pImpl->mpTube, - LIBO_TUBES_DBUS_PATH, introspection_data->interfaces[0], - &interface_vtable, this, nullptr, nullptr); - g_assert (pImpl->maObjectRegistrationId > 0); - - g_dbus_node_info_unref (introspection_data); - - return true; -} - -void TeleConference::setTubeOfferedHandlerInvoked( bool b ) -{ - pImpl->mbTubeOfferedHandlerInvoked = b; -} - -bool TeleConference::isTubeOfferedHandlerInvoked() const -{ - return pImpl->mbTubeOfferedHandlerInvoked; -} - -bool TeleConference::isReady() const -{ - return mpChannel && pImpl->mpTube; -} - -void TeleConference::close() -{ - INFO_LOGGER( "TeleConference::close"); - - if (mpChannel) - tp_cli_channel_call_close( TP_CHANNEL( mpChannel), 5000, TeleConference_ChannelCloseHandler, this, nullptr, nullptr); - else - finalize(); -} - - -void TeleConference::finalize() -{ - INFO_LOGGER( "TeleConference::finalize"); - - TeleManager::unregisterDemoConference( this ); - - if (mpChannel) - { - g_object_unref( mpChannel); - mpChannel = nullptr; - } - - if (mpAccount) - { - g_object_unref( mpAccount); - mpAccount = nullptr; - } - - if (pImpl->mpTube) - { - g_dbus_connection_unregister_object( pImpl->mpTube, pImpl->maObjectRegistrationId); - g_dbus_connection_close_sync( pImpl->mpTube, nullptr, nullptr ); - g_object_unref( pImpl->mpTube ); - pImpl->mpTube = nullptr; - } - - //! *this gets destructed here! -} - - -bool TeleConference::sendPacket( const OString& rPacket ) -{ - INFO_LOGGER( "TeleConference::sendPacket"); - - if (!mpChannel && !pImpl->mpTube) - { - TeleManager::broadcastPacket( rPacket ); - return true; - } - - SAL_WARN_IF( !pImpl->mpTube, "tubes", "TeleConference::sendPacket: no tube"); - if (!pImpl->mpTube) - return false; - - /* FIXME: in GLib 2.32 we can use g_variant_new_fixed_array(). It does - * essentially this. - */ - void* pData = g_memdup( rPacket.getStr(), rPacket.getLength() ); - GVariant *pParameters = g_variant_new_from_data( G_VARIANT_TYPE("(ay)"), - pData, rPacket.getLength(), - FALSE, - g_free, pData); - - g_dbus_connection_call( pImpl->mpTube, - nullptr, /* bus name; in multi-user case we'd address this to the master. */ - LIBO_TUBES_DBUS_PATH, - LIBO_TUBES_DBUS_INTERFACE, - LIBO_TUBES_DBUS_MSG_METHOD, - pParameters, /* consumes the floating reference */ - nullptr, - G_DBUS_CALL_FLAGS_NONE, - -1, nullptr, nullptr, nullptr); - - // If we started the session, we can execute commands immediately. - if (mbMaster && mpCollaboration) - mpCollaboration->PacketReceived( rPacket ); - - return true; -} - -bool TeleConference::isMaster() const -{ - return mbMaster; -} - -Collaboration* TeleConference::getCollaboration() const -{ - return mpCollaboration; -} - -void TeleConference::setCollaboration( Collaboration* pCollaboration ) -{ - mpCollaboration = pCollaboration; - if (mpChannel) - { - GError *error = nullptr; - if (!tp_cli_channel_connect_to_closed( TP_CHANNEL (mpChannel), - channel_closed_cb, mpCollaboration, nullptr, nullptr, &error )) - { - SAL_WARN( "tubes", "Error when connecting to signal closed: " << error->message ); - g_error_free (error); - } - } -} - -void TeleConference::invite( TpContact *pContact ) -{ - INFO_LOGGER( "TeleConference::invite" ); - TpHandle aHandle = tp_contact_get_handle( pContact ); - GArray handles = { reinterpret_cast<gchar *> (&aHandle), 1 }; - tp_cli_channel_interface_group_call_add_members( TP_CHANNEL( mpChannel ), - -1, &handles, nullptr, nullptr, nullptr, nullptr, nullptr ); -} - -namespace { -class SendFileRequest { -public: - SendFileRequest( TeleConference::FileSentCallback pCallback, void* pUserData, const char* sUuid ) - : mpCallback(pCallback) - , mpUserData(pUserData) - , msUuid(sUuid) - {} - - TeleConference::FileSentCallback mpCallback; - void* mpUserData; - const char* msUuid; -}; -} - -static void TeleConference_TransferDone( EmpathyFTHandler *handler, TpFileTransferChannel *, gpointer user_data) -{ - SendFileRequest *request = static_cast<SendFileRequest *>(user_data); - - if (request->mpCallback) - request->mpCallback(true, request->mpUserData); - delete request; - g_object_unref (handler); -} - -static void TeleConference_TransferError( EmpathyFTHandler *handler, const GError *error, gpointer user_data) -{ - SendFileRequest *request = static_cast<SendFileRequest *>(user_data); - - SAL_INFO( "tubes", "TeleConference_TransferError: " << error->message); - - if (request->mpCallback) - request->mpCallback(false, request->mpUserData); - delete request; - g_object_unref (handler); -} - -static void TeleConference_FTReady( EmpathyFTHandler *handler, GError *error, gpointer user_data) -{ - SendFileRequest *request = static_cast<SendFileRequest *>(user_data); - - if ( error != nullptr ) - { - if (request->mpCallback) - request->mpCallback(error == nullptr, request->mpUserData); - delete request; - g_object_unref (handler); - } - else - { - g_signal_connect(handler, "transfer-done", - G_CALLBACK (TeleConference_TransferDone), request); - g_signal_connect(handler, "transfer-error", - G_CALLBACK (TeleConference_TransferError), request); - empathy_ft_handler_set_service_name(handler, TeleManager::getFullServiceName().getStr()); - empathy_ft_handler_set_description(handler, request->msUuid); - empathy_ft_handler_start_transfer(handler); - } -} - -// TODO: move sending file to TeleManager -void TeleConference::sendFile( TpContact* pContact, const OUString& localUri, FileSentCallback pCallback, void* pUserData) -{ - INFO_LOGGER( "TeleConference::sendFile"); - - if (!pContact) - { - // used in demo mode - TeleManager_fileReceived( localUri, "demo" ); - return; - } - - SAL_WARN_IF( ( !mpAccount || !mpChannel), "tubes", - "can't send a file before the tube is set up"); - if ( !mpAccount || !mpChannel) - return; - - GFile *pSource = g_file_new_for_uri( - OUStringToOString( localUri, RTL_TEXTENCODING_UTF8).getStr() ); - SendFileRequest *pReq = new SendFileRequest( pCallback, pUserData, msUuid.getStr() ); - - empathy_ft_handler_new_outgoing( mpAccount, - pContact, - pSource, - 0, - TeleConference_FTReady, pReq); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/conference.hxx b/tubes/source/conference.hxx deleted file mode 100644 index b39b8fbf79c9..000000000000 --- a/tubes/source/conference.hxx +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef INCLUDED_TUBES_CONFERENCE_HXX -#define INCLUDED_TUBES_CONFERENCE_HXX - -#include <sal/config.h> -#include <rtl/ustring.hxx> - -#include <telepathy-glib/telepathy-glib.h> - -class Collaboration; -class TeleConferenceImpl; - -/** Conference setup by TeleManager */ -class TeleConference -{ -public: - - TeleConference( TpAccount* pAccount, - TpDBusTubeChannel* pChannel, - const OString & sUuid = OString(), - bool bMaster = false ); - ~TeleConference(); - - /// Close channel and call finalize() - void close(); - - /// Unrefs, unregisters from manager and calls dtor if last reference! - void finalize(); - - bool sendPacket( const OString& rPacket ); - - void invite( TpContact *pContact ); - - typedef void (*FileSentCallback)( bool aSuccess, void* pUserData); - void sendFile( TpContact* pContact, const OUString& rURL, FileSentCallback pCallback, void* pUserData); - const OString& getUuid() const { return msUuid; } - - Collaboration* getCollaboration() const; - void setCollaboration( Collaboration* pCollaboration ); - - // --- following only to be called only by manager's callbacks --- - // TODO: make friends instead - void setChannel( TpAccount* pAccount, TpDBusTubeChannel* pChannel ); - bool offerTube(); - bool acceptTube(); - - // Only for callbacks. - bool setTube( GDBusConnection* pTube ); - void setTubeOfferedHandlerInvoked( bool b ); - bool isTubeOfferedHandlerInvoked() const; - bool isMaster() const; - void setUuid( const OString& rUuid ) { msUuid = rUuid; } - -private: - friend class TeleManager; - // Used only by TeleManager: - /// got tube accepted on other end as well? - bool isReady() const; - - // Private: - bool spinUntilTubeEstablished(); - - Collaboration* mpCollaboration; - TpAccount* mpAccount; - TpDBusTubeChannel* mpChannel; - OString msUuid; - bool mbMaster; - TeleConferenceImpl* pImpl; -}; - -#endif // INCLUDED_TUBES_CONFERENCE_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/constants.h b/tubes/source/constants.h deleted file mode 100644 index 5f861e5ea738..000000000000 --- a/tubes/source/constants.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef INCLUDED_TUBES_CONSTANTS_H -#define INCLUDED_TUBES_CONSTANTS_H - -/* DBusTube.ServiceName. - * - * FIXME: Should be something like - * - * org.libreoffice.calc - * org.libreoffice.writer - * - * etc. This does not need to include the org.freedesktop.Telepathy.Client - * stuff. - */ -#define LIBO_DTUBE_SERVICE "org.libreoffice.calc" - -/* Client name suffix, for passing as 'name' to - * tp_simple_handler_new_with_am(). */ -#define LIBO_CLIENT_SUFFIX "LibreOffice" - -/* Key value storing UUID for TeleConference - */ -#define LIBO_TUBES_UUID "LIBO_TUBES_UUID" - -#endif // INCLUDED_TUBES_CONSTANTS_H - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/contacts.cxx b/tubes/source/contacts.cxx deleted file mode 100644 index 96a1b25b9d45..000000000000 --- a/tubes/source/contacts.cxx +++ /dev/null @@ -1,191 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <sal/config.h> - -#include <vcl/graphicfilter.hxx> -#include <tubes/collaboration.hxx> - -#include <telepathy-glib/telepathy-glib.h> - -#include <conference.hxx> -#include <contacts.hxx> - -void tubes::TubeContacts::Invite() -{ - if (mpList->GetSelectEntryCount()) - { - sal_uInt16 i = mpList->GetSelectEntryPos(); - TpContact* pContact = maACs[i].second; - mpCollaboration->Invite( pContact ); - } -} - -void tubes::TubeContacts::StartDemoSession() -{ - TeleConference* pConference = TeleManager::startDemoSession(); - if (!pConference) - SAL_WARN( "tubes", "Could not start demo session!" ); - else - { - mpCollaboration->StartCollaboration( pConference ); - mpCollaboration->SaveAndSendFile( nullptr ); - } -} - -void tubes::TubeContacts::StartBuddySession() -{ - if (mpList->GetSelectEntryCount()) - { - sal_uInt16 i = mpList->GetSelectEntryPos(); - TpAccount* pAccount = maACs[i].first; - TpContact* pContact = maACs[i].second; - SAL_INFO( "tubes", "picked " << tp_contact_get_identifier( pContact ) ); - TeleConference* pConference = TeleManager::startBuddySession( pAccount, pContact ); - if (!pConference) - SAL_WARN( "tubes", "Could not start session with " << - tp_contact_get_identifier( pContact ) ); - else - { - mpCollaboration->StartCollaboration( pConference ); - mpCollaboration->SaveAndSendFile( pContact ); - } - } -} - -void tubes::TubeContacts::StartGroupSession() -{ - if (mpList->GetSelectEntryCount()) - { - sal_uInt16 i = mpList->GetSelectEntryPos(); - TpAccount* pAccount = maACs[i].first; - SAL_INFO( "tubes", "picked " << tp_account_get_display_name( pAccount ) ); - TeleConference* pConference = TeleManager::startGroupSession( pAccount, - "liboroom", "conference.jabber.org" ); - if (!pConference) - SAL_WARN( "tubes", "Could not start group session." ); - else - { - mpCollaboration->StartCollaboration( pConference ); - } - } -} - -tubes::TubeContacts::TubeContacts( Collaboration* pCollaboration ) : - ModelessDialog( nullptr, "ContactsDialog", "tubes/ui/contacts.ui" ), - mpCollaboration( pCollaboration ) -{ - get( mpBtnListen, "listen"); - get( mpBtnInvite, "invite"); - get( mpBtnDemo, "demo"); - get( mpBtnBuddy, "buddy"); - get( mpBtnGroup, "group"); - get( mpList, "contacts"); - mpBtnListen->SetClickHdl( LINK( this, TubeContacts, BtnListenHdl ) ); - mpBtnInvite->SetClickHdl( LINK( this, TubeContacts, BtnInviteHdl ) ); - mpBtnDemo->SetClickHdl( LINK( this, TubeContacts, BtnDemoHdl ) ); - mpBtnBuddy->SetClickHdl( LINK( this, TubeContacts, BtnConnectHdl ) ); - mpBtnGroup->SetClickHdl( LINK( this, TubeContacts, BtnGroupHdl ) ); -} - -tubes::TubeContacts::~TubeContacts() -{ - disposeOnce(); -} - -void tubes::TubeContacts::dispose() -{ - mpBtnListen.disposeAndClear(); - mpBtnInvite.disposeAndClear(); - mpBtnDemo.disposeAndClear(); - mpBtnBuddy.disposeAndClear(); - mpBtnGroup.disposeAndClear(); - mpList.disposeAndClear(); - ModelessDialog::dispose(); -} - -namespace { - -OUString fromUTF8( const char *pStr ) -{ - return OStringToOUString( OString( pStr, strlen( pStr ) ), - RTL_TEXTENCODING_UTF8 ); -} - -} - -void tubes::TubeContacts::Populate() -{ - SAL_INFO( "tubes", "Populating contact list dialog" ); - mpList->Clear(); - maACs.clear(); - - AccountContactPairV aPairs = TeleManager::getContacts(); - AccountContactPairV::iterator it; - // make sure we have enough memory to not need re-allocation - // which would invalidate pointers stored in mpList entries - maACs.reserve( aPairs.size() ); - for( it = aPairs.begin(); it != aPairs.end(); ++it ) - { - Image aImage; - GFile *pAvatarFile = tp_contact_get_avatar_file( it->second ); - if( pAvatarFile ) - { - const OUString sAvatarFileUrl = fromUTF8( g_file_get_path ( pAvatarFile ) ); - Graphic aGraphic; - if( GRFILTER_OK == GraphicFilter::LoadGraphic( sAvatarFileUrl, "", aGraphic ) ) - { - BitmapEx aBitmap = aGraphic.GetBitmapEx(); - double fScale = 30.0 / aBitmap.GetSizePixel().Height(); - aBitmap.Scale( fScale, fScale ); - aImage = Image( aBitmap ); - } - } - OUStringBuffer aEntry( 128 ); - aEntry.append( " " ); - aEntry.append( fromUTF8 ( tp_contact_get_alias( it->second ) ) ); - aEntry.append( " - " ); - aEntry.append( fromUTF8 ( tp_contact_get_identifier( it->second ) ) ); - mpList->InsertEntry( aEntry.makeStringAndClear(), aImage); - // FIXME: ref the TpAccount, TpContact ... - maACs.push_back( AccountContactPair( it->first, it->second ) ); - - g_object_unref (it->first); - g_object_unref (it->second); - } - Show(); -} - -IMPL_LINK_NOARG( tubes::TubeContacts, BtnDemoHdl, Button*, void ) -{ - StartDemoSession(); -} - -IMPL_LINK_NOARG( tubes::TubeContacts, BtnConnectHdl, Button*, void ) -{ - StartBuddySession(); -} - -IMPL_LINK_NOARG( tubes::TubeContacts, BtnGroupHdl, Button*, void ) -{ - StartGroupSession(); -} - -IMPL_LINK_NOARG( tubes::TubeContacts, BtnInviteHdl, Button*, void ) -{ - Invite(); -} - -IMPL_STATIC_LINK_NOARG( tubes::TubeContacts, BtnListenHdl, Button*, void ) -{ - if (!TeleManager::registerClients()) - SAL_INFO( "tubes", "Could not register client handlers." ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/contacts.hxx b/tubes/source/contacts.hxx deleted file mode 100644 index 7684db962d22..000000000000 --- a/tubes/source/contacts.hxx +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef INCLUDED_TUBES_SOURCE_CONTACTS_HXX -#define INCLUDED_TUBES_SOURCE_CONTACTS_HXX - -#include <sal/config.h> - -#include <tubes/manager.hxx> -#include <vcl/button.hxx> -#include <vcl/dialog.hxx> -#include <vcl/lstbox.hxx> - -class Collaboration; - -namespace tubes { - -class TubeContacts : public ModelessDialog -{ - VclPtr<PushButton> mpBtnDemo; - VclPtr<PushButton> mpBtnBuddy; - VclPtr<PushButton> mpBtnGroup; - VclPtr<PushButton> mpBtnInvite; - VclPtr<PushButton> mpBtnListen; - VclPtr<ListBox> mpList; - Collaboration* mpCollaboration; - - DECL_LINK( BtnDemoHdl, Button*, void ); - DECL_LINK( BtnConnectHdl, Button*, void ); - DECL_LINK( BtnGroupHdl, Button*, void ); - DECL_LINK( BtnInviteHdl, Button*, void ); - DECL_STATIC_LINK( TubeContacts, BtnListenHdl, Button*, void ); - - AccountContactPairV maACs; - - void Invite(); - - void StartDemoSession(); - - void StartBuddySession(); - - void StartGroupSession(); - -public: - explicit TubeContacts( Collaboration* pCollaboration ); - - virtual ~TubeContacts() override; - - virtual void dispose() override; - - void Populate(); -}; - -} - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/tubes/source/file-transfer-helper.c b/tubes/source/file-transfer-helper.c deleted file mode 100644 index 043d464df820..000000000000 --- a/tubes/source/file-transfer-helper.c +++ /dev/null @@ -1,1853 +0,0 @@ -/* - * empathy-ft-handler.c - Source for EmpathyFTHandler - * Copyright © 2009, 2012 Collabora Ltd. - * Copyright © 2009 Frédéric Péters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> - */ - -/* empathy-ft-handler.c */ - -#include <glib.h> -#include <glib/gi18n.h> -#include <telepathy-glib/account-channel-request.h> -#include <telepathy-glib/util.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> - -#include <file-transfer-helper.h> - -#define DEBUG(...) - -/** - * SECTION:empathy-ft-handler - * @title: EmpathyFTHandler - * @short_description: an object representing a File Transfer - * @include: libempathy/empathy-ft-handler - * - * #EmpathyFTHandler is the object which represents a File Transfer with all - * its properties. - * The creation of an #EmpathyFTHandler is done with - * empathy_ft_handler_new_outgoing() or empathy_ft_handler_new_incoming(), - * even though clients should not need to call them directly, as - * #EmpathyFTFactory does it for them. Remember that for the file transfer - * to work with an incoming handler, - * empathy_ft_handler_incoming_set_destination() should be called after - * empathy_ft_handler_new_incoming(). #EmpathyFTFactory does this - * automatically. - * It's important to note that, as the creation of the handlers is async, once - * an handler is created, it already has all the interesting properties set, - * like filename, total bytes, content type and so on, making it useful - * to be displayed in an UI. - * The transfer API works like a state machine; it has three signals, - * ::transfer-started, ::transfer-progress, ::transfer-done, which will be - * emitted in the relevant phases. - * In addition, if the handler is created with checksumming enabled, - * other three signals (::hashing-started, ::hashing-progress, ::hashing-done) - * will be emitted before or after the transfer, depending on the direction - * (respectively outgoing and incoming) of the handler. - * At any time between the call to empathy_ft_handler_start_transfer() and - * the last signal, a ::transfer-error can be emitted, indicating that an - * error has happened in the operation. The message of the error is localized - * to use in an UI. - */ - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#endif -G_DEFINE_TYPE (EmpathyFTHandler, empathy_ft_handler, G_TYPE_OBJECT) -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#define BUFFER_SIZE 4096 - -enum { - PROP_CHANNEL = 1, - PROP_G_FILE, - PROP_ACCOUNT, - PROP_CONTACT, - PROP_CONTENT_TYPE, - PROP_DESCRIPTION, - PROP_FILENAME, - PROP_MODIFICATION_TIME, - PROP_TOTAL_BYTES, - PROP_TRANSFERRED_BYTES, - PROP_USER_ACTION_TIME -}; - -enum { - HASHING_STARTED, - HASHING_PROGRESS, - HASHING_DONE, - TRANSFER_STARTED, - TRANSFER_PROGRESS, - TRANSFER_DONE, - TRANSFER_ERROR, - LAST_SIGNAL -}; - -typedef struct { - GInputStream *stream; - GError *error /* comment to make the style checker happy */; - guchar *buffer; - GChecksum *checksum; - gssize total_read; - guint64 total_bytes; - EmpathyFTHandler *handler; -} HashingData; - -typedef struct { - EmpathyFTHandlerReadyCallback callback; - gpointer user_data; - EmpathyFTHandler *handler; -} CallbacksData; - -/* private data */ -struct EmpathyFTHandlerPriv_ { - gboolean dispose_run; - - GFile *gfile; - TpFileTransferChannel *channel; - GCancellable *cancellable; - gboolean use_hash; - - /* request for the new transfer */ - GHashTable *request; - - /* transfer properties */ - TpAccount *account; - TpContact *contact; - gchar *content_type; - gchar *filename; - gchar *description; - guint64 total_bytes; - guint64 transferred_bytes; - guint64 mtime; - gchar *content_hash; - TpFileHashType content_hash_type; - gchar *service_name; - - gint64 user_action_time; - - /* time and speed */ - gdouble speed; - guint remaining_time; - gint64 last_update_time; - - gboolean is_completed; -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static gboolean do_hash_job_incoming (GIOSchedulerJob *job, - GCancellable *cancellable, gpointer user_data); - -/* GObject implementations */ -static void -do_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - EmpathyFTHandler *self = EMPATHY_FT_HANDLER (object); - EmpathyFTHandlerPriv *priv = self->priv; - - switch (property_id) - { - case PROP_ACCOUNT: - g_value_set_object (value, priv->account); - break; - case PROP_CONTACT: - g_value_set_object (value, priv->contact); - break; - case PROP_CONTENT_TYPE: - g_value_set_string (value, priv->content_type); - break; - case PROP_DESCRIPTION: - g_value_set_string (value, priv->description); - break; - case PROP_FILENAME: - g_value_set_string (value, priv->filename); - break; - case PROP_MODIFICATION_TIME: - g_value_set_uint64 (value, priv->mtime); - break; - case PROP_TOTAL_BYTES: - g_value_set_uint64 (value, priv->total_bytes); - break; - case PROP_TRANSFERRED_BYTES: - g_value_set_uint64 (value, priv->transferred_bytes); - break; - case PROP_G_FILE: - g_value_set_object (value, priv->gfile); - break; - case PROP_CHANNEL: - g_value_set_object (value, priv->channel); - break; - case PROP_USER_ACTION_TIME: - g_value_set_int64 (value, priv->user_action_time); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -do_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - EmpathyFTHandler *self = EMPATHY_FT_HANDLER (object); - EmpathyFTHandlerPriv *priv = self->priv; - - switch (property_id) - { - case PROP_ACCOUNT: - priv->account = g_value_dup_object (value); - break; - case PROP_CONTACT: - priv->contact = g_value_dup_object (value); - break; - case PROP_CONTENT_TYPE: - priv->content_type = g_value_dup_string (value); - break; - case PROP_DESCRIPTION: - priv->description = g_value_dup_string (value); - break; - case PROP_FILENAME: - priv->filename = g_value_dup_string (value); - break; - case PROP_MODIFICATION_TIME: - priv->mtime = g_value_get_uint64 (value); - break; - case PROP_TOTAL_BYTES: - priv->total_bytes = g_value_get_uint64 (value); - break; - case PROP_TRANSFERRED_BYTES: - priv->transferred_bytes = g_value_get_uint64 (value); - break; - case PROP_G_FILE: - priv->gfile = g_value_dup_object (value); - break; - case PROP_CHANNEL: - priv->channel = g_value_dup_object (value); - break; - case PROP_USER_ACTION_TIME: - priv->user_action_time = g_value_get_int64 (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -do_dispose (GObject *object) -{ - EmpathyFTHandler *self = EMPATHY_FT_HANDLER (object); - EmpathyFTHandlerPriv *priv = self->priv; - - if (priv->dispose_run) - return; - - 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; - } - - if (priv->gfile != NULL) { - g_object_unref (priv->gfile); - priv->gfile = NULL; - } - - if (priv->channel != NULL) { - tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL); - g_object_unref (priv->channel); - priv->channel = NULL; - } - - if (priv->cancellable != NULL) { - g_object_unref (priv->cancellable); - priv->cancellable = NULL; - } - - if (priv->request != NULL) - { - g_hash_table_unref (priv->request); - priv->request = NULL; - } - - G_OBJECT_CLASS (empathy_ft_handler_parent_class)->dispose (object); -} - -static void -do_finalize (GObject *object) -{ - EmpathyFTHandler *self = EMPATHY_FT_HANDLER (object); - EmpathyFTHandlerPriv *priv = self->priv; - - DEBUG ("%p", object); - - g_free (priv->content_type); - priv->content_type = NULL; - - g_free (priv->filename); - priv->filename = NULL; - - g_free (priv->description); - priv->description = NULL; - - 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); -} - -static void -empathy_ft_handler_class_init (EmpathyFTHandlerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - g_type_class_add_private (klass, sizeof (EmpathyFTHandlerPriv)); - - object_class->get_property = do_get_property; - object_class->set_property = do_set_property; - object_class->dispose = do_dispose; - object_class->finalize = do_finalize; - - /* properties */ - - /** - * EmpathyFTHandler:account: - * - * The local #TpAccount for the file transfer - */ - param_spec = g_param_spec_object ("account", - "account", "The remote account", - TP_TYPE_ACCOUNT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec); - - /** - * EmpathyFTHandler:contact: - * - * The remote #TpContact for the transfer - */ - param_spec = g_param_spec_object ("contact", - "contact", "The remote contact", - TP_TYPE_CONTACT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_CONTACT, param_spec); - - /** - * EmpathyFTHandler:content-type: - * - * The content type of the file being transferred - */ - param_spec = g_param_spec_string ("content-type", - "content-type", "The content type of the file", NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_CONTENT_TYPE, param_spec); - - /** - * EmpathyFTHandler:description: - * - * The description of the file being transferred - */ - param_spec = g_param_spec_string ("description", - "description", "The description of the file", NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_DESCRIPTION, param_spec); - - /** - * EmpathyFTHandler:filename: - * - * The name of the file being transferred - */ - param_spec = g_param_spec_string ("filename", - "filename", "The name of the file", NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_FILENAME, param_spec); - - /** - * EmpathyFTHandler:modification-time: - * - * The modification time of the file being transferred - */ - param_spec = g_param_spec_uint64 ("modification-time", - "modification-time", "The mtime of the file", 0, - G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_MODIFICATION_TIME, param_spec); - - /** - * EmpathyFTHandler:total-bytes: - * - * The size (in bytes) of the file being transferred - */ - param_spec = g_param_spec_uint64 ("total-bytes", - "total-bytes", "The size of the file", 0, - G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_TOTAL_BYTES, param_spec); - - /** - * EmpathyFTHandler:transferred-bytes: - * - * The number of the bytes already transferred - */ - param_spec = g_param_spec_uint64 ("transferred-bytes", - "transferred-bytes", "The number of bytes already transferred", 0, - G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_TRANSFERRED_BYTES, param_spec); - - /** - * EmpathyFTHandler:gfile: - * - * The #GFile object where the transfer actually happens - */ - param_spec = g_param_spec_object ("gfile", - "gfile", "The GFile we're handling", - G_TYPE_FILE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_G_FILE, param_spec); - - /** - * EmpathyFTHandler:channel: - * - * The underlying #TpFileTransferChannel managing the transfer - */ - param_spec = g_param_spec_object ("channel", - "channel", "The file transfer channel", - TP_TYPE_FILE_TRANSFER_CHANNEL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_CHANNEL, param_spec); - - param_spec = g_param_spec_int64 ("user-action-time", "user action time", - "User action time", - 0, G_MAXINT64, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_USER_ACTION_TIME, - param_spec); - - /* signals */ - - /** - * EmpathyFTHandler::transfer-started - * @handler: the object which has received the signal - * @channel: the #TpFileTransferChannel for which the transfer has started - * - * This signal is emitted when the actual transfer starts. - */ - signals[TRANSFER_STARTED] = - g_signal_new ("transfer-started", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 1, TP_TYPE_FILE_TRANSFER_CHANNEL); - - /** - * EmpathyFTHandler::transfer-done - * @handler: the object which has received the signal - * @channel: the #TpFileTransferChannel for which the transfer has started - * - * This signal will be emitted when the actual transfer is completed - * successfully. - */ - signals[TRANSFER_DONE] = - g_signal_new ("transfer-done", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 1, TP_TYPE_FILE_TRANSFER_CHANNEL); - - /** - * EmpathyFTHandler::transfer-error - * @handler: the object which has received the signal - * @error: a #GError - * - * This signal can be emitted anytime between the call to - * empathy_ft_handler_start_transfer() and the last expected signal - * (::transfer-done or ::hashing-done), and it's guaranteed to be the last - * signal coming from the handler, meaning that no other operation will - * take place after this signal. - */ - signals[TRANSFER_ERROR] = - g_signal_new ("transfer-error", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 1, G_TYPE_POINTER); - - /** - * EmpathyFTHandler::transfer-progress - * @handler: the object which has received the signal - * @current_bytes: the bytes currently transferred - * @total_bytes: the total bytes of the handler - * @remaining_time: the number of seconds remaining for the transfer - * to be completed - * @speed: the current speed of the transfer (in KB/s) - * - * This signal is emitted to notify clients of the progress of the - * transfer. - */ - signals[TRANSFER_PROGRESS] = - g_signal_new ("transfer-progress", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 4, G_TYPE_UINT64, G_TYPE_UINT64, G_TYPE_UINT, G_TYPE_DOUBLE); - - /** - * EmpathyFTHandler::hashing-started - * @handler: the object which has received the signal - * - * This signal is emitted when the hashing operation of the handler - * is started. Note that this might happen or not, depending on the CM - * and remote contact capabilities. Clients should use - * empathy_ft_handler_get_use_hash() before calling - * empathy_ft_handler_start_transfer() to know whether they should connect - * to this signal. - */ - signals[HASHING_STARTED] = - g_signal_new ("hashing-started", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 0); - - /** - * EmpathyFTHandler::hashing-progress - * @handler: the object which has received the signal - * @current_bytes: the bytes currently hashed - * @total_bytes: the total bytes of the handler - * - * This signal is emitted to notify clients of the progress of the - * hashing operation. - */ - signals[HASHING_PROGRESS] = - g_signal_new ("hashing-progress", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 2, G_TYPE_UINT64, G_TYPE_UINT64); - - /** - * EmpathyFTHandler::hashing-done - * @handler: the object which has received the signal - * - * This signal is emitted when the hashing operation of the handler - * is completed. - */ - signals[HASHING_DONE] = - g_signal_new ("hashing-done", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 0); -} - -static void -empathy_ft_handler_init (EmpathyFTHandler *self) -{ - EmpathyFTHandlerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - EMPATHY_TYPE_FT_HANDLER, EmpathyFTHandlerPriv); - - self->priv = priv; - priv->cancellable = g_cancellable_new (); -} - -/* private functions */ - -static void -hash_data_free (HashingData *data) -{ - g_free (data->buffer); - - if (data->stream != NULL) - g_object_unref (data->stream); - - if (data->checksum != NULL) - g_checksum_free (data->checksum); - - if (data->error != NULL) - g_error_free (data->error); - - if (data->handler != NULL) - g_object_unref (data->handler); - - g_slice_free (HashingData, data); -} - -static GChecksumType -tp_file_hash_to_g_checksum (TpFileHashType type) -{ - GChecksumType retval; - - switch (type) - { - case TP_FILE_HASH_TYPE_MD5: - retval = G_CHECKSUM_MD5; - break; - case TP_FILE_HASH_TYPE_SHA1: - retval = G_CHECKSUM_SHA1; - break; - case TP_FILE_HASH_TYPE_SHA256: - retval = G_CHECKSUM_SHA256; - break; - case TP_FILE_HASH_TYPE_NONE: - default: - g_assert_not_reached (); - break; - } - - return retval; -} - -static void -check_hash_incoming (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv = handler->priv; - - if (!tp_str_empty (priv->content_hash)) - { - HashingData *hash_data; - hash_data = g_slice_new0 (HashingData); - hash_data->total_bytes = priv->total_bytes; - hash_data->handler = g_object_ref (handler); - hash_data->checksum = g_checksum_new - (tp_file_hash_to_g_checksum (priv->content_hash_type)); - - g_signal_emit (handler, signals[HASHING_STARTED], 0); - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - g_io_scheduler_push_job (do_hash_job_incoming, hash_data, NULL, - G_PRIORITY_DEFAULT, priv->cancellable); - #pragma GCC diagnostic pop - } -} - -static void -emit_error_signal (EmpathyFTHandler *handler, - const GError *error) -{ - EmpathyFTHandlerPriv *priv = handler->priv; - - DEBUG ("Error in transfer: %s\n", error->message); - - if (!g_cancellable_is_cancelled (priv->cancellable)) - g_cancellable_cancel (priv->cancellable); - - g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error); -} - -static gint64 -time_get_current (void) -{ - GDateTime *now; - gint64 result; - - now = g_date_time_new_now_utc (); - result = g_date_time_to_unix (now); - g_date_time_unref (now); - - return result; -} - -static void -update_remaining_time_and_speed (EmpathyFTHandler *handler, - guint64 transferred_bytes) -{ - EmpathyFTHandlerPriv *priv = handler->priv; - gint64 elapsed_time, current_time; - guint64 transferred, last_transferred_bytes; - gdouble speed; - gint remaining_time; - - last_transferred_bytes = priv->transferred_bytes; - priv->transferred_bytes = transferred_bytes; - - current_time = time_get_current (); - elapsed_time = current_time - priv->last_update_time; - - if (elapsed_time >= 1) - { - transferred = transferred_bytes - last_transferred_bytes; - speed = (gdouble) transferred / (gdouble) elapsed_time; - remaining_time = (priv->total_bytes - priv->transferred_bytes) / speed; - priv->speed = speed; - priv->remaining_time = remaining_time; - priv->last_update_time = current_time; - } -} - -static void -ft_transfer_transferred_bytes_cb (TpFileTransferChannel *channel, - GParamSpec *pspec, - EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv = handler->priv; - guint64 bytes; - - (void)pspec; /* suppress unused-parameter warning */ - - if (empathy_ft_handler_is_cancelled (handler)) - return; - - bytes = tp_file_transfer_channel_get_transferred_bytes (channel); - - if (priv->transferred_bytes == 0) - { - priv->last_update_time = time_get_current (); - g_signal_emit (handler, signals[TRANSFER_STARTED], 0, channel); - } - - if (priv->transferred_bytes != bytes) - { - update_remaining_time_and_speed (handler, bytes); - - g_signal_emit (handler, signals[TRANSFER_PROGRESS], 0, - bytes, priv->total_bytes, priv->remaining_time, - priv->speed); - } -} - -static void -ft_transfer_provide_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - TpFileTransferChannel *channel = TP_FILE_TRANSFER_CHANNEL (source); - EmpathyFTHandler *handler = user_data; - GError *error = NULL; - - if (!tp_file_transfer_channel_provide_file_finish (channel, result, &error)) - { - emit_error_signal (handler, error); - g_clear_error (&error); - } -} - -static void -ft_transfer_accept_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - TpFileTransferChannel *channel = TP_FILE_TRANSFER_CHANNEL (source); - EmpathyFTHandler *handler = user_data; - GError *error = NULL; - - if (!tp_file_transfer_channel_accept_file_finish (channel, result, &error)) - { - emit_error_signal (handler, error); - g_clear_error (&error); - } -} - -static GError * -error_from_state_change_reason (TpFileTransferStateChangeReason reason) -{ - const char *string; - GError *retval = NULL; - - string = NULL; - - switch (reason) - { - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE: - string = _("No reason was specified"); - break; - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_REQUESTED: - string = _("The change in state was requested"); - break; - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_STOPPED: - string = _("You canceled the file transfer"); - break; - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_REMOTE_STOPPED: - string = _("The other participant canceled the file transfer"); - break; - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_ERROR: - string = _("Error while trying to transfer the file"); - break; - case TP_FILE_TRANSFER_STATE_CHANGE_REASON_REMOTE_ERROR: - string = _("The other participant is unable to transfer the file"); - break; - default: - string = _("Unknown reason"); - break; - } - - retval = g_error_new_literal (EMPATHY_FT_ERROR_QUARK, - EMPATHY_FT_ERROR_TP_ERROR, string); - - return retval; -} - -static void -ft_transfer_state_cb (TpFileTransferChannel *channel, - GParamSpec *pspec, - EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv = handler->priv; - TpFileTransferStateChangeReason reason; - TpFileTransferState state = tp_file_transfer_channel_get_state ( - channel, &reason); - - (void)pspec; /* suppress unused-parameter warning */ - - if (state == TP_FILE_TRANSFER_STATE_COMPLETED) - { - priv->is_completed = TRUE; - g_signal_emit (handler, signals[TRANSFER_DONE], 0, channel); - - tp_channel_close_async (TP_CHANNEL (channel), NULL, NULL); - - if (empathy_ft_handler_is_incoming (handler) && priv->use_hash) - { - check_hash_incoming (handler); - } - } - else if (state == TP_FILE_TRANSFER_STATE_CANCELLED) - { - GError *error = error_from_state_change_reason (reason); - emit_error_signal (handler, error); - g_clear_error (&error); - } -} - -static void -ft_handler_create_channel_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - EmpathyFTHandler *handler = user_data; - EmpathyFTHandlerPriv *priv = handler->priv; - GError *error = NULL; - TpChannel *channel; - - DEBUG ("Dispatcher create channel CB"); - - channel = tp_account_channel_request_create_and_handle_channel_finish ( - TP_ACCOUNT_CHANNEL_REQUEST (source), result, NULL, &error); - - if (channel == NULL) - DEBUG ("Failed to request FT channel: %s", error->message); - else - g_cancellable_set_error_if_cancelled (priv->cancellable, &error); - - if (error != NULL) - { - emit_error_signal (handler, error); - - g_clear_object (&channel); - g_error_free (error); - return; - } - - priv->channel = TP_FILE_TRANSFER_CHANNEL (channel); - - tp_g_signal_connect_object (priv->channel, "notify::state", - G_CALLBACK (ft_transfer_state_cb), handler, 0); - tp_g_signal_connect_object (priv->channel, "notify::transferred-bytes", - G_CALLBACK (ft_transfer_transferred_bytes_cb), handler, 0); - - tp_file_transfer_channel_provide_file_async (priv->channel, priv->gfile, - ft_transfer_provide_cb, handler); -} - -static void -ft_handler_push_to_dispatcher (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv = handler->priv; - TpAccountChannelRequest *req; - - DEBUG ("Pushing request to the dispatcher"); - - req = tp_account_channel_request_new (priv->account, priv->request, - priv->user_action_time); - - tp_account_channel_request_create_and_handle_channel_async (req, NULL, - ft_handler_create_channel_cb, handler); - - g_object_unref (req); -} - -static void -ft_handler_populate_outgoing_request (EmpathyFTHandler *handler) -{ - guint contact_handle; - EmpathyFTHandlerPriv *priv = handler->priv; - gchar *uri; - - contact_handle = tp_contact_get_handle (priv->contact); - uri = g_file_get_uri (priv->gfile); - - priv->request = 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_TARGET_HANDLE, G_TYPE_UINT, - contact_handle, - TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_CONTENT_TYPE, G_TYPE_STRING, - priv->content_type, - TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_FILENAME, G_TYPE_STRING, - priv->filename, - TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_SIZE, G_TYPE_UINT64, - priv->total_bytes, - TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_DATE, G_TYPE_UINT64, - priv->mtime, - 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); - - if (priv->description != NULL) - tp_asv_set_string (priv->request, TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_DESCRIPTION, priv->description); - - g_free (uri); -} - -static gboolean -hash_job_done (gpointer user_data) -{ - HashingData *hash_data = user_data; - EmpathyFTHandler *handler = hash_data->handler; - EmpathyFTHandlerPriv *priv; - GError *error = NULL; - - DEBUG ("Closing stream after hashing."); - - priv = handler->priv; - - if (hash_data->error != NULL) - { - error = hash_data->error; - hash_data->error = NULL; - goto cleanup; - } - - DEBUG ("Got file hash %s", g_checksum_get_string (hash_data->checksum)); - - if (empathy_ft_handler_is_incoming (handler)) - { - if (g_strcmp0 (g_checksum_get_string (hash_data->checksum), - priv->content_hash)) - { - DEBUG ("Hash mismatch when checking incoming handler: " - "received %s, calculated %s", priv->content_hash, - g_checksum_get_string (hash_data->checksum)); - - error = g_error_new_literal (EMPATHY_FT_ERROR_QUARK, - EMPATHY_FT_ERROR_HASH_MISMATCH, - _("File transfer completed, but the file was corrupted")); - goto cleanup; - } - else - { - DEBUG ("Hash verification matched, received %s, calculated %s", - priv->content_hash, - g_checksum_get_string (hash_data->checksum)); - } - } - else - { - /* set the checksum in the request... - * org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHash - */ - tp_asv_set_string (priv->request, - TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_CONTENT_HASH, - g_checksum_get_string (hash_data->checksum)); - } - -cleanup: - - if (error != NULL) - { - emit_error_signal (handler, error); - g_clear_error (&error); - } - else - { - g_signal_emit (handler, signals[HASHING_DONE], 0); - - if (!empathy_ft_handler_is_incoming (handler)) - /* the request is complete now, push it to the dispatcher */ - ft_handler_push_to_dispatcher (handler); - } - - hash_data_free (hash_data); - - return FALSE; -} - -static gboolean -emit_hashing_progress (gpointer user_data) -{ - HashingData *hash_data = user_data; - - g_signal_emit (hash_data->handler, signals[HASHING_PROGRESS], 0, - (guint64) hash_data->total_read, (guint64) hash_data->total_bytes); - - return FALSE; -} - -static gboolean -do_hash_job (GIOSchedulerJob *job, - GCancellable *cancellable, - gpointer user_data) -{ - HashingData *hash_data = user_data; - gssize bytes_read; - GError *error = NULL; - -again: - if (hash_data->buffer == NULL) - hash_data->buffer = g_malloc0 (BUFFER_SIZE); - - bytes_read = g_input_stream_read (hash_data->stream, hash_data->buffer, - BUFFER_SIZE, cancellable, &error); - if (error != NULL) - goto out; - - hash_data->total_read += bytes_read; - - /* we now have the chunk */ - if (bytes_read > 0) - { - g_checksum_update (hash_data->checksum, hash_data->buffer, bytes_read); - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - g_io_scheduler_job_send_to_mainloop_async (job, emit_hashing_progress, - hash_data, NULL); - #pragma GCC diagnostic pop - g_free (hash_data->buffer); - hash_data->buffer = NULL; - - goto again; - } - else - { - g_input_stream_close (hash_data->stream, cancellable, &error); - } - -out: - if (error != NULL) - hash_data->error = error; - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - g_io_scheduler_job_send_to_mainloop_async (job, hash_job_done, - hash_data, NULL); - #pragma GCC diagnostic pop - - return FALSE; -} - -static gboolean -do_hash_job_incoming (GIOSchedulerJob *job, - GCancellable *cancellable, - gpointer user_data) -{ - HashingData *hash_data = user_data; - EmpathyFTHandler *handler = hash_data->handler; - EmpathyFTHandlerPriv *priv = handler->priv; - GError *error = NULL; - - DEBUG ("checking integrity for incoming handler"); - - /* need to get the stream first */ - hash_data->stream = - G_INPUT_STREAM (g_file_read (priv->gfile, cancellable, &error)); - - if (error != NULL) - { - hash_data->error = error; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - g_io_scheduler_job_send_to_mainloop_async (job, hash_job_done, - hash_data, NULL); - #pragma GCC diagnostic pop - return FALSE; - } - - return do_hash_job (job, cancellable, user_data); -} - -static void -ft_handler_read_async_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) -{ - GFileInputStream *stream; - GError *error = NULL; - HashingData *hash_data; - EmpathyFTHandler *handler = user_data; - EmpathyFTHandlerPriv *priv = handler->priv; - - (void)source; /* suppress unused-parameter warning */ - - DEBUG ("GFile read async CB."); - - stream = g_file_read_finish (priv->gfile, res, &error); - if (error != NULL) - { - emit_error_signal (handler, error); - g_clear_error (&error); - - return; - } - - hash_data = g_slice_new0 (HashingData); - hash_data->stream = G_INPUT_STREAM (stream); - hash_data->total_bytes = priv->total_bytes; - hash_data->handler = g_object_ref (handler); - /* FIXME: MD5 is the only ContentHashType supported right now */ - hash_data->checksum = g_checksum_new (G_CHECKSUM_MD5); - - tp_asv_set_uint32 (priv->request, - TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_CONTENT_HASH_TYPE, - TP_FILE_HASH_TYPE_MD5); - - g_signal_emit (handler, signals[HASHING_STARTED], 0); - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - g_io_scheduler_push_job (do_hash_job, hash_data, NULL, - G_PRIORITY_DEFAULT, priv->cancellable); - #pragma GCC diagnostic pop -} - -static void -callbacks_data_free (gpointer user_data) -{ - CallbacksData *data = user_data; - - if (data->handler != NULL) - g_object_unref (data->handler); - - g_slice_free (CallbacksData, data); -} - -static gint -cmp_uint ( - gconstpointer a, - gconstpointer b) -{ - return *(guint *) a - *(guint *) b; -} - -static gboolean -set_content_hash_type_from_classes (EmpathyFTHandler *handler, - GPtrArray *classes) -{ - GArray *possible_values; - guint value; - gboolean valid; - EmpathyFTHandlerPriv *priv = handler->priv; - gboolean support_ft = FALSE; - guint i; - - possible_values = g_array_new (TRUE, TRUE, sizeof (guint)); - - for (i = 0; i < classes->len; i++) - { - GHashTable *fixed; - GStrv allowed; - const gchar *chan_type; - - tp_value_array_unpack (g_ptr_array_index (classes, i), 2, - &fixed, &allowed); - - chan_type = tp_asv_get_string (fixed, TP_PROP_CHANNEL_CHANNEL_TYPE); - - if (tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) - continue; - - if (tp_asv_get_uint32 (fixed, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != - TP_HANDLE_TYPE_CONTACT) - continue; - - support_ft = TRUE; - - value = tp_asv_get_uint32 - (fixed, TP_PROP_CHANNEL_TYPE_FILE_TRANSFER_CONTENT_HASH_TYPE, - &valid); - - if (valid) - g_array_append_val (possible_values, value); - } - - if (!support_ft) - { - g_array_unref (possible_values); - return FALSE; - } - - if (possible_values->len == 0) - { - /* there are no channel classes with hash support, disable it. */ - priv->use_hash = FALSE; - priv->content_hash_type = TP_FILE_HASH_TYPE_NONE; - - goto out; - } - - priv->use_hash = TRUE; - - if (possible_values->len == 1) - { - priv->content_hash_type = g_array_index (possible_values, guint, 0); - } - else - { - /* order the array and pick the first non zero, so that MD5 - * is the preferred value. - */ - g_array_sort (possible_values, cmp_uint); - - if (g_array_index (possible_values, guint, 0) == 0) - priv->content_hash_type = g_array_index (possible_values, guint, 1); - else - priv->content_hash_type = g_array_index (possible_values, guint, 0); - } - -out: - g_array_unref (possible_values); - - DEBUG ("Hash enabled %s; setting content hash type as %u", - priv->use_hash ? "True" : "False", priv->content_hash_type); - - return TRUE; -} - -static void -check_hashing (CallbacksData *data) -{ - EmpathyFTHandler *handler = data->handler; - EmpathyFTHandlerPriv *priv = handler->priv; - GError *myerr = NULL; - TpCapabilities *caps; - GPtrArray *classes; - TpConnection *conn; - - conn = tp_account_get_connection (priv->account); - - caps = tp_connection_get_capabilities (conn); - if (caps == NULL) - { - data->callback (handler, NULL, data->user_data); - goto out; - } - - classes = tp_capabilities_get_channel_classes (caps); - - /* set whether we support hash and the type of it */ - if (!set_content_hash_type_from_classes (handler, classes)) - { - g_set_error_literal (&myerr, EMPATHY_FT_ERROR_QUARK, - EMPATHY_FT_ERROR_NOT_SUPPORTED, - _("File transfer not supported by remote contact")); - - if (!g_cancellable_is_cancelled (priv->cancellable)) - g_cancellable_cancel (priv->cancellable); - - data->callback (handler, myerr, data->user_data); - g_clear_error (&myerr); - } - else - { - /* get back to the caller now */ - data->callback (handler, NULL, data->user_data); - } - -out: - callbacks_data_free (data); -} - -static void -ft_handler_complete_request (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv = handler->priv; - - /* populate the request table with all the known properties */ - ft_handler_populate_outgoing_request (handler); - - if (priv->use_hash) - /* start hashing the file */ - g_file_read_async (priv->gfile, G_PRIORITY_DEFAULT, - priv->cancellable, ft_handler_read_async_cb, handler); - else - /* push directly the handler to the dispatcher */ - ft_handler_push_to_dispatcher (handler); -} - -static void -ft_handler_gfile_ready_cb (GObject *source, - GAsyncResult *res, - CallbacksData *cb_data) -{ - GFileInfo *info; - GError *error = NULL; - GTimeVal mtime; - EmpathyFTHandlerPriv *priv = cb_data->handler->priv; - - (void)source; /* suppress unused-parameter warning */ - - DEBUG ("Got GFileInfo."); - - info = g_file_query_info_finish (priv->gfile, res, &error); - - if (error != NULL) - goto out; - - if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR) - { - error = g_error_new_literal (EMPATHY_FT_ERROR_QUARK, - EMPATHY_FT_ERROR_INVALID_SOURCE_FILE, - _("The selected file is not a regular file")); - goto out; - } - - priv->total_bytes = g_file_info_get_size (info); - if (priv->total_bytes == 0) - { - error = g_error_new_literal (EMPATHY_FT_ERROR_QUARK, - EMPATHY_FT_ERROR_EMPTY_SOURCE_FILE, - _("The selected file is empty")); - goto out; - } - - priv->content_type = g_strdup (g_file_info_get_content_type (info)); - priv->filename = g_strdup (g_file_info_get_display_name (info)); - g_file_info_get_modification_time (info, &mtime); - priv->mtime = mtime.tv_sec; - priv->transferred_bytes = 0; - priv->description = NULL; - - g_object_unref (info); - -out: - if (error != NULL) - { - if (!g_cancellable_is_cancelled (priv->cancellable)) - g_cancellable_cancel (priv->cancellable); - - cb_data->callback (cb_data->handler, error, cb_data->user_data); - g_error_free (error); - - callbacks_data_free (cb_data); - } - else - { - /* see if FT/hashing are allowed */ - check_hashing (cb_data); - } -} - -static void -channel_prepared_cb ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - TpFileTransferChannel *channel = TP_FILE_TRANSFER_CHANNEL (source); - CallbacksData *cb_data = user_data; - EmpathyFTHandler *handler = cb_data->handler; - EmpathyFTHandlerPriv *priv = handler->priv; - GHashTable *properties; - GError *error = NULL; - - if (!tp_proxy_prepare_finish (channel, result, &error)) - { - if (!g_cancellable_is_cancelled (priv->cancellable)) - g_cancellable_cancel (priv->cancellable); - - cb_data->callback (handler, error, cb_data->user_data); - g_clear_error (&error); - callbacks_data_free (cb_data); - return; - } - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - properties = tp_channel_borrow_immutable_properties (TP_CHANNEL (channel)); - #pragma GCC diagnostic pop - - priv->content_hash = g_strdup ( - tp_asv_get_string (properties, "ContentHash")); - - priv->content_hash_type = tp_asv_get_uint32 ( - properties, "ContentHashType", NULL); - - priv->contact = g_object_ref (tp_channel_get_target_contact (TP_CHANNEL (channel))); - - cb_data->callback (handler, NULL, cb_data->user_data); -} - - -/* public methods */ - -/** - * empathy_ft_handler_new_outgoing: - * @account: the #TpAccount to send @source to - * @contact: the #TpContact to send @source to - * @source: the #GFile to send - * @callback: callback to be called when the handler has been created - * @user_data: user data to be passed to @callback - * - * Triggers the creation of a new #EmpathyFTHandler for an outgoing transfer. - */ -void -empathy_ft_handler_new_outgoing ( - TpAccount *account, - TpContact *contact, - GFile *source, - gint64 action_time, - EmpathyFTHandlerReadyCallback callback, - gpointer user_data) -{ - EmpathyFTHandler *handler; - CallbacksData *data; - EmpathyFTHandlerPriv *priv; - - DEBUG ("New handler outgoing"); - - g_return_if_fail (TP_IS_ACCOUNT (account)); - g_return_if_fail (TP_IS_CONTACT (contact)); - g_return_if_fail (G_IS_FILE (source)); - - handler = g_object_new (EMPATHY_TYPE_FT_HANDLER, - "account", account, - "contact", contact, - "gfile", source, - "user-action-time", action_time, - NULL); - - priv = handler->priv; - - data = g_slice_new0 (CallbacksData); - data->callback = callback; - data->user_data = user_data; - data->handler = g_object_ref (handler); - - /* start collecting info about the file */ - g_file_query_info_async (priv->gfile, - G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," - G_FILE_ATTRIBUTE_STANDARD_SIZE "," - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," - G_FILE_ATTRIBUTE_STANDARD_TYPE "," - G_FILE_ATTRIBUTE_TIME_MODIFIED, - G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, - 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); -} - -void -empathy_ft_handler_set_description ( - EmpathyFTHandler *self, - const gchar *description) -{ - g_free (self->priv->description); - self->priv->description = g_strdup (description); -} - -/** - * empathy_ft_handler_new_incoming: - * @channel: the #TpFileTransferChannel proxy to the incoming channel - * @callback: callback to be called when the handler has been created - * @user_data: user data to be passed to @callback - * - * Triggers the creation of a new #EmpathyFTHandler for an incoming transfer. - * Note that for the handler to be useful, you will have to set a destination - * file with empathy_ft_handler_incoming_set_destination() after the handler - * is ready. - */ -void -empathy_ft_handler_new_incoming (TpFileTransferChannel *channel, - EmpathyFTHandlerReadyCallback callback, - gpointer user_data) -{ - EmpathyFTHandler *handler; - CallbacksData *data; - EmpathyFTHandlerPriv *priv; - GQuark features[] = { TP_CHANNEL_FEATURE_CONTACTS, 0 }; - - g_return_if_fail (TP_IS_FILE_TRANSFER_CHANNEL (channel)); - - handler = g_object_new (EMPATHY_TYPE_FT_HANDLER, - "channel", channel, NULL); - - priv = handler->priv; - - data = g_slice_new0 (CallbacksData); - data->callback = callback; - data->user_data = user_data; - data->handler = g_object_ref (handler); - - priv->total_bytes = tp_file_transfer_channel_get_size (channel); - - priv->transferred_bytes = tp_file_transfer_channel_get_transferred_bytes ( - channel); - - priv->filename = g_strdup (tp_file_transfer_channel_get_filename (channel)); - - priv->content_type = g_strdup (tp_file_transfer_channel_get_mime_type ( - channel)); - - priv->description = g_strdup (tp_file_transfer_channel_get_description ( - channel)); - - tp_proxy_prepare_async (channel, features, - channel_prepared_cb, data); -} - -/** - * empathy_ft_handler_start_transfer: - * @handler: an #EmpathyFTHandler - * - * Starts the transfer machinery. After this call, the transfer and hashing - * signals will be emitted by the handler. - */ -void -empathy_ft_handler_start_transfer (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler)); - - priv = handler->priv; - - if (priv->channel == NULL) - { - ft_handler_complete_request (handler); - } - else - { - /* TODO: add support for resume. */ - tp_file_transfer_channel_accept_file_async (priv->channel, - priv->gfile, 0, ft_transfer_accept_cb, handler); - - tp_g_signal_connect_object (priv->channel, "notify::state", - G_CALLBACK (ft_transfer_state_cb), handler, 0); - tp_g_signal_connect_object (priv->channel, "notify::transferred-bytes", - G_CALLBACK (ft_transfer_transferred_bytes_cb), handler, 0); - } -} - -/** - * empathy_ft_handler_cancel_transfer: - * @handler: an #EmpathyFTHandler - * - * Cancels an ongoing handler operation. Note that this doesn't destroy - * the object, which will keep all the properties, although it won't be able - * to do any more I/O. - */ -void -empathy_ft_handler_cancel_transfer (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler)); - - priv = handler->priv; - - /* if we don't have a channel, we are hashing, so - * we can just cancel the GCancellable to stop it. - */ - if (priv->channel == NULL) - g_cancellable_cancel (priv->cancellable); - else - tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL); -} - -/** - * empathy_ft_handler_incoming_set_destination: - * @handler: an #EmpathyFTHandler - * @destination: the #GFile where the transfer should be saved - * - * Sets the destination of the incoming handler to be @destination. - * Note that calling this method is mandatory before starting the transfer - * for incoming handlers. - */ -void -empathy_ft_handler_incoming_set_destination (EmpathyFTHandler *handler, - GFile *destination) -{ - EmpathyFTHandlerPriv *priv; - - g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler)); - g_return_if_fail (G_IS_FILE (destination)); - - priv = handler->priv; - - g_object_set (handler, "gfile", destination, NULL); - - /* check if hash is supported. if it isn't, set use_hash to FALSE - * anyway, so that clients won't be expecting us to checksum. - */ - if (tp_str_empty (priv->content_hash) || - priv->content_hash_type == TP_FILE_HASH_TYPE_NONE) - priv->use_hash = FALSE; - else - priv->use_hash = TRUE; -} - -/** - * empathy_ft_handler_get_filename: - * @handler: an #EmpathyFTHandler - * - * Returns the name of the file being transferred. - * - * Return value: the name of the file being transferred - */ -const char * -empathy_ft_handler_get_filename (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL); - - priv = handler->priv; - - return priv->filename; -} - -const char * -empathy_ft_handler_get_description (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL); - - priv = handler->priv; - - return priv->description; -} - -/** - * empathy_ft_handler_get_content_type: - * @handler: an #EmpathyFTHandler - * - * Returns the content type of the file being transferred. - * - * Return value: the content type of the file being transferred - */ -const char * -empathy_ft_handler_get_content_type (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL); - - priv = handler->priv; - - return priv->content_type; -} - -/** - * empathy_ft_handler_get_contact: - * @handler: an #EmpathyFTHandler - * - * Returns the remote #TpContact at the other side of the transfer. - * - * Return value: the remote #TpContact for @handler - */ -TpContact * -empathy_ft_handler_get_contact (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL); - - priv = handler->priv; - - return priv->contact; -} - -/** - * empathy_ft_handler_get_gfile: - * @handler: an #EmpathyFTHandler - * - * Returns the #GFile where the transfer is being read/saved. - * - * Return value: the #GFile where the transfer is being read/saved - */ -GFile * -empathy_ft_handler_get_gfile (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL); - - priv = handler->priv; - - return priv->gfile; -} - -/** - * empathy_ft_handler_get_use_hash: - * @handler: an #EmpathyFTHandler - * - * Returns whether @handler has checksumming enabled. This can depend on - * the CM and the remote contact capabilities. - * - * Return value: %TRUE if the handler has checksumming enabled, - * %FALSE otherwise. - */ -gboolean -empathy_ft_handler_get_use_hash (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE); - - priv = handler->priv; - - return priv->use_hash; -} - -/** - * empathy_ft_handler_is_incoming: - * @handler: an #EmpathyFTHandler - * - * Returns whether @handler is incoming or outgoing. - * - * Return value: %TRUE if the handler is incoming, %FALSE otherwise. - */ -gboolean -empathy_ft_handler_is_incoming (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE); - - priv = handler->priv; - - if (priv->channel == NULL) - return FALSE; - - return !tp_channel_get_requested ((TpChannel *) priv->channel); -} - -/** - * empathy_ft_handler_get_transferred_bytes: - * @handler: an #EmpathyFTHandler - * - * Returns the number of bytes already transferred by the handler. - * - * Return value: the number of bytes already transferred by the handler. - */ -guint64 -empathy_ft_handler_get_transferred_bytes (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), 0); - - priv = handler->priv; - - return priv->transferred_bytes; -} - -/** - * empathy_ft_handler_get_total_bytes: - * @handler: an #EmpathyFTHandler - * - * Returns the total size of the file being transferred by the handler. - * - * Return value: a number of bytes indicating the total size of the file being - * transferred by the handler. - */ -guint64 -empathy_ft_handler_get_total_bytes (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), 0); - - priv = handler->priv; - - return priv->total_bytes; -} - -/** - * empathy_ft_handler_is_completed: - * @handler: an #EmpathyFTHandler - * - * Returns whether the transfer for @handler has been completed successfully. - * - * Return value: %TRUE if the handler has been transferred correctly, %FALSE - * otherwise - */ -gboolean -empathy_ft_handler_is_completed (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE); - - priv = handler->priv; - - return priv->is_completed; -} - -/** - * empathy_ft_handler_is_cancelled: - * @handler: an #EmpathyFTHandler - * - * Returns whether the transfer for @handler has been cancelled or has stopped - * due to an error. - * - * Return value: %TRUE if the transfer for @handler has been cancelled - * or has stopped due to an error, %FALSE otherwise. - */ -gboolean -empathy_ft_handler_is_cancelled (EmpathyFTHandler *handler) -{ - EmpathyFTHandlerPriv *priv; - - g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE); - - priv = handler->priv; - - return g_cancellable_is_cancelled (priv->cancellable); -} diff --git a/tubes/source/file-transfer-helper.h b/tubes/source/file-transfer-helper.h deleted file mode 100644 index ffcbc4b19837..000000000000 --- a/tubes/source/file-transfer-helper.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * empathy-ft-handler.h - Header for EmpathyFTHandler - * Copyright (C) 2009 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> - */ - -/* empathy-ft-handler.h */ - -#ifndef INCLUDED_TUBES_FILE_TRANSFER_HELPER_H -#define INCLUDED_TUBES_FILE_TRANSFER_HELPER_H - -#include <config_lgpl.h> -#include <glib-object.h> -#include <gio/gio.h> - -#include <telepathy-glib/contact.h> -#include <telepathy-glib/file-transfer-channel.h> - -G_BEGIN_DECLS - -#define EMPATHY_TYPE_FT_HANDLER empathy_ft_handler_get_type() -#define EMPATHY_FT_HANDLER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - EMPATHY_TYPE_FT_HANDLER, EmpathyFTHandler)) -#define EMPATHY_IS_FT_HANDLER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_FT_HANDLER)) - -typedef struct EmpathyFTHandlerPriv_ EmpathyFTHandlerPriv; - -typedef struct { - GObject parent; - EmpathyFTHandlerPriv *priv; -} EmpathyFTHandler; - -typedef struct { - GObjectClass parent_class; -} EmpathyFTHandlerClass; - -#define EMPATHY_FT_ERROR_QUARK g_quark_from_static_string ("EmpathyFTError") - -typedef enum { - EMPATHY_FT_ERROR_FAILED, - EMPATHY_FT_ERROR_HASH_MISMATCH, - EMPATHY_FT_ERROR_TP_ERROR, - EMPATHY_FT_ERROR_SOCKET, - EMPATHY_FT_ERROR_NOT_SUPPORTED, - EMPATHY_FT_ERROR_INVALID_SOURCE_FILE, - EMPATHY_FT_ERROR_EMPTY_SOURCE_FILE -} EmpathyFTErrorEnum; - -/** - * EmpathyFTHandlerReadyCallback: - * @handler: the handler which is now ready - * @error: a #GError if the operation failed, or %NULL - * @user_data: user data passed to the callback - */ -typedef void (* EmpathyFTHandlerReadyCallback) (EmpathyFTHandler *handler, - GError *error, - gpointer user_data); - -GType empathy_ft_handler_get_type (void); - -/* public methods */ -void empathy_ft_handler_new_outgoing ( - TpAccount *account, - TpContact *contact, - GFile *source, - 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_set_description ( - EmpathyFTHandler *self, - const gchar *description); - - -void empathy_ft_handler_new_incoming (TpFileTransferChannel *channel, - EmpathyFTHandlerReadyCallback callback, - gpointer user_data); -void empathy_ft_handler_incoming_set_destination (EmpathyFTHandler *handler, - GFile *destination); - -void empathy_ft_handler_start_transfer (EmpathyFTHandler *handler); -void empathy_ft_handler_cancel_transfer (EmpathyFTHandler *handler); - -/* properties of the transfer */ -const char * empathy_ft_handler_get_filename (EmpathyFTHandler *handler); -const char * empathy_ft_handler_get_content_type (EmpathyFTHandler *handler); -TpContact * empathy_ft_handler_get_contact (EmpathyFTHandler *handler); -GFile * empathy_ft_handler_get_gfile (EmpathyFTHandler *handler); -const char *empathy_ft_handler_get_description(EmpathyFTHandler*); -gboolean empathy_ft_handler_get_use_hash (EmpathyFTHandler *handler); -gboolean empathy_ft_handler_is_incoming (EmpathyFTHandler *handler); -guint64 empathy_ft_handler_get_transferred_bytes (EmpathyFTHandler *handler); -guint64 empathy_ft_handler_get_total_bytes (EmpathyFTHandler *handler); -gboolean empathy_ft_handler_is_completed (EmpathyFTHandler *handler); -gboolean empathy_ft_handler_is_cancelled (EmpathyFTHandler *handler); - -G_END_DECLS - -#endif // INCLUDED_TUBES_FILE_TRANSFER_HELPER_H - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/source/manager.cxx b/tubes/source/manager.cxx deleted file mode 100644 index 08dacfb3ed58..000000000000 --- a/tubes/source/manager.cxx +++ /dev/null @@ -1,905 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <tubes/collaboration.hxx> -#include <tubes/manager.hxx> - -#include <conference.hxx> -#include <constants.h> -#include <file-transfer-helper.h> - -#include <com/sun/star/uno/Sequence.hxx> -#include <com/sun/star/frame/Desktop.hpp> -#include <com/sun/star/frame/XComponentLoader.hpp> -#include <com/sun/star/lang/XMultiServiceFactory.hpp> -#include <com/sun/star/beans/PropertyValue.hpp> -#include <com/sun/star/util/XCloseable.hpp> -#include <comphelper/processfactory.hxx> -#include <osl/mutex.hxx> -#include <rtl/strbuf.hxx> -#include <rtl/uuid.h> -#include <vcl/svapp.hxx> - -#include <telepathy-glib/telepathy-glib.h> -#include <stdio.h> -#include <map> -#include <set> - -#if defined SAL_LOG_INFO -namespace -{ -struct InfoLogger -{ - const void* mpThat; - const char* mpMethod; - explicit InfoLogger( const void* pThat, const char* pMethod ) - : - mpThat( pThat), - mpMethod( pMethod) - { - SAL_INFO( "tubes.method", mpThat << " entering " << mpMethod); - } - ~InfoLogger() - { - SAL_INFO( "tubes.method", mpThat << " leaving " << mpMethod); - } -}; -} -#define INFO_LOGGER_F(s) InfoLogger aLogger(nullptr,(s)) -#else -#define INFO_LOGGER_F(s) -#endif // SAL_LOG_INFO - -using namespace osl; - -/** Refcounted singleton implementation class. */ -class TeleManagerImpl -{ -public: - TpSimpleClientFactory* mpFactory; - TpBaseClient* mpClient; - TpBaseClient* mpFileTransferClient; - TpAccountManager* mpAccountManager; - static bool mbAccountManagerReady; - static bool mbAccountManagerReadyHandlerInvoked; - static bool mbChannelReadyHandlerInvoked; - OString msCurrentUUID; - OString msNameSuffix; - typedef std::map< OString, TeleConference* > MapStringConference; - MapStringConference maAcceptedConferences; - typedef std::set< TeleConference* > DemoConferences; - DemoConferences maDemoConferences; - typedef std::set< Collaboration* > Collaborations; - Collaborations maCollaborations; - typedef std::set< TpContact* > RegisteredContacts; - RegisteredContacts maRegisteredContacts; - - TeleManagerImpl(); - ~TeleManagerImpl(); - static void AccountManagerReadyHandler( GObject* pSourceObject, GAsyncResult* pResult, gpointer pUserData ); - static void ChannelReadyHandler( GObject* pSourceObject, GAsyncResult* pResult, gpointer pUserData ); -}; - -TeleManagerImpl* TeleManager::pImpl = new TeleManagerImpl(); -bool TeleManagerImpl::mbAccountManagerReady; -bool TeleManagerImpl::mbAccountManagerReadyHandlerInvoked; -bool TeleManagerImpl::mbChannelReadyHandlerInvoked; - -static void TeleManager_DBusChannelHandler( - TpSimpleHandler* /*handler*/, - TpAccount* pAccount, - TpConnection* /*connection*/, - GList* pChannels, - GList* /*requests_satisfied*/, - gint64 /*user_action_time*/, - TpHandleChannelsContext* pContext, - gpointer /*pUserData*/ ) -{ - bool aAccepted = false; - INFO_LOGGER_F( "TeleManager_DBusChannelHandler"); - - for (GList* p = pChannels; p; p = p->next) - { - TpChannel* pChannel = TP_CHANNEL(p->data); - if (!pChannel) - continue; - - SAL_INFO( "tubes", "TeleManager_DBusChannelHandler: incoming dbus channel: " - << tp_channel_get_identifier( pChannel)); - - if (TP_IS_DBUS_TUBE_CHANNEL( pChannel)) - { - SAL_INFO( "tubes", "accepting"); - aAccepted = true; - - TeleConference* pConference = new TeleConference( pAccount, TP_DBUS_TUBE_CHANNEL( pChannel ) ); - pConference->acceptTube(); - TeleManager::addConference( pConference ); - } - else - { - SAL_INFO( "tubes", "ignored"); - } - } - - if (aAccepted) - tp_handle_channels_context_accept( pContext); - else - { - SAL_WNODEPRECATED_DECLARATIONS_PUSH - // 'tp_errors_quark' [expanded from macro 'TP_ERRORS'] is deprecated - GError *pError = g_error_new_literal( TP_ERRORS, TP_ERROR_CONFUSED, - "None of these channels were LibreOffice D-Bus tubes; " - "why did the Channel Dispatcher give them to us?"); - SAL_WNODEPRECATED_DECLARATIONS_PUSH - tp_handle_channels_context_fail( pContext, pError); - g_clear_error (&pError); - } -} - - -void TeleManager::addConference( TeleConference* pConference ) -{ - MutexGuard aGuard( GetMutex()); - - SAL_WARN_IF( pConference->getUuid().isEmpty(), "tubes", - "Adding conference with empty UUID should not happen!" ); - pImpl->maAcceptedConferences[ pConference->getUuid() ] = pConference; -} - -TeleConference* TeleManager::getConference() -{ - MutexGuard aGuard( GetMutex()); - - TeleManagerImpl::MapStringConference::const_iterator it = - pImpl->maAcceptedConferences.find( pImpl->msCurrentUUID ); - TeleConference* pConference = nullptr; - if (it != pImpl->maAcceptedConferences.end()) - pConference = it->second; - SAL_WARN_IF( !pConference, "tubes", "TeleManager::getConference: " - << pImpl->msCurrentUUID.getStr() << " not found!" ); - (pImpl->msCurrentUUID).clear(); - return pConference; -} - -void TeleManager::registerCollaboration( Collaboration* pCollaboration ) -{ - MutexGuard aGuard( GetMutex()); - - pImpl->maCollaborations.insert( pCollaboration ); -} - -void TeleManager::unregisterCollaboration( Collaboration* pCollaboration ) -{ - MutexGuard aGuard( GetMutex()); - - pImpl->maCollaborations.erase( pCollaboration ); -} - -bool TeleManager::existsCollaboration( Collaboration* pCollaboration ) -{ - MutexGuard aGuard( GetMutex()); - - return pImpl->maCollaborations.find( pCollaboration ) != pImpl->maCollaborations.end(); -} - -void TeleManager::displayAllContacts() -{ - MutexGuard aGuard( GetMutex()); - - for (TeleManagerImpl::Collaborations::iterator it = pImpl->maCollaborations.begin(); - it != pImpl->maCollaborations.end(); ++it) - (*it)->DisplayContacts(); -} - -void TeleManager::registerDemoConference( TeleConference* pConference ) -{ - MutexGuard aGuard( GetMutex()); - - pImpl->maDemoConferences.insert( pConference ); -} - -void TeleManager::unregisterDemoConference( TeleConference* pConference ) -{ - MutexGuard aGuard( GetMutex()); - - pImpl->maDemoConferences.erase( pConference ); -} - -void TeleManager::broadcastPacket( const OString& rPacket ) -{ - MutexGuard aGuard( GetMutex()); - - INFO_LOGGER_F( "TeleManager::broadcastPacket" ); - for (TeleManagerImpl::DemoConferences::iterator it = pImpl->maDemoConferences.begin(); - it != pImpl->maDemoConferences.end(); ++it) - if ((*it)->getCollaboration()) - (*it)->getCollaboration()->PacketReceived( rPacket ); -} - -bool TeleManager::hasWaitingConference() -{ - MutexGuard aGuard( GetMutex()); - - return !pImpl->msCurrentUUID.isEmpty(); -} - -void TeleManager::setCurrentUuid( const OString& rUuid ) -{ - MutexGuard aGuard( GetMutex()); - - pImpl->msCurrentUUID = rUuid; -} - -void TeleManager_fileReceived( const OUString& rStr, const OString& rUuid ) -{ - SAL_INFO( "tubes", "TeleManager_fileReceived: incoming file: " << rStr ); - - OString sUuid( rUuid ); - if (sUuid == "demo") - { - sUuid = TeleManager::createUuid(); - TeleConference* pConference = new TeleConference( nullptr, nullptr, sUuid ); - TeleManager::addConference( pConference ); - TeleManager::registerDemoConference( pConference ); - } - TeleManager::setCurrentUuid( sUuid ); - - try - { - css::uno::Reference < css::frame::XDesktop2 > xLoader = css::frame::Desktop::create( - ::comphelper::getProcessComponentContext() ); - css::uno::Sequence < css::beans::PropertyValue > args(0); - css::uno::Reference < css::util::XCloseable > xDoc( - xLoader->loadComponentFromURL( rStr, "_blank", 0, args ), - css::uno::UNO_QUERY_THROW ); - } - catch ( const css::uno::Exception& e ) - { - // Expected to happen for unit test - SAL_WARN( "tubes", "TeleManager_fileReceived: exception when loading: " << e.Message ); - } -} - -static void TeleManager_TransferDone( EmpathyFTHandler *handler, TpFileTransferChannel *, gpointer ) -{ - SAL_INFO( "tubes", "TeleManager_TransferDone: hooray!"); - GFile *gfile = empathy_ft_handler_get_gfile( handler); - char *uri = g_file_get_uri( gfile); - OUString aUri( OUString::createFromAscii( uri ) ); - g_free( uri); - - TeleManager_fileReceived( aUri, empathy_ft_handler_get_description( handler ) ); - - g_object_unref( handler); -} - -static void TeleManager_TransferError( EmpathyFTHandler *handler, const GError *error, void*) -{ - SAL_INFO( "tubes", "TeleManager_TransferError: " << error->message); - - g_object_unref( handler); -} - -static void lcl_IncomingHandlerReady ( - EmpathyFTHandler* pHandler, - GError* pError, - void* /*pUserData*/ ) -{ - if (pError) - { - SAL_INFO ("tubes", "failed to prepare incoming transfer: " << pError->message); - g_object_unref( pHandler); - return; - } - - /* The filename suggested by the sender, which in our case is the last bit - * of whatever URI got passed to ::sendFile() - */ - const char* pFileName = empathy_ft_handler_get_filename( pHandler); - char* pLocalUri = g_strdup_printf( "file:///tmp/LibreOffice-collab-%s", pFileName); - GFile *pDestination = g_file_new_for_uri( pLocalUri); - g_free( pLocalUri); - - empathy_ft_handler_incoming_set_destination( pHandler, pDestination); - g_object_unref( pDestination); - - g_signal_connect( pHandler, "transfer-done", G_CALLBACK (TeleManager_TransferDone), nullptr); - g_signal_connect( pHandler, "transfer-error", G_CALLBACK (TeleManager_TransferError), nullptr); - SAL_INFO ("tubes", "lcl_IncomingHandlerReady: starting file transfer.."); - 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"); - - 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), - lcl_IncomingHandlerReady, nullptr); - aAccepted = true; - } - else - { - SAL_INFO( "tubes", "ignored"); - } - } - - if (aAccepted) - tp_handle_channels_context_accept( pContext); - else - { - SAL_WNODEPRECATED_DECLARATIONS_PUSH - // 'tp_errors_quark' [expanded from macro 'TP_ERRORS'] is deprecated - 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?"); - SAL_WNODEPRECATED_DECLARATIONS_POP - tp_handle_channels_context_fail( pContext, pError); - g_clear_error (&pError); - } -} - - -void TeleManagerImpl::ChannelReadyHandler( - GObject* pSourceObject, - GAsyncResult* pResult, - gpointer pUserData - ) -{ - INFO_LOGGER_F( "TeleManagerImpl::ChannelReadyHandler"); - - TeleConference* pConference = static_cast<TeleConference*>(pUserData); - SAL_WARN_IF( !pConference, "tubes", "TeleManagerImpl::ChannelReadyHandler: no conference"); - if (!pConference) - return; - - mbChannelReadyHandlerInvoked = true; - - TpAccountChannelRequest* pChannelRequest = TP_ACCOUNT_CHANNEL_REQUEST( pSourceObject); - GError* pError = nullptr; - TpChannel * pChannel = tp_account_channel_request_create_and_handle_channel_finish( - pChannelRequest, pResult, nullptr, &pError); - if (!pChannel) - { - // "account isn't Enabled" means just that.. - /* FIXME: detect and handle, domain=132, code=3 */ - SAL_WARN( "tubes", "TeleManagerImpl::ChannelReadyHandler: no channel: " << pError->message); - g_error_free( pError); - return; - } - pConference->setChannel( tp_account_channel_request_get_account( pChannelRequest), - TP_DBUS_TUBE_CHANNEL (pChannel)); - pConference->offerTube(); -} - -void TeleManagerImpl::AccountManagerReadyHandler( - GObject* pSourceObject, - GAsyncResult* pResult, - gpointer /*pUserData*/ - ) -{ - INFO_LOGGER_F( "TeleManagerImpl::AccountManagerReadyHandler"); - - GError* pError = nullptr; - gboolean bPrepared = tp_proxy_prepare_finish( pSourceObject, pResult, &pError); - SAL_WARN_IF( !bPrepared, "tubes", "TeleManagerImpl::AccountManagerReadyHandler: not prepared"); - if (!bPrepared || pError) - { - SAL_WARN_IF( pError, "tubes", "TeleManagerImpl::AccountManagerReadyHandler: error: " << pError->message); - g_error_free( pError); - } - - mbAccountManagerReady = bPrepared; - mbAccountManagerReadyHandlerInvoked = true; -} - - -bool TeleManager::init( bool bListen ) -{ - if (createAccountManager()) - { - if (bListen && !registerClients()) - SAL_WARN( "tubes", "TeleManager::init: Could not register client handlers." ); - - return true; - } - else - SAL_WARN( "tubes", "TeleManager::init: Could not create AccountManager." ); - - return false; -} - -void TeleManager::finalize() -{ - pImpl.reset(); -} - -bool TeleManager::createAccountManager() -{ - INFO_LOGGER_F( "TeleManager::createAccountManager"); - - MutexGuard aGuard( GetMutex()); - - SAL_INFO_IF( pImpl->mpAccountManager, "tubes", "TeleManager::createAccountManager: already connected"); - if (pImpl->mpAccountManager) - return true; - - GError* pError = nullptr; - TpDBusDaemon *pDBus = tp_dbus_daemon_dup( &pError); - SAL_WARN_IF( !pDBus, "tubes", "TeleManager::createAccountManager: no dbus daemon"); - if (!pDBus || pError) - { - SAL_WARN_IF( pError, "tubes", "TeleManager::createAccountManager: dbus daemon error: " << pError->message); - g_error_free( pError); - return false; - } - - pImpl->mpFactory = TP_SIMPLE_CLIENT_FACTORY( tp_automatic_client_factory_new( pDBus)); - g_object_unref( pDBus); - SAL_WARN_IF( !pImpl->mpFactory, "tubes", "TeleManager::createAccountManager: no client factory"); - if (!pImpl->mpFactory) - return false; - - /* Tell the client factory (which creates and prepares proxy objects) to - * get the features we need ready before giving us any objects. - */ - /* We need every online account's connection object to be available... */ - tp_simple_client_factory_add_account_features_varargs (pImpl->mpFactory, - TP_ACCOUNT_FEATURE_CONNECTION, - 0); - /* ...and we want those connection objects to have the contact list - * available... */ - tp_simple_client_factory_add_connection_features_varargs (pImpl->mpFactory, - TP_CONNECTION_FEATURE_CONTACT_LIST, - 0); - /* ...and those contacts should have their alias and their capabilities - * available. - */ - tp_simple_client_factory_add_contact_features_varargs (pImpl->mpFactory, - TP_CONTACT_FEATURE_ALIAS, - TP_CONTACT_FEATURE_AVATAR_DATA, - TP_CONTACT_FEATURE_CAPABILITIES, - TP_CONTACT_FEATURE_PRESENCE, - TP_CONTACT_FEATURE_INVALID); - - pImpl->mpAccountManager = tp_account_manager_new_with_factory (pImpl->mpFactory); - tp_account_manager_set_default (pImpl->mpAccountManager); - - TeleManagerImpl::mbAccountManagerReadyHandlerInvoked = false; - tp_proxy_prepare_async( pImpl->mpAccountManager, nullptr, TeleManagerImpl::AccountManagerReadyHandler, nullptr); - while (!TeleManagerImpl::mbAccountManagerReadyHandlerInvoked) - { - SolarMutexReleaser rel; - g_main_context_iteration( nullptr, TRUE); - } - - return TeleManagerImpl::mbAccountManagerReady; -} - -bool TeleManager::registerClients() -{ - INFO_LOGGER_F( "TeleManager::registerClients"); - - MutexGuard aGuard( GetMutex()); - - /* TODO: also check whether client could be registered and retry if not? */ - SAL_INFO_IF( pImpl->mpClient && pImpl->mpFileTransferClient, "tubes", "TeleManager::registerClients: already registered"); - if (pImpl->mpClient && pImpl->mpFileTransferClient) - return true; - - pImpl->mpClient = tp_simple_handler_new_with_factory( - pImpl->mpFactory, // factory - FALSE, // bypass_approval - FALSE, // requests - getFullClientName().getStr(), // name - FALSE, // uniquify - TeleManager_DBusChannelHandler, // callback - nullptr, // user_data - nullptr // destroy - ); - SAL_WARN_IF( !pImpl->mpClient, "tubes", "TeleManager::registerClients: no client"); - if (!pImpl->mpClient) - return false; - - // Setup client handler for buddy channels with our service. - tp_base_client_take_handler_filter( pImpl->mpClient, - tp_asv_new( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, getFullServiceName().getStr(), - nullptr)); - - /* TODO: setup filters for LibreOfficeCalc, LibreOfficeWriter, ... */ - - // Setup client handler for MUC channels with our service. - tp_base_client_take_handler_filter( pImpl->mpClient, - tp_asv_new( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_ROOM, - TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, getFullServiceName().getStr(), - nullptr)); - - GError* pError = nullptr; - if (!tp_base_client_register( pImpl->mpClient, &pError)) - { - SAL_WARN( "tubes", "TeleManager::registerClients: error registering client handler: " << pError->message); - g_error_free( pError); - return false; - } - - SAL_INFO( "tubes", "TeleManager::registerClients: bus name: " << tp_base_client_get_bus_name( pImpl->mpClient)); - SAL_INFO( "tubes", "TeleManager::registerClients: 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 ( - pImpl->mpFactory, // 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 - nullptr, // user_data - nullptr // 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(), - nullptr)); - - if (!tp_base_client_register( pImpl->mpFileTransferClient, &pError)) - { - /* This shouldn't fail if registering the main handler succeeded */ - SAL_WARN( "tubes", "TeleManager::registerClients: error registering file transfer handler: " << pError->message); - g_error_free( pError); - return false; - } - - return true; -} - -TeleConference* TeleManager::startDemoSession() -{ - INFO_LOGGER_F( "TeleManager::startDemoSession"); - - TeleConference* pConference = new TeleConference( nullptr, nullptr, "demo" ); - registerDemoConference( pConference ); - - return pConference; -} - -/* TODO: factor out common code with startBuddySession() */ -TeleConference* TeleManager::startGroupSession( TpAccount *pAccount, - const OUString& rUConferenceRoom, - const OUString& rUConferenceServer ) -{ - INFO_LOGGER_F( "TeleManager::startGroupSession"); - - OString aSessionId( TeleManager::createUuid()); - - /* FIXME: does this work at all _creating_ a MUC? */ - // Use conference and server if given, else create conference. - OString aConferenceRoom( OUStringToOString( rUConferenceRoom, RTL_TEXTENCODING_UTF8)); - OString aConferenceServer( OUStringToOString( rUConferenceServer, RTL_TEXTENCODING_UTF8)); - OStringBuffer aBuf(64); - if (!aConferenceRoom.isEmpty() && !aConferenceServer.isEmpty()) - aBuf.append( aConferenceRoom).append( '@').append( aConferenceServer); - else - { - aBuf.append( aSessionId); - if (!aConferenceServer.isEmpty()) - aBuf.append( '@').append( aConferenceServer); - /* FIXME: else? bail out? we have only a session ID without server then */ - } - OString aTarget( aBuf.makeStringAndClear()); - - SAL_INFO( "tubes", "TeleManager::startGroupSession: creating channel request from " - << tp_account_get_path_suffix( pAccount ) << " to " << aTarget.getStr() ); - - // MUC request - GHashTable* pRequest = tp_asv_new( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, TP_TYPE_HANDLE, TP_HANDLE_TYPE_ROOM, - TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, aTarget.getStr(), - TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, getFullServiceName().getStr(), - nullptr); - - TpAccountChannelRequest * pChannelRequest = tp_account_channel_request_new( - pAccount, pRequest, TP_USER_ACTION_TIME_NOT_USER_ACTION); - SAL_WARN_IF( !pChannelRequest, "tubes", "TeleManager::startGroupSession: no channel"); - if (!pChannelRequest) - { - g_hash_table_unref( pRequest); - return nullptr; - } - - TeleManagerImpl::mbChannelReadyHandlerInvoked = false; - - TeleConference* pConference = new TeleConference( nullptr, nullptr, aSessionId ); - - tp_account_channel_request_create_and_handle_channel_async( - pChannelRequest, nullptr, TeleManagerImpl::ChannelReadyHandler, pConference); - - while (!TeleManagerImpl::mbChannelReadyHandlerInvoked) - g_main_context_iteration( nullptr, TRUE ); - - g_object_unref( pChannelRequest); - g_hash_table_unref( pRequest); - - if (!pConference->isReady()) - return nullptr; - - return pConference; -} - -static void lcl_ensureLegacyChannel( TpAccount* pAccount, TpContact* pBuddy ) -{ - /* This is a workaround for a Telepathy bug. - * <https://bugs.libreoffice.org/show_bug.cgi?id=47760>. The first time you - * request a tube to a contact on an account, you actually get two channels - * back: the tube you asked for, along with a legacy Channel.Type.Tubes - * object. This breaks create_and_handle_channel_async(), which expects to - * only get one channel back. - * - * To work around this, we make sure the legacy Tubes channel already - * exists before we request the channel we actually want. We don't actually - * have to wait for this request to succeed - we fire it off and forget - * about it. - */ - GHashTable* pRequest = tp_asv_new( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TUBES, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, TP_TYPE_HANDLE, TP_HANDLE_TYPE_CONTACT, - TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, tp_contact_get_identifier (pBuddy), - nullptr); - TpAccountChannelRequest* pChannelRequest = tp_account_channel_request_new( - pAccount, pRequest, TP_USER_ACTION_TIME_NOT_USER_ACTION); - tp_account_channel_request_ensure_channel_async( pChannelRequest, nullptr, - nullptr, nullptr, nullptr ); - g_object_unref( pChannelRequest ); - g_hash_table_unref( pRequest ); -} - -/* TODO: factor out common code with startGroupSession() */ -TeleConference* TeleManager::startBuddySession( TpAccount *pAccount, TpContact *pBuddy ) -{ - INFO_LOGGER_F( "TeleManager::startBuddySession"); - - lcl_ensureLegacyChannel( pAccount, pBuddy ); - - const char *pIdentifier = tp_contact_get_identifier( pBuddy); - SAL_INFO( "tubes", "TeleManager::startBuddySession: creating channel request from " - << tp_account_get_path_suffix( pAccount) - << " to " << pIdentifier); - - GHashTable* pRequest = tp_asv_new( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, TP_TYPE_HANDLE, TP_HANDLE_TYPE_CONTACT, - TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, pIdentifier, - TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, getFullServiceName().getStr(), - nullptr); - - TpAccountChannelRequest * pChannelRequest = tp_account_channel_request_new( - pAccount, pRequest, TP_USER_ACTION_TIME_NOT_USER_ACTION); - SAL_WARN_IF( !pChannelRequest, "tubes", "TeleManager::startBuddySession: no channel"); - if (!pChannelRequest) - { - g_hash_table_unref( pRequest); - return nullptr; - } - - TeleManagerImpl::mbChannelReadyHandlerInvoked = false; - - TeleConference* pConference = new TeleConference( nullptr, nullptr, createUuid(), true ); - - tp_account_channel_request_create_and_handle_channel_async( - pChannelRequest, nullptr, TeleManagerImpl::ChannelReadyHandler, pConference ); - - while (!TeleManagerImpl::mbChannelReadyHandlerInvoked) - g_main_context_iteration( nullptr, TRUE ); - - g_object_unref( pChannelRequest); - g_hash_table_unref( pRequest); - - if (!pConference->isReady()) - return nullptr; - - return pConference; -} - -static bool tb_presence_is_online( const TpConnectionPresenceType& presence ) -{ - switch (presence) - { - case TP_CONNECTION_PRESENCE_TYPE_UNSET: - case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: - return false; - case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE: - case TP_CONNECTION_PRESENCE_TYPE_AWAY: - case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY: - case TP_CONNECTION_PRESENCE_TYPE_HIDDEN: - case TP_CONNECTION_PRESENCE_TYPE_BUSY: - return true; - case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: - case TP_CONNECTION_PRESENCE_TYPE_ERROR: - default: - return false; - } -} - -static bool tb_contact_is_online( TpContact *contact ) -{ - return tb_presence_is_online (tp_contact_get_presence_type (contact)); -} - -static void presence_changed_cb( TpContact* /* contact */, - guint /* type */, - gchar* /* status */, - gchar* /* message */, - gpointer /* pContactList*/ ) -{ - TeleManager::displayAllContacts(); -} - -AccountContactPairV TeleManager::getContacts() -{ - AccountContactPairV pairs; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - for (GList *accounts = tp_account_manager_get_valid_accounts (pImpl->mpAccountManager); - accounts != nullptr; accounts = g_list_delete_link (accounts, accounts)) - { - TpAccount *account = static_cast<TpAccount *>(accounts->data); - TpConnection *connection = tp_account_get_connection (account); - - /* Verify account is online and received its contact list. If state is not - * SUCCESS this means we didn't received the roster from server yet and - * we would have to wait for the "notify:contact-list-state" signal. */ - if (connection == nullptr || tp_connection_get_contact_list_state (connection) != - TP_CONTACT_LIST_STATE_SUCCESS) - continue; - - TpContact *self = tp_connection_get_self_contact (connection); - GPtrArray *contacts = tp_connection_dup_contact_list (connection); - for (guint i = 0; i < contacts->len; i++) - { - TpContact *contact = static_cast<TpContact *>(g_ptr_array_index (contacts, i)); - if (pImpl->maRegisteredContacts.find (contact) == pImpl->maRegisteredContacts.end()) - { - pImpl->maRegisteredContacts.insert (contact); - g_signal_connect (contact, "presence-changed", - G_CALLBACK (presence_changed_cb), nullptr ); - } - if (contact != self && tb_contact_is_online (contact)) - { - g_object_ref (account); - g_object_ref (contact); - - AccountContactPair pair(account, contact); - pairs.push_back(pair); - } - } - g_ptr_array_unref (contacts); - } - #pragma GCC diagnostic pop - return pairs; -} - -OString TeleManager::getFullClientName() -{ - OStringBuffer aBuf(64); - aBuf.append( LIBO_CLIENT_SUFFIX ).append( pImpl->msNameSuffix); - return aBuf.makeStringAndClear(); -} - -OString TeleManager::getFullServiceName() -{ - OStringBuffer aBuf(64); - aBuf.append( LIBO_DTUBE_SERVICE ).append( pImpl->msNameSuffix); - return aBuf.makeStringAndClear(); -} - -OString TeleManager::getFullObjectPath() -{ - OStringBuffer aBuf(64); - aBuf.append( '/').append( LIBO_DTUBE_SERVICE ).append( pImpl->msNameSuffix); - OString aStr( aBuf.makeStringAndClear().replace( '.', '/')); - return aStr; -} - -OString TeleManager::createUuid() -{ - sal_uInt8 nId[16]; - rtl_createUuid( nId, nullptr, true); - char aBuf[33]; - for (size_t i=0; i<16; ++i) - { - snprintf( aBuf+2*i, 3, "%02x", (unsigned char)nId[i]); - } - aBuf[32] = 0; - return OString( aBuf); -} - -Mutex& TeleManager::GetMutex() -{ - static Mutex* pMutex = nullptr; - if (!pMutex) - { - MutexGuard aGuard( Mutex::getGlobalMutex()); - if (!pMutex) - pMutex = new Mutex; - } - return *pMutex; -} - -void TeleManager::addSuffixToNames( const char* pName ) -{ - pImpl->msNameSuffix = pName; -} - - -TeleManagerImpl::TeleManagerImpl() - : - mpFactory( nullptr), - mpClient( nullptr), - mpFileTransferClient( nullptr), - mpAccountManager( nullptr) -{ -#if !GLIB_CHECK_VERSION(2,36,0) - g_type_init(); -#endif -} - -TeleManagerImpl::~TeleManagerImpl() -{ - // There may be unused conferences left opened, so close them. - // It should not make a problem to close already closed conference. - for (MapStringConference::iterator it = maAcceptedConferences.begin(); - it != maAcceptedConferences.end(); ++it) - it->second->close(); - if (mpClient) - { - tp_base_client_unregister( mpClient); - g_object_unref( mpClient); - } - if (mpFileTransferClient) - { - tp_base_client_unregister( mpFileTransferClient); - g_object_unref( mpFileTransferClient); - } - if (mpFactory) - g_object_unref( mpFactory); - if (mpAccountManager) - g_object_unref( mpAccountManager); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/tubes/uiconfig/ui/contacts.ui b/tubes/uiconfig/ui/contacts.ui deleted file mode 100644 index 25fc40005230..000000000000 --- a/tubes/uiconfig/ui/contacts.ui +++ /dev/null @@ -1,143 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <!-- interface-requires gtk+ 3.0 --> - <object class="GtkDialog" id="ContactsDialog"> - <property name="can_focus">False</property> - <property name="border_width">6</property> - <property name="type_hint">dialog</property> - <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox1"> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">12</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="dialog-action_area1"> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="listen"> - <property name="label" translatable="yes">Listen</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="invite"> - <property name="label" translatable="yes">Invite</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkButton" id="demo"> - <property name="label" translatable="yes">StartDemoSession</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkButton" id="buddy"> - <property name="label" translatable="yes">StartBuddySession</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkButton" id="group"> - <property name="label" translatable="yes">StartGroupSession</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">4</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkGrid" id="grid1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="vexpand">True</property> - <property name="row_spacing">6</property> - <child> - <object class="GtkTreeView" id="contacts"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - <child internal-child="selection"> - <object class="GtkTreeSelection" id="treeview-selection"/> - </child> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Select a contact to collaborate with</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="0">listen</action-widget> - <action-widget response="0">invite</action-widget> - <action-widget response="0">demo</action-widget> - <action-widget response="0">buddy</action-widget> - <action-widget response="0">group</action-widget> - </action-widgets> - </object> -</interface> |