fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / sd / source / ui / remotecontrol / Server.cxx
blob846ea9eae3db7cb990331a60fe344af03500209b
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 */
9 #include <stdlib.h>
10 #include <algorithm>
11 #include <vector>
13 #include <officecfg/Office/Common.hxx>
14 #include <officecfg/Office/Impress.hxx>
16 #include <com/sun/star/container/XNameAccess.hpp>
17 #include <com/sun/star/container/XNameContainer.hpp>
18 #include <com/sun/star/uno/Sequence.hxx>
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/configuration.hxx>
22 #include <sal/log.hxx>
24 #include "sddll.hxx"
26 #include "DiscoveryService.hxx"
27 #include "Listener.hxx"
28 #include "Receiver.hxx"
29 #include "RemoteServer.hxx"
30 #include "BluetoothServer.hxx"
31 #include "Communicator.hxx"
32 #include "BufferedStreamSocket.hxx"
34 using namespace std;
35 using namespace sd;
36 using namespace ::com::sun::star;
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star::beans;
39 using namespace ::com::sun::star::container;
40 using namespace ::com::sun::star::lang;
41 using namespace ::osl;
42 using namespace ::comphelper;
44 namespace sd {
45 /**
46 * Used to keep track of clients that have attempted to connect, but haven't
47 * yet been approved.
49 struct ClientInfoInternal:
50 ClientInfo
52 BufferedStreamSocket *mpStreamSocket;
53 OUString mPin;
55 ClientInfoInternal( const OUString rName,
56 const OUString rAddress,
57 BufferedStreamSocket *pSocket, OUString rPin ):
58 ClientInfo( rName, rAddress ),
59 mpStreamSocket( pSocket ),
60 mPin( rPin ) {}
64 RemoteServer::RemoteServer() :
65 Thread( "RemoteServerThread" ),
66 mSocket(),
67 mAvailableClients()
69 SAL_INFO( "sdremote", "Instantiated RemoteServer" );
72 RemoteServer::~RemoteServer()
76 void RemoteServer::execute()
78 SAL_INFO( "sdremote", "RemoteServer::execute called" );
79 uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
80 if (!xContext.is() || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext))
82 SAL_INFO("sdremote", "not in experimental mode, disabling TCP server");
83 spServer = NULL;
84 return;
86 osl::SocketAddr aAddr( "0", PORT );
87 if ( !mSocket.bind( aAddr ) )
89 SAL_WARN( "sdremote", "bind failed" << mSocket.getErrorAsString() );
90 spServer = NULL;
91 return;
94 if ( !mSocket.listen(3) )
96 SAL_WARN( "sdremote", "listen failed" << mSocket.getErrorAsString() );
97 spServer = NULL;
98 return;
100 while ( true )
102 StreamSocket aSocket;
103 SAL_INFO( "sdremote", "waiting on accept" );
104 if ( mSocket.acceptConnection( aSocket ) == osl_Socket_Error )
106 SAL_WARN( "sdremote", "accept failed" << mSocket.getErrorAsString() );
107 spServer = NULL;
108 return; // Closed, or other issue.
110 BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
111 OString aLine;
112 if ( pSocket->readLine( aLine)
113 && aLine.equals( "LO_SERVER_CLIENT_PAIR" ) &&
114 pSocket->readLine( aLine ) )
116 OString aName( aLine );
118 if ( ! pSocket->readLine( aLine ) ) delete pSocket;
119 OString aPin( aLine );
121 SocketAddr aClientAddr;
122 pSocket->getPeerAddr( aClientAddr );
123 OUString aAddress = aClientAddr.getHostname();
125 MutexGuard aGuard( sDataMutex );
126 ClientInfoInternal* pClient = new ClientInfoInternal(
127 OStringToOUString( aName, RTL_TEXTENCODING_UTF8 ),
128 aAddress, pSocket, OStringToOUString( aPin,
129 RTL_TEXTENCODING_UTF8 ) );
130 mAvailableClients.push_back( pClient );
132 // Read off any additional non-empty lines
133 // We know that we at least have the empty termination line to read.
136 pSocket->readLine( aLine );
138 while ( aLine.getLength() > 0 );
140 // Check if we already have this server.
141 Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
142 Sequence< OUString > aNames = xConfig->getElementNames();
143 bool aFound = false;
144 for ( int i = 0; i < aNames.getLength(); i++ )
146 if ( aNames[i].equals( pClient->mName ) )
148 Reference<XNameAccess> xSetItem( xConfig->getByName(aNames[i]), UNO_QUERY );
149 Any axPin(xSetItem->getByName("PIN"));
150 OUString sPin;
151 axPin >>= sPin;
153 if ( sPin.equals( pClient->mPin ) ) {
154 SAL_INFO( "sdremote", "client found on validated list -- connecting" );
155 connectClient( pClient, sPin );
156 aFound = true;
157 break;
162 // Pin not found so inform the client.
163 if ( !aFound )
165 SAL_INFO( "sdremote", "client not found on validated list" );
166 pSocket->write( "LO_SERVER_VALIDATING_PIN\n\n",
167 strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
169 } else {
170 SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
171 delete pSocket;
174 spServer = NULL; // Object is destroyed when Thread::execute() ends.
177 RemoteServer *sd::RemoteServer::spServer = NULL;
178 ::osl::Mutex sd::RemoteServer::sDataMutex;
179 ::std::vector<Communicator*> sd::RemoteServer::sCommunicators;
181 void RemoteServer::setup()
183 if (spServer)
184 return;
186 spServer = new RemoteServer();
187 spServer->launch();
189 #ifdef ENABLE_SDREMOTE_BLUETOOTH
190 sd::BluetoothServer::setup( &sCommunicators );
191 #endif
195 void RemoteServer::presentationStarted( const css::uno::Reference<
196 css::presentation::XSlideShowController > &rController )
198 if ( !spServer )
199 return;
200 MutexGuard aGuard( sDataMutex );
201 for ( vector<Communicator*>::const_iterator aIt = sCommunicators.begin();
202 aIt != sCommunicators.end(); ++aIt )
204 (*aIt)->presentationStarted( rController );
207 void RemoteServer::presentationStopped()
209 if ( !spServer )
210 return;
211 MutexGuard aGuard( sDataMutex );
212 for ( vector<Communicator*>::const_iterator aIt = sCommunicators.begin();
213 aIt != sCommunicators.end(); ++aIt )
215 (*aIt)->disposeListener();
219 void RemoteServer::removeCommunicator( Communicator* mCommunicator )
221 if ( !spServer )
222 return;
223 MutexGuard aGuard( sDataMutex );
224 for ( vector<Communicator*>::iterator aIt = sCommunicators.begin();
225 aIt != sCommunicators.end(); ++aIt )
227 if ( mCommunicator == *aIt )
229 sCommunicators.erase( aIt );
230 break;
235 std::vector<ClientInfo*> RemoteServer::getClients()
237 SAL_INFO( "sdremote", "RemoteServer::getClients() called" );
238 std::vector<ClientInfo*> aClients;
239 if ( !spServer )
241 SAL_INFO( "sdremote", "No remote server instance => no clients" );
242 return aClients;
245 MutexGuard aGuard( sDataMutex );
246 aClients.assign( spServer->mAvailableClients.begin(),
247 spServer->mAvailableClients.end() );
248 return aClients;
251 sal_Bool RemoteServer::connectClient( ClientInfo* pClient, OUString aPin )
253 SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
254 if ( !spServer )
255 return false;
257 ClientInfoInternal *apClient = (ClientInfoInternal*) pClient;
258 if ( apClient->mPin.equals( aPin ) )
260 // Save in settings first
261 boost::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
262 Reference< XNameContainer > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
264 Reference<XSingleServiceFactory> xChildFactory (
265 xConfig, UNO_QUERY);
266 Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
267 Any aValue;
268 if (xChild.is())
270 // Check whether the client is already saved
271 bool aSaved = false;
272 Sequence< OUString > aNames = xConfig->getElementNames();
273 for ( int i = 0; i < aNames.getLength(); i++ )
275 if ( aNames[i].equals( apClient->mName ) )
277 xConfig->replaceByName( apClient->mName, makeAny( xChild ) );
278 aSaved = true;
279 break;
282 if ( !aSaved )
283 xConfig->insertByName( apClient->mName, makeAny( xChild ) );
284 aValue <<= OUString( apClient->mPin );
285 xChild->replaceByName("PIN", aValue);
286 aChanges->commit();
289 Communicator* pCommunicator = new Communicator( apClient->mpStreamSocket );
290 MutexGuard aGuard( sDataMutex );
292 sCommunicators.push_back( pCommunicator );
294 for ( vector<ClientInfoInternal*>::iterator aIt = spServer->mAvailableClients.begin();
295 aIt != spServer->mAvailableClients.end(); ++aIt )
297 if ( pClient == *aIt )
299 spServer->mAvailableClients.erase( aIt );
300 break;
303 pCommunicator->launch();
304 return true;
306 else
308 return false;
312 void SdDLL::RegisterRemotes()
314 // Disable unless in experimental mode for now
315 SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
316 uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
317 if ( xContext.is() && !officecfg::Office::Impress::Misc::Start::EnableSdremote::get( xContext ) )
318 return;
320 sd::RemoteServer::setup();
321 sd::DiscoveryService::setup();
324 void RemoteServer::ensureDiscoverable()
326 // FIXME: we could also enable listening on our WiFi
327 // socket here to significantly reduce the attack surface.
328 #ifdef ENABLE_SDREMOTE_BLUETOOTH
329 BluetoothServer::ensureDiscoverable();
330 #endif
333 void RemoteServer::restoreDiscoverable()
335 #ifdef ENABLE_SDREMOTE_BLUETOOTH
336 BluetoothServer::restoreDiscoverable();
337 #endif
339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */