summaryrefslogtreecommitdiffstats
path: root/tubes/source
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2012-03-16 22:14:54 +0100
committerMatúš Kukan <matus.kukan@gmail.com>2012-07-17 16:39:16 +0200
commita3a8b803f346681da50fc6d59bf2a3fba58d4da1 (patch)
treed3ff28747bb7e51a9a5efb5fd94d976bacd9d2f5 /tubes/source
parentNSS_Initialize is actually in nssutil3 (diff)
downloadcore-a3a8b803f346681da50fc6d59bf2a3fba58d4da1.tar.gz
core-a3a8b803f346681da50fc6d59bf2a3fba58d4da1.zip
implementing Telepathy Tubes interface
Diffstat (limited to 'tubes/source')
-rw-r--r--tubes/source/conference.cxx384
-rw-r--r--tubes/source/manager.cxx668
-rw-r--r--tubes/source/packet.cxx33
3 files changed, 1085 insertions, 0 deletions
diff --git a/tubes/source/conference.cxx b/tubes/source/conference.cxx
new file mode 100644
index 000000000000..3195df6bceab
--- /dev/null
+++ b/tubes/source/conference.cxx
@@ -0,0 +1,384 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2012 Red Hat, Inc., Eike Rathke <erack@redhat.com>
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#include <tubes/conference.hxx>
+#include <tubes/manager.hxx>
+
+
+#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(0,(s))
+#define INFO_LOGGER(s) InfoLogger aLogger(this,(s))
+#else
+#define INFO_LOGGER_F(s)
+#define INFO_LOGGER(s)
+#endif // SAL_LOG_INFO
+
+
+static DBusHandlerResult TeleConference_DBusMessageHandler(
+ DBusConnection* pConnection,
+ DBusMessage* pMessage,
+ void* pUserData
+ )
+{
+ INFO_LOGGER_F( "TeleConference_DBusMessageHandler");
+
+ SAL_WARN_IF( !pConnection || !pMessage, "tubes", "TeleConference_DBusMessageHandler: unhandled");
+ if (!pConnection || !pMessage)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ TeleConference* pConference = reinterpret_cast<TeleConference*>(pUserData);
+ SAL_WARN_IF( !pConference, "tubes", "TeleConference_DBusMessageHandler: no conference");
+ if (!pConference)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ TeleManager* pManager = pConference->getManager();
+ SAL_WARN_IF( !pManager, "tubes", "TeleConference_DBusMessageHandler: no manager");
+ if (!pManager)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (dbus_message_is_method_call( pMessage, pManager->getFullServiceName().getStr(), LIBO_TUBES_DBUS_MSG_METHOD))
+ {
+ const char* pSender = dbus_message_get_sender( pMessage);
+
+ DBusError aDBusError;
+ dbus_error_init( &aDBusError);
+ const char* pPacketData = 0;
+ int nPacketSize = 0;
+ if (dbus_message_get_args( pMessage, &aDBusError,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pPacketData, &nPacketSize,
+ DBUS_TYPE_INVALID))
+ {
+ SAL_INFO( "tubes", "TeleConference_DBusMessageHandler: received packet from sender "
+ << pSender << " with size " << nPacketSize);
+ pConference->queue( pSender, pPacketData, nPacketSize);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else
+ {
+ SAL_INFO( "tubes", "TeleConference_DBusMessageHandler: unhandled message from sender "
+ << pSender << " " << aDBusError.message);
+ dbus_error_free( &aDBusError);
+ }
+ }
+ else
+ {
+ SAL_INFO( "tubes", "TeleConference_DBusMessageHandler: unhandled method");
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+static void TeleConference_ChannelCloseHandler(
+ TpChannel* /*proxy*/,
+ const GError* pError,
+ gpointer pUserData,
+ GObject* /*weak_object*/
+ )
+{
+ INFO_LOGGER_F( "TeleConference_ChannelCloseHandler");
+
+ TeleConference* pConference = reinterpret_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(
+ TpChannel* pChannel,
+ const gchar* pOutAddress,
+ const GError* pError,
+ gpointer pUserData,
+ GObject* /*weak_object*/
+ )
+{
+ INFO_LOGGER_F( "TeleConference_TubeOfferedHandler");
+
+ // "can't find contact ... presence" means contact is not a contact.
+ /* FIXME: detect and handle */
+ SAL_WARN_IF( pError, "tubes", "TeleConference_TubeOfferedHandler: entered with error: " << pError->message);
+ if (pError)
+ return;
+
+ SAL_WARN_IF( !pOutAddress, "tubes", "TeleConference_TubeOfferedHandler: no out address");
+ if (!pOutAddress)
+ return;
+
+ TeleConference* pConference = reinterpret_cast<TeleConference*>(pUserData);
+ SAL_WARN_IF( !pConference, "tubes", "TeleConference_TubeOfferedHandler: no conference");
+ if (!pConference)
+ return;
+
+ SAL_WARN_IF( pChannel != pConference->getChannel(), "tubes", "TeleConference_TubeOfferedHandler: not my channel");
+ if (pChannel != pConference->getChannel())
+ return;
+
+ TeleManager* pManager = pConference->getManager();
+ SAL_WARN_IF( !pManager, "tubes", "TeleConference_TubeOfferedHandler: no manager");
+ if (!pManager)
+ return;
+
+ pConference->setTubeOfferedHandlerInvoked( true);
+
+ DBusError aDBusError;
+ dbus_error_init( &aDBusError);
+ DBusConnection* pTube = dbus_connection_open_private( pOutAddress, &aDBusError);
+ if (!pTube)
+ {
+ SAL_WARN( "tubes", "TeleConference_TubeOfferedHandler: no dbus connection: " << aDBusError.message);
+ dbus_error_free( &aDBusError);
+ return;
+ }
+
+ pConference->setTube( pTube);
+}
+
+
+TeleConference::TeleConference( TeleManager* pManager, TpChannel* pChannel, const rtl::OString& rSessionId )
+ :
+ maSessionId( rSessionId ),
+ mpManager( pManager),
+ mpChannel( pChannel),
+ mpTube( NULL),
+ mbTubeOfferedHandlerInvoked( false)
+{
+ if (mpChannel)
+ g_object_ref( mpChannel);
+}
+
+
+TeleConference::~TeleConference()
+{
+ // Do nothing here, we're destructed from finalize()
+}
+
+
+void TeleConference::setTarget( const rtl::OString& rTarget )
+{
+ maTarget = rTarget;
+}
+
+
+void TeleConference::setChannel( TpChannel* pChannel )
+{
+ OSL_ENSURE( !mpChannel, "TeleConference::setChannel: already have channel");
+ if (mpChannel)
+ g_object_unref( mpChannel);
+ mpChannel = pChannel;
+ if (mpChannel)
+ g_object_ref( mpChannel);
+}
+
+
+bool TeleConference::acceptTube( const char* pAddress )
+{
+ INFO_LOGGER( "TeleConference::acceptTube");
+
+ SAL_WARN_IF( !pAddress, "tubes", "TeleConference::acceptTube: no address");
+ if (!pAddress)
+ return false;
+ SAL_INFO( "tubes", "TeleConference::acceptTube: address: " << pAddress);
+
+ SAL_WARN_IF( !mpChannel, "tubes", "TeleConference::acceptTube: no channel setup");
+ SAL_WARN_IF( mpTube, "tubes", "TeleConference::acceptTube: already tubed");
+ if (!mpChannel || mpTube)
+ return false;
+
+ DBusError aDBusError;
+ dbus_error_init( &aDBusError);
+ mpTube = dbus_connection_open_private( pAddress, &aDBusError);
+ if (!mpTube)
+ {
+ SAL_WARN( "tubes", "TeleConference::acceptTube: no dbus connection: " << aDBusError.message);
+ dbus_error_free( &aDBusError);
+ return false;
+ }
+
+ dbus_connection_setup_with_g_main( mpTube, mpManager->getMainContext());
+ dbus_connection_add_filter( mpTube, TeleConference_DBusMessageHandler, this, NULL);
+
+ return true;
+}
+
+
+bool TeleConference::offerTube()
+{
+ INFO_LOGGER( "TeleConference::offerTube");
+
+ OSL_ENSURE( mpChannel, "TeleConference::offerTube: no channel");
+ if (!mpChannel)
+ return false;
+
+ setTubeOfferedHandlerInvoked( false);
+
+ // There must be a hash table with some content.
+ /* TODO: anything meaningful to go in here? */
+ GHashTable* pParams = tp_asv_new(
+ "LibreOffice", G_TYPE_STRING, "Collaboration",
+ NULL);
+
+ tp_cli_channel_type_dbus_tube_call_offer(
+ mpChannel, // proxy
+ -1, // timeout_ms
+ pParams, // in_parameters
+ TP_SOCKET_ACCESS_CONTROL_LOCALHOST, // in_access_control
+ TeleConference_TubeOfferedHandler, // callback
+ this, // user_data
+ NULL, // destroy
+ NULL); // weak_object
+
+ mpManager->iterateLoop( this, &TeleConference::isTubeOfferedHandlerInvoked);
+
+ g_hash_table_unref( pParams);
+
+ return true;
+}
+
+
+bool TeleConference::setTube( DBusConnection* pTube )
+{
+ INFO_LOGGER( "TeleConference::setTube");
+
+ OSL_ENSURE( !mpTube, "TeleConference::setTube: already tubed");
+ mpTube = pTube;
+
+ dbus_connection_setup_with_g_main( mpTube, mpManager->getMainContext());
+ dbus_connection_add_filter( mpTube, TeleConference_DBusMessageHandler, this, NULL);
+
+ /* TODO: anything else? */
+
+ return true;
+}
+
+
+void TeleConference::close()
+{
+ INFO_LOGGER( "TeleConference::close");
+
+ if (mpChannel)
+ tp_cli_channel_call_close( mpChannel, 5000, TeleConference_ChannelCloseHandler, this, NULL, NULL);
+ else
+ finalize();
+}
+
+
+void TeleConference::finalize()
+{
+ INFO_LOGGER( "TeleConference::finalize");
+
+ if (mpChannel)
+ {
+ g_object_unref( mpChannel);
+ mpChannel = NULL;
+ }
+
+ if (mpTube)
+ {
+ dbus_connection_remove_filter( mpTube, TeleConference_DBusMessageHandler, this);
+ dbus_connection_close( mpTube);
+ dbus_connection_unref( mpTube);
+ mpTube = NULL;
+ }
+
+ TeleConferencePtr pThis( shared_from_this());
+ mpManager->unregisterConference( pThis);
+
+ //! *this gets destructed here!
+}
+
+
+bool TeleConference::sendPacket( TelePacket& rPacket ) const
+{
+ INFO_LOGGER( "TeleConference::sendPacket");
+
+ OSL_ENSURE( mpManager, "tubes: TeleConference::sendPacket: no TeleManager");
+ SAL_WARN_IF( !mpTube, "tubes", "TeleConference::sendPacket: no tube");
+ if (!(mpManager && mpTube))
+ return false;
+
+ DBusMessage* pMessage = dbus_message_new_method_call(
+ mpManager->getFullServiceName().getStr(),
+ mpManager->getFullObjectPath().getStr(),
+ mpManager->getFullServiceName().getStr(),
+ LIBO_TUBES_DBUS_MSG_METHOD);
+ SAL_WARN_IF( !pMessage, "tubes", "TeleConference::sendPacket: no DBusMessage");
+ if (!pMessage)
+ return false;
+
+ const char* pPacketData = rPacket.getData();
+ dbus_message_append_args( pMessage,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pPacketData, rPacket.getSize(),
+ DBUS_TYPE_INVALID);
+
+ SAL_INFO( "tubes", "TeleConference::sendPacket: from " <<
+ dbus_message_get_sender( pMessage) << " to " << dbus_message_get_destination( pMessage));
+
+ bool bSent = dbus_connection_send( mpTube, pMessage, NULL);
+ SAL_WARN_IF( !bSent, "tubes", "TeleConference::sendPacket: not sent");
+ dbus_message_unref( pMessage);
+ return bSent;
+}
+
+
+void TeleConference::queue( const char* pDBusSender, const char* pPacketData, int nPacketSize )
+{
+ INFO_LOGGER( "TeleConference::queue");
+
+ maPacketQueue.push( TelePacket( pDBusSender, pPacketData, nPacketSize));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tubes/source/manager.cxx b/tubes/source/manager.cxx
new file mode 100644
index 000000000000..ba9185258469
--- /dev/null
+++ b/tubes/source/manager.cxx
@@ -0,0 +1,668 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2012 Red Hat, Inc., Eike Rathke <erack@redhat.com>
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#include "tubes/manager.hxx"
+#include <rtl/strbuf.hxx>
+#include <rtl/uuid.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(0,(s))
+#define INFO_LOGGER(s) InfoLogger aLogger(this,(s))
+#else
+#define INFO_LOGGER_F(s)
+#define INFO_LOGGER(s)
+#endif // SAL_LOG_INFO
+
+
+using namespace rtl;
+
+// To form "org.freedesktop.Telepathy.Client.LibreOfficeWhatEver" (bus name)
+// or "/org/freedesktop/Telepathy/Client/LibreOfficeWhatEver" (object path)
+#define LIBO_TP_NAME_PREFIX "LibreOffice"
+
+
+static void TeleManager_DBusTubeAcceptHandler(
+ TpChannel* pChannel,
+ const char* pAddress,
+ const GError* pError,
+ gpointer pUserData,
+ GObject* /*weak_object*/)
+{
+ INFO_LOGGER_F( "TeleManager_DBusTubeAcceptHandler");
+
+ SAL_WARN_IF( pError, "tubes", "TeleManager_DBusTubeAcceptHandler: entered with error: " << pError->message);
+ if (pError)
+ return;
+
+ TeleManager* pManager = reinterpret_cast<TeleManager*>(pUserData);
+ SAL_WARN_IF( !pManager, "tubes", "TeleManager_DBusTubeAcceptHandler: no manager");
+ if (!pManager)
+ return;
+
+ pManager->acceptTube( pChannel, pAddress);
+}
+
+
+static void TeleManager_DBusChannelHandler(
+ TpSimpleHandler* /*handler*/,
+ TpAccount* /*account*/,
+ TpConnection* /*connection*/,
+ GList* pChannels,
+ GList* /*requests_satisfied*/,
+ gint64 /*user_action_time*/,
+ TpHandleChannelsContext* pContext,
+ gpointer pUserData)
+{
+ INFO_LOGGER_F( "TeleManager_DBusChannelHandler");
+
+ TeleManager* pManager = reinterpret_cast<TeleManager*>(pUserData);
+ SAL_WARN_IF( !pManager, "tubes", "TeleManager_DBusChannelHandler: no manager");
+ if (!pManager)
+ return;
+
+ 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_channel_get_channel_type_id( pChannel) == TP_IFACE_QUARK_CHANNEL_TYPE_DBUS_TUBE)
+ {
+ SAL_INFO( "tubes", "accepting");
+ tp_cli_channel_type_dbus_tube_call_accept( pChannel, -1,
+ TP_SOCKET_ACCESS_CONTROL_LOCALHOST,
+ TeleManager_DBusTubeAcceptHandler, pUserData, NULL, NULL);
+ }
+ else
+ {
+ SAL_INFO( "tubes", "ignored");
+ }
+ }
+
+ tp_handle_channels_context_accept( pContext);
+}
+
+
+static void TeleManager_ChannelReadyHandler(
+ GObject* pSourceObject,
+ GAsyncResult* pResult,
+ gpointer pUserData
+ )
+{
+ INFO_LOGGER_F( "TeleManager_ChannelReadyHandler");
+
+ TeleConference* pConference = reinterpret_cast<TeleConference*>(pUserData);
+ SAL_WARN_IF( !pConference, "tubes", "TeleManager_ChannelReadyHandler: no conference");
+ if (!pConference)
+ return;
+
+ TeleManager* pManager = pConference->getManager();
+ SAL_WARN_IF( !pManager, "tubes", "TeleManager_ChannelReadyHandler: no manager");
+ if (!pManager)
+ return;
+
+ pManager->setChannelReadyHandlerInvoked( true);
+
+ GError* pError = NULL;
+ TpChannel * pChannel = tp_account_channel_request_create_and_handle_channel_finish(
+ TP_ACCOUNT_CHANNEL_REQUEST( pSourceObject), pResult, NULL, &pError);
+ if (!pChannel)
+ {
+ // "account isn't Enabled" means just that..
+ /* FIXME: detect and handle, domain=132, code=3 */
+ SAL_WARN( "tubes", "TeleManager_ChannelReadyHandler: no channel: " << pError->message);
+ g_error_free( pError);
+ return;
+ }
+
+ pConference->setChannel( pChannel);
+ pConference->offerTube();
+}
+
+
+static void TeleManager_AccountManagerReadyHandler(
+ GObject* pSourceObject,
+ GAsyncResult* pResult,
+ gpointer pUserData
+ )
+{
+ INFO_LOGGER_F( "TeleManager_AccountManagerReadyHandler");
+
+ TeleManager* pManager = reinterpret_cast<TeleManager*>(pUserData);
+ SAL_WARN_IF( !pManager, "tubes", "TeleManager_AccountManagerReadyHandler: no manager");
+ if (!pManager)
+ return;
+
+ pManager->setAccountManagerReadyHandlerInvoked( true);
+
+ GError* pError = NULL;
+ gboolean bPrepared = tp_proxy_prepare_finish( pSourceObject, pResult, &pError);
+ SAL_WARN_IF( !bPrepared, "tubes", "TeleManager_AccountManagerReadyHandler: not prepared");
+ if (!bPrepared || pError)
+ {
+ SAL_WARN_IF( pError, "tubes", "TeleManager_AccountManagerReadyHandler: error: " << pError->message);
+ g_error_free( pError);
+ }
+
+ pManager->setAccountManagerReady( bPrepared);
+}
+
+
+TeleManager::TeleManager( const rtl::OUString& rAccount, const rtl::OUString& rService, bool bCreateOwnGMainLoop )
+ :
+ maAccountID( OUStringToOString( rAccount, RTL_TEXTENCODING_UTF8)),
+ mpLoop( NULL),
+ mpDBus( NULL),
+ mpAccountManager( NULL),
+ mpAccount( NULL),
+ mpConnection( NULL),
+ mpClient( NULL),
+ meAccountManagerStatus( AMS_UNINITIALIZED),
+ mbChannelReadyHandlerInvoked( false),
+ mbAccountManagerReadyHandlerInvoked( false)
+{
+ OStringBuffer aBuf(64);
+ aBuf.append( RTL_CONSTASCII_STRINGPARAM( LIBO_TP_NAME_PREFIX)).append(
+ OUStringToOString( rService, RTL_TEXTENCODING_UTF8));
+ maService = aBuf.makeStringAndClear();
+ // Ensure a clean name suitable for object paths.
+ maService.replace( '.', '_');
+
+ // The glib object types need to be initialized, else we aren't going
+ // anywhere.
+ g_type_init();
+
+ // We need a main loop, else no callbacks.
+ /* TODO: could the loop be run in another thread? */
+ if (bCreateOwnGMainLoop)
+ mpLoop = g_main_loop_new( NULL, FALSE);
+}
+
+
+TeleManager::~TeleManager()
+{
+ disconnect();
+
+ if (mpDBus)
+ g_object_unref( mpDBus);
+ if (mpAccountManager)
+ g_object_unref( mpAccountManager);
+ if (mpAccount)
+ g_object_unref( mpAccount);
+ if (mpConnection)
+ g_object_unref( mpConnection);
+ if (mpClient)
+ g_object_unref( mpClient);
+
+ if (mpLoop)
+ g_main_loop_unref( mpLoop);
+}
+
+
+bool TeleManager::connect()
+{
+ INFO_LOGGER( "TeleManager::connect");
+
+ MainLoopFlusher aFlusher( this);
+
+ SAL_WARN_IF( mpDBus || mpClient, "tubes", "TeleManager::connect: already connected");
+ if (mpDBus || mpClient)
+ return false;
+
+ GError* pError = NULL;
+ mpDBus = tp_dbus_daemon_dup( &pError);
+ SAL_WARN_IF( !mpDBus, "tubes", "TeleManager::connect: no dbus daemon");
+ if (!mpDBus || pError)
+ {
+ SAL_WARN_IF( pError, "tubes", "TeleManager::connect: dbus daemon error: " << pError->message);
+ g_error_free( pError);
+ return false;
+ }
+
+ TpSimpleClientFactory* pFactory = tp_simple_client_factory_new( mpDBus);
+ SAL_WARN_IF( !pFactory, "tubes", "TeleManager::connect: no client factory");
+ if (!pFactory)
+ return false;
+
+ /* TODO: does that still work with uniquify? Or is the service not
+ * recognized anymore? Without uniquify it is not possible to register two
+ * instances of clients on the same DBus. */
+
+ /* FIXME: testing, first real, all others uniquified */
+ static gboolean bUniquify = FALSE;
+
+ mpClient = tp_simple_handler_new_with_factory(
+ pFactory, // factory
+ TRUE, // bypass_approval
+ FALSE, // requests
+ maService.getStr(), // name
+ bUniquify, // uniquify
+ TeleManager_DBusChannelHandler, // callback
+ this, // user_data
+ NULL // destroy
+ );
+ bUniquify = TRUE;
+ SAL_WARN_IF( !mpClient, "tubes", "TeleManager::connect: no client");
+ if (!mpClient)
+ return false;
+
+ // Setup client handler for buddy channels with our service.
+ tp_base_client_take_handler_filter( 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(),
+ NULL));
+
+/* FIXME: once we can handle MUCs, this is additional to buddy channels! */
+#if 0
+ // Setup client handler for MUC channels with our service.
+ tp_base_client_take_handler_filter( 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(),
+ NULL));
+#endif
+
+ if (!tp_base_client_register( mpClient, &pError))
+ {
+ SAL_WARN( "tubes", "TeleManager::connect: error registering client handler: " << pError->message);
+ g_error_free( pError);
+ return false;
+ }
+
+ SAL_INFO( "tubes", "TeleManager::connect: bus name: " << tp_base_client_get_bus_name( mpClient));
+ SAL_INFO( "tubes", "TeleManager::connect: object path: " << tp_base_client_get_object_path( mpClient));
+
+ return true;
+}
+
+
+/* TODO: factor out common code with startBuddySession() */
+bool TeleManager::startGroupSession( const rtl::OUString& rUConferenceRoom, const rtl::OUString& rUConferenceServer )
+{
+ INFO_LOGGER( "TeleManager::startGroupSession");
+
+ MainLoopFlusher aFlusher( this);
+
+ if (!getMyAccount())
+ return false;
+
+ OString aSessionId( TeleManager::createUuid());
+
+ TeleConferencePtr pConference( new TeleConference( this, NULL, aSessionId));
+ maConferences.push_back( pConference);
+
+ /* TODO: associate the document with this session and conference */
+
+ /* 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());
+ pConference->setTarget( aTarget);
+
+ SAL_INFO( "tubes", "TeleManager::startGroupSession: creating channel request from "
+ << maAccountID.getStr() << " 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(),
+ NULL);
+
+ TpAccountChannelRequest * pChannelRequest = tp_account_channel_request_new(
+ mpAccount, pRequest, TP_USER_ACTION_TIME_NOT_USER_ACTION);
+ g_hash_table_unref( pRequest);
+ SAL_WARN_IF( !pChannelRequest, "tubes", "TeleManager::startGroupSession: no channel");
+ if (!pChannelRequest)
+ return false;
+
+ setChannelReadyHandlerInvoked( false);
+
+ tp_account_channel_request_create_and_handle_channel_async(
+ pChannelRequest, NULL, TeleManager_ChannelReadyHandler, pConference.get());
+
+ iterateLoop( &TeleManager::isChannelReadyHandlerInvoked);
+
+ return pConference->getChannel() != NULL;
+}
+
+
+/* TODO: factor out common code with startGroupSession() */
+bool TeleManager::startBuddySession( const rtl::OUString& rBuddy )
+{
+ INFO_LOGGER( "TeleManager::startBuddySession");
+
+ MainLoopFlusher aFlusher( this);
+
+ if (!getMyAccount())
+ return false;
+
+ OString aSessionId( TeleManager::createUuid());
+
+ TeleConferencePtr pConference( new TeleConference( this, NULL, aSessionId));
+ maConferences.push_back( pConference);
+
+ /* TODO: associate the document with this session and conference */
+
+ OString aTarget( OUStringToOString( rBuddy, RTL_TEXTENCODING_UTF8));
+ pConference->setTarget( aTarget);
+
+ SAL_INFO( "tubes", "TeleManager::startBuddySession: creating channel request from "
+ << maAccountID.getStr() << " to " << aTarget.getStr());
+
+ 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, aTarget.getStr(),
+ TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, getFullServiceName().getStr(),
+ NULL);
+
+ TpAccountChannelRequest * pChannelRequest = tp_account_channel_request_new(
+ mpAccount, 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 false;
+ }
+
+ setChannelReadyHandlerInvoked( false);
+
+ tp_account_channel_request_create_and_handle_channel_async(
+ pChannelRequest, NULL, TeleManager_ChannelReadyHandler, pConference.get());
+
+ iterateLoop( &TeleManager::isChannelReadyHandlerInvoked);
+
+ g_object_unref( pChannelRequest);
+ g_hash_table_unref( pRequest);
+
+ return pConference->getChannel() != NULL;
+}
+
+
+void TeleManager::prepareAccountManager()
+{
+ INFO_LOGGER( "TeleManager::prepareAccountManager");
+
+ MainLoopFlusher aFlusher( this);
+
+ SAL_WARN_IF( meAccountManagerStatus == AMS_INPREPARATION, "tubes",
+ "TeleManager::prepareAccountManager: already in preparation");
+ if (meAccountManagerStatus == AMS_INPREPARATION)
+ return;
+
+ SAL_WARN_IF( meAccountManagerStatus != AMS_UNINITIALIZED, "tubes",
+ "TeleManager::prepareAccountManager: yet another attempt");
+
+ if (!mpAccountManager)
+ {
+ mpAccountManager = tp_account_manager_dup();
+ SAL_WARN_IF( !mpAccountManager, "tubes", "TeleManager::prepareAccountManager: no account manager");
+ if (!mpAccountManager)
+ return;
+ g_object_ref( mpAccountManager);
+ }
+
+ meAccountManagerStatus = AMS_INPREPARATION;
+ setAccountManagerReadyHandlerInvoked( false);
+
+ tp_proxy_prepare_async( mpAccountManager, NULL, TeleManager_AccountManagerReadyHandler, this);
+
+ iterateLoop( &TeleManager::isAccountManagerReadyHandlerInvoked);
+}
+
+
+TpAccount* TeleManager::getMyAccount()
+{
+ INFO_LOGGER( "TeleManager::getMyAccount");
+
+ MainLoopFlusher aFlusher( this);
+
+ if (mpAccount)
+ return mpAccount;
+
+ SAL_WARN_IF( meAccountManagerStatus != AMS_PREPARED, "tubes",
+ "TeleManager::getMyAccount: Account Manager not prepared");
+ if (meAccountManagerStatus != AMS_PREPARED)
+ return NULL;
+
+ GList* pAccounts = tp_account_manager_get_valid_accounts( mpAccountManager);
+ SAL_WARN_IF( !pAccounts, "tubes", "TeleManager::getMyAccount: no valid accounts");
+ if (!pAccounts)
+ return NULL;
+
+ // Find our account to use.
+ for (GList* pA = pAccounts; pA; pA = pA->next)
+ {
+ TpAccount* pAcc = TP_ACCOUNT( pA->data);
+ const GHashTable* pPar = tp_account_get_parameters( pAcc);
+ const gchar* pID = tp_asv_get_string( pPar, "account");
+ SAL_WARN_IF( !pID, "tubes", "TeleManager::getMyAccount: account without account??");
+ if (pID && maAccountID == pID)
+ {
+ mpAccount = pAcc;
+ break; // for
+ }
+ }
+
+ g_list_free( pAccounts);
+ SAL_WARN_IF( !mpAccount, "tubes", "TeleManager::getMyAccount: no account");
+ if (!mpAccount)
+ return NULL;
+
+ g_object_ref( mpAccount);
+ return mpAccount;
+}
+
+
+bool TeleManager::sendPacket( const TelePacket& rPacket ) const
+{
+ INFO_LOGGER( "TeleManager::sendPacket");
+
+ MainLoopFlusher aFlusher( this);
+
+ bool bToSend = false;
+ bool bSent = true;
+ // Access to data ByteStream array forces reference count of one, provide
+ // non-const instance here before passing it down to each conference.
+ TelePacket aPacket( rPacket);
+ for (TeleConferenceVector::const_iterator it = maConferences.begin(); it != maConferences.end(); ++it)
+ {
+ bToSend = true;
+ if (!(*it)->sendPacket( aPacket))
+ bSent = false;
+ }
+ return bSent && bToSend;
+}
+
+
+void TeleManager::unregisterConference( TeleConferencePtr pConference )
+{
+ TeleConferenceVector::iterator it = ::std::find( maConferences.begin(), maConferences.end(), pConference);
+ if (it != maConferences.end())
+ maConferences.erase( it);
+}
+
+
+void TeleManager::disconnect()
+{
+ INFO_LOGGER( "TeleManager::disconnect");
+
+ //! No MainLoopFlusher here!
+
+ if (!mpClient)
+ return;
+
+ tp_base_client_unregister( mpClient);
+ mpClient = NULL;
+
+ size_t nSize = maConferences.size();
+ for (size_t i=0; i < nSize; /*nop*/)
+ {
+ maConferences[i]->close();
+ // close() may remove the conference from the vector and move following
+ // elements to this position (hence we don't use an iterator here),
+ // adjust accordingly.
+ size_t n = maConferences.size();
+ if (n < nSize)
+ nSize = n;
+ else
+ ++i;
+ }
+}
+
+
+void TeleManager::acceptTube( TpChannel* pChannel, const char* pAddress )
+{
+ INFO_LOGGER( "TeleManager::acceptTube");
+
+ SAL_INFO( "tubes", "TeleManager::acceptTube: address " << pAddress);
+
+ MainLoopFlusher aFlusher( this);
+
+ SAL_WARN_IF( !pChannel || !pAddress, "tubes", "TeleManager::acceptTube: no channel or no address");
+ if (!pChannel || !pAddress)
+ return;
+
+ TeleConferencePtr pConference( new TeleConference( this, pChannel, ""));
+ maConferences.push_back( pConference);
+ pConference->acceptTube( pAddress);
+}
+
+
+void TeleManager::setAccountManagerReady( bool bPrepared)
+{
+ meAccountManagerStatus = (bPrepared ? AMS_PREPARED : AMS_UNPREPARABLE);
+}
+
+
+rtl::OString TeleManager::getFullServiceName() const
+{
+ OStringBuffer aBuf(64);
+ aBuf.append( RTL_CONSTASCII_STRINGPARAM( TP_CLIENT_BUS_NAME_BASE)).append( maService);
+ return aBuf.makeStringAndClear();
+}
+
+
+rtl::OString TeleManager::getFullObjectPath() const
+{
+ OStringBuffer aBuf(64);
+ aBuf.append( RTL_CONSTASCII_STRINGPARAM( TP_CLIENT_OBJECT_PATH_BASE)).append( maService);
+ return aBuf.makeStringAndClear();
+}
+
+
+void TeleManager::iterateLoop( CallBackInvokedFunc pFunc )
+{
+ GMainContext* pContext = (mpLoop ? g_main_loop_get_context( mpLoop) : NULL);
+ while (!(this->*pFunc)())
+ {
+ g_main_context_iteration( pContext, TRUE);
+ SAL_INFO( "tubes.loop", "TeleManager::iterateLoop");
+ }
+}
+
+
+void TeleManager::iterateLoop( const TeleConference* pConference, ConferenceCallBackInvokedFunc pFunc )
+{
+ GMainContext* pContext = (mpLoop ? g_main_loop_get_context( mpLoop) : NULL);
+ while (!(pConference->*pFunc)())
+ {
+ g_main_context_iteration( pContext, TRUE);
+ SAL_INFO( "tubes.loop", "TeleManager::iterateLoop conference");
+ }
+}
+
+
+void TeleManager::flushLoop() const
+{
+ if (mpLoop)
+ {
+ GMainContext* pContext = g_main_loop_get_context( mpLoop);
+ while (g_main_context_iteration( pContext, FALSE))
+ {
+ SAL_INFO( "tubes.loop", "TeleManager::flushLoop");
+ }
+ }
+}
+
+
+// static
+rtl::OString TeleManager::createUuid()
+{
+ sal_uInt8 nId[16];
+ rtl_createUuid( nId, 0, sal_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 rtl::OString( aBuf);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tubes/source/packet.cxx b/tubes/source/packet.cxx
new file mode 100644
index 000000000000..279398603270
--- /dev/null
+++ b/tubes/source/packet.cxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Version: MPL 1.1 / GPLv3+ / LGPLv3+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2012 Red Hat, Inc., Eike Rathke <erack@redhat.com>
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
+ * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
+ * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
+ * instead of those above.
+ */
+
+#include <tubes/packet.hxx>
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */