Files
libreoffice/tubes/source/manager.cxx
Brij Mohan Lal Srivastava d32be3ace8 fdo#86023 - O[U]String needs a 'clear' method
Added clear() method to OString and OUString class, Updated appropriate call-sites.

Change-Id: I0ba97fa6dc7af3e31b605953089a4e8e9c3e61ac
Signed-off-by: Stephan Bergmann <sbergman@redhat.com>
2014-11-14 09:20:38 +01:00

901 lines
32 KiB
C++

/* -*- 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/manager.hxx>
#include <tubes/collaboration.hxx>
#include <tubes/conference.hxx>
#include <tubes/constants.h>
#include <tubes/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 <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(0,(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
{
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?");
tp_handle_channels_context_fail( pContext, pError);
g_clear_error (&pError);
}
}
// - TeleManager -
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 = NULL;
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;
}
// FIXME: should be static and not used in conference.cxx
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( NULL, NULL, 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), NULL);
g_signal_connect( pHandler, "transfer-error", G_CALLBACK (TeleManager_TransferError), NULL);
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, NULL);
aAccepted = true;
}
else
{
SAL_INFO( "tubes", "ignored");
}
}
if (aAccepted)
tp_handle_channels_context_accept( pContext);
else
{
GError *pError = g_error_new_literal( TP_ERRORS, TP_ERROR_CONFUSED,
"None of these channels were file transfers; "
"why did the Channel Dispatcher give them to us?");
tp_handle_channels_context_fail( pContext, pError);
g_clear_error (&pError);
}
}
// - TeleManagerImpl -
void TeleManagerImpl::ChannelReadyHandler(
GObject* pSourceObject,
GAsyncResult* pResult,
gpointer pUserData
)
{
INFO_LOGGER_F( "TeleManagerImpl::ChannelReadyHandler");
TeleConference* pConference = reinterpret_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 = NULL;
TpChannel * pChannel = tp_account_channel_request_create_and_handle_channel_finish(
pChannelRequest, pResult, NULL, &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 = NULL;
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;
}
// - TeleManager -
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()
{
delete pImpl;
}
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 = NULL;
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);
pImpl->mbAccountManagerReadyHandlerInvoked = false;
tp_proxy_prepare_async( pImpl->mpAccountManager, NULL, TeleManagerImpl::AccountManagerReadyHandler, NULL);
while (!pImpl->mbAccountManagerReadyHandlerInvoked)
g_main_context_iteration( NULL, TRUE);
return pImpl->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
NULL, // user_data
NULL // 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(),
NULL));
/* 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(),
NULL));
GError* pError = NULL;
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
NULL, // user_data
NULL // destroy
);
tp_base_client_take_handler_filter( pImpl->mpFileTransferClient,
tp_asv_new(
TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER,
TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME, G_TYPE_STRING, getFullServiceName().getStr(),
NULL));
if (!tp_base_client_register( pImpl->mpFileTransferClient, &pError))
{
/* This shouldn't fail if registering the main handler succeeded */
SAL_WARN( "tubes", "TeleManager::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( NULL, NULL, "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(),
NULL);
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 NULL;
}
pImpl->mbChannelReadyHandlerInvoked = false;
TeleConference* pConference = new TeleConference( NULL, NULL, aSessionId );
tp_account_channel_request_create_and_handle_channel_async(
pChannelRequest, NULL, TeleManagerImpl::ChannelReadyHandler, pConference);
while (!pImpl->mbChannelReadyHandlerInvoked)
g_main_context_iteration( NULL, TRUE );
g_object_unref( pChannelRequest);
g_hash_table_unref( pRequest);
if (!pConference->isReady())
return NULL;
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),
NULL);
TpAccountChannelRequest* pChannelRequest = tp_account_channel_request_new(
pAccount, pRequest, TP_USER_ACTION_TIME_NOT_USER_ACTION);
tp_account_channel_request_ensure_channel_async( pChannelRequest, NULL,
NULL, NULL, NULL );
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(),
NULL);
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 NULL;
}
pImpl->mbChannelReadyHandlerInvoked = false;
TeleConference* pConference = new TeleConference( NULL, NULL, createUuid(), true );
tp_account_channel_request_create_and_handle_channel_async(
pChannelRequest, NULL, TeleManagerImpl::ChannelReadyHandler, pConference );
while (!pImpl->mbChannelReadyHandlerInvoked)
g_main_context_iteration( NULL, TRUE );
g_object_unref( pChannelRequest);
g_hash_table_unref( pRequest);
if (!pConference->isReady())
return NULL;
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 != NULL; accounts = g_list_delete_link (accounts, accounts))
{
TpAccount *account = reinterpret_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 == NULL || 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 = reinterpret_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), NULL );
}
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, 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 OString( aBuf);
}
Mutex& TeleManager::GetMutex()
{
static Mutex* pMutex = NULL;
if (!pMutex)
{
MutexGuard aGuard( Mutex::getGlobalMutex());
if (!pMutex)
pMutex = new Mutex;
}
return *pMutex;
}
void TeleManager::addSuffixToNames( const char* pName )
{
pImpl->msNameSuffix = pName;
}
// - TeleManagerImpl -
TeleManagerImpl::TeleManagerImpl()
:
mpFactory( NULL),
mpClient( NULL),
mpFileTransferClient( NULL),
mpAccountManager( NULL)
{
#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: */