LCOV - code coverage report
Current view: top level - sd/source/ui/remotecontrol - BluetoothServer.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 452 0.2 %
Date: 2014-11-03 Functions: 2 40 5.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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             : 
      10             : #include "BluetoothServer.hxx"
      11             : 
      12             : #include <iostream>
      13             : #include <iomanip>
      14             : #include <new>
      15             : 
      16             : #include <boost/scoped_ptr.hpp>
      17             : 
      18             : #include <sal/log.hxx>
      19             : 
      20             : #ifdef LINUX_BLUETOOTH
      21             :   #include <glib.h>
      22             :   #include <dbus/dbus.h>
      23             :   #include <errno.h>
      24             :   #include <fcntl.h>
      25             :   #include <sys/unistd.h>
      26             :   #include <sys/socket.h>
      27             :   #include <bluetooth/bluetooth.h>
      28             :   #include <bluetooth/rfcomm.h>
      29             :   #include "BluetoothServiceRecord.hxx"
      30             :   #include "BufferedStreamSocket.hxx"
      31             : #endif
      32             : 
      33             : #ifdef WIN32
      34             :   // LO vs WinAPI conflict
      35             :   #undef WB_LEFT
      36             :   #undef WB_RIGHT
      37             :   #include <winsock2.h>
      38             :   #include <ws2bth.h>
      39             :   #include "BufferedStreamSocket.hxx"
      40             : #endif
      41             : 
      42             : #ifdef MACOSX
      43             :   #include <osl/conditn.hxx>
      44             :   #include <premac.h>
      45             :   #if MACOSX_SDK_VERSION == 1070 || MACOSX_SDK_VERSION == 1080
      46             :     #import <IOBluetooth/IOBluetooth.h>
      47             :   #else
      48             :     #import <CoreFoundation/CoreFoundation.h>
      49             :     #import <IOBluetooth/IOBluetoothUtilities.h>
      50             :     #import <IOBluetooth/objc/IOBluetoothSDPUUID.h>
      51             :     #import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
      52             :   #endif
      53             :   #include <postmac.h>
      54             :   #import "OSXBluetooth.h"
      55             :   #include "OSXBluetoothWrapper.hxx"
      56             : #endif
      57             : 
      58             : #ifdef __MINGW32__
      59             : // Value taken from http://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx
      60             : #define NS_BTH 16
      61             : #endif
      62             : 
      63             : #include "Communicator.hxx"
      64             : 
      65             : using namespace sd;
      66             : 
      67             : #ifdef LINUX_BLUETOOTH
      68             : 
      69           0 : struct DBusObject {
      70             :     OString maBusName;
      71             :     OString maPath;
      72             :     OString maInterface;
      73             : 
      74           0 :     DBusObject() { }
      75           0 :     DBusObject( const char *pBusName, const char *pPath, const char *pInterface )
      76           0 :         : maBusName( pBusName ), maPath( pPath ), maInterface( pInterface ) { }
      77             : 
      78           0 :     DBusMessage *getMethodCall( const char *pName )
      79             :     {
      80             :         return dbus_message_new_method_call( maBusName.getStr(), maPath.getStr(),
      81           0 :                                              maInterface.getStr(), pName );
      82             :     }
      83           0 :     DBusObject *cloneForInterface( const char *pInterface )
      84             :     {
      85           0 :         DBusObject *pObject = new DBusObject();
      86             : 
      87           0 :         pObject->maBusName = maBusName;
      88           0 :         pObject->maPath = maPath;
      89           0 :         pObject->maInterface = pInterface;
      90             : 
      91           0 :         return pObject;
      92             :     }
      93             : };
      94             : 
      95             : static DBusObject* getBluez5Adapter(DBusConnection *pConnection);
      96             : 
      97             : struct sd::BluetoothServer::Impl {
      98             :     // the glib mainloop running in the thread
      99             :     GMainContext *mpContext;
     100             :     DBusConnection *mpConnection;
     101             :     DBusObject *mpService;
     102             :     volatile bool mbExitMainloop;
     103             :     enum BluezVersion { BLUEZ4, BLUEZ5, UNKNOWN };
     104             :     BluezVersion maBluezVersion;
     105             : 
     106           0 :     Impl()
     107           0 :         : mpContext( g_main_context_new() )
     108             :         , mpConnection( NULL )
     109             :         , mpService( NULL )
     110             :         , mbExitMainloop( false )
     111           0 :         , maBluezVersion( UNKNOWN )
     112           0 :     { }
     113             : 
     114           0 :     DBusObject *getAdapter()
     115             :     {
     116           0 :         if (mpService)
     117             :         {
     118           0 :             DBusObject* pAdapter = mpService->cloneForInterface( "org.bluez.Adapter" );
     119           0 :             return pAdapter;
     120             :         }
     121           0 :         else if (spServer->mpImpl->maBluezVersion == BLUEZ5)
     122             :         {
     123           0 :             return getBluez5Adapter(mpConnection);
     124             :         }
     125             :         else
     126             :         {
     127           0 :             return NULL;
     128             :         }
     129             :     }
     130             : };
     131             : 
     132             : static DBusConnection *
     133           0 : dbusConnectToNameOnBus()
     134             : {
     135             :     DBusError aError;
     136             :     DBusConnection *pConnection;
     137             : 
     138           0 :     dbus_error_init( &aError );
     139             : 
     140           0 :     pConnection = dbus_bus_get( DBUS_BUS_SYSTEM, &aError );
     141           0 :     if( !pConnection || dbus_error_is_set( &aError ))
     142             :     {
     143             :         SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus: " << aError.message );
     144           0 :         dbus_error_free( &aError );
     145           0 :         return NULL;
     146             :     }
     147             : 
     148           0 :     return pConnection;
     149             : }
     150             : 
     151             : static DBusMessage *
     152           0 : sendUnrefAndWaitForReply( DBusConnection *pConnection, DBusMessage *pMsg )
     153             : {
     154           0 :     DBusPendingCall *pPending = NULL;
     155             : 
     156           0 :     if( !pMsg || !dbus_connection_send_with_reply( pConnection, pMsg, &pPending,
     157           0 :                                                    -1 /* default timeout */ ) )
     158             :     {
     159             :         SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message send" );
     160           0 :         dbus_message_unref( pMsg );
     161           0 :         return NULL;
     162             :     }
     163           0 :     dbus_connection_flush( pConnection );
     164           0 :     dbus_message_unref( pMsg );
     165             : 
     166           0 :     dbus_pending_call_block( pPending ); // block for reply
     167             : 
     168           0 :     pMsg = dbus_pending_call_steal_reply( pPending );
     169           0 :     if( !pMsg )
     170             :         SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
     171             : 
     172           0 :     dbus_pending_call_unref( pPending );
     173           0 :     return pMsg;
     174             : }
     175             : 
     176             : static bool
     177           0 : isBluez5Available(DBusConnection *pConnection)
     178             : {
     179             :     DBusMessage *pMsg;
     180             : 
     181             :     // Simplest wasy to check whether we have Bluez 5+ is to check
     182             :     // that we can obtain adapters using the new interfaces.
     183             :     // The first two error checks however don't tell us anything as they should
     184             :     // succeed as long as dbus is working correctly.
     185           0 :     pMsg = DBusObject( "org.bluez", "/", "org.freedesktop.DBus.ObjectManager" ).getMethodCall( "GetManagedObjects" );
     186           0 :     if (!pMsg)
     187             :     {
     188             :         SAL_INFO("sdremote.bluetooth", "No GetManagedObjects call created");
     189           0 :         return false;
     190             :     }
     191             : 
     192           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
     193           0 :     if (!pMsg)
     194             :     {
     195             :         SAL_INFO("sdremote.bluetooth", "No reply received");
     196           0 :         return false;
     197             :     }
     198             : 
     199             :     // If dbus is working correctly and we aren't on bluez 5 this is where we
     200             :     // should actually get the error.
     201           0 :     if (dbus_message_get_error_name( pMsg ))
     202             :     {
     203             :         SAL_INFO( "sdremote.bluetooth", "GetManagedObjects call failed with \""
     204             :                     << dbus_message_get_error_name( pMsg )
     205             :                     << "\" -- we don't seem to have Bluez 5 available");
     206           0 :         return false;
     207             :     }
     208             :     SAL_INFO("sdremote.bluetooth", "GetManagedObjects call seems to have succeeded -- we must be on Bluez 5");
     209           0 :     dbus_message_unref(pMsg);
     210           0 :     return true;
     211             : }
     212             : 
     213             : static DBusObject*
     214           0 : getBluez5Adapter(DBusConnection *pConnection)
     215             : {
     216             :     DBusMessage *pMsg;
     217             :     // This returns a list of objects where we need to find the first
     218             :     // org.bluez.Adapter1 .
     219           0 :     pMsg = DBusObject( "org.bluez", "/", "org.freedesktop.DBus.ObjectManager" ).getMethodCall( "GetManagedObjects" );
     220           0 :     if (!pMsg)
     221           0 :         return NULL;
     222             : 
     223           0 :     const gchar* pInterfaceType = "org.bluez.Adapter1";
     224             : 
     225           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
     226             : 
     227             :     DBusMessageIter aObjectIterator;
     228           0 :     if (pMsg && dbus_message_iter_init(pMsg, &aObjectIterator))
     229             :     {
     230           0 :         if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&aObjectIterator))
     231             :         {
     232             :             DBusMessageIter aObject;
     233           0 :             dbus_message_iter_recurse(&aObjectIterator, &aObject);
     234           0 :             do
     235             :             {
     236           0 :                 if (DBUS_TYPE_DICT_ENTRY == dbus_message_iter_get_arg_type(&aObject))
     237             :                 {
     238             :                     DBusMessageIter aContainerIter;
     239           0 :                     dbus_message_iter_recurse(&aObject, &aContainerIter);
     240           0 :                     char *pPath = 0;
     241           0 :                     do
     242             :                     {
     243           0 :                         if (DBUS_TYPE_OBJECT_PATH == dbus_message_iter_get_arg_type(&aContainerIter))
     244             :                         {
     245           0 :                             dbus_message_iter_get_basic(&aContainerIter, &pPath);
     246             :                             SAL_INFO( "sdremote.bluetooth", "Something retrieved: '"
     247             :                             << pPath << "' '");
     248             :                         }
     249           0 :                         else if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&aContainerIter))
     250             :                         {
     251             :                             DBusMessageIter aInnerIter;
     252           0 :                             dbus_message_iter_recurse(&aContainerIter, &aInnerIter);
     253           0 :                             do
     254             :                             {
     255           0 :                                 if (DBUS_TYPE_DICT_ENTRY == dbus_message_iter_get_arg_type(&aInnerIter))
     256             :                                 {
     257             :                                     DBusMessageIter aInnerInnerIter;
     258           0 :                                     dbus_message_iter_recurse(&aInnerIter, &aInnerInnerIter);
     259           0 :                                     do
     260             :                                     {
     261           0 :                                         if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&aInnerInnerIter))
     262             :                                         {
     263             :                                             char* pMessage;
     264             : 
     265           0 :                                             dbus_message_iter_get_basic(&aInnerInnerIter, &pMessage);
     266           0 :                                             if (OString(pMessage) == "org.bluez.Adapter1")
     267             :                                             {
     268           0 :                                                 dbus_message_unref(pMsg);
     269           0 :                                                 if (pPath)
     270             :                                                 {
     271           0 :                                                     return new DBusObject( "org.bluez", pPath, pInterfaceType );
     272             :                                                 }
     273             :                                                 assert(false); // We should already have pPath provided for us.
     274             :                                             }
     275             :                                         }
     276             :                                     }
     277           0 :                                     while (dbus_message_iter_next(&aInnerInnerIter));
     278             :                                 }
     279             :                             }
     280           0 :                             while (dbus_message_iter_next(&aInnerIter));
     281             :                         }
     282             :                     }
     283           0 :                     while (dbus_message_iter_next(&aContainerIter));
     284             :                 }
     285             :             }
     286           0 :             while (dbus_message_iter_next(&aObject));
     287             :         }
     288           0 :         dbus_message_unref(pMsg);
     289             :     }
     290             : 
     291           0 :     return NULL;
     292             : }
     293             : 
     294             : static DBusObject *
     295           0 : bluez4GetDefaultService( DBusConnection *pConnection )
     296             : {
     297             :     DBusMessage *pMsg;
     298             :     DBusMessageIter it;
     299           0 :     const gchar* pInterfaceType = "org.bluez.Service";
     300             : 
     301             :     // org.bluez.manager only exists for bluez 4.
     302             :     // getMethodCall should return NULL if there is any issue e.g. the
     303             :     // if org.bluez.manager doesn't exist.
     304           0 :     pMsg = DBusObject( "org.bluez", "/", "org.bluez.Manager" ).getMethodCall( "DefaultAdapter" );
     305             : 
     306           0 :     if (!pMsg)
     307             :     {
     308             :         SAL_WARN("sdremote.bluetooth", "Couldn't retrieve DBusObject for DefaultAdapter");
     309           0 :         return NULL;
     310             :     }
     311             : 
     312             :     SAL_INFO("sdremote.bluetooth", "successfully retrieved org.bluez.Manager.DefaultAdapter, attempting to use.");
     313           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
     314             : 
     315           0 :     if(!pMsg || !dbus_message_iter_init( pMsg, &it ) )
     316             :     {
     317           0 :         return NULL;
     318             :     }
     319             : 
     320             :     // This works for Bluez 4
     321           0 :     if( DBUS_TYPE_OBJECT_PATH == dbus_message_iter_get_arg_type( &it ) )
     322             :     {
     323           0 :         const char *pObjectPath = NULL;
     324           0 :         dbus_message_iter_get_basic( &it, &pObjectPath );
     325             :         SAL_INFO( "sdremote.bluetooth", "DefaultAdapter retrieved: '"
     326             :                 << pObjectPath << "' '" << pInterfaceType << "'" );
     327           0 :         dbus_message_unref( pMsg );
     328           0 :         return new DBusObject( "org.bluez", pObjectPath, pInterfaceType );
     329             :     }
     330             :     // Some form of error, e.g. if we have bluez 5 we get a message that
     331             :     // this method doesn't exist.
     332           0 :     else if ( DBUS_TYPE_STRING == dbus_message_iter_get_arg_type( &it ) )
     333             :     {
     334           0 :         const char *pMessage = NULL;
     335           0 :         dbus_message_iter_get_basic( &it, &pMessage );
     336             :         SAL_INFO( "sdremote.bluetooth", "Error message: '"
     337             :                 << pMessage << "' '" << pInterfaceType << "'" );
     338             :     }
     339             :     else
     340             :     {
     341             :         SAL_INFO( "sdremote.bluetooth", "invalid type of reply to DefaultAdapter: '"
     342             :                 << (const char) dbus_message_iter_get_arg_type( &it ) << "'" );
     343             :     }
     344           0 :     dbus_message_unref(pMsg);
     345           0 :     return NULL;
     346             : }
     347             : 
     348             : static bool
     349           0 : bluez4RegisterServiceRecord( DBusConnection *pConnection, DBusObject *pAdapter,
     350             :                             const char *pServiceRecord )
     351             : {
     352             :     DBusMessage *pMsg;
     353             :     DBusMessageIter it;
     354             : 
     355           0 :     pMsg = pAdapter->getMethodCall( "AddRecord" );
     356           0 :     dbus_message_iter_init_append( pMsg, &it );
     357           0 :     dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pServiceRecord );
     358             : 
     359           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
     360             : 
     361           0 :     if( !pMsg || !dbus_message_iter_init( pMsg, &it ) ||
     362           0 :         dbus_message_iter_get_arg_type( &it ) != DBUS_TYPE_UINT32 )
     363             :     {
     364             :         SAL_WARN( "sdremote.bluetooth", "SDP registration failed" );
     365           0 :         return false;
     366             :     }
     367             : 
     368             :     // We ignore the uint de-registration handle we get back:
     369             :     // bluez will clean us up automatically on exit
     370             : 
     371           0 :     return true;
     372             : }
     373             : 
     374             : static void
     375           0 : bluezCreateAttachListeningSocket( GMainContext *pContext, GPollFD *pSocketFD )
     376             : {
     377             :     int nSocket;
     378             : 
     379           0 :     pSocketFD->fd = -1;
     380             : 
     381           0 :     if( ( nSocket = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM ) ) < 0 )
     382             :     {
     383             :         SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << nSocket );
     384           0 :         return;
     385             :     }
     386             : 
     387             :     sockaddr_rc aAddr;
     388             :     // Initialize whole structure. Mainly to appease valgrind, which
     389             :     // doesn't know about the padding at the end of sockaddr_rc which
     390             :     // it will dutifully check for definedness. But also the standard
     391             :     // definition of BDADDR_ANY is unusable in C++ code, so just use
     392             :     // memset to set aAddr.rc_bdaddr to 0.
     393           0 :     memset( &aAddr, 0, sizeof( aAddr ) );
     394           0 :     aAddr.rc_family = AF_BLUETOOTH;
     395           0 :     aAddr.rc_channel = 5;
     396             : 
     397             :     int a;
     398           0 :     if ( ( a = bind( nSocket, (sockaddr*) &aAddr, sizeof(aAddr) ) ) < 0 ) {
     399             :         SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a );
     400           0 :         close( nSocket );
     401           0 :         return;
     402             :     }
     403             : 
     404           0 :     if ( ( a = listen( nSocket, 1 ) ) < 0 )
     405             :     {
     406             :         SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a );
     407           0 :         close( nSocket );
     408           0 :         return;
     409             :     }
     410             : 
     411             :     // set non-blocking behaviour ...
     412           0 :     if( fcntl( nSocket, F_SETFL, O_NONBLOCK) < 0 )
     413             :     {
     414           0 :         close( nSocket );
     415           0 :         return;
     416             :     }
     417             : 
     418           0 :     pSocketFD->fd = nSocket;
     419           0 :     pSocketFD->events = G_IO_IN | G_IO_PRI;
     420           0 :     pSocketFD->revents = 0;
     421             : 
     422           0 :     g_main_context_add_poll( pContext, pSocketFD, G_PRIORITY_DEFAULT );
     423             : }
     424             : 
     425             : static void
     426           0 : bluezDetachCloseSocket( GMainContext *pContext, GPollFD *pSocketFD )
     427             : {
     428           0 :     if( pSocketFD->fd >= 0 )
     429             :     {
     430           0 :         close( pSocketFD->fd );
     431           0 :         g_main_context_remove_poll( pContext, pSocketFD );
     432           0 :         pSocketFD->fd = -1;
     433             :     }
     434           0 : }
     435             : 
     436             : #endif // LINUX_BLUETOOTH
     437             : 
     438             : #if defined(MACOSX)
     439             : 
     440             : OSXBluetoothWrapper::OSXBluetoothWrapper( IOBluetoothRFCOMMChannel* channel ) :
     441             :     mpChannel(channel),
     442             :     mnMTU(0),
     443             :     mHaveBytes(),
     444             :     mMutex(),
     445             :     mBuffer()
     446             : {
     447             :     // silly enough, can't write more than mnMTU bytes at once
     448             :     mnMTU = [channel getMTU];
     449             : 
     450             :     SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::OSXBluetoothWrapper(): mnMTU=" << mnMTU );
     451             : }
     452             : 
     453             : sal_Int32 OSXBluetoothWrapper::readLine( OString& aLine )
     454             : {
     455             :     SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine()" );
     456             : 
     457             :     while( true )
     458             :     {
     459             :         {
     460             :             SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entering mutex" );
     461             :             ::osl::MutexGuard aQueueGuard( mMutex );
     462             :             SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: entered mutex" );
     463             : 
     464             : #ifdef SAL_LOG_INFO
     465             :             // We should have in the sal logging some standard way to
     466             :             // output char buffers with non-printables escaped.
     467             :             std::ostringstream s;
     468             :             if (mBuffer.size() > 0)
     469             :             {
     470             :                 for (unsigned char *p = (unsigned char *) &mBuffer.front(); p != (unsigned char *) &mBuffer.front() + mBuffer.size(); p++)
     471             :                 {
     472             :                     if (*p == '\n')
     473             :                         s << "\\n";
     474             :                     else if (*p < ' ' || *p >= 0x7F)
     475             :                         s << "\\0x" << std::hex << std::setw(2) << std::setfill('0') << (int) *p << std::setfill(' ') << std::setw(1) << std::dec;
     476             :                     else
     477             :                         s << *p;
     478             :                 }
     479             :             }
     480             :             SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine mBuffer:  \"" << s.str() << "\"" );
     481             : #endif
     482             : 
     483             :             // got enough bytes to return a line?
     484             :             std::vector<char>::iterator aIt;
     485             :             if ( (aIt = find( mBuffer.begin(), mBuffer.end(), '\n' ))
     486             :                  != mBuffer.end() )
     487             :             {
     488             :                 sal_uInt64 aLocation = aIt - mBuffer.begin();
     489             : 
     490             :                 aLine = OString( &(*mBuffer.begin()), aLocation );
     491             : 
     492             :                 mBuffer.erase( mBuffer.begin(), aIt + 1 ); // Also delete the empty line
     493             : 
     494             :                 // yeps
     495             :                 SAL_INFO( "sdremote.bluetooth", "  returning, got \"" << OStringToOUString( aLine, RTL_TEXTENCODING_UTF8 ) << "\"" );
     496             :                 return aLine.getLength() + 1;
     497             :             }
     498             : 
     499             :             // nope - wait some more (after releasing the mutex)
     500             :             SAL_INFO( "sdremote.bluetooth", "  resetting mHaveBytes" );
     501             :             mHaveBytes.reset();
     502             :             SAL_INFO( "sdremote.bluetooth", "  leaving mutex" );
     503             :         }
     504             : 
     505             :         SAL_INFO( "sdremote.bluetooth", "  waiting for mHaveBytes" );
     506             :         mHaveBytes.wait();
     507             :         SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::readLine: got mHaveBytes" );
     508             :     }
     509             : }
     510             : 
     511             : sal_Int32 OSXBluetoothWrapper::write( const void* pBuffer, sal_uInt32 n )
     512             : {
     513             :     SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::write(" << pBuffer << ", " << n << ") mpChannel=" << mpChannel );
     514             : 
     515             :     char* ptr = (char*)pBuffer;
     516             :     sal_uInt32 nBytesWritten = 0;
     517             : 
     518             :     if (mpChannel == nil)
     519             :         return 0;
     520             : 
     521             :     while( nBytesWritten < n )
     522             :     {
     523             :         int toWrite = n - nBytesWritten;
     524             :         toWrite = toWrite <= mnMTU ? toWrite : mnMTU;
     525             :         if ( [mpChannel writeSync:ptr length:toWrite] != kIOReturnSuccess )
     526             :         {
     527             :             SAL_INFO( "sdremote.bluetooth", "  [mpChannel writeSync:" << (void *) ptr << " length:" << toWrite << "] returned error, total written " << nBytesWritten );
     528             :             return nBytesWritten;
     529             :         }
     530             :         ptr += toWrite;
     531             :         nBytesWritten += toWrite;
     532             :     }
     533             :     SAL_INFO( "sdremote.bluetooth", "  total written " << nBytesWritten );
     534             :     return nBytesWritten;
     535             : }
     536             : 
     537             : void OSXBluetoothWrapper::appendData(void* pBuffer, size_t len)
     538             : {
     539             :     SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData(" << pBuffer << ", " << len << ")" );
     540             : 
     541             :     if( len )
     542             :     {
     543             :         SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entering mutex" );
     544             :         ::osl::MutexGuard aQueueGuard( mMutex );
     545             :         SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::appendData: entered mutex" );
     546             :         mBuffer.insert(mBuffer.begin()+mBuffer.size(),
     547             :                        (char*)pBuffer, (char *)pBuffer+len);
     548             :         SAL_INFO( "sdremote.bluetooth", "  setting mHaveBytes" );
     549             :         mHaveBytes.set();
     550             :         SAL_INFO( "sdremote.bluetooth", "  leaving mutex" );
     551             :     }
     552             : }
     553             : 
     554             : void OSXBluetoothWrapper::channelClosed()
     555             : {
     556             :     SAL_INFO( "sdremote.bluetooth", "OSXBluetoothWrapper::channelClosed()" );
     557             : 
     558             :     mpChannel = nil;
     559             : }
     560             : 
     561             : void incomingCallback( void *userRefCon,
     562             :                        IOBluetoothUserNotificationRef inRef,
     563             :                        IOBluetoothObjectRef objectRef )
     564             : {
     565             :     (void) inRef;
     566             : 
     567             :     SAL_INFO( "sdremote.bluetooth", "incomingCallback()" );
     568             : 
     569             :     BluetoothServer* pServer = (BluetoothServer*)userRefCon;
     570             : 
     571             :     IOBluetoothRFCOMMChannel* channel = [IOBluetoothRFCOMMChannel withRFCOMMChannelRef:(IOBluetoothRFCOMMChannelRef)objectRef];
     572             : 
     573             :     OSXBluetoothWrapper* socket = new OSXBluetoothWrapper( channel);
     574             :     Communicator* pCommunicator = new Communicator( socket );
     575             :     pServer->addCommunicator( pCommunicator );
     576             : 
     577             :     ChannelDelegate* delegate = [[ChannelDelegate alloc] initWithCommunicatorAndSocket: pCommunicator socket: socket];
     578             :     [channel setDelegate: delegate];
     579             :     [delegate retain];
     580             : 
     581             :     pCommunicator->launch();
     582             : }
     583             : 
     584             : void BluetoothServer::addCommunicator( Communicator* pCommunicator )
     585             : {
     586             :     mpCommunicators->push_back( pCommunicator );
     587             : }
     588             : 
     589             : #endif // MACOSX
     590             : 
     591             : #ifdef LINUX_BLUETOOTH
     592             : 
     593             : extern "C" {
     594           0 :     static gboolean ensureDiscoverable_cb(gpointer)
     595             :     {
     596           0 :         BluetoothServer::doEnsureDiscoverable();
     597           0 :         return FALSE; // remove source
     598             :     }
     599           0 :     static gboolean restoreDiscoverable_cb(gpointer)
     600             :     {
     601           0 :         BluetoothServer::doRestoreDiscoverable();
     602           0 :         return FALSE; // remove source
     603             :     }
     604             : }
     605             : 
     606             : /*
     607             :  * Bluez 4 uses custom methods for setting properties, whereas Bluez 5+
     608             :  * implements properties using the generic "org.freedesktop.DBus.Properties"
     609             :  * interface -- hence we have a specific Bluez 4 function to deal with the
     610             :  * old style of reading properties.
     611             :  */
     612             : static bool
     613           0 : getBluez4BooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
     614             :                     const char *pPropertyName, bool *pBoolean )
     615             : {
     616           0 :     *pBoolean = false;
     617             : 
     618           0 :     if( !pAdapter )
     619           0 :         return false;
     620             : 
     621             :     DBusMessage *pMsg;
     622             :     pMsg = sendUnrefAndWaitForReply( pConnection,
     623           0 :                                      pAdapter->getMethodCall( "GetProperties" ) );
     624             : 
     625             :     DBusMessageIter it;
     626           0 :     if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
     627             :     {
     628             :         SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
     629           0 :         return false;
     630             :     }
     631             : 
     632           0 :     if( DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type( &it ) )
     633             :     {
     634             :         SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
     635           0 :         return false;
     636             :     }
     637             : 
     638             :     DBusMessageIter arrayIt;
     639           0 :     dbus_message_iter_recurse( &it, &arrayIt );
     640             : 
     641           0 :     while( dbus_message_iter_get_arg_type( &arrayIt ) == DBUS_TYPE_DICT_ENTRY )
     642             :     {
     643             :         DBusMessageIter dictIt;
     644           0 :         dbus_message_iter_recurse( &arrayIt, &dictIt );
     645             : 
     646           0 :         const char *pName = NULL;
     647           0 :         if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_STRING )
     648             :         {
     649           0 :             dbus_message_iter_get_basic( &dictIt, &pName );
     650           0 :             if( pName != NULL && !strcmp( pName, pPropertyName ) )
     651             :             {
     652             :                 SAL_INFO( "sdremote.bluetooth", "hit " << pPropertyName << " property" );
     653           0 :                 dbus_message_iter_next( &dictIt );
     654           0 :                 dbus_bool_t bBool = false;
     655             : 
     656           0 :                 if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_VARIANT )
     657             :                 {
     658             :                     DBusMessageIter variantIt;
     659           0 :                     dbus_message_iter_recurse( &dictIt, &variantIt );
     660             : 
     661           0 :                     if( dbus_message_iter_get_arg_type( &variantIt ) == DBUS_TYPE_BOOLEAN )
     662             :                     {
     663           0 :                         dbus_message_iter_get_basic( &variantIt, &bBool );
     664             :                         SAL_INFO( "sdremote.bluetooth", "" << pPropertyName << " is " << bBool );
     665           0 :                         *pBoolean = bBool;
     666           0 :                         return true;
     667             :                     }
     668             :                     else
     669             :                         SAL_WARN( "sdremote.bluetooth", "" << pPropertyName << " type " <<
     670             :                                   dbus_message_iter_get_arg_type( &variantIt ) );
     671             :                 }
     672             :                 else
     673             :                     SAL_WARN( "sdremote.bluetooth", "variant type ? " <<
     674           0 :                               dbus_message_iter_get_arg_type( &dictIt ) );
     675             :             }
     676             :             else
     677             :             {
     678           0 :                 const char *pStr = pName ? pName : "<null>";
     679             :                 SAL_INFO( "sdremote.bluetooth", "property '" << pStr << "'" );
     680             :             }
     681             :         }
     682             :         else
     683             :             SAL_WARN( "sdremote.bluetooth", "unexpected property key type "
     684             :                       << dbus_message_iter_get_arg_type( &dictIt ) );
     685           0 :         dbus_message_iter_next( &arrayIt );
     686             :     }
     687           0 :     dbus_message_unref( pMsg );
     688             : 
     689           0 :     return false;
     690             : }
     691             : 
     692             : /*
     693             :  * This gets an org.freedesktop.DBus.Properties boolean
     694             :  * (as opposed to the old Bluez 4 custom properties methods as visible above).
     695             :  */
     696             : static bool
     697           0 : getDBusBooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
     698             :                         const char *pPropertyName, bool *pBoolean )
     699             : {
     700             :     assert( pAdapter );
     701             : 
     702           0 :     *pBoolean = false;
     703           0 :     bool bRet = false;
     704             : 
     705             :     ::boost::scoped_ptr< DBusObject > pProperties (
     706           0 :             pAdapter->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
     707             : 
     708           0 :     DBusMessage *pMsg = pProperties->getMethodCall( "Get" );
     709             : 
     710             :     DBusMessageIter itIn;
     711           0 :     dbus_message_iter_init_append( pMsg, &itIn );
     712           0 :     const char* pInterface = "org.bluez.Adapter1";
     713           0 :     dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pInterface );
     714           0 :     dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pPropertyName );
     715           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
     716             : 
     717             :     DBusMessageIter it;
     718           0 :     if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
     719             :     {
     720             :         SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
     721           0 :         return false;
     722             :     }
     723             : 
     724           0 :     if( DBUS_TYPE_VARIANT != dbus_message_iter_get_arg_type( &it ) )
     725             :     {
     726             :         SAL_WARN( "sdremote.bluetooth", "invalid return type" );
     727             :     }
     728             :     else
     729             :     {
     730             :         DBusMessageIter variantIt;
     731           0 :         dbus_message_iter_recurse( &it, &variantIt );
     732             : 
     733           0 :         if( dbus_message_iter_get_arg_type( &variantIt ) == DBUS_TYPE_BOOLEAN )
     734             :         {
     735           0 :             dbus_bool_t bBool = false;
     736           0 :             dbus_message_iter_get_basic( &variantIt, &bBool );
     737             :             SAL_INFO( "sdremote.bluetooth", "" << pPropertyName << " is " << bBool );
     738           0 :             *pBoolean = bBool;
     739           0 :             bRet = true;
     740             :         }
     741             :         else
     742             :         {
     743             :             SAL_WARN( "sdremote.bluetooth", "" << pPropertyName << " type " <<
     744             :                         dbus_message_iter_get_arg_type( &variantIt ) );
     745             :         }
     746             : 
     747           0 :         const char* pError = dbus_message_get_error_name( pMsg );
     748           0 :         if ( pError )
     749             :         {
     750             :             SAL_WARN( "sdremote.bluetooth",
     751             :                       "Get failed for " << pPropertyName << " on " <<
     752             :                       pAdapter->maPath  << " with error: " << pError );
     753             :         }
     754             :     }
     755           0 :     dbus_message_unref( pMsg );
     756             : 
     757           0 :     return bRet;
     758             : }
     759             : 
     760             : static void
     761           0 : setDBusBooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
     762             :                         const char *pPropertyName, bool bBoolean )
     763             : {
     764             :     assert( pAdapter );
     765             : 
     766             :     ::boost::scoped_ptr< DBusObject > pProperties(
     767           0 :             pAdapter->cloneForInterface( "org.freedesktop.DBus.Properties" ) );
     768             : 
     769           0 :     DBusMessage *pMsg = pProperties->getMethodCall( "Set" );
     770             : 
     771             :     DBusMessageIter itIn;
     772           0 :     dbus_message_iter_init_append( pMsg, &itIn );
     773           0 :     const char* pInterface = "org.bluez.Adapter1";
     774           0 :     dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pInterface );
     775           0 :     dbus_message_iter_append_basic( &itIn, DBUS_TYPE_STRING, &pPropertyName );
     776             : 
     777             :     {
     778             :         DBusMessageIter varIt;
     779             :         dbus_message_iter_open_container( &itIn, DBUS_TYPE_VARIANT,
     780           0 :                                         DBUS_TYPE_BOOLEAN_AS_STRING, &varIt );
     781           0 :         dbus_bool_t bDBusBoolean = bBoolean;
     782           0 :         dbus_message_iter_append_basic( &varIt, DBUS_TYPE_BOOLEAN, &bDBusBoolean );
     783           0 :         dbus_message_iter_close_container( &itIn, &varIt );
     784             :     }
     785             : 
     786           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
     787             : 
     788           0 :     if( !pMsg )
     789             :     {
     790             :         SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
     791             :     }
     792             :     else
     793             :     {
     794           0 :         const char* pError = dbus_message_get_error_name( pMsg );
     795           0 :         if ( pError )
     796             :         {
     797             :             SAL_WARN( "sdremote.bluetooth",
     798             :                       "Set failed for " << pPropertyName << " on " <<
     799             :                       pAdapter->maPath << " with error: " << pError );
     800             :         }
     801           0 :         dbus_message_unref( pMsg );
     802           0 :     }
     803           0 : }
     804             : 
     805             : static bool
     806           0 : getDiscoverable( DBusConnection *pConnection, DBusObject *pAdapter )
     807             : {
     808           0 :     if (pAdapter->maInterface == "org.bluez.Adapter") // Bluez 4
     809             :     {
     810             :         bool bDiscoverable;
     811           0 :         if( getBluez4BooleanProperty(pConnection, pAdapter, "Discoverable", &bDiscoverable ) )
     812           0 :             return bDiscoverable;
     813             :     }
     814           0 :     else if (pAdapter->maInterface == "org.bluez.Adapter1") // Bluez 5
     815             :     {
     816             :         bool bDiscoverable;
     817           0 :         if ( getDBusBooleanProperty(pConnection, pAdapter, "Discoverable", &bDiscoverable ) )
     818           0 :             return bDiscoverable;
     819             :     }
     820           0 :     return false;
     821             : }
     822             : 
     823             : static void
     824           0 : setDiscoverable( DBusConnection *pConnection, DBusObject *pAdapter, bool bDiscoverable )
     825             : {
     826             :     SAL_INFO( "sdremote.bluetooth", "setDiscoverable to " << bDiscoverable );
     827             : 
     828           0 :     if (pAdapter->maInterface == "org.bluez.Adapter") // Bluez 4
     829             :     {
     830           0 :         bool bPowered = false;
     831           0 :         if( !getBluez4BooleanProperty( pConnection, pAdapter, "Powered", &bPowered ) || !bPowered )
     832           0 :             return; // nothing to do
     833             : 
     834             :         DBusMessage *pMsg;
     835             :         DBusMessageIter it, varIt;
     836             : 
     837             :         // set timeout to zero
     838           0 :         pMsg = pAdapter->getMethodCall( "SetProperty" );
     839           0 :         dbus_message_iter_init_append( pMsg, &it );
     840           0 :         const char *pTimeoutStr = "DiscoverableTimeout";
     841           0 :         dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pTimeoutStr );
     842             :         dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
     843           0 :                                         DBUS_TYPE_UINT32_AS_STRING, &varIt );
     844           0 :         dbus_uint32_t nTimeout = 0;
     845           0 :         dbus_message_iter_append_basic( &varIt, DBUS_TYPE_UINT32, &nTimeout );
     846           0 :         dbus_message_iter_close_container( &it, &varIt );
     847           0 :         dbus_connection_send( pConnection, pMsg, NULL ); // async send - why not ?
     848           0 :         dbus_message_unref( pMsg );
     849             : 
     850             :         // set discoverable value
     851           0 :         pMsg = pAdapter->getMethodCall( "SetProperty" );
     852           0 :         dbus_message_iter_init_append( pMsg, &it );
     853           0 :         const char *pDiscoverableStr = "Discoverable";
     854           0 :         dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pDiscoverableStr );
     855             :         dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
     856           0 :                                         DBUS_TYPE_BOOLEAN_AS_STRING, &varIt );
     857           0 :         dbus_bool_t bValue = bDiscoverable;
     858           0 :         dbus_message_iter_append_basic( &varIt, DBUS_TYPE_BOOLEAN, &bValue );
     859           0 :         dbus_message_iter_close_container( &it, &varIt ); // async send - why not ?
     860           0 :         dbus_connection_send( pConnection, pMsg, NULL );
     861           0 :         dbus_message_unref( pMsg );
     862             :     }
     863           0 :     else if  (pAdapter->maInterface == "org.bluez.Adapter1") // Bluez 5
     864             :     {
     865           0 :         setDBusBooleanProperty(pConnection, pAdapter, "Discoverable", bDiscoverable );
     866             :     }
     867             : }
     868             : 
     869             : static DBusObject *
     870           0 : registerWithDefaultAdapter( DBusConnection *pConnection )
     871             : {
     872             :     DBusObject *pService;
     873           0 :     pService = bluez4GetDefaultService( pConnection );
     874           0 :     if( pService )
     875             :     {
     876           0 :         if( !bluez4RegisterServiceRecord( pConnection, pService,
     877           0 :                                      bluetooth_service_record ) )
     878             :         {
     879           0 :             delete pService;
     880           0 :             return NULL;
     881             :         }
     882             :     }
     883             : 
     884           0 :     return pService;
     885             : }
     886             : 
     887           0 : void ProfileUnregisterFunction
     888             : (DBusConnection *connection, void *user_data)
     889             : {
     890             :     // We specifically don't need to do anything here.
     891             :     (void) connection;
     892             :     (void) user_data;
     893           0 : }
     894             : 
     895           0 : DBusHandlerResult ProfileMessageFunction
     896             : (DBusConnection *pConnection, DBusMessage *pMessage, void *user_data)
     897             : {
     898             :     SAL_INFO("sdremote.bluetooth", "ProfileMessageFunction||" << dbus_message_get_interface(pMessage) << "||" <<  dbus_message_get_member(pMessage));
     899           0 :     DBusHandlerResult aRet = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     900             : 
     901           0 :     if (OString(dbus_message_get_interface(pMessage)).equals("org.bluez.Profile1"))
     902             :     {
     903           0 :         if (OString(dbus_message_get_member(pMessage)).equals("Release"))
     904             :         {
     905           0 :             return DBUS_HANDLER_RESULT_HANDLED;
     906             :         }
     907           0 :         else if (OString(dbus_message_get_member(pMessage)).equals("NewConnection"))
     908             :         {
     909           0 :             if (!dbus_message_has_signature(pMessage, "oha{sv}"))
     910             :             {
     911             :                 SAL_WARN("sdremote.bluetooth", "wrong signature for NewConnection");
     912             :             }
     913             : 
     914             :             DBusMessageIter it;
     915           0 :             if (!dbus_message_iter_init(pMessage, &it))
     916             :                 SAL_WARN( "sdremote.bluetooth", "error init dbus" );
     917             :             else
     918             :             {
     919             :                 char* pPath;
     920           0 :                 dbus_message_iter_get_basic(&it, &pPath);
     921             :                 SAL_INFO("sdremote.bluetooth", "Adapter path:" << pPath);
     922             : 
     923           0 :                 if (!dbus_message_iter_next(&it))
     924             :                     SAL_WARN("sdremote.bluetooth", "not enough parameters passed");
     925             : 
     926             :                 // DBUS_TYPE_UNIX_FD == 'h' -- doesn't exist in older versions
     927             :                 // of dbus (< 1.3?) hence defined manually for now
     928           0 :                 if ('h' == dbus_message_iter_get_arg_type(&it))
     929             :                 {
     930             : 
     931             :                     int nDescriptor;
     932           0 :                     dbus_message_iter_get_basic(&it, &nDescriptor);
     933           0 :                     std::vector<Communicator*>* pCommunicators = (std::vector<Communicator*>*) user_data;
     934             : 
     935             :                     // Bluez gives us non-blocking sockets, but our code relies
     936             :                     // on blocking behaviour.
     937           0 :                     (void)fcntl(nDescriptor, F_SETFL, fcntl(nDescriptor, F_GETFL) & ~O_NONBLOCK);
     938             : 
     939             :                     SAL_INFO( "sdremote.bluetooth", "connection accepted " << nDescriptor);
     940           0 :                     Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( nDescriptor ) );
     941           0 :                     pCommunicators->push_back( pCommunicator );
     942           0 :                     pCommunicator->launch();
     943             :                 }
     944             : 
     945             :                 // For some reason an (empty?) reply is expected.
     946           0 :                 DBusMessage* pRet = dbus_message_new_method_return(pMessage);
     947           0 :                 dbus_connection_send(pConnection, pRet, NULL);
     948           0 :                 dbus_message_unref(pRet);
     949             : 
     950             :                 // We could read the remote profile version and features here
     951             :                 // (i.e. they are provided as part of the DBusMessage),
     952             :                 // however for us they are irrelevant (as our protocol handles
     953             :                 // equivalent functionality independently of whether we're on
     954             :                 // bluetooth or normal network connection).
     955           0 :                 return DBUS_HANDLER_RESULT_HANDLED;
     956             :             }
     957             :         }
     958           0 :         else if (OString(dbus_message_get_member(pMessage)).equals("RequestDisconnection"))
     959             :         {
     960           0 :             return DBUS_HANDLER_RESULT_HANDLED;
     961             :         }
     962             :     }
     963             :     SAL_WARN("sdremote.bluetooth", "Couldn't handle message correctly.");
     964           0 :     return aRet;
     965             : 
     966             : }
     967             : 
     968             : static void
     969           0 : setupBluez5Profile1(DBusConnection* pConnection, std::vector<Communicator*>* pCommunicators)
     970             : {
     971             :     bool bErr;
     972             : 
     973             :     SAL_INFO("sdremote.bluetooth", "Attempting to register our org.bluez.Profile1");
     974             :     static DBusObjectPathVTable aVTable;
     975           0 :     aVTable.unregister_function = ProfileUnregisterFunction;
     976           0 :     aVTable.message_function = ProfileMessageFunction;
     977             : 
     978             :     // dbus_connection_try_register_object_path could be used but only exists for
     979             :     // dbus-glib >= 1.2 -- we really shouldn't be trying this twice in any case.
     980             :     // (dbus_connection_try_register_object_path also returns an error with more
     981             :     // information which could be useful for debugging purposes.)
     982           0 :     bErr = !dbus_connection_register_object_path(pConnection, "/org/libreoffice/bluez/profile1", &aVTable, pCommunicators);
     983             : 
     984           0 :     if (bErr)
     985             :     {
     986             :         SAL_WARN("sdremote.bluetooth", "Failed to register Bluez 5 Profile1 callback, bluetooth won't work.");
     987             :     }
     988             : 
     989           0 :     dbus_connection_flush( pConnection );
     990           0 : }
     991             : 
     992             : static void
     993           0 : unregisterBluez5Profile(DBusConnection* pConnection)
     994             : {
     995             :     DBusMessage* pMsg = dbus_message_new_method_call("org.bluez", "/org/bluez",
     996           0 :                                         "org.bluez.ProfileManager1", "UnregisterProfile");
     997             :     DBusMessageIter it;
     998           0 :     dbus_message_iter_init_append(pMsg, &it);
     999             : 
    1000           0 :     const char *pPath = "/org/libreoffice/bluez/profile1";
    1001           0 :     dbus_message_iter_append_basic(&it, DBUS_TYPE_OBJECT_PATH, &pPath);
    1002             : 
    1003           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
    1004             : 
    1005           0 :     if (pMsg)
    1006           0 :         dbus_message_unref(pMsg);
    1007             : 
    1008           0 :     dbus_connection_unregister_object_path( pConnection, "/org/libreoffice/bluez/profile1");
    1009             : 
    1010           0 :     dbus_connection_flush(pConnection);
    1011           0 : }
    1012             : 
    1013             : static bool
    1014           0 : registerBluez5Profile(DBusConnection* pConnection, std::vector<Communicator*>* pCommunicators)
    1015             : {
    1016           0 :     setupBluez5Profile1(pConnection, pCommunicators);
    1017             : 
    1018             :     DBusMessage *pMsg;
    1019             :     DBusMessageIter it;
    1020             : 
    1021             :     pMsg = dbus_message_new_method_call("org.bluez", "/org/bluez",
    1022           0 :                                         "org.bluez.ProfileManager1", "RegisterProfile");
    1023           0 :     dbus_message_iter_init_append(pMsg, &it);
    1024             : 
    1025           0 :     const char *pPath = "/org/libreoffice/bluez/profile1";
    1026           0 :     dbus_message_iter_append_basic(&it, DBUS_TYPE_OBJECT_PATH, &pPath);
    1027           0 :     const char *pUUID =  "spp"; // Bluez translates this to 0x1101 for spp
    1028           0 :     dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &pUUID);
    1029             : 
    1030             :     DBusMessageIter aOptionsIter;
    1031           0 :     dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "{sv}", &aOptionsIter);
    1032             : 
    1033             :     DBusMessageIter aEntry;
    1034             : 
    1035             :     {
    1036           0 :         dbus_message_iter_open_container(&aOptionsIter, DBUS_TYPE_DICT_ENTRY, NULL, &aEntry);
    1037             : 
    1038           0 :         const char *pString = "Name";
    1039           0 :         dbus_message_iter_append_basic(&aEntry, DBUS_TYPE_STRING, &pString);
    1040             : 
    1041           0 :         const char *pValue = "LibreOffice Impress Remote";
    1042             :         DBusMessageIter aValue;
    1043           0 :         dbus_message_iter_open_container(&aEntry, DBUS_TYPE_VARIANT, "s", &aValue);
    1044           0 :         dbus_message_iter_append_basic(&aValue, DBUS_TYPE_STRING, &pValue);
    1045           0 :         dbus_message_iter_close_container(&aEntry, &aValue);
    1046           0 :         dbus_message_iter_close_container(&aOptionsIter, &aEntry);
    1047             :     }
    1048             : 
    1049           0 :     dbus_message_iter_close_container(&it, &aOptionsIter);
    1050             : 
    1051             :     // Other properties that we could set (but don't, since they appear
    1052             :     // to be useless for us):
    1053             :     // "Service": "0x1101" (not needed, but we used to have it in the manually defined profile).
    1054             :     // "Role": setting this to "server" breaks things, although we think we're a server?
    1055             :     // "Channel": seems to be dealt with automatically (but we used to use 5 in the manual profile).
    1056             : 
    1057           0 :     bool bSuccess = true;
    1058             : 
    1059           0 :     pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
    1060             : 
    1061             :     DBusError aError;
    1062           0 :     dbus_error_init(&aError);
    1063           0 :     if (pMsg && dbus_set_error_from_message( &aError, pMsg ))
    1064             :     {
    1065           0 :         bSuccess = false;
    1066             :         SAL_WARN("sdremote.bluetooth",
    1067             :                  "Failed to register our Profile1 with bluez ProfileManager "
    1068             :                  << (const char *)(aError.message ? aError.message : "<null>"));
    1069             :     }
    1070             : 
    1071           0 :     dbus_error_free(&aError);
    1072           0 :     if (pMsg)
    1073           0 :         dbus_message_unref(pMsg);
    1074             : 
    1075           0 :     dbus_connection_flush(pConnection);
    1076             : 
    1077           0 :     return bSuccess;
    1078             : }
    1079             : 
    1080             : #endif // LINUX_BLUETOOTH
    1081             : 
    1082           0 : BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
    1083             :   : meWasDiscoverable( UNKNOWN ),
    1084           0 :     mpCommunicators( pCommunicators )
    1085             : {
    1086             : #ifdef LINUX_BLUETOOTH
    1087             :     // D-Bus requires the following in order to be thread-safe (and we
    1088             :     // potentially access D-Bus from different threads in different places of
    1089             :     // the code base):
    1090           0 :     if (!dbus_threads_init_default()) {
    1091           0 :         throw std::bad_alloc();
    1092             :     }
    1093             : 
    1094           0 :     mpImpl.reset(new BluetoothServer::Impl());
    1095             : #endif
    1096           0 : }
    1097             : 
    1098           0 : BluetoothServer::~BluetoothServer()
    1099             : {
    1100           0 : }
    1101             : 
    1102           0 : void BluetoothServer::ensureDiscoverable()
    1103             : {
    1104             : #ifdef LINUX_BLUETOOTH
    1105             :     // Push it all across into our mainloop
    1106           0 :     if( !spServer )
    1107           0 :         return;
    1108           0 :     GSource *pIdle = g_idle_source_new();
    1109           0 :     g_source_set_callback( pIdle, ensureDiscoverable_cb, NULL, NULL );
    1110           0 :     g_source_set_priority( pIdle, G_PRIORITY_DEFAULT );
    1111           0 :     g_source_attach( pIdle, spServer->mpImpl->mpContext );
    1112           0 :     g_source_unref( pIdle );
    1113             : #endif
    1114             : }
    1115             : 
    1116           0 : void BluetoothServer::restoreDiscoverable()
    1117             : {
    1118             : #ifdef LINUX_BLUETOOTH
    1119             :     // Push it all across into our mainloop
    1120           0 :     if( !spServer )
    1121           0 :         return;
    1122           0 :     GSource *pIdle = g_idle_source_new();
    1123           0 :     g_source_set_callback( pIdle, restoreDiscoverable_cb, NULL, NULL );
    1124           0 :     g_source_set_priority( pIdle, G_PRIORITY_DEFAULT_IDLE );
    1125           0 :     g_source_attach( pIdle, spServer->mpImpl->mpContext );
    1126           0 :     g_source_unref( pIdle );
    1127             : #endif
    1128             : }
    1129             : 
    1130           0 : void BluetoothServer::doEnsureDiscoverable()
    1131             : {
    1132             : #ifdef LINUX_BLUETOOTH
    1133           0 :     if (!spServer->mpImpl->mpConnection ||
    1134           0 :         spServer->meWasDiscoverable != UNKNOWN )
    1135           0 :         return;
    1136             : 
    1137             :     // Find out if we are discoverable already ...
    1138           0 :     DBusObject *pAdapter = spServer->mpImpl->getAdapter();
    1139           0 :     if( !pAdapter )
    1140           0 :         return;
    1141             : 
    1142           0 :     bool bDiscoverable = getDiscoverable(spServer->mpImpl->mpConnection, pAdapter );
    1143             : 
    1144           0 :     spServer->meWasDiscoverable = bDiscoverable ? DISCOVERABLE : NOT_DISCOVERABLE;
    1145           0 :     if( !bDiscoverable )
    1146           0 :         setDiscoverable( spServer->mpImpl->mpConnection, pAdapter, true );
    1147             : 
    1148           0 :     delete pAdapter;
    1149             : #endif
    1150             : }
    1151             : 
    1152           0 : void BluetoothServer::doRestoreDiscoverable()
    1153             : {
    1154           0 :     if( spServer->meWasDiscoverable == NOT_DISCOVERABLE )
    1155             :     {
    1156             : #ifdef LINUX_BLUETOOTH
    1157           0 :         DBusObject *pAdapter = spServer->mpImpl->getAdapter();
    1158           0 :         if( !pAdapter )
    1159           0 :             return;
    1160           0 :         setDiscoverable( spServer->mpImpl->mpConnection, pAdapter, false );
    1161           0 :         delete pAdapter;
    1162             : #endif
    1163             :     }
    1164           0 :     spServer->meWasDiscoverable = UNKNOWN;
    1165             : }
    1166             : 
    1167             : // We have to have all our clients shut otherwise we can't
    1168             : // re-bind to the same port number it appears.
    1169           0 : void BluetoothServer::cleanupCommunicators()
    1170             : {
    1171           0 :     for (std::vector<Communicator *>::iterator it = mpCommunicators->begin();
    1172           0 :          it != mpCommunicators->end(); ++it)
    1173           0 :         (*it)->forceClose();
    1174             :     // the hope is that all the threads then terminate cleanly and
    1175             :     // clean themselves up.
    1176           0 : }
    1177             : 
    1178           0 : void SAL_CALL BluetoothServer::run()
    1179             : {
    1180             :     SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
    1181           0 :     osl::Thread::setName("BluetoothServer");
    1182             : #ifdef LINUX_BLUETOOTH
    1183           0 :     DBusConnection *pConnection = dbusConnectToNameOnBus();
    1184           0 :     if( !pConnection )
    1185           0 :         return;
    1186             : 
    1187             :     // For either implementation we need to poll the dbus fd
    1188           0 :     int fd = -1;
    1189             :     GPollFD aDBusFD;
    1190           0 :     if( dbus_connection_get_unix_fd( pConnection, &fd ) && fd >= 0 )
    1191             :     {
    1192           0 :         aDBusFD.fd = fd;
    1193           0 :         aDBusFD.events = G_IO_IN | G_IO_PRI;
    1194           0 :         g_main_context_add_poll( mpImpl->mpContext, &aDBusFD, G_PRIORITY_DEFAULT );
    1195             :     }
    1196             :     else
    1197             :         SAL_WARN( "sdremote.bluetooth", "failed to poll for incoming dbus signals" );
    1198             : 
    1199           0 :     if (isBluez5Available(pConnection))
    1200             :     {
    1201             :         SAL_INFO("sdremote.bluetooth", "Using Bluez 5");
    1202           0 :         registerBluez5Profile(pConnection, mpCommunicators);
    1203           0 :         mpImpl->mpConnection = pConnection;
    1204           0 :         mpImpl->maBluezVersion = Impl::BLUEZ5;
    1205             : 
    1206             :         // We don't need to listen to adapter changes anymore -- profile
    1207             :         // registration is done globally for the entirety of bluez, so we only
    1208             :         // need adapters when setting discovereability, which can be done
    1209             :         // dyanmically without the need to listen for changes.
    1210             : 
    1211             :         // TODO: exit on SD deinit
    1212             :         // Probably best to do that in SdModule::~SdModule?
    1213           0 :         while (!mpImpl->mbExitMainloop)
    1214             :         {
    1215           0 :             aDBusFD.revents = 0;
    1216           0 :             g_main_context_iteration( mpImpl->mpContext, TRUE );
    1217           0 :             if( aDBusFD.revents )
    1218             :             {
    1219           0 :                 dbus_connection_read_write( pConnection, 0 );
    1220           0 :                 while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status( pConnection ))
    1221           0 :                     dbus_connection_dispatch( pConnection );
    1222             :             }
    1223             :         }
    1224           0 :         unregisterBluez5Profile( pConnection );
    1225           0 :         g_main_context_unref( mpImpl->mpContext );
    1226           0 :         mpImpl->mpConnection = NULL;
    1227           0 :         mpImpl->mpContext = NULL;
    1228           0 :         return;
    1229             :     }
    1230             : 
    1231             :     // Otherwise we could be on Bluez 4 and continue as usual.
    1232           0 :     mpImpl->maBluezVersion = Impl::BLUEZ4;
    1233             : 
    1234             :     // Try to setup the default adapter, otherwise wait for add/remove signal
    1235           0 :     mpImpl->mpService = registerWithDefaultAdapter( pConnection );
    1236             :     // listen for connection state and power changes - we need to close
    1237             :     // and re-create our socket code on suspend / resume, enable/disable
    1238             :     DBusError aError;
    1239           0 :     dbus_error_init( &aError );
    1240           0 :     dbus_bus_add_match( pConnection, "type='signal',interface='org.bluez.Manager'", &aError );
    1241           0 :     dbus_connection_flush( pConnection );
    1242             : 
    1243             :     // Try to setup the default adapter, otherwise wait for add/remove signal
    1244           0 :     mpImpl->mpService = registerWithDefaultAdapter( pConnection );
    1245             : 
    1246             :     // poll on our bluetooth socket - if we can.
    1247             :     GPollFD aSocketFD;
    1248           0 :     if( mpImpl->mpService )
    1249           0 :         bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
    1250             : 
    1251           0 :     mpImpl->mpConnection = pConnection;
    1252             : 
    1253           0 :     while( !mpImpl->mbExitMainloop )
    1254             :     {
    1255           0 :         aDBusFD.revents = 0;
    1256           0 :         aSocketFD.revents = 0;
    1257           0 :         g_main_context_iteration( mpImpl->mpContext, TRUE );
    1258             : 
    1259             :         SAL_INFO( "sdremote.bluetooth", "main-loop spin "
    1260             :                   << aDBusFD.revents << " " << aSocketFD.revents );
    1261           0 :         if( aDBusFD.revents )
    1262             :         {
    1263           0 :             dbus_connection_read_write( pConnection, 0 );
    1264           0 :             DBusMessage *pMsg = dbus_connection_pop_message( pConnection );
    1265           0 :             if( pMsg )
    1266             :             {
    1267           0 :                 if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterRemoved" ) )
    1268             :                 {
    1269             :                     SAL_WARN( "sdremote.bluetooth", "lost adapter - cleaning up sockets" );
    1270           0 :                     bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
    1271           0 :                     cleanupCommunicators();
    1272             :                 }
    1273           0 :                 else if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterAdded" ) ||
    1274           0 :                          dbus_message_is_signal( pMsg, "org.bluez.Manager", "DefaultAdapterChanged" ) )
    1275             :                 {
    1276             :                     SAL_WARN( "sdremote.bluetooth", "gained adapter - re-generating sockets" );
    1277           0 :                     bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
    1278           0 :                     cleanupCommunicators();
    1279           0 :                     mpImpl->mpService = registerWithDefaultAdapter( pConnection );
    1280           0 :                     if( mpImpl->mpService )
    1281           0 :                         bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
    1282             :                 }
    1283             :                 else
    1284             :                     SAL_INFO( "sdremote.bluetooth", "unknown incoming dbus message, "
    1285             :                                  " type: " << dbus_message_get_type( pMsg )
    1286             :                               << " path: '" << dbus_message_get_path( pMsg )
    1287             :                               << "' interface: '" << dbus_message_get_interface( pMsg )
    1288             :                               << "' member: '" << dbus_message_get_member( pMsg ) );
    1289             :             }
    1290           0 :             dbus_message_unref( pMsg );
    1291             :         }
    1292             : 
    1293           0 :         if( aSocketFD.revents )
    1294             :         {
    1295             :             sockaddr_rc aRemoteAddr;
    1296           0 :             socklen_t aRemoteAddrLen = sizeof(aRemoteAddr);
    1297             : 
    1298             :             int nClient;
    1299             :             SAL_INFO( "sdremote.bluetooth", "performing accept" );
    1300           0 :             if ( ( nClient = accept( aSocketFD.fd, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) < 0 &&
    1301           0 :                  errno != EAGAIN )
    1302             :             {
    1303             :                 SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << errno );
    1304             :             } else {
    1305             :                 SAL_INFO( "sdremote.bluetooth", "connection accepted " << nClient );
    1306           0 :                 Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( nClient ) );
    1307           0 :                 mpCommunicators->push_back( pCommunicator );
    1308           0 :                 pCommunicator->launch();
    1309             :             }
    1310             :         }
    1311             :     }
    1312             : 
    1313           0 :     unregisterBluez5Profile( pConnection );
    1314           0 :     g_main_context_unref( mpImpl->mpContext );
    1315           0 :     mpImpl->mpConnection = NULL;
    1316           0 :     mpImpl->mpContext = NULL;
    1317             : 
    1318             : #elif defined(WIN32)
    1319             :     WORD wVersionRequested;
    1320             :     WSADATA wsaData;
    1321             : 
    1322             :     wVersionRequested = MAKEWORD(2, 2);
    1323             : 
    1324             :     if ( WSAStartup(wVersionRequested, &wsaData) )
    1325             :     {
    1326             :         return; // winsock dll couldn't be loaded
    1327             :     }
    1328             : 
    1329             :     int aSocket = socket( AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM );
    1330             :     if ( !aSocket )
    1331             :     {
    1332             :         WSACleanup();
    1333             :         return;
    1334             :     }
    1335             :     SOCKADDR_BTH aAddr;
    1336             :     aAddr.addressFamily = AF_BTH;
    1337             :     aAddr.btAddr = 0;
    1338             :     aAddr.serviceClassId = GUID_NULL;
    1339             :     aAddr.port = BT_PORT_ANY; // Select any free socket.
    1340             :     if ( bind( aSocket, (SOCKADDR*) &aAddr, sizeof(aAddr) ) == SOCKET_ERROR )
    1341             :     {
    1342             :         closesocket( aSocket );
    1343             :         WSACleanup();
    1344             :         return;
    1345             :     }
    1346             : 
    1347             :     SOCKADDR aName;
    1348             :     int aNameSize = sizeof(aAddr);
    1349             :     getsockname( aSocket, &aName, &aNameSize ); // Retrieve the local address and port
    1350             : 
    1351             :     CSADDR_INFO aAddrInfo;
    1352             :     memset( &aAddrInfo, 0, sizeof(aAddrInfo) );
    1353             :     aAddrInfo.LocalAddr.lpSockaddr = &aName;
    1354             :     aAddrInfo.LocalAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );
    1355             :     aAddrInfo.RemoteAddr.lpSockaddr = &aName;
    1356             :     aAddrInfo.RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );
    1357             :     aAddrInfo.iSocketType = SOCK_STREAM;
    1358             :     aAddrInfo.iProtocol = BTHPROTO_RFCOMM;
    1359             : 
    1360             :     // To be used for setting a custom UUID once available.
    1361             : //    GUID uuid;
    1362             : //    uuid.Data1 = 0x00001101;
    1363             : //  memset( &uuid, 0x1000 + UUID*2^96, sizeof( GUID ) );
    1364             : //    uuid.Data2 = 0;
    1365             : //    uuid.Data3 = 0x1000;
    1366             : //    ULONGLONG aData4 = 0x800000805F9B34FB;
    1367             : //    memcpy( uuid.Data4, &aData4, sizeof(uuid.Data4) );
    1368             : 
    1369             :     WSAQUERYSET aRecord;
    1370             :     memset( &aRecord, 0, sizeof(aRecord));
    1371             :     aRecord.dwSize = sizeof(aRecord);
    1372             :     aRecord.lpszServiceInstanceName = (char *)"LibreOffice Impress Remote Control";
    1373             :     aRecord.lpszComment = (char *)"Remote control of presentations over bluetooth.";
    1374             :     aRecord.lpServiceClassId = (LPGUID) &SerialPortServiceClass_UUID;
    1375             :     aRecord.dwNameSpace = NS_BTH;
    1376             :     aRecord.dwNumberOfCsAddrs = 1;
    1377             :     aRecord.lpcsaBuffer = &aAddrInfo;
    1378             : 
    1379             :     if ( WSASetService( &aRecord, RNRSERVICE_REGISTER, 0 ) == SOCKET_ERROR )
    1380             :     {
    1381             :         closesocket( aSocket );
    1382             :         WSACleanup();
    1383             :         return;
    1384             :     }
    1385             : 
    1386             :     if ( listen( aSocket, 1 ) == SOCKET_ERROR )
    1387             :     {
    1388             :         closesocket( aSocket );
    1389             :         WSACleanup();
    1390             :         return;
    1391             :     }
    1392             : 
    1393             :     SOCKADDR_BTH aRemoteAddr;
    1394             :     int aRemoteAddrLen = sizeof(aRemoteAddr);
    1395             :     while ( true )
    1396             :     {
    1397             :         SOCKET socket;
    1398             :         if ( (socket = accept(aSocket, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) == INVALID_SOCKET )
    1399             :         {
    1400             :             closesocket( aSocket );
    1401             :             WSACleanup();
    1402             :             return;
    1403             :         } else {
    1404             :             Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( socket) );
    1405             :             mpCommunicators->push_back( pCommunicator );
    1406             :             pCommunicator->launch();
    1407             :         }
    1408             :     }
    1409             : 
    1410             : #elif defined(MACOSX)
    1411             :     // Build up dictionary at run-time instead of bothering with a
    1412             :     // .plist file, using the Objective-C API
    1413             : 
    1414             :     // Compare to BluetoothServiceRecord.hxx
    1415             : 
    1416             :     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    1417             : 
    1418             :     NSDictionary *dict =
    1419             :         [NSDictionary dictionaryWithObjectsAndKeys:
    1420             : 
    1421             :          // Service class ID list
    1422             :          [NSArray arrayWithObject:
    1423             :           [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassSerialPort]],
    1424             :          @"0001 - ServiceClassIDList",
    1425             : 
    1426             :          // Protocol descriptor list
    1427             :          [NSArray arrayWithObjects:
    1428             :           [NSArray arrayWithObject: [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16L2CAP]],
    1429             :           [NSArray arrayWithObjects:
    1430             :            [IOBluetoothSDPUUID uuid16: kBluetoothL2CAPPSMRFCOMM],
    1431             :            [NSDictionary dictionaryWithObjectsAndKeys:
    1432             :             [NSNumber numberWithInt: 1],
    1433             :             @"DataElementSize",
    1434             :             [NSNumber numberWithInt: 1],
    1435             :             @"DataElementType",
    1436             :             [NSNumber numberWithInt: 5], // RFCOMM port number, will be replaced if necessary automatically
    1437             :             @"DataElementValue",
    1438             :             nil],
    1439             :            nil],
    1440             :           nil],
    1441             :          @"0004 - Protocol descriptor list",
    1442             : 
    1443             :          // Browse group list
    1444             :          [NSArray arrayWithObject:
    1445             :           [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassPublicBrowseGroup]],
    1446             :          @"0005 - BrowseGroupList",
    1447             : 
    1448             :          // Language base attribute ID list
    1449             :          [NSArray arrayWithObjects:
    1450             :           [NSData dataWithBytes: "en" length: 2],
    1451             :           [NSDictionary dictionaryWithObjectsAndKeys:
    1452             :            [NSNumber numberWithInt: 2],
    1453             :            @"DataElementSize",
    1454             :            [NSNumber numberWithInt: 1],
    1455             :            @"DataElementType",
    1456             :            [NSNumber numberWithInt: 0x006a], // encoding
    1457             :            @"DataElementValue",
    1458             :            nil],
    1459             :           [NSDictionary dictionaryWithObjectsAndKeys:
    1460             :            [NSNumber numberWithInt: 2],
    1461             :            @"DataElementSize",
    1462             :            [NSNumber numberWithInt: 1],
    1463             :            @"DataElementType",
    1464             :            [NSNumber numberWithInt: 0x0100], // offset
    1465             :            @"DataElementValue",
    1466             :            nil],
    1467             :           nil],
    1468             :          @"0006 - LanguageBaseAttributeIDList",
    1469             : 
    1470             :          // Bluetooth profile descriptor list
    1471             :          [NSArray arrayWithObject:
    1472             :           [NSArray arrayWithObjects:
    1473             :            [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16ServiceClassSerialPort],
    1474             :            [NSDictionary dictionaryWithObjectsAndKeys:
    1475             :             [NSNumber numberWithInt: 2],
    1476             :             @"DataElementSize",
    1477             :             [NSNumber numberWithInt: 1],
    1478             :             @"DataElementType",
    1479             :             [NSNumber numberWithInt: 0x0100], // version number ?
    1480             :             @"DataElementValue",
    1481             :             nil],
    1482             :            nil]],
    1483             :          @"0009 - BluetoothProfileDescriptorList",
    1484             : 
    1485             :          // Attributes pointed to by the LanguageBaseAttributeIDList
    1486             :          @"LibreOffice Impress Remote Control",
    1487             :          @"0100 - ServiceName",
    1488             :          @"The Document Foundation",
    1489             :          @"0102 - ProviderName",
    1490             :          nil];
    1491             : 
    1492             :     // Create service
    1493             :     IOBluetoothSDPServiceRecordRef serviceRecordRef;
    1494             :     IOReturn rc = IOBluetoothAddServiceDict((CFDictionaryRef) dict, &serviceRecordRef);
    1495             : 
    1496             :     SAL_INFO("sdremote.bluetooth", "IOBluetoothAddServiceDict returned " << rc);
    1497             : 
    1498             :     if (rc == kIOReturnSuccess)
    1499             :     {
    1500             :         IOBluetoothSDPServiceRecord *serviceRecord =
    1501             :             [IOBluetoothSDPServiceRecord withSDPServiceRecordRef: serviceRecordRef];
    1502             : 
    1503             :         BluetoothRFCOMMChannelID channelID;
    1504             :         [serviceRecord getRFCOMMChannelID: &channelID];
    1505             : 
    1506             :         BluetoothSDPServiceRecordHandle serviceRecordHandle;
    1507             :         [serviceRecord getServiceRecordHandle: &serviceRecordHandle];
    1508             : 
    1509             :         // Register callback for incoming connections
    1510             :         IOBluetoothUserNotificationRef callbackRef =
    1511             :             IOBluetoothRegisterForFilteredRFCOMMChannelOpenNotifications(
    1512             :                 incomingCallback,
    1513             :                 this,
    1514             :                 channelID,
    1515             :                 kIOBluetoothUserNotificationChannelDirectionIncoming);
    1516             : 
    1517             :         (void) callbackRef;
    1518             : 
    1519             :         [serviceRecord release];
    1520             :     }
    1521             : 
    1522             :     [pool release];
    1523             : 
    1524             :     (void) mpCommunicators;
    1525             : #else
    1526             :     (void) mpCommunicators; // avoid warnings about unused member
    1527             : #endif
    1528             : }
    1529             : 
    1530             : BluetoothServer *sd::BluetoothServer::spServer = NULL;
    1531             : 
    1532           0 : void BluetoothServer::setup( std::vector<Communicator*>* pCommunicators )
    1533             : {
    1534           0 :     if (spServer)
    1535           0 :         return;
    1536             : 
    1537           0 :     spServer = new BluetoothServer( pCommunicators );
    1538           0 :     spServer->create();
    1539         114 : }
    1540             : 
    1541             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10