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
62 /** Refcounted singleton implementation class. */
66 TpSimpleClientFactory
* mpFactory
;
67 TpBaseClient
* mpClient
;
68 TpBaseClient
* mpFileTransferClient
;
69 TpAccountManager
* mpAccountManager
;
70 static bool mbAccountManagerReady
;
71 static bool mbAccountManagerReadyHandlerInvoked
;
72 static bool mbChannelReadyHandlerInvoked
;
73 OString msCurrentUUID
;
75 typedef std::map
< OString
, TeleConference
* > MapStringConference
;
76 MapStringConference maAcceptedConferences
;
77 typedef std::set
< TeleConference
* > DemoConferences
;
78 DemoConferences maDemoConferences
;
79 typedef std::set
< Collaboration
* > Collaborations
;
80 Collaborations maCollaborations
;
81 typedef std::set
< TpContact
* > RegisteredContacts
;
82 RegisteredContacts maRegisteredContacts
;
86 static void AccountManagerReadyHandler( GObject
* pSourceObject
, GAsyncResult
* pResult
, gpointer pUserData
);
87 static void ChannelReadyHandler( GObject
* pSourceObject
, GAsyncResult
* pResult
, gpointer pUserData
);
90 TeleManagerImpl
* TeleManager::pImpl
= new TeleManagerImpl();
91 bool TeleManagerImpl::mbAccountManagerReady
;
92 bool TeleManagerImpl::mbAccountManagerReadyHandlerInvoked
;
93 bool TeleManagerImpl::mbChannelReadyHandlerInvoked
;
95 static void TeleManager_DBusChannelHandler(
96 TpSimpleHandler
* /*handler*/,
98 TpConnection
* /*connection*/,
100 GList
* /*requests_satisfied*/,
101 gint64
/*user_action_time*/,
102 TpHandleChannelsContext
* pContext
,
103 gpointer
/*pUserData*/ )
105 bool aAccepted
= false;
106 INFO_LOGGER_F( "TeleManager_DBusChannelHandler");
108 for (GList
* p
= pChannels
; p
; p
= p
->next
)
110 TpChannel
* pChannel
= TP_CHANNEL(p
->data
);
114 SAL_INFO( "tubes", "TeleManager_DBusChannelHandler: incoming dbus channel: "
115 << tp_channel_get_identifier( pChannel
));
117 if (TP_IS_DBUS_TUBE_CHANNEL( pChannel
))
119 SAL_INFO( "tubes", "accepting");
122 TeleConference
* pConference
= new TeleConference( pAccount
, TP_DBUS_TUBE_CHANNEL( pChannel
) );
123 pConference
->acceptTube();
124 TeleManager::addConference( pConference
);
128 SAL_INFO( "tubes", "ignored");
133 tp_handle_channels_context_accept( pContext
);
136 GError
*pError
= g_error_new_literal( TP_ERRORS
, TP_ERROR_CONFUSED
,
137 "None of these channels were LibreOffice D-Bus tubes; "
138 "why did the Channel Dispatcher give them to us?");
139 tp_handle_channels_context_fail( pContext
, pError
);
140 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
= OString();
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 void TeleManagerImpl::ChannelReadyHandler(
363 GObject
* pSourceObject
,
364 GAsyncResult
* pResult
,
368 INFO_LOGGER_F( "TeleManagerImpl::ChannelReadyHandler");
370 TeleConference
* pConference
= reinterpret_cast<TeleConference
*>(pUserData
);
371 SAL_WARN_IF( !pConference
, "tubes", "TeleManagerImpl::ChannelReadyHandler: no conference");
375 mbChannelReadyHandlerInvoked
= true;
377 TpAccountChannelRequest
* pChannelRequest
= TP_ACCOUNT_CHANNEL_REQUEST( pSourceObject
);
378 GError
* pError
= NULL
;
379 TpChannel
* pChannel
= tp_account_channel_request_create_and_handle_channel_finish(
380 pChannelRequest
, pResult
, NULL
, &pError
);
383 // "account isn't Enabled" means just that..
384 /* FIXME: detect and handle, domain=132, code=3 */
385 SAL_WARN( "tubes", "TeleManagerImpl::ChannelReadyHandler: no channel: " << pError
->message
);
386 g_error_free( pError
);
389 pConference
->setChannel( tp_account_channel_request_get_account( pChannelRequest
),
390 TP_DBUS_TUBE_CHANNEL (pChannel
));
391 pConference
->offerTube();
394 void TeleManagerImpl::AccountManagerReadyHandler(
395 GObject
* pSourceObject
,
396 GAsyncResult
* pResult
,
397 gpointer
/*pUserData*/
400 INFO_LOGGER_F( "TeleManagerImpl::AccountManagerReadyHandler");
402 GError
* pError
= NULL
;
403 gboolean bPrepared
= tp_proxy_prepare_finish( pSourceObject
, pResult
, &pError
);
404 SAL_WARN_IF( !bPrepared
, "tubes", "TeleManagerImpl::AccountManagerReadyHandler: not prepared");
405 if (!bPrepared
|| pError
)
407 SAL_WARN_IF( pError
, "tubes", "TeleManagerImpl::AccountManagerReadyHandler: error: " << pError
->message
);
408 g_error_free( pError
);
411 mbAccountManagerReady
= bPrepared
;
412 mbAccountManagerReadyHandlerInvoked
= true;
415 bool TeleManager::init( bool bListen
)
417 if (createAccountManager())
419 if (bListen
&& !registerClients())
420 SAL_WARN( "tubes", "TeleManager::init: Could not register client handlers." );
425 SAL_WARN( "tubes", "TeleManager::init: Could not create AccountManager." );
430 void TeleManager::finalize()
435 bool TeleManager::createAccountManager()
437 INFO_LOGGER_F( "TeleManager::createAccountManager");
439 MutexGuard
aGuard( GetMutex());
441 SAL_INFO_IF( pImpl
->mpAccountManager
, "tubes", "TeleManager::createAccountManager: already connected");
442 if (pImpl
->mpAccountManager
)
445 GError
* pError
= NULL
;
446 TpDBusDaemon
*pDBus
= tp_dbus_daemon_dup( &pError
);
447 SAL_WARN_IF( !pDBus
, "tubes", "TeleManager::createAccountManager: no dbus daemon");
448 if (!pDBus
|| pError
)
450 SAL_WARN_IF( pError
, "tubes", "TeleManager::createAccountManager: dbus daemon error: " << pError
->message
);
451 g_error_free( pError
);
455 pImpl
->mpFactory
= TP_SIMPLE_CLIENT_FACTORY( tp_automatic_client_factory_new( pDBus
));
456 g_object_unref( pDBus
);
457 SAL_WARN_IF( !pImpl
->mpFactory
, "tubes", "TeleManager::createAccountManager: no client factory");
458 if (!pImpl
->mpFactory
)
461 /* Tell the client factory (which creates and prepares proxy objects) to
462 * get the features we need ready before giving us any objects.
464 /* We need every online account's connection object to be available... */
465 tp_simple_client_factory_add_account_features_varargs (pImpl
->mpFactory
,
466 TP_ACCOUNT_FEATURE_CONNECTION
,
468 /* ...and we want those connection objects to have the contact list
470 tp_simple_client_factory_add_connection_features_varargs (pImpl
->mpFactory
,
471 TP_CONNECTION_FEATURE_CONTACT_LIST
,
473 /* ...and those contacts should have their alias and their capabilities
476 tp_simple_client_factory_add_contact_features_varargs (pImpl
->mpFactory
,
477 TP_CONTACT_FEATURE_ALIAS
,
478 TP_CONTACT_FEATURE_AVATAR_DATA
,
479 TP_CONTACT_FEATURE_CAPABILITIES
,
480 TP_CONTACT_FEATURE_PRESENCE
,
481 TP_CONTACT_FEATURE_INVALID
);
483 pImpl
->mpAccountManager
= tp_account_manager_new_with_factory (pImpl
->mpFactory
);
484 tp_account_manager_set_default (pImpl
->mpAccountManager
);
486 pImpl
->mbAccountManagerReadyHandlerInvoked
= false;
487 tp_proxy_prepare_async( pImpl
->mpAccountManager
, NULL
, TeleManagerImpl::AccountManagerReadyHandler
, NULL
);
488 while (!pImpl
->mbAccountManagerReadyHandlerInvoked
)
489 g_main_context_iteration( NULL
, TRUE
);
491 return pImpl
->mbAccountManagerReady
;
494 bool TeleManager::registerClients()
496 INFO_LOGGER_F( "TeleManager::registerClients");
498 MutexGuard
aGuard( GetMutex());
500 /* TODO: also check whether client could be registered and retry if not? */
501 SAL_INFO_IF( pImpl
->mpClient
&& pImpl
->mpFileTransferClient
, "tubes", "TeleManager::registerClients: already registered");
502 if (pImpl
->mpClient
&& pImpl
->mpFileTransferClient
)
505 pImpl
->mpClient
= tp_simple_handler_new_with_factory(
506 pImpl
->mpFactory
, // factory
507 FALSE
, // bypass_approval
509 getFullClientName().getStr(), // name
511 TeleManager_DBusChannelHandler
, // callback
515 SAL_WARN_IF( !pImpl
->mpClient
, "tubes", "TeleManager::registerClients: no client");
516 if (!pImpl
->mpClient
)
519 // Setup client handler for buddy channels with our service.
520 tp_base_client_take_handler_filter( pImpl
->mpClient
,
522 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
523 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_CONTACT
,
524 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
527 /* TODO: setup filters for LibreOfficeCalc, LibreOfficeWriter, ... */
529 // Setup client handler for MUC channels with our service.
530 tp_base_client_take_handler_filter( pImpl
->mpClient
,
532 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
533 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_ROOM
,
534 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
537 GError
* pError
= NULL
;
538 if (!tp_base_client_register( pImpl
->mpClient
, &pError
))
540 SAL_WARN( "tubes", "TeleManager::registerClients: error registering client handler: " << pError
->message
);
541 g_error_free( pError
);
545 SAL_INFO( "tubes", "TeleManager::registerClients: bus name: " << tp_base_client_get_bus_name( pImpl
->mpClient
));
546 SAL_INFO( "tubes", "TeleManager::registerClients: object path: " << tp_base_client_get_object_path( pImpl
->mpClient
));
548 /* Register a second "head" for incoming file transfers. This uses a more
549 * specific filter than Empathy's handler by matching on the file
550 * transfer's ServiceName property, and uses bypass_approval to ensure the
551 * user isn't prompted before the channel gets passed to us.
553 pImpl
->mpFileTransferClient
= tp_simple_handler_new_with_factory (
554 pImpl
->mpFactory
, // factory
555 TRUE
, // bypass_approval
557 getFullClientName().getStr(), // name
558 TRUE
, // uniquify to get a different bus name to the main client, above
559 TeleManager_FileTransferHandler
, // callback
563 tp_base_client_take_handler_filter( pImpl
->mpFileTransferClient
,
565 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER
,
566 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, G_TYPE_UINT
, TP_HANDLE_TYPE_CONTACT
,
567 TP_PROP_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
570 if (!tp_base_client_register( pImpl
->mpFileTransferClient
, &pError
))
572 /* This shouldn't fail if registering the main handler succeeded */
573 SAL_WARN( "tubes", "TeleManager::registerClients: error registering file transfer handler: " << pError
->message
);
574 g_error_free( pError
);
581 TeleConference
* TeleManager::startDemoSession()
583 INFO_LOGGER_F( "TeleManager::startDemoSession");
585 TeleConference
* pConference
= new TeleConference( NULL
, NULL
, "demo" );
586 registerDemoConference( pConference
);
591 /* TODO: factor out common code with startBuddySession() */
592 TeleConference
* TeleManager::startGroupSession( TpAccount
*pAccount
,
593 const OUString
& rUConferenceRoom
,
594 const OUString
& rUConferenceServer
)
596 INFO_LOGGER_F( "TeleManager::startGroupSession");
598 OString
aSessionId( TeleManager::createUuid());
600 /* FIXME: does this work at all _creating_ a MUC? */
601 // Use conference and server if given, else create conference.
602 OString
aConferenceRoom( OUStringToOString( rUConferenceRoom
, RTL_TEXTENCODING_UTF8
));
603 OString
aConferenceServer( OUStringToOString( rUConferenceServer
, RTL_TEXTENCODING_UTF8
));
604 OStringBuffer
aBuf(64);
605 if (!aConferenceRoom
.isEmpty() && !aConferenceServer
.isEmpty())
606 aBuf
.append( aConferenceRoom
).append( '@').append( aConferenceServer
);
609 aBuf
.append( aSessionId
);
610 if (!aConferenceServer
.isEmpty())
611 aBuf
.append( '@').append( aConferenceServer
);
612 /* FIXME: else? bail out? we have only a session ID without server then */
614 OString
aTarget( aBuf
.makeStringAndClear());
616 SAL_INFO( "tubes", "TeleManager::startGroupSession: creating channel request from "
617 << tp_account_get_path_suffix( pAccount
) << " to " << aTarget
.getStr() );
620 GHashTable
* pRequest
= tp_asv_new(
621 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
622 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, TP_TYPE_HANDLE
, TP_HANDLE_TYPE_ROOM
,
623 TP_PROP_CHANNEL_TARGET_ID
, G_TYPE_STRING
, aTarget
.getStr(),
624 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
627 TpAccountChannelRequest
* pChannelRequest
= tp_account_channel_request_new(
628 pAccount
, pRequest
, TP_USER_ACTION_TIME_NOT_USER_ACTION
);
629 SAL_WARN_IF( !pChannelRequest
, "tubes", "TeleManager::startGroupSession: no channel");
630 if (!pChannelRequest
)
632 g_hash_table_unref( pRequest
);
636 pImpl
->mbChannelReadyHandlerInvoked
= false;
638 TeleConference
* pConference
= new TeleConference( NULL
, NULL
, aSessionId
);
640 tp_account_channel_request_create_and_handle_channel_async(
641 pChannelRequest
, NULL
, TeleManagerImpl::ChannelReadyHandler
, pConference
);
643 while (!pImpl
->mbChannelReadyHandlerInvoked
)
644 g_main_context_iteration( NULL
, TRUE
);
646 g_object_unref( pChannelRequest
);
647 g_hash_table_unref( pRequest
);
649 if (!pConference
->isReady())
656 static void lcl_ensureLegacyChannel( TpAccount
* pAccount
, TpContact
* pBuddy
)
658 /* This is a workaround for a Telepathy bug.
659 * <https://bugs.freedesktop.org/show_bug.cgi?id=47760>. The first time you
660 * request a tube to a contact on an account, you actually get two channels
661 * back: the tube you asked for, along with a legacy Channel.Type.Tubes
662 * object. This breaks create_and_handle_channel_async(), which expects to
663 * only get one channel back.
665 * To work around this, we make sure the legacy Tubes channel already
666 * exists before we request the channel we actually want. We don't actually
667 * have to wait for this request to succeed—we fire it off and forget about
670 GHashTable
* pRequest
= tp_asv_new(
671 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_TUBES
,
672 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, TP_TYPE_HANDLE
, TP_HANDLE_TYPE_CONTACT
,
673 TP_PROP_CHANNEL_TARGET_ID
, G_TYPE_STRING
, tp_contact_get_identifier (pBuddy
),
675 TpAccountChannelRequest
* pChannelRequest
= tp_account_channel_request_new(
676 pAccount
, pRequest
, TP_USER_ACTION_TIME_NOT_USER_ACTION
);
677 tp_account_channel_request_ensure_channel_async( pChannelRequest
, NULL
,
679 g_object_unref( pChannelRequest
);
680 g_hash_table_unref( pRequest
);
684 /* TODO: factor out common code with startGroupSession() */
685 TeleConference
* TeleManager::startBuddySession( TpAccount
*pAccount
, TpContact
*pBuddy
)
687 INFO_LOGGER_F( "TeleManager::startBuddySession");
689 lcl_ensureLegacyChannel( pAccount
, pBuddy
);
691 const char *pIdentifier
= tp_contact_get_identifier( pBuddy
);
692 SAL_INFO( "tubes", "TeleManager::startBuddySession: creating channel request from "
693 << tp_account_get_path_suffix( pAccount
)
694 << " to " << pIdentifier
);
696 GHashTable
* pRequest
= tp_asv_new(
697 TP_PROP_CHANNEL_CHANNEL_TYPE
, G_TYPE_STRING
, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE
,
698 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE
, TP_TYPE_HANDLE
, TP_HANDLE_TYPE_CONTACT
,
699 TP_PROP_CHANNEL_TARGET_ID
, G_TYPE_STRING
, pIdentifier
,
700 TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME
, G_TYPE_STRING
, getFullServiceName().getStr(),
703 TpAccountChannelRequest
* pChannelRequest
= tp_account_channel_request_new(
704 pAccount
, pRequest
, TP_USER_ACTION_TIME_NOT_USER_ACTION
);
705 SAL_WARN_IF( !pChannelRequest
, "tubes", "TeleManager::startBuddySession: no channel");
706 if (!pChannelRequest
)
708 g_hash_table_unref( pRequest
);
712 pImpl
->mbChannelReadyHandlerInvoked
= false;
714 TeleConference
* pConference
= new TeleConference( NULL
, NULL
, createUuid(), true );
716 tp_account_channel_request_create_and_handle_channel_async(
717 pChannelRequest
, NULL
, TeleManagerImpl::ChannelReadyHandler
, pConference
);
719 while (!pImpl
->mbChannelReadyHandlerInvoked
)
720 g_main_context_iteration( NULL
, TRUE
);
722 g_object_unref( pChannelRequest
);
723 g_hash_table_unref( pRequest
);
725 if (!pConference
->isReady())
731 static bool tb_presence_is_online( const TpConnectionPresenceType
& presence
)
735 case TP_CONNECTION_PRESENCE_TYPE_UNSET
:
736 case TP_CONNECTION_PRESENCE_TYPE_OFFLINE
:
738 case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE
:
739 case TP_CONNECTION_PRESENCE_TYPE_AWAY
:
740 case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY
:
741 case TP_CONNECTION_PRESENCE_TYPE_HIDDEN
:
742 case TP_CONNECTION_PRESENCE_TYPE_BUSY
:
744 case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN
:
745 case TP_CONNECTION_PRESENCE_TYPE_ERROR
:
751 static bool tb_contact_is_online( TpContact
*contact
)
753 return tb_presence_is_online (tp_contact_get_presence_type (contact
));
756 static void presence_changed_cb( TpContact
* /* contact */,
759 gchar
* /* message */,
760 gpointer
/* pContactList*/ )
762 TeleManager::displayAllContacts();
765 AccountContactPairV
TeleManager::getContacts()
767 AccountContactPairV pairs
;
769 for (GList
*accounts
= tp_account_manager_get_valid_accounts (pImpl
->mpAccountManager
);
770 accounts
!= NULL
; accounts
= g_list_delete_link (accounts
, accounts
))
772 TpAccount
*account
= reinterpret_cast<TpAccount
*>(accounts
->data
);
773 TpConnection
*connection
= tp_account_get_connection (account
);
775 /* Verify account is online and received its contact list. If state is not
776 * SUCCESS this means we didn't received the roster from server yet and
777 * we would have to wait for the "notify:contact-list-state" signal. */
778 if (connection
== NULL
|| tp_connection_get_contact_list_state (connection
) !=
779 TP_CONTACT_LIST_STATE_SUCCESS
)
782 TpContact
*self
= tp_connection_get_self_contact (connection
);
783 GPtrArray
*contacts
= tp_connection_dup_contact_list (connection
);
784 for (guint i
= 0; i
< contacts
->len
; i
++)
786 TpContact
*contact
= reinterpret_cast<TpContact
*>(g_ptr_array_index (contacts
, i
));
787 if (pImpl
->maRegisteredContacts
.find (contact
) == pImpl
->maRegisteredContacts
.end())
789 pImpl
->maRegisteredContacts
.insert (contact
);
790 g_signal_connect (contact
, "presence-changed",
791 G_CALLBACK (presence_changed_cb
), NULL
);
793 if (contact
!= self
&& tb_contact_is_online (contact
))
795 g_object_ref (account
);
796 g_object_ref (contact
);
798 AccountContactPair
pair(account
, contact
);
799 pairs
.push_back(pair
);
802 g_ptr_array_unref (contacts
);
808 OString
TeleManager::getFullClientName()
810 OStringBuffer
aBuf(64);
811 aBuf
.append( LIBO_CLIENT_SUFFIX
).append( pImpl
->msNameSuffix
);
812 return aBuf
.makeStringAndClear();
815 OString
TeleManager::getFullServiceName()
817 OStringBuffer
aBuf(64);
818 aBuf
.append( LIBO_DTUBE_SERVICE
).append( pImpl
->msNameSuffix
);
819 return aBuf
.makeStringAndClear();
822 OString
TeleManager::getFullObjectPath()
824 OStringBuffer
aBuf(64);
825 aBuf
.append( '/').append( LIBO_DTUBE_SERVICE
).append( pImpl
->msNameSuffix
);
826 OString
aStr( aBuf
.makeStringAndClear().replace( '.', '/'));
830 OString
TeleManager::createUuid()
833 rtl_createUuid( nId
, 0, sal_True
);
835 for (size_t i
=0; i
<16; ++i
)
837 snprintf( aBuf
+2*i
, 3, "%02x", (unsigned char)nId
[i
]);
840 return OString( aBuf
);
843 Mutex
& TeleManager::GetMutex()
845 static Mutex
* pMutex
= NULL
;
848 MutexGuard
aGuard( Mutex::getGlobalMutex());
855 void TeleManager::addSuffixToNames( const char* pName
)
857 pImpl
->msNameSuffix
= pName
;
860 // ===========================================================================
862 TeleManagerImpl::TeleManagerImpl()
866 mpFileTransferClient( NULL
),
867 mpAccountManager( NULL
)
869 #if !GLIB_CHECK_VERSION(2,36,0)
874 TeleManagerImpl::~TeleManagerImpl()
876 // There may be unused conferences left opened, so close them.
877 // It should not make a problem to close already closed conference.
878 for (MapStringConference::iterator it
= maAcceptedConferences
.begin();
879 it
!= maAcceptedConferences
.end(); ++it
)
883 tp_base_client_unregister( mpClient
);
884 g_object_unref( mpClient
);
886 if (mpFileTransferClient
)
888 tp_base_client_unregister( mpFileTransferClient
);
889 g_object_unref( mpFileTransferClient
);
892 g_object_unref( mpFactory
);
893 if (mpAccountManager
)
894 g_object_unref( mpAccountManager
);
897 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */