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

Generated by: LCOV version 1.10