tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sd / source / ui / remotecontrol / Server.cxx
blob12c494121e9e0f3232a3a2dae851442434f2ec36
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 <algorithm>
11 #include <utility>
12 #include <vector>
14 #include <officecfg/Office/Impress.hxx>
15 #include <officecfg/Office/Security.hxx>
17 #include <com/sun/star/container/XNameAccess.hpp>
18 #include <com/sun/star/container/XNameContainer.hpp>
19 #include <com/sun/star/uno/Sequence.hxx>
20 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
22 #include <comphelper/processfactory.hxx>
23 #include <comphelper/configuration.hxx>
24 #include <comphelper/sequence.hxx>
25 #include <sal/log.hxx>
26 #include <vcl/svapp.hxx>
27 #include <osl/socket.hxx>
29 #include <sddll.hxx>
31 #include "DiscoveryService.hxx"
32 #include "Listener.hxx"
33 #include <RemoteServer.hxx>
34 #include "BluetoothServer.hxx"
35 #include "Communicator.hxx"
36 #include "BufferedStreamSocket.hxx"
38 using namespace sd;
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::container;
42 using namespace ::com::sun::star::lang;
43 using namespace ::osl;
44 using namespace ::comphelper;
46 namespace sd {
47 /**
48 * Used to keep track of clients that have attempted to connect, but haven't
49 * yet been approved.
51 struct ClientInfoInternal:
52 ClientInfo
54 BufferedStreamSocket *mpStreamSocket;
55 OUString mPin;
57 ClientInfoInternal( const OUString& rName,
58 BufferedStreamSocket *pSocket,
59 OUString aPin ):
60 ClientInfo( rName, false ),
61 mpStreamSocket( pSocket ),
62 mPin(std::move( aPin )) {}
66 IPRemoteServer::IPRemoteServer()
67 : Thread("IPRemoteServerThread")
69 SAL_INFO("sdremote", "Instantiated IPRemoteServer");
72 IPRemoteServer::~IPRemoteServer()
76 void IPRemoteServer::execute()
78 SAL_INFO("sdremote", "IPRemoteServer::execute called");
79 osl::SocketAddr aAddr( u"0.0.0.0"_ustr, PORT );
80 if ( !mSocket.bind( aAddr ) )
82 SAL_WARN( "sdremote", "bind failed" << mSocket.getErrorAsString() );
83 spServer = nullptr;
84 return;
87 if ( !mSocket.listen(3) )
89 SAL_WARN( "sdremote", "listen failed" << mSocket.getErrorAsString() );
90 spServer = nullptr;
91 return;
93 while ( true )
95 StreamSocket aSocket;
96 SAL_INFO( "sdremote", "waiting on accept" );
97 if ( mSocket.acceptConnection( aSocket ) == osl_Socket_Error )
99 SAL_WARN( "sdremote", "accept failed" << mSocket.getErrorAsString() );
100 break; // Closed, or other issue.
102 BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
103 handleAcceptedConnection( pSocket );
105 SAL_INFO("sdremote", "shutting down IPRemoteServer");
106 spServer = nullptr; // Object is destroyed when Thread::execute() ends.
109 void IPRemoteServer::handleAcceptedConnection( BufferedStreamSocket *pSocket )
111 OString aLine;
112 if ( ! ( pSocket->readLine( aLine)
113 && aLine == "LO_SERVER_CLIENT_PAIR"
114 && pSocket->readLine( aLine ) ) )
116 SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
117 delete pSocket;
118 return;
121 OString aName( aLine );
123 if ( ! pSocket->readLine( aLine ) )
125 delete pSocket;
126 return;
128 OString aPin( aLine );
130 SocketAddr aClientAddr;
131 pSocket->getPeerAddr( aClientAddr );
135 // Read off any additional non-empty lines
136 // We know that we at least have the empty termination line to read.
137 if ( ! pSocket->readLine( aLine ) ) {
138 delete pSocket;
139 return;
142 while ( aLine.getLength() > 0 );
144 MutexGuard aGuard(RemoteServer::sDataMutex);
145 std::shared_ptr< ClientInfoInternal > pClient =
146 std::make_shared<ClientInfoInternal>(
147 OStringToOUString( aName, RTL_TEXTENCODING_UTF8 ),
148 pSocket, OStringToOUString( aPin, RTL_TEXTENCODING_UTF8 ) );
149 mAvailableClients.push_back( pClient );
151 // Check if we already have this server.
152 Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
153 const Sequence< OUString > aNames = xConfig->getElementNames();
154 for ( const auto& rName : aNames )
156 if ( rName == pClient->mName )
158 Reference<XNameAccess> xSetItem( xConfig->getByName(rName), UNO_QUERY );
159 Any axPin(xSetItem->getByName(u"PIN"_ustr));
160 OUString sPin;
161 axPin >>= sPin;
163 if ( sPin == pClient->mPin ) {
164 SAL_INFO( "sdremote", "client found on validated list -- connecting" );
165 connectClient( pClient, sPin );
166 return;
171 // Pin not found so inform the client.
172 SAL_INFO( "sdremote", "client not found on validated list" );
173 pSocket->write( "LO_SERVER_VALIDATING_PIN\n\n",
174 strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
177 IPRemoteServer *sd::IPRemoteServer::spServer = nullptr;
178 ::osl::Mutex sd::RemoteServer::sDataMutex;
179 ::std::vector<Communicator*> sd::RemoteServer::sCommunicators;
181 void IPRemoteServer::setup()
183 if (spServer)
184 return;
186 spServer = new IPRemoteServer();
187 spServer->launch();
190 void RemoteServer::presentationStarted( const css::uno::Reference<
191 css::presentation::XSlideShowController > &rController )
193 // note this can be invoked even when there is no IPRemoteServer instance
194 // but there are communicators belonging to a BluetoothServer
195 MutexGuard aGuard( sDataMutex );
196 for ( const auto& rpCommunicator : sCommunicators )
198 rpCommunicator->presentationStarted( rController );
201 void RemoteServer::presentationStopped()
203 MutexGuard aGuard( sDataMutex );
204 for ( const auto& rpCommunicator : sCommunicators )
206 rpCommunicator->disposeListener();
210 void RemoteServer::removeCommunicator( Communicator const * mCommunicator )
212 MutexGuard aGuard( sDataMutex );
213 auto aIt = std::find(sCommunicators.begin(), sCommunicators.end(), mCommunicator);
214 if (aIt != sCommunicators.end())
215 sCommunicators.erase( aIt );
218 std::vector<std::shared_ptr<ClientInfo>> IPRemoteServer::getClients()
220 SAL_INFO( "sdremote", "IPRemoteServer::getClients() called" );
221 std::vector< std::shared_ptr< ClientInfo > > aClients;
222 if ( spServer )
224 MutexGuard aGuard(RemoteServer::sDataMutex);
225 aClients.assign( spServer->mAvailableClients.begin(),
226 spServer->mAvailableClients.end() );
228 else
230 SAL_INFO( "sdremote", "No remote server instance => no remote clients" );
232 // We also need to provide authorised clients (no matter whether or not
233 // they are actually available), so that they can be de-authorised if
234 // necessary. We specifically want these to be at the end of the list
235 // since the user is more likely to be trying to connect a new remote
236 // than removing an existing remote.
237 // We can also be sure that pre-authorised clients will not be on the
238 // available clients list, as they get automatically connected if seen.
239 // TODO: we should probably add some sort of extra labelling to mark
240 // authorised AND connected client.
241 Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
242 const Sequence< OUString > aNames = xConfig->getElementNames();
243 std::transform(aNames.begin(), aNames.end(), std::back_inserter(aClients),
244 [](const OUString& rName) -> std::shared_ptr<ClientInfo> {
245 return std::make_shared<ClientInfo>(rName, true); });
247 return aClients;
250 bool IPRemoteServer::connectClient(const std::shared_ptr<ClientInfo>& pClient, std::u16string_view aPin)
252 SAL_INFO("sdremote", "IPRemoteServer::connectClient called");
253 if ( !spServer )
254 return false;
256 ClientInfoInternal* apClient = dynamic_cast< ClientInfoInternal* >( pClient.get() );
257 if ( !apClient )
258 // could happen if we try to "connect" an already authorised client
260 return false;
263 if ( apClient->mPin == aPin )
265 // Save in settings first
266 std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
267 Reference< XNameContainer > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
269 Reference<XSingleServiceFactory> xChildFactory (
270 xConfig, UNO_QUERY);
271 Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
272 Any aValue;
273 if (xChild.is())
275 // Check whether the client is already saved
276 Sequence< OUString > aNames = xConfig->getElementNames();
277 if (comphelper::findValue(aNames, apClient->mName) != -1)
278 xConfig->replaceByName( apClient->mName, Any( xChild ) );
279 else
280 xConfig->insertByName( apClient->mName, Any( xChild ) );
281 aValue <<= apClient->mPin;
282 xChild->replaceByName(u"PIN"_ustr, aValue);
283 aChanges->commit();
286 Communicator* pCommunicator = new Communicator( std::unique_ptr<IBluetoothSocket>(apClient->mpStreamSocket) );
287 MutexGuard aGuard(RemoteServer::sDataMutex);
289 RemoteServer::sCommunicators.push_back( pCommunicator );
291 auto aIt = std::find(spServer->mAvailableClients.begin(), spServer->mAvailableClients.end(), pClient);
292 if (aIt != spServer->mAvailableClients.end())
293 spServer->mAvailableClients.erase( aIt );
294 pCommunicator->launch();
295 return true;
297 else
299 return false;
303 void IPRemoteServer::deauthoriseClient(const std::shared_ptr<ClientInfo>& pClient)
305 // TODO: we probably want to forcefully disconnect at this point too?
306 // But possibly via a separate function to allow just disconnecting from
307 // the UI.
309 SAL_INFO("sdremote", "IPRemoteServer::deauthoriseClient called");
311 if ( !pClient->mbIsAlreadyAuthorised )
312 // We can't remove unauthorised clients from the authorised list...
314 return;
317 std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
318 Reference< XNameContainer > const xConfig =
319 officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
321 xConfig->removeByName( pClient->mName );
322 aChanges->commit();
325 void SdDLL::RegisterRemotes()
327 SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
329 // The remote server is likely of no use in headless mode. And as only
330 // one instance of the server can actually own the appropriate ports its
331 // probably best to not even try to do so from our headless instance
332 // (i.e. as to avoid blocking expected usage).
333 // It could perhaps be argued that we would still need the remote
334 // server for tiled rendering of presentations, but even then this
335 // implementation would not be of much use, i.e. would be controlling
336 // the purely imaginary headless presentation -- instead we'd need
337 // to have some sort of mechanism of plugging in our tiled rendering
338 // client to be controlled by the remote server, or provide an
339 // alternative implementation.
340 if ( Application::IsHeadlessModeEnabled() )
341 return;
343 if ( !officecfg::Office::Impress::Misc::Start::EnableSdremote::get() )
344 return;
346 #ifdef ENABLE_SDREMOTE_BLUETOOTH
347 sd::BluetoothServer::setup( &RemoteServer::sCommunicators );
348 #endif
350 if (!officecfg::Office::Security::Net::AllowInsecureImpressRemoteWiFi::get())
352 SAL_WARN("desktop", "Impress remote WiFi is disabled by configuration");
353 return;
356 // this is the IP/WiFi server
357 sd::IPRemoteServer::setup();
358 // assumption is that BluetoothServer doesn't need DiscoveryService
359 sd::DiscoveryService::setup();
362 void RemoteServer::ensureDiscoverable()
364 // FIXME: we could also enable listening on our WiFi
365 // socket here to significantly reduce the attack surface.
366 #ifdef ENABLE_SDREMOTE_BLUETOOTH
367 BluetoothServer::ensureDiscoverable();
368 #endif
371 void RemoteServer::restoreDiscoverable()
373 #ifdef ENABLE_SDREMOTE_BLUETOOTH
374 BluetoothServer::restoreDiscoverable();
375 #endif
377 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */