1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <tubes/manager.hxx>
12 #include <tubes/collaboration.hxx>
13 #include <tubes/conference.hxx>
14 #include <tubes/constants.h>
15 #include <tubes/file-transfer-helper.h>
17 #include <com/sun/star/uno/Sequence.hxx>
18 #include <com/sun/star/frame/Desktop.hpp>
19 #include <com/sun/star/frame/XComponentLoader.hpp>
20 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
21 #include <com/sun/star/beans/PropertyValue.hpp>
22 #include <com/sun/star/util/XCloseable.hpp>
23 #include <comphelper/processfactory.hxx>
24 #include <osl/mutex.hxx>
25 #include <rtl/strbuf.hxx>
28 #include <telepathy-glib/telepathy-glib.h>
33 #if defined SAL_LOG_INFO
40 explicit InfoLogger( const void* pThat
, const char* pMethod
)
45 SAL_INFO( "tubes.method", mpThat
<< " entering " << mpMethod
);
49 SAL_INFO( "tubes.method", mpThat
<< " leaving " << mpMethod
);
53 #define INFO_LOGGER_F(s) InfoLogger aLogger(0,(s))
55 #define INFO_LOGGER_F(s)
56 #endif // SAL_LOG_INFO
60 /** Refcounted singleton implementation class. */
64 TpSimpleClientFactory
* mpFactory
;
65 TpBaseClient
* mpClient
;
66 TpBaseClient
* mpFileTransferClient
;
67 TpAccountManager
* mpAccountManager
;
68 static bool mbAccountManagerReady
;
69 static bool mbAccountManagerReadyHandlerInvoked
;
70 static bool mbChannelReadyHandlerInvoked
;
71 OString msCurrentUUID
;
73 typedef std::map
< OString
, TeleConference
* > MapStringConference
;
74 MapStringConference maAcceptedConferences
;
75 typedef std::set
< TeleConference
* > DemoConferences
;
76 DemoConferences maDemoConferences
;
77 typedef std::set
< Collaboration
* > Collaborations
;
78 Collaborations maCollaborations
;
79 typedef std::set
< TpContact
* > RegisteredContacts
;
80 RegisteredContacts maRegisteredContacts
;
84 static void AccountManagerReadyHandler( GObject
* pSourceObject
, GAsyncResult
* pResult
, gpointer pUserData
);
85 static void ChannelReadyHandler( GObject
* pSourceObject
, GAsyncResult
* pResult
, gpointer pUserData
);
88 TeleManagerImpl
* TeleManager::pImpl
= new TeleManagerImpl();
89 bool TeleManagerImpl::mbAccountManagerReady
;
90 bool TeleManagerImpl::mbAccountManagerReadyHandlerInvoked
;
91 bool TeleManagerImpl::mbChannelReadyHandlerInvoked
;
93 static void TeleManager_DBusChannelHandler(
94 TpSimpleHandler
* /*handler*/,
96 TpConnection
* /*connection*/,
98 GList
* /*requests_satisfied*/,
99 gint64
/*user_action_time*/,
100 TpHandleChannelsContext
* pContext
,
101 gpointer
/*pUserData*/ )
103 bool aAccepted
= false;
104 INFO_LOGGER_F( "TeleManager_DBusChannelHandler");
106 for (GList
* p
= pChannels
; p
; p
= p
->next
)
108 TpChannel
* pChannel
= TP_CHANNEL(p
->data
);
112 SAL_INFO( "tubes", "TeleManager_DBusChannelHandler: incoming dbus channel: "
113 << tp_channel_get_identifier( pChannel
));
115 if (TP_IS_DBUS_TUBE_CHANNEL( pChannel
))
117 SAL_INFO( "tubes", "accepting");
120 TeleConference
* pConference
= new TeleConference( pAccount
, TP_DBUS_TUBE_CHANNEL( pChannel
) );
121 pConference
->acceptTube();
122 TeleManager::addConference( pConference
);
126 SAL_INFO( "tubes", "ignored");
131 tp_handle_channels_context_accept( pContext
);
134 GError
*pError
= g_error_new_literal( TP_ERRORS
, TP_ERROR_CONFUSED
,
135 "None of these channels were LibreOffice D-Bus tubes; "
136 "why did the Channel Dispatcher give them to us?");
137 tp_handle_channels_context_fail( pContext
, pError
);
138 g_clear_error (&pError
);
144 void TeleManager::addConference( TeleConference
* pConference
)
146 MutexGuard
aGuard( GetMutex());
148 SAL_WARN_IF( pConference
->getUuid().isEmpty(), "tubes",
149 "Adding conference with empty UUID should not happen!" );
150 pImpl
->maAcceptedConferences
[ pConference
->getUuid() ] = pConference
;
153 TeleConference
* TeleManager::getConference()
155 MutexGuard
aGuard( GetMutex());
157 TeleManagerImpl::MapStringConference::const_iterator it
=
158 pImpl
->maAcceptedConferences
.find( pImpl
->msCurrentUUID
);
159 TeleConference
* pConference
= NULL
;
160 if (it
!= pImpl
->maAcceptedConferences
.end())
161 pConference
= it
->second
;
162 SAL_WARN_IF( !pConference
, "tubes", "TeleManager::getConference: "
163 << pImpl
->msCurrentUUID
.getStr() << " not found!" );
164 (pImpl
->msCurrentUUID
).clear();
168 void TeleManager::registerCollaboration( Collaboration
* pCollaboration
)
170 MutexGuard
aGuard( GetMutex());
172 pImpl
->maCollaborations
.insert( pCollaboration
);
175 void TeleManager::unregisterCollaboration( Collaboration
* pCollaboration
)
177 MutexGuard
aGuard( GetMutex());
179 pImpl
->maCollaborations
.erase( pCollaboration
);
182 bool TeleManager::existsCollaboration( Collaboration
* pCollaboration
)
184 MutexGuard
aGuard( GetMutex());
186 return pImpl
->maCollaborations
.find( pCollaboration
) != pImpl
->maCollaborations
.end();
189 void TeleManager::displayAllContacts()
191 MutexGuard
aGuard( GetMutex());
193 for (TeleManagerImpl::Collaborations::iterator it
= pImpl
->maCollaborations
.begin();
194 it
!= pImpl
->maCollaborations
.end(); ++it
)
195 (*it
)->DisplayContacts();
198 void TeleManager::registerDemoConference( TeleConference
* pConference
)
200 MutexGuard
aGuard( GetMutex());
202 pImpl
->maDemoConferences
.insert( pConference
);
205 void TeleManager::unregisterDemoConference( TeleConference
* pConference
)
207 MutexGuard
aGuard( GetMutex());
209 pImpl
->maDemoConferences
.erase( pConference
);
212 void TeleManager::broadcastPacket( const OString
& rPacket
)
214 MutexGuard
aGuard( GetMutex());
216 INFO_LOGGER_F( "TeleManager::broadcastPacket" );
217 for (TeleManagerImpl::DemoConferences::iterator it
= pImpl
->maDemoConferences
.begin();
218 it
!= pImpl
->maDemoConferences
.end(); ++it
)
219 if ((*it
)->getCollaboration())
220 (*it
)->getCollaboration()->PacketReceived( rPacket
);
223 bool TeleManager::hasWaitingConference()
225 MutexGuard
aGuard( GetMutex());
227 return !pImpl
->msCurrentUUID
.isEmpty();
230 void TeleManager::setCurrentUuid( const OString
& rUuid
)
232 MutexGuard
aGuard( GetMutex());
234 pImpl
->msCurrentUUID
= rUuid
;
237 // FIXME: should be static and not used in conference.cxx
238 void TeleManager_fileReceived( const OUString
& rStr
, const OString
& rUuid
)
240 SAL_INFO( "tubes", "TeleManager_fileReceived: incoming file: " << rStr
);
242 OString
sUuid( rUuid
);
245 sUuid
= TeleManager::createUuid();
246 TeleConference
* pConference
= new TeleConference( NULL
, NULL
, sUuid
);
247 TeleManager::addConference( pConference
);
248 TeleManager::registerDemoConference( pConference
);
250 TeleManager::setCurrentUuid( sUuid
);
254 css::uno::Reference
< css::frame::XDesktop2
> xLoader
= css::frame::Desktop::create(
255 ::comphelper::getProcessComponentContext() );
256 css::uno::Sequence
< css::beans::PropertyValue
> args(0);
257 css::uno::Reference
< css::util::XCloseable
> xDoc(
258 xLoader
->loadComponentFromURL( rStr
, "_blank", 0, args
),
259 css::uno::UNO_QUERY_THROW
);
261 catch ( const css::uno::Exception
& e
)
263 // Expected to happen for unit test
264 SAL_WARN( "tubes", "TeleManager_fileReceived: exception when loading: " << e
.Message
);
268 static void TeleManager_TransferDone( EmpathyFTHandler
*handler
, TpFileTransferChannel
*, gpointer
)
270 SAL_INFO( "tubes", "TeleManager_TransferDone: hooray!");
271 GFile
*gfile
= empathy_ft_handler_get_gfile( handler
);
272 char *uri
= g_file_get_uri( gfile
);
273 OUString
aUri( OUString::createFromAscii( uri
) );
276 TeleManager_fileReceived( aUri
, empathy_ft_handler_get_description( handler
) );
278 g_object_unref( handler
);
281 static void TeleManager_TransferError( EmpathyFTHandler
*handler
, const GError
*error
, void*)
283 SAL_INFO( "tubes", "TeleManager_TransferError: " << error
->message
);
285 g_object_unref( handler
);
288 static void lcl_IncomingHandlerReady (
289 EmpathyFTHandler
* pHandler
,
291 void* /*pUserData*/ )
295 SAL_INFO ("tubes", "failed to prepare incoming transfer: " << pError
->message
);
296 g_object_unref( pHandler
);
300 /* The filename suggested by the sender, which in our case is the last bit
301 * of whatever URI got passed to ::sendFile()
303 const char* pFileName
= empathy_ft_handler_get_filename( pHandler
);
304 char* pLocalUri
= g_strdup_printf( "file:///tmp/LibreOffice-collab-%s", pFileName
);
305 GFile
*pDestination
= g_file_new_for_uri( pLocalUri
);
308 empathy_ft_handler_incoming_set_destination( pHandler
, pDestination
);
309 g_object_unref( pDestination
);
311 g_signal_connect( pHandler
, "transfer-done", G_CALLBACK (TeleManager_TransferDone
), NULL
);
312 g_signal_connect( pHandler
, "transfer-error", G_CALLBACK (TeleManager_TransferError
), NULL
);
313 SAL_INFO ("tubes", "lcl_IncomingHandlerReady: starting file transfer..");
314 empathy_ft_handler_start_transfer( pHandler
);
317 static void TeleManager_FileTransferHandler(
318 TpSimpleHandler
* /*handler*/,
319 TpAccount
* /*Account*/,
320 TpConnection
* /*connection*/,
322 GList
* /*requests_satisfied*/,
323 gint64
/*user_action_time*/,
324 TpHandleChannelsContext
* pContext
,
325 gpointer
/*pUserData*/ )
327 bool aAccepted
= false;
328 INFO_LOGGER_F( "TeleManager_FileTransferHandler");
330 for (GList
* p
= pChannels
; p
; p
= p
->next
)
332 TpChannel
* pChannel
= TP_CHANNEL(p
->data
);
334 SAL_INFO( "tubes", "TeleManager_FileTransferHandler: incoming dbus channel: "
335 << tp_channel_get_identifier( pChannel
));
337 if (TP_IS_FILE_TRANSFER_CHANNEL( pChannel
))
339 SAL_INFO( "tubes", "accepting file transfer");
340 empathy_ft_handler_new_incoming( TP_FILE_TRANSFER_CHANNEL( pChannel
),
341 lcl_IncomingHandlerReady
, NULL
);
346 SAL_INFO( "tubes", "ignored");
351 tp_handle_channels_context_accept( pContext
);
354 GError
*pError
= g_error_new_literal( TP_ERRORS
, TP_ERROR_CONFUSED
,
355 "None of these channels were file transfers; "
356 "why did the Channel Dispatcher give them to us?");
357 tp_handle_channels_context_fail( pContext
, pError
);
358 g_clear_error (&pError
);
362 // - TeleManagerImpl -
364 void TeleManagerImpl::ChannelReadyHandler(
365 GObject
* pSourceObject
,
366 GAsyncResult
* pResult
,
370 INFO_LOGGER_F( "TeleManagerImpl::ChannelReadyHandler");
372 TeleConference
* pConference
= reinterpret_cast<TeleConference
*>(pUserData
);
373 SAL_WARN_IF( !pConference
, "tubes", "TeleManagerImpl::ChannelReadyHandler: no conference");
377 mbChannelReadyHandlerInvoked
= true;
379 TpAccountChannelRequest
* pChannelRequest
= TP_ACCOUNT_CHANNEL_REQUEST( pSourceObject
);
380 GError
* pError
= NULL
;
381 TpChannel
* pChannel
= tp_account_channel_request_create_and_handle_channel_finish(
382 pChannelRequest
, pResult
, NULL
, &pError
);
385 // "account isn't Enabled" means just that..
386 /* FIXME: detect and handle, domain=132, code=3 */
387 SAL_WARN( "tubes", "TeleManagerImpl::ChannelReadyHandler: no channel: " << pError
->message
);
388 g_error_free( pError
);
391 pConference
->setChannel( tp_account_channel_request_get_account( pChannelRequest
),
392 TP_DBUS_TUBE_CHANNEL (pChannel
));
393 pConference
->offerTube();
396 void TeleManagerImpl::AccountManagerReadyHandler(
397 GObject
* pSourceObject
,
398 GAsyncResult
* pResult
,
399 gpointer
/*pUserData*/
402 INFO_LOGGER_F( "TeleManagerImpl::AccountManagerReadyHandler");
404 GError
* pError
= NULL
;
405 gboolean bPrepared
= tp_proxy_prepare_finish( pSourceObject
, pResult
, &pError
);
406 SAL_WARN_IF( !bPrepared
, "tubes", "TeleManagerImpl::AccountManagerReadyHandler: not prepared");
407 if (!bPrepared
|| pError
)
409 SAL_WARN_IF( pError
, "tubes", "TeleManagerImpl::AccountManagerReadyHandler: error: " << pError
->message
);
410 g_error_free( pError
);
413 mbAccountManagerReady
= bPrepared
;
414 mbAccountManagerReadyHandlerInvoked
= true;
419 bool TeleManager::init( bool bListen
)
421 if (createAccountManager())
423 if (bListen
&& !registerClients())
424 SAL_WARN( "tubes", "TeleManager::init: Could not register client handlers." );
429 SAL_WARN( "tubes", "TeleManager::init: Could not create AccountManager." );
434 void TeleManager::finalize()
439 bool TeleManager::createAccountManager()
441 INFO_LOGGER_F( "TeleManager::createAccountManager");
443 MutexGuard
aGuard( GetMutex());
445 SAL_INFO_IF( pImpl
->mpAccountManager
, "tubes", "TeleManager::createAccountManager: already connected");
446 if (pImpl
->mpAccountManager
)
449 GError
* pError
= NULL
;
450 TpDBusDaemon
*pDBus
= tp_dbus_daemon_dup( &pError
);
451 SAL_WARN_IF( !pDBus
, "tubes", "TeleManager::createAccountManager: no dbus daemon");
452 if (!pDBus
|| pError
)
454 SAL_WARN_IF( pError
, "tubes", "TeleManager::createAccountManager: dbus daemon error: " << pError
->message
);
455 g_error_free( pError
);
459 pImpl
->mpFactory
= TP_SIMPLE_CLIENT_FACTORY( tp_automatic_client_factory_new( pDBus
));
460 g_object_unref( pDBus
);
461 SAL_WARN_IF( !pImpl
->mpFactory
, "tubes", "TeleManager::createAccountManager: no client factory");
462 if (!pImpl
->mpFactory
)
465 /* Tell the client factory (which creates and prepares proxy objects) to
466 * get the features we need ready before giving us any objects.
468 /* We need every online account's connection object to be available... */
469 tp_simple_client_factory_add_account_features_varargs (pImpl
->mpFactory
,
470 TP_ACCOUNT_FEATURE_CONNECTION
,
472 /* ...and we want those connection objects to have the contact list
474 tp_simple_client_factory_add_connection_features_varargs (pImpl
->mpFactory
,
475 TP_CONNECTION_FEATURE_CONTACT_LIST
,
477 /* ...and those contacts should have their alias and their capabilities
480 tp_simple_client_factory_add_contact_features_varargs (pImpl
->mpFactory
,
481 TP_CONTACT_FEATURE_ALIAS
,
482 TP_CONTACT_FEATURE_AVATAR_DATA
,
483 TP_CONTACT_FEATURE_CAPABILITIES
,
484 TP_CONTACT_FEATURE_PRESENCE
,
485 TP_CONTACT_FEATURE_INVALID
);
487 pImpl
->mpAccountManager
= tp_account_manager_new_with_factory (pImpl
->mpFactory
);
488 tp_account_manager_set_default (pImpl
->mpAccountManager
);
490 pImpl
->mbAccountManagerReadyHandlerInvoked
= false;
491 tp_proxy_prepare_async( pImpl
->mpAccountManager
, NULL
, TeleManagerImpl::AccountManagerReadyHandler
, NULL
);
492 while (!pImpl
->mbAccountManagerReadyHandlerInvoked
)
493 g_main_context_iteration( NULL
, TRUE
);
495 return pImpl
->mbAccountManagerReady
;
498 bool TeleManager::registerClients()
500 INFO_LOGGER_F( "TeleManager::registerClients");
502 MutexGuard
aGuard( GetMutex());
504 /* TODO: also check whether client could be registered and retry if not? */
505 SAL_INFO_IF( pImpl
->mpClient
&& pImpl
->mpFileTransferClient
, "tubes", "TeleManager::registerClients: already registered");
506 if (pImpl
->mpClient
&& pImpl
->mpFileTransferClient
)
509 pImpl
->mpClient
= tp_simple_handler_new_with_factory(
510 pImpl
->mpFactory
, // factory
511 FALSE
, // bypass_approval
513 getFullClientName().getStr(), // name
515 TeleManager_DBusChannelHandler
, // callback
519 SAL_WARN_IF( !pImpl
->mpClient
, "tubes", "TeleManager::registerClients: no client");
520 if (!pImpl
->mpClient
)
523 // Setup client handler for buddy channels with our service.
524 tp_base_client_take_handler_filter( pImpl
->mpClient
,
526 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
527 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_CONTACT
,
528 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
531 /* TODO: setup filters for LibreOfficeCalc, LibreOfficeWriter, ... */
533 // Setup client handler for MUC channels with our service.
534 tp_base_client_take_handler_filter( pImpl
->mpClient
,
536 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
537 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_ROOM
,
538 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
541 GError
* pError
= NULL
;
542 if (!tp_base_client_register( pImpl
->mpClient
, &pError
))
544 SAL_WARN( "tubes", "TeleManager::registerClients: error registering client handler: " << pError
->message
);
545 g_error_free( pError
);
549 SAL_INFO( "tubes", "TeleManager::registerClients: bus name: " << tp_base_client_get_bus_name( pImpl
->mpClient
));
550 SAL_INFO( "tubes", "TeleManager::registerClients: object path: " << tp_base_client_get_object_path( pImpl
->mpClient
));
552 /* Register a second "head" for incoming file transfers. This uses a more
553 * specific filter than Empathy's handler by matching on the file
554 * transfer's ServiceName property, and uses bypass_approval to ensure the
555 * user isn't prompted before the channel gets passed to us.
557 pImpl
->mpFileTransferClient
= tp_simple_handler_new_with_factory (
558 pImpl
->mpFactory
, // factory
559 TRUE
, // bypass_approval
561 getFullClientName().getStr(), // name
562 TRUE
, // uniquify to get a different bus name to the main client, above
563 TeleManager_FileTransferHandler
, // callback
567 tp_base_client_take_handler_filter( pImpl
->mpFileTransferClient
,
569 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER
,
570 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_CONTACT
,
571 TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
574 if (!tp_base_client_register( pImpl
->mpFileTransferClient
, &pError
))
576 /* This shouldn't fail if registering the main handler succeeded */
577 SAL_WARN( "tubes", "TeleManager::registerClients: error registering file transfer handler: " << pError
->message
);
578 g_error_free( pError
);
585 TeleConference
* TeleManager::startDemoSession()
587 INFO_LOGGER_F( "TeleManager::startDemoSession");
589 TeleConference
* pConference
= new TeleConference( NULL
, NULL
, "demo" );
590 registerDemoConference( pConference
);
595 /* TODO: factor out common code with startBuddySession() */
596 TeleConference
* TeleManager::startGroupSession( TpAccount
*pAccount
,
597 const OUString
& rUConferenceRoom
,
598 const OUString
& rUConferenceServer
)
600 INFO_LOGGER_F( "TeleManager::startGroupSession");
602 OString
aSessionId( TeleManager::createUuid());
604 /* FIXME: does this work at all _creating_ a MUC? */
605 // Use conference and server if given, else create conference.
606 OString
aConferenceRoom( OUStringToOString( rUConferenceRoom
, RTL_TEXTENCODING_UTF8
));
607 OString
aConferenceServer( OUStringToOString( rUConferenceServer
, RTL_TEXTENCODING_UTF8
));
608 OStringBuffer
aBuf(64);
609 if (!aConferenceRoom
.isEmpty() && !aConferenceServer
.isEmpty())
610 aBuf
.append( aConferenceRoom
).append( '@').append( aConferenceServer
);
613 aBuf
.append( aSessionId
);
614 if (!aConferenceServer
.isEmpty())
615 aBuf
.append( '@').append( aConferenceServer
);
616 /* FIXME: else? bail out? we have only a session ID without server then */
618 OString
aTarget( aBuf
.makeStringAndClear());
620 SAL_INFO( "tubes", "TeleManager::startGroupSession: creating channel request from "
621 << tp_account_get_path_suffix( pAccount
) << " to " << aTarget
.getStr() );
624 GHashTable
* pRequest
= tp_asv_new(
625 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
626 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, TP_TYPE_HANDLE
, TP_HANDLE_TYPE_ROOM
,
627 TP_PROP_CHANNEL_TARGET_ID
, G_TYPE_STRING
, aTarget
.getStr(),
628 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
631 TpAccountChannelRequest
* pChannelRequest
= tp_account_channel_request_new(
632 pAccount
, pRequest
, TP_USER_ACTION_TIME_NOT_USER_ACTION
);
633 SAL_WARN_IF( !pChannelRequest
, "tubes", "TeleManager::startGroupSession: no channel");
634 if (!pChannelRequest
)
636 g_hash_table_unref( pRequest
);
640 pImpl
->mbChannelReadyHandlerInvoked
= false;
642 TeleConference
* pConference
= new TeleConference( NULL
, NULL
, aSessionId
);
644 tp_account_channel_request_create_and_handle_channel_async(
645 pChannelRequest
, NULL
, TeleManagerImpl::ChannelReadyHandler
, pConference
);
647 while (!pImpl
->mbChannelReadyHandlerInvoked
)
648 g_main_context_iteration( NULL
, TRUE
);
650 g_object_unref( pChannelRequest
);
651 g_hash_table_unref( pRequest
);
653 if (!pConference
->isReady())
659 static void lcl_ensureLegacyChannel( TpAccount
* pAccount
, TpContact
* pBuddy
)
661 /* This is a workaround for a Telepathy bug.
662 * <https://bugs.libreoffice.org/show_bug.cgi?id=47760>. The first time you
663 * request a tube to a contact on an account, you actually get two channels
664 * back: the tube you asked for, along with a legacy Channel.Type.Tubes
665 * object. This breaks create_and_handle_channel_async(), which expects to
666 * only get one channel back.
668 * To work around this, we make sure the legacy Tubes channel already
669 * exists before we request the channel we actually want. We don't actually
670 * have to wait for this request to succeed - we fire it off and forget
673 GHashTable
* pRequest
= tp_asv_new(
674 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_TUBES
,
675 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, TP_TYPE_HANDLE
, TP_HANDLE_TYPE_CONTACT
,
676 TP_PROP_CHANNEL_TARGET_ID
, G_TYPE_STRING
, tp_contact_get_identifier (pBuddy
),
678 TpAccountChannelRequest
* pChannelRequest
= tp_account_channel_request_new(
679 pAccount
, pRequest
, TP_USER_ACTION_TIME_NOT_USER_ACTION
);
680 tp_account_channel_request_ensure_channel_async( pChannelRequest
, NULL
,
682 g_object_unref( pChannelRequest
);
683 g_hash_table_unref( pRequest
);
686 /* TODO: factor out common code with startGroupSession() */
687 TeleConference
* TeleManager::startBuddySession( TpAccount
*pAccount
, TpContact
*pBuddy
)
689 INFO_LOGGER_F( "TeleManager::startBuddySession");
691 lcl_ensureLegacyChannel( pAccount
, pBuddy
);
693 const char *pIdentifier
= tp_contact_get_identifier( pBuddy
);
694 SAL_INFO( "tubes", "TeleManager::startBuddySession: creating channel request from "
695 << tp_account_get_path_suffix( pAccount
)
696 << " to " << pIdentifier
);
698 GHashTable
* pRequest
= tp_asv_new(
699 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
700 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, TP_TYPE_HANDLE
, TP_HANDLE_TYPE_CONTACT
,
701 TP_PROP_CHANNEL_TARGET_ID
, G_TYPE_STRING
, pIdentifier
,
702 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
705 TpAccountChannelRequest
* pChannelRequest
= tp_account_channel_request_new(
706 pAccount
, pRequest
, TP_USER_ACTION_TIME_NOT_USER_ACTION
);
707 SAL_WARN_IF( !pChannelRequest
, "tubes", "TeleManager::startBuddySession: no channel");
708 if (!pChannelRequest
)
710 g_hash_table_unref( pRequest
);
714 pImpl
->mbChannelReadyHandlerInvoked
= false;
716 TeleConference
* pConference
= new TeleConference( NULL
, NULL
, createUuid(), true );
718 tp_account_channel_request_create_and_handle_channel_async(
719 pChannelRequest
, NULL
, TeleManagerImpl::ChannelReadyHandler
, pConference
);
721 while (!pImpl
->mbChannelReadyHandlerInvoked
)
722 g_main_context_iteration( NULL
, TRUE
);
724 g_object_unref( pChannelRequest
);
725 g_hash_table_unref( pRequest
);
727 if (!pConference
->isReady())
733 static bool tb_presence_is_online( const TpConnectionPresenceType
& presence
)
737 case TP_CONNECTION_PRESENCE_TYPE_UNSET
:
738 case TP_CONNECTION_PRESENCE_TYPE_OFFLINE
:
740 case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE
:
741 case TP_CONNECTION_PRESENCE_TYPE_AWAY
:
742 case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY
:
743 case TP_CONNECTION_PRESENCE_TYPE_HIDDEN
:
744 case TP_CONNECTION_PRESENCE_TYPE_BUSY
:
746 case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN
:
747 case TP_CONNECTION_PRESENCE_TYPE_ERROR
:
753 static bool tb_contact_is_online( TpContact
*contact
)
755 return tb_presence_is_online (tp_contact_get_presence_type (contact
));
758 static void presence_changed_cb( TpContact
* /* contact */,
761 gchar
* /* message */,
762 gpointer
/* pContactList*/ )
764 TeleManager::displayAllContacts();
767 AccountContactPairV
TeleManager::getContacts()
769 AccountContactPairV pairs
;
770 #pragma GCC diagnostic push
771 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
772 for (GList
*accounts
= tp_account_manager_get_valid_accounts (pImpl
->mpAccountManager
);
773 accounts
!= NULL
; accounts
= g_list_delete_link (accounts
, accounts
))
775 TpAccount
*account
= reinterpret_cast<TpAccount
*>(accounts
->data
);
776 TpConnection
*connection
= tp_account_get_connection (account
);
778 /* Verify account is online and received its contact list. If state is not
779 * SUCCESS this means we didn't received the roster from server yet and
780 * we would have to wait for the "notify:contact-list-state" signal. */
781 if (connection
== NULL
|| tp_connection_get_contact_list_state (connection
) !=
782 TP_CONTACT_LIST_STATE_SUCCESS
)
785 TpContact
*self
= tp_connection_get_self_contact (connection
);
786 GPtrArray
*contacts
= tp_connection_dup_contact_list (connection
);
787 for (guint i
= 0; i
< contacts
->len
; i
++)
789 TpContact
*contact
= reinterpret_cast<TpContact
*>(g_ptr_array_index (contacts
, i
));
790 if (pImpl
->maRegisteredContacts
.find (contact
) == pImpl
->maRegisteredContacts
.end())
792 pImpl
->maRegisteredContacts
.insert (contact
);
793 g_signal_connect (contact
, "presence-changed",
794 G_CALLBACK (presence_changed_cb
), NULL
);
796 if (contact
!= self
&& tb_contact_is_online (contact
))
798 g_object_ref (account
);
799 g_object_ref (contact
);
801 AccountContactPair
pair(account
, contact
);
802 pairs
.push_back(pair
);
805 g_ptr_array_unref (contacts
);
807 #pragma GCC diagnostic pop
811 OString
TeleManager::getFullClientName()
813 OStringBuffer
aBuf(64);
814 aBuf
.append( LIBO_CLIENT_SUFFIX
).append( pImpl
->msNameSuffix
);
815 return aBuf
.makeStringAndClear();
818 OString
TeleManager::getFullServiceName()
820 OStringBuffer
aBuf(64);
821 aBuf
.append( LIBO_DTUBE_SERVICE
).append( pImpl
->msNameSuffix
);
822 return aBuf
.makeStringAndClear();
825 OString
TeleManager::getFullObjectPath()
827 OStringBuffer
aBuf(64);
828 aBuf
.append( '/').append( LIBO_DTUBE_SERVICE
).append( pImpl
->msNameSuffix
);
829 OString
aStr( aBuf
.makeStringAndClear().replace( '.', '/'));
833 OString
TeleManager::createUuid()
836 rtl_createUuid( nId
, 0, sal_True
);
838 for (size_t i
=0; i
<16; ++i
)
840 snprintf( aBuf
+2*i
, 3, "%02x", (unsigned char)nId
[i
]);
843 return OString( aBuf
);
846 Mutex
& TeleManager::GetMutex()
848 static Mutex
* pMutex
= NULL
;
851 MutexGuard
aGuard( Mutex::getGlobalMutex());
858 void TeleManager::addSuffixToNames( const char* pName
)
860 pImpl
->msNameSuffix
= pName
;
863 // - TeleManagerImpl -
865 TeleManagerImpl::TeleManagerImpl()
869 mpFileTransferClient( NULL
),
870 mpAccountManager( NULL
)
872 #if !GLIB_CHECK_VERSION(2,36,0)
877 TeleManagerImpl::~TeleManagerImpl()
879 // There may be unused conferences left opened, so close them.
880 // It should not make a problem to close already closed conference.
881 for (MapStringConference::iterator it
= maAcceptedConferences
.begin();
882 it
!= maAcceptedConferences
.end(); ++it
)
886 tp_base_client_unregister( mpClient
);
887 g_object_unref( mpClient
);
889 if (mpFileTransferClient
)
891 tp_base_client_unregister( mpFileTransferClient
);
892 g_object_unref( mpFileTransferClient
);
895 g_object_unref( mpFactory
);
896 if (mpAccountManager
)
897 g_object_unref( mpAccountManager
);
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */