bump product version to 5.0.4.1
[LibreOffice.git] / tubes / source / manager.cxx
blob467baf5802289b3d0c387812b0adf3c862e51aa2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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>
26 #include <rtl/uuid.h>
28 #include <telepathy-glib/telepathy-glib.h>
29 #include <stdio.h>
30 #include <map>
31 #include <set>
33 #if defined SAL_LOG_INFO
34 namespace
36 struct InfoLogger
38 const void* mpThat;
39 const char* mpMethod;
40 explicit InfoLogger( const void* pThat, const char* pMethod )
42 mpThat( pThat),
43 mpMethod( pMethod)
45 SAL_INFO( "tubes.method", mpThat << " entering " << mpMethod);
47 ~InfoLogger()
49 SAL_INFO( "tubes.method", mpThat << " leaving " << mpMethod);
53 #define INFO_LOGGER_F(s) InfoLogger aLogger(0,(s))
54 #else
55 #define INFO_LOGGER_F(s)
56 #endif // SAL_LOG_INFO
58 using namespace osl;
60 /** Refcounted singleton implementation class. */
61 class TeleManagerImpl
63 public:
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;
72 OString msNameSuffix;
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;
82 TeleManagerImpl();
83 ~TeleManagerImpl();
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*/,
95 TpAccount* pAccount,
96 TpConnection* /*connection*/,
97 GList* pChannels,
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);
109 if (!pChannel)
110 continue;
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");
118 aAccepted = true;
120 TeleConference* pConference = new TeleConference( pAccount, TP_DBUS_TUBE_CHANNEL( pChannel ) );
121 pConference->acceptTube();
122 TeleManager::addConference( pConference );
124 else
126 SAL_INFO( "tubes", "ignored");
130 if (aAccepted)
131 tp_handle_channels_context_accept( pContext);
132 else
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);
142 // - TeleManager -
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();
165 return pConference;
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 );
243 if (sUuid == "demo")
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 ) );
274 g_free( 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,
290 GError* pError,
291 void* /*pUserData*/ )
293 if (pError)
295 SAL_INFO ("tubes", "failed to prepare incoming transfer: " << pError->message);
296 g_object_unref( pHandler);
297 return;
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);
306 g_free( 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*/,
321 GList* pChannels,
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);
342 aAccepted = true;
344 else
346 SAL_INFO( "tubes", "ignored");
350 if (aAccepted)
351 tp_handle_channels_context_accept( pContext);
352 else
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,
367 gpointer pUserData
370 INFO_LOGGER_F( "TeleManagerImpl::ChannelReadyHandler");
372 TeleConference* pConference = reinterpret_cast<TeleConference*>(pUserData);
373 SAL_WARN_IF( !pConference, "tubes", "TeleManagerImpl::ChannelReadyHandler: no conference");
374 if (!pConference)
375 return;
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);
383 if (!pChannel)
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);
389 return;
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;
417 // - TeleManager -
419 bool TeleManager::init( bool bListen )
421 if (createAccountManager())
423 if (bListen && !registerClients())
424 SAL_WARN( "tubes", "TeleManager::init: Could not register client handlers." );
426 return true;
428 else
429 SAL_WARN( "tubes", "TeleManager::init: Could not create AccountManager." );
431 return false;
434 void TeleManager::finalize()
436 delete pImpl;
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)
447 return true;
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);
456 return false;
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)
463 return false;
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
473 * available... */
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
478 * available.
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)
507 return true;
509 pImpl->mpClient = tp_simple_handler_new_with_factory(
510 pImpl->mpFactory, // factory
511 FALSE, // bypass_approval
512 FALSE, // requests
513 getFullClientName().getStr(), // name
514 FALSE, // uniquify
515 TeleManager_DBusChannelHandler, // callback
516 NULL, // user_data
517 NULL // destroy
519 SAL_WARN_IF( !pImpl->mpClient, "tubes", "TeleManager::registerClients: no client");
520 if (!pImpl->mpClient)
521 return false;
523 // Setup client handler for buddy channels with our service.
524 tp_base_client_take_handler_filter( pImpl->mpClient,
525 tp_asv_new(
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(),
529 NULL));
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,
535 tp_asv_new(
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(),
539 NULL));
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);
546 return false;
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
560 FALSE, // requests
561 getFullClientName().getStr(), // name
562 TRUE, // uniquify to get a different bus name to the main client, above
563 TeleManager_FileTransferHandler, // callback
564 NULL, // user_data
565 NULL // destroy
567 tp_base_client_take_handler_filter( pImpl->mpFileTransferClient,
568 tp_asv_new(
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(),
572 NULL));
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);
579 return false;
582 return true;
585 TeleConference* TeleManager::startDemoSession()
587 INFO_LOGGER_F( "TeleManager::startDemoSession");
589 TeleConference* pConference = new TeleConference( NULL, NULL, "demo" );
590 registerDemoConference( pConference );
592 return 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);
611 else
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() );
623 // MUC request
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(),
629 NULL);
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);
637 return NULL;
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())
654 return NULL;
656 return pConference;
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
671 * about it.
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),
677 NULL);
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,
681 NULL, NULL, 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(),
703 NULL);
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);
711 return NULL;
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())
728 return NULL;
730 return pConference;
733 static bool tb_presence_is_online( const TpConnectionPresenceType& presence )
735 switch (presence)
737 case TP_CONNECTION_PRESENCE_TYPE_UNSET:
738 case TP_CONNECTION_PRESENCE_TYPE_OFFLINE:
739 return false;
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:
745 return true;
746 case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN:
747 case TP_CONNECTION_PRESENCE_TYPE_ERROR:
748 default:
749 return false;
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 */,
759 guint /* type */,
760 gchar* /* status */,
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)
783 continue;
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
808 return pairs;
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( '.', '/'));
830 return aStr;
833 OString TeleManager::createUuid()
835 sal_uInt8 nId[16];
836 rtl_createUuid( nId, 0, sal_True);
837 char aBuf[33];
838 for (size_t i=0; i<16; ++i)
840 snprintf( aBuf+2*i, 3, "%02x", (unsigned char)nId[i]);
842 aBuf[32] = 0;
843 return OString( aBuf);
846 Mutex& TeleManager::GetMutex()
848 static Mutex* pMutex = NULL;
849 if (!pMutex)
851 MutexGuard aGuard( Mutex::getGlobalMutex());
852 if (!pMutex)
853 pMutex = new Mutex;
855 return *pMutex;
858 void TeleManager::addSuffixToNames( const char* pName )
860 pImpl->msNameSuffix = pName;
863 // - TeleManagerImpl -
865 TeleManagerImpl::TeleManagerImpl()
867 mpFactory( NULL),
868 mpClient( NULL),
869 mpFileTransferClient( NULL),
870 mpAccountManager( NULL)
872 #if !GLIB_CHECK_VERSION(2,36,0)
873 g_type_init();
874 #endif
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)
883 it->second->close();
884 if (mpClient)
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);
894 if (mpFactory)
895 g_object_unref( mpFactory);
896 if (mpAccountManager)
897 g_object_unref( mpAccountManager);
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */