[Libreoffice-commits] core.git: Branch 'libreoffice-4-0' - 6 commits - sd/source

Michael Meeks michael.meeks at suse.com
Tue Feb 19 04:01:36 PST 2013


 sd/source/ui/dlg/RemoteDialog.cxx                   |   21 
 sd/source/ui/dlg/RemoteDialog.hxx                   |    2 
 sd/source/ui/inc/RemoteServer.hxx                   |    6 
 sd/source/ui/remotecontrol/BluetoothServer.cxx      |  720 +++++++++++++-------
 sd/source/ui/remotecontrol/BluetoothServer.hxx      |   19 
 sd/source/ui/remotecontrol/BufferedStreamSocket.cxx |   13 
 sd/source/ui/remotecontrol/BufferedStreamSocket.hxx |    2 
 sd/source/ui/remotecontrol/Communicator.cxx         |    8 
 sd/source/ui/remotecontrol/Communicator.hxx         |    1 
 sd/source/ui/remotecontrol/IBluetoothSocket.hxx     |    2 
 sd/source/ui/remotecontrol/Server.cxx               |   14 
 11 files changed, 547 insertions(+), 261 deletions(-)

New commits:
commit 156be5f435bcaddfeaffa1055c9be9be8aa3b27a
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Feb 19 10:07:29 2013 +0000

    sdremote: fix linux conditional.
    
    Change-Id: I911863f07b08e771d78a4a98d9a4f82c93a7d55e
    (cherry picked from commit da8cf16796b916552e4aa0ab294359f91a9b8c0e)
    
    Signed-off-by: Thorsten Behrens <tbehrens at suse.com>

diff --git a/sd/source/ui/remotecontrol/BluetoothServer.cxx b/sd/source/ui/remotecontrol/BluetoothServer.cxx
index 69cc593..8706e67 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.cxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.cxx
@@ -633,11 +633,11 @@ void BluetoothServer::restoreDiscoverable()
 
 void BluetoothServer::doEnsureDiscoverable()
 {
+#ifdef LINUX_BLUETOOTH
     if (!spServer->mpImpl->mpConnection ||
         spServer->meWasDiscoverable != UNKNOWN )
         return;
 
-#ifdef LINUX_BLUETOOTH
     // Find out if we are discoverable already ...
     DBusObject *pAdapter = spServer->mpImpl->getAdapter();
     if( !pAdapter )
commit 4a7f9c7da446aeb6a5a9010ed7f44ffc40fc67ca
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Feb 18 14:40:24 2013 +0000

    sdremote: listening to dynamic changes to adapters.
    
    Allows LibreOffice to start with no bluetooth, and for it to
    appear and disappear dynamically at run-time, cleaning up stale
    bluetooth sockets, and re-binding successfully each time.
    
    Change-Id: Ifa04c8cc1859c98adca94ac0e57c7ebd85f2f31f
    (cherry picked from commit 93abe8688a4700c04b5ab045eb296298e1b49031)
    
    Signed-off-by: Thorsten Behrens <tbehrens at suse.com>

diff --git a/sd/source/ui/remotecontrol/BluetoothServer.cxx b/sd/source/ui/remotecontrol/BluetoothServer.cxx
index a4cad7b..69cc593 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.cxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.cxx
@@ -222,15 +222,17 @@ bluezRegisterServiceRecord( DBusConnection *pConnection, DBusObject *pAdapter,
     return true;
 }
 
-static int
-bluezCreateListeningSocket()
+static void
+bluezCreateAttachListeningSocket( GMainContext *pContext, GPollFD *pSocketFD )
 {
     int nSocket;
 
+    pSocketFD->fd = -1;
+
     if( ( nSocket = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM ) ) < 0 )
     {
         SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << nSocket );
-        return -1;
+        return;
     }
 
     sockaddr_rc aAddr;
@@ -243,24 +245,39 @@ bluezCreateListeningSocket()
     if ( ( a = bind( nSocket, (sockaddr*) &aAddr, sizeof(aAddr) ) ) < 0 ) {
         SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a );
         close( nSocket );
-        return -1;
+        return;
     }
 
     if ( ( a = listen( nSocket, 1 ) ) < 0 )
     {
         SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a );
         close( nSocket );
-        return -1;
+        return;
     }
 
     // set non-blocking behaviour ...
     if( fcntl( nSocket, F_SETFL, O_NONBLOCK) < 0 )
     {
         close( nSocket );
-        return -1;
+        return;
     }
 
-    return nSocket;
+    pSocketFD->fd = nSocket;
+    pSocketFD->events = G_IO_IN | G_IO_PRI;
+    pSocketFD->revents = 0;
+
+    g_main_context_add_poll( pContext, pSocketFD, G_PRIORITY_DEFAULT );
+}
+
+static void
+bluezDetachCloseSocket( GMainContext *pContext, GPollFD *pSocketFD )
+{
+    if( pSocketFD->fd >= 0 )
+    {
+        close( pSocketFD->fd );
+        g_main_context_remove_poll( pContext, pSocketFD );
+        pSocketFD->fd = -1;
+    }
 }
 
 #endif // LINUX_BLUETOOTH
@@ -552,6 +569,24 @@ setDiscoverable( DBusConnection *pConnection, DBusObject *pAdapter, bool bDiscov
     dbus_message_unref( pMsg );
 }
 
+static DBusObject *
+registerWithDefaultAdapter( DBusConnection *pConnection )
+{
+    DBusObject *pService;
+    pService = bluezGetDefaultService( pConnection );
+    if( !pService )
+        return NULL;
+
+    if( !bluezRegisterServiceRecord( pConnection, pService,
+                                     bluetooth_service_record ) )
+    {
+        delete pService;
+        return NULL;
+    }
+
+    return pService;
+}
+
 #endif // LINUX_BLUETOOTH
 
 BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
@@ -636,6 +671,17 @@ void BluetoothServer::doRestoreDiscoverable()
     spServer->meWasDiscoverable = UNKNOWN;
 }
 
+// We have to have all our clients shut otherwise we can't
+// re-bind to the same port number it appears.
+void BluetoothServer::cleanupCommunicators()
+{
+    for (std::vector<Communicator *>::iterator it = mpCommunicators->begin();
+         it != mpCommunicators->end(); it++)
+        (*it)->forceClose();
+    // the hope is that all the threads then terminate cleanly and
+    // clean themselves up.
+}
+
 void SAL_CALL BluetoothServer::run()
 {
     SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
@@ -645,33 +691,20 @@ void SAL_CALL BluetoothServer::run()
     if( !pConnection )
         return;
 
-    mpImpl->mpService = bluezGetDefaultService( pConnection );
-    if( !mpImpl->mpService )
-    {
-        dbus_connection_unref( pConnection );
-        return;
-    }
-
-    if( !bluezRegisterServiceRecord( pConnection, mpImpl->mpService,
-                                     bluetooth_service_record ) )
-        return;
-
-    int nSocket = bluezCreateListeningSocket();
-    if( nSocket < 0 )
-        return;
-
-    // ---------------- Socket code ----------------
-
-    sockaddr_rc aRemoteAddr;
-    socklen_t  aRemoteAddrLen = sizeof(aRemoteAddr);
+    // listen for connection state and power changes - we need to close
+    // and re-create our socket code on suspend / resume, enable/disable
+    DBusError aError;
+    dbus_error_init( &aError );
+    dbus_bus_add_match( pConnection, "type='signal',interface='org.bluez.Manager'", &aError );
+    dbus_connection_flush( pConnection );
 
-    // Avoid using GSources where we can
+    // Try to setup the default adapter, otherwise wait for add/remove signal
+    mpImpl->mpService = registerWithDefaultAdapter( pConnection );
 
-    // poll on our socket
+    // poll on our bluetooth socket - if we can.
     GPollFD aSocketFD;
-    aSocketFD.fd = nSocket;
-    aSocketFD.events = G_IO_IN | G_IO_PRI;
-    g_main_context_add_poll( mpImpl->mpContext, &aSocketFD, G_PRIORITY_DEFAULT );
+    if( mpImpl->mpService )
+        bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
 
     // also poll on our dbus connection
     int fd = -1;
@@ -696,13 +729,45 @@ void SAL_CALL BluetoothServer::run()
         SAL_INFO( "sdremote.bluetooth", "main-loop spin "
                   << aDBusFD.revents << " " << aSocketFD.revents );
         if( aDBusFD.revents )
-            dbus_connection_read_write_dispatch( pConnection, 0 );
+        {
+            dbus_connection_read_write( pConnection, 0 );
+            DBusMessage *pMsg = dbus_connection_pop_message( pConnection );
+            if( pMsg )
+            {
+                if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterRemoved" ) )
+                {
+                    SAL_WARN( "sdremote.bluetooth", "lost adapter - cleaning up sockets" );
+                    bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
+                    cleanupCommunicators();
+                }
+                else if( dbus_message_is_signal( pMsg, "org.bluez.Manager", "AdapterAdded" ) ||
+                         dbus_message_is_signal( pMsg, "org.bluez.Manager", "DefaultAdapterChanged" ) )
+                {
+                    SAL_WARN( "sdremote.bluetooth", "gained adapter - re-generating sockets" );
+                    bluezDetachCloseSocket( mpImpl->mpContext, &aSocketFD );
+                    cleanupCommunicators();
+                    mpImpl->mpService = registerWithDefaultAdapter( pConnection );
+                    if( mpImpl->mpService )
+                        bluezCreateAttachListeningSocket( mpImpl->mpContext, &aSocketFD );
+                }
+                else
+                    SAL_INFO( "sdremote.bluetooth", "unknown incoming dbus message, "
+                              << " type: " << dbus_message_get_type( pMsg )
+                              << " path: '" << dbus_message_get_path( pMsg )
+                              << "' interface: '" << dbus_message_get_interface( pMsg )
+                              << "' member: '" << dbus_message_get_member( pMsg ) );
+            }
+            dbus_message_unref( pMsg );
+        }
 
         if( aSocketFD.revents )
         {
+            sockaddr_rc aRemoteAddr;
+            socklen_t aRemoteAddrLen = sizeof(aRemoteAddr);
+
             int nClient;
             SAL_INFO( "sdremote.bluetooth", "performing accept" );
-            if ( ( nClient = accept( nSocket, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) < 0 &&
+            if ( ( nClient = accept( aSocketFD.fd, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) < 0 &&
                  errno != EAGAIN )
             {
                 SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << errno );
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.hxx b/sd/source/ui/remotecontrol/BluetoothServer.hxx
index 24b8dec..8078ede 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.hxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.hxx
@@ -43,6 +43,7 @@ namespace sd
         BluetoothServerImpl *mpImpl;
         virtual void SAL_CALL run();
 
+        void cleanupCommunicators();
         std::vector<Communicator*>* mpCommunicators;
     };
 }
diff --git a/sd/source/ui/remotecontrol/BufferedStreamSocket.cxx b/sd/source/ui/remotecontrol/BufferedStreamSocket.cxx
index d35b606..c4f7f611 100644
--- a/sd/source/ui/remotecontrol/BufferedStreamSocket.cxx
+++ b/sd/source/ui/remotecontrol/BufferedStreamSocket.cxx
@@ -27,7 +27,7 @@ BufferedStreamSocket::BufferedStreamSocket( const osl::StreamSocket &aSocket ):
     aRead( 0 ),
     aBuffer(),
     mSocket( 0 ),
-    usingCSocket( false)
+    usingCSocket( false )
 {
 }
 
@@ -55,6 +55,17 @@ sal_Int32 BufferedStreamSocket::write( const void* pBuffer, sal_uInt32 n )
         return ::send( mSocket, (const char *) pBuffer, (size_t) n, 0 );
 }
 
+void BufferedStreamSocket::close()
+{
+    if( usingCSocket )
+    {
+        ::close( mSocket );
+        mSocket = -1;
+    }
+    else
+        close();
+}
+
 sal_Int32 BufferedStreamSocket::readLine( OString& aLine )
 {
     while ( true )
diff --git a/sd/source/ui/remotecontrol/BufferedStreamSocket.hxx b/sd/source/ui/remotecontrol/BufferedStreamSocket.hxx
index 0e6b99a..005cc73 100644
--- a/sd/source/ui/remotecontrol/BufferedStreamSocket.hxx
+++ b/sd/source/ui/remotecontrol/BufferedStreamSocket.hxx
@@ -51,6 +51,8 @@ namespace sd
 
             virtual sal_Int32 write( const void* pBuffer, sal_uInt32 n );
 
+            virtual void close();
+
             void getPeerAddr(osl::SocketAddr&);
         private:
             sal_Int32 aRet, aRead;
diff --git a/sd/source/ui/remotecontrol/Communicator.cxx b/sd/source/ui/remotecontrol/Communicator.cxx
index 7f01334..de73dcc 100644
--- a/sd/source/ui/remotecontrol/Communicator.cxx
+++ b/sd/source/ui/remotecontrol/Communicator.cxx
@@ -33,6 +33,14 @@ Communicator::~Communicator()
 {
 }
 
+/// Close the underlying socket from another thread to force
+/// an early exit / termination
+void Communicator::forceClose()
+{
+    if( mpSocket )
+        mpSocket->close();
+}
+
 // Run as a thread
 void Communicator::execute()
 {
diff --git a/sd/source/ui/remotecontrol/Communicator.hxx b/sd/source/ui/remotecontrol/Communicator.hxx
index a783bac..7883401 100644
--- a/sd/source/ui/remotecontrol/Communicator.hxx
+++ b/sd/source/ui/remotecontrol/Communicator.hxx
@@ -43,6 +43,7 @@ namespace sd
                 css::presentation::XSlideShowController > &rController );
             void informListenerDestroyed();
             void disposeListener();
+            void forceClose();
 
         private:
             void execute();
diff --git a/sd/source/ui/remotecontrol/IBluetoothSocket.hxx b/sd/source/ui/remotecontrol/IBluetoothSocket.hxx
index 1949367..0359807 100644
--- a/sd/source/ui/remotecontrol/IBluetoothSocket.hxx
+++ b/sd/source/ui/remotecontrol/IBluetoothSocket.hxx
@@ -33,6 +33,8 @@ namespace sd
             @return number of bytes actually written
          */
         virtual sal_Int32 write( const void* pBuffer, sal_uInt32 n ) = 0;
+
+        virtual void close() {};
     };
 }
 
commit 25819137fe00afa6ec5cb900a742fa9368a52a16
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Feb 18 13:31:21 2013 +0000

    sdremote: re-work discoverable property get/set to use libdbus.
    
    Change-Id: I5e11a0fcfd8db648a40c738cbc8181889cb36136
    (cherry picked from commit 618fe83d6e8aeabc309540fae998aeb78465bb4d)
    
    Signed-off-by: Thorsten Behrens <tbehrens at suse.com>

diff --git a/sd/source/ui/remotecontrol/BluetoothServer.cxx b/sd/source/ui/remotecontrol/BluetoothServer.cxx
index 5229e9d..a4cad7b 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.cxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.cxx
@@ -21,20 +21,12 @@
 #ifdef LINUX_BLUETOOTH
   #include <glib.h>
   #include <dbus/dbus.h>
-  #include <dbus/dbus-glib.h>
   #include <errno.h>
   #include <fcntl.h>
   #include <sys/unistd.h>
   #include <sys/socket.h>
   #include <bluetooth/bluetooth.h>
   #include <bluetooth/rfcomm.h>
-  #define DBUS_TYPE_G_STRING_ANY_HASHTABLE (dbus_g_type_get_map( "GHashTable", G_TYPE_STRING, G_TYPE_VALUE ))
-  #ifndef G_VALUE_INIT
-    #define G_VALUE_INIT {0,{{0}}} // G_VALUE_INIT only present in glib >= 2.30
-  #endif
-  #ifndef DBusGObjectPath
-    #define DBusGObjectPath char // DBusGObjectPath is only present in newer version of dbus-glib
-  #endif
   #include "BluetoothServiceRecord.hxx"
   #include "BufferedStreamSocket.hxx"
 #endif
@@ -83,26 +75,52 @@ using namespace sd;
 
 #ifdef LINUX_BLUETOOTH
 
-struct sd::BluetoothServerImpl {
-    // the glib mainloop running in the thread
-    GMainContext *mpContext;
-    volatile bool mbExitMainloop;
-};
-
 struct DBusObject {
     OString maBusName;
     OString maPath;
     OString maInterface;
 
+    DBusObject() { }
     DBusObject( const char *pBusName, const char *pPath, const char *pInterface )
-        : maBusName( pBusName ), maPath( pPath ), maInterface( pInterface )
-    { }
+        : maBusName( pBusName ), maPath( pPath ), maInterface( pInterface ) { }
 
     DBusMessage *getMethodCall( const char *pName )
     {
         return dbus_message_new_method_call( maBusName.getStr(), maPath.getStr(),
                                              maInterface.getStr(), pName );
     }
+    DBusObject *cloneForInterface( const char *pInterface )
+    {
+        DBusObject *pObject = new DBusObject();
+
+        pObject->maBusName = maBusName;
+        pObject->maPath = maPath;
+        pObject->maInterface = pInterface;
+
+        return pObject;
+    }
+};
+
+struct sd::BluetoothServerImpl {
+    // the glib mainloop running in the thread
+    GMainContext *mpContext;
+    DBusConnection *mpConnection;
+    DBusObject *mpService;
+    volatile bool mbExitMainloop;
+
+    BluetoothServerImpl() :
+        mpContext( g_main_context_new() ),
+        mpConnection( NULL ),
+        mpService( NULL ),
+        mbExitMainloop( false )
+    { }
+
+    DBusObject *getAdapter()
+    {
+        if( !mpService )
+            return NULL;
+        return mpService->cloneForInterface( "org.bluez.Adapter" );
+    }
 };
 
 static DBusConnection *
@@ -124,19 +142,15 @@ dbusConnectToNameOnBus()
     return pConnection;
 }
 
-static DBusObject *
-bluezGetDefaultAdapter( DBusConnection *pConnection,
-                        const gchar* pInterfaceType = "org.bluez.Adapter" )
+static DBusMessage *
+sendUnrefAndWaitForReply( DBusConnection *pConnection, DBusMessage *pMsg )
 {
-    DBusMessage *pMsg;
-    DBusMessageIter it;
-    DBusPendingCall *pPending;
+    DBusPendingCall *pPending = NULL;
 
-    pMsg = DBusObject( "org.bluez", "/", "org.bluez.Manager" ).getMethodCall( "DefaultAdapter" );
     if( !pMsg || !dbus_connection_send_with_reply( pConnection, pMsg, &pPending,
                                                    -1 /* default timeout */ ) )
     {
-        SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message" );
+        SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message send" );
         dbus_message_unref( pMsg );
         return NULL;
     }
@@ -146,14 +160,25 @@ bluezGetDefaultAdapter( DBusConnection *pConnection,
     dbus_pending_call_block( pPending ); // block for reply
 
     pMsg = dbus_pending_call_steal_reply( pPending );
-    if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
-    {
+    if( !pMsg )
         SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
-        dbus_pending_call_unref( pPending );
-        return NULL;
-    }
+
     dbus_pending_call_unref( pPending );
+    return pMsg;
+}
+
+static DBusObject *
+bluezGetDefaultService( DBusConnection *pConnection )
+{
+    DBusMessage *pMsg;
+    DBusMessageIter it;
+    const gchar* pInterfaceType = "org.bluez.Service";
 
+    pMsg = DBusObject( "org.bluez", "/", "org.bluez.Manager" ).getMethodCall( "DefaultAdapter" );
+    pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
+
+    if(!pMsg || !dbus_message_iter_init( pMsg, &it ) )
+        return NULL;
 
     if( DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type( &it ) )
         SAL_WARN( "sdremote.bluetooth", "invalid type of reply to DefaultAdapter: '"
@@ -177,25 +202,13 @@ bluezRegisterServiceRecord( DBusConnection *pConnection, DBusObject *pAdapter,
 {
     DBusMessage *pMsg;
     DBusMessageIter it;
-    DBusPendingCall *pPending;
 
     pMsg = pAdapter->getMethodCall( "AddRecord" );
     dbus_message_iter_init_append( pMsg, &it );
     dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pServiceRecord );
 
-    if(!dbus_connection_send_with_reply( pConnection, pMsg, &pPending,
-                                         -1 /* default timeout */ ) )
-    if( !dbus_connection_send( pConnection, pMsg, NULL ) )
-    {
-        SAL_WARN( "sdremote.bluetooth", "failed to send service record" );
-        return false;
-    }
-    dbus_connection_flush( pConnection );
-    dbus_message_unref( pMsg );
-
-    dbus_pending_call_block( pPending ); // block for reply
+    pMsg = sendUnrefAndWaitForReply( pConnection, pMsg );
 
-    pMsg = dbus_pending_call_steal_reply( pPending );
     if( !pMsg || !dbus_message_iter_init( pMsg, &it ) ||
         dbus_message_iter_get_arg_type( &it ) != DBUS_TYPE_UINT32 )
     {
@@ -206,8 +219,6 @@ bluezRegisterServiceRecord( DBusConnection *pConnection, DBusObject *pAdapter,
     // We ignore the uint de-registration handle we get back:
     // bluez will clean us up automatically on exit
 
-    dbus_pending_call_unref( pPending );
-
     return true;
 }
 
@@ -252,7 +263,12 @@ bluezCreateListeningSocket()
     return nSocket;
 }
 
-#endif // defined(LINUX) && defined(ENABLE_DBUS)
+#endif // LINUX_BLUETOOTH
+
+void BluetoothServer::addCommunicator( Communicator* pCommunicator )
+{
+    mpCommunicators->push_back( pCommunicator );
+}
 
 #if defined(MACOSX)
 
@@ -402,195 +418,222 @@ void incomingCallback( void *userRefCon,
 
 #endif // MACOSX
 
-
-BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
-  : meWasDiscoverable( UNKNOWN ),
-    mpImpl( NULL ),
-    mpCommunicators( pCommunicators )
-{
 #ifdef LINUX_BLUETOOTH
-    g_type_init();
-    mpImpl = new BluetoothServerImpl();
-    mpImpl->mpContext = g_main_context_new();
-    mpImpl->mbExitMainloop = false;
-#endif
-}
-
-BluetoothServer::~BluetoothServer()
-{
-}
-
-
-void BluetoothServer::ensureDiscoverable()
-{
-     if( !spServer || spServer->meWasDiscoverable != UNKNOWN )
-        return;
 
-     bool bDiscoverable = spServer->isDiscoverable();
-     spServer->meWasDiscoverable = bDiscoverable ? DISCOVERABLE : NOT_DISCOVERABLE;
-     spServer->setDiscoverable( true );
-}
-
-void BluetoothServer::restoreDiscoverable()
-{
-     if(!spServer)
-        return;
-
-     if ( spServer->meWasDiscoverable == NOT_DISCOVERABLE )
-         spServer->setDiscoverable( false );
-     spServer->meWasDiscoverable = UNKNOWN;
+extern "C" {
+    static gboolean ensureDiscoverable_cb(gpointer)
+    {
+        BluetoothServer::doEnsureDiscoverable();
+        return FALSE; // remove source
+    }
+    static gboolean restoreDiscoverable_cb(gpointer)
+    {
+        BluetoothServer::doRestoreDiscoverable();
+        return FALSE; // remove source
+    }
 }
 
-bool BluetoothServer::isDiscoverable()
+static bool
+getBooleanProperty( DBusConnection *pConnection, DBusObject *pAdapter,
+                    const char *pPropertyName, bool *pBoolean )
 {
-#if 0 // (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
-    SAL_INFO( "sdremote.bluetooth", "BluetoothServer::isDiscoverable called" );
-    g_type_init();
-    gboolean aResult;
+    *pBoolean = false;
 
-    GError *aError = NULL;
+    if( !pAdapter )
+        return false;
 
-    DBusGConnection *aConnection = NULL;
-    aConnection = dbus_g_bus_get( DBUS_BUS_SYSTEM, &aError );
+    DBusMessage *pMsg;
+    pMsg = sendUnrefAndWaitForReply( pConnection,
+                                     pAdapter->getMethodCall( "GetProperties" ) );
 
-    if ( aError != NULL ) {
-        g_error_free (aError);
-        SAL_INFO( "sdremote.bluetooth", "did not get DBusGConnection" );
+    DBusMessageIter it;
+    if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
+    {
+        SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
         return false;
     }
 
-    DBusGProxy* aAdapter = bluezGetDefaultAdapter( pConnection );
-    if ( aAdapter == NULL )
+    if( DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type( &it ) )
     {
-        dbus_g_connection_unref( aConnection );
-        SAL_INFO( "sdremote.bluetooth", "did not get default adaptor" );
+        SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
         return false;
     }
 
-    GHashTable* aProperties = NULL;
-    aResult = dbus_g_proxy_call( aAdapter, "GetProperties", &aError,
-                                G_TYPE_INVALID,
-                                DBUS_TYPE_G_STRING_ANY_HASHTABLE, &aProperties,
-                                G_TYPE_INVALID);
-    g_object_unref( G_OBJECT( aAdapter ));
-    dbus_g_connection_unref( aConnection );
-    if ( !aResult || aError )
+    DBusMessageIter arrayIt;
+    dbus_message_iter_recurse( &it, &arrayIt );
+
+    while( dbus_message_iter_get_arg_type( &arrayIt ) == DBUS_TYPE_DICT_ENTRY )
     {
-        if ( aError )
-            g_error_free( aError );
-        SAL_INFO( "sdremote.bluetooth", "did not get properties" );
-        return false;
-    }
+        DBusMessageIter dictIt;
+        dbus_message_iter_recurse( &arrayIt, &dictIt );
 
-    gboolean aIsDiscoverable = g_value_get_boolean( (GValue*) g_hash_table_lookup(
-                aProperties, "Discoverable" ) );
+        const char *pName = NULL;
+        if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_STRING )
+        {
+            dbus_message_iter_get_basic( &dictIt, &pName );
+            if( pName != NULL && !strcmp( pName, pPropertyName ) )
+            {
+                SAL_INFO( "sdremote.bluetooth", "hit " << pPropertyName << " property" );
+                dbus_message_iter_next( &dictIt );
+                dbus_bool_t bBool = false;
 
-    g_hash_table_unref( aProperties );
+                if( dbus_message_iter_get_arg_type( &dictIt ) == DBUS_TYPE_VARIANT )
+                {
+                    DBusMessageIter variantIt;
+                    dbus_message_iter_recurse( &dictIt, &variantIt );
+
+                    if( dbus_message_iter_get_arg_type( &variantIt ) == DBUS_TYPE_BOOLEAN )
+                    {
+                        dbus_message_iter_get_basic( &variantIt, &bBool );
+                        SAL_INFO( "sdremote.bluetooth", "" << pPropertyName << " is " << bBool );
+                        *pBoolean = bBool;
+                        return true;
+                    }
+                    else
+                        SAL_WARN( "sdremote.bluetooth", "" << pPropertyName << " type " <<
+                                  dbus_message_iter_get_arg_type( &variantIt ) );
+                }
+                else
+                    SAL_WARN( "sdremote.bluetooth", "variant type ? " <<
+                              dbus_message_iter_get_arg_type( &dictIt ) );
+            }
+            else
+            {
+                const char *pStr = pName ? pName : "<null>";
+                SAL_INFO( "sdremote.bluetooth", "property '" << pStr << "'" );
+            }
+        }
+        else
+            SAL_WARN( "sdremote.bluetooth", "unexpected property key type "
+                      << dbus_message_iter_get_arg_type( &dictIt ) );
+        dbus_message_iter_next( &arrayIt );
+    }
+    dbus_message_unref( pMsg );
 
-    SAL_INFO( "sdremote.bluetooth", "BluetoothServer::isDiscoverable() returns " << static_cast< bool >( aIsDiscoverable ) );
-    return aIsDiscoverable;
-#else // defined(LINUX) && defined(ENABLE_DBUS)
     return false;
-#endif
 }
 
-void BluetoothServer::setDiscoverable( bool bDiscoverable )
+static void
+setDiscoverable( DBusConnection *pConnection, DBusObject *pAdapter, bool bDiscoverable )
 {
-#if 0 // (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
-    SAL_INFO( "sdremote.bluetooth", "BluetoothServer::setDiscoverable called" );
-    g_type_init();
-    gboolean aResult;
+    SAL_INFO( "sdremote.bluetooth", "setDiscoverable to " << bDiscoverable );
 
-    GError *aError = NULL;
+    bool bPowered = false;
+    if( !getBooleanProperty( pConnection, pAdapter, "Powered", &bPowered ) || !bPowered )
+        return; // nothing to do
 
-    DBusGConnection *aConnection = NULL;
-    aConnection = dbus_g_bus_get( DBUS_BUS_SYSTEM, &aError );
+    DBusMessage *pMsg;
+    DBusMessageIter it, varIt;
 
-    if ( aError != NULL )
-    {
-        g_error_free (aError);
-        return;
-    }
+    // set timeout to zero
+    pMsg = pAdapter->getMethodCall( "SetProperty" );
+    dbus_message_iter_init_append( pMsg, &it );
+    const char *pTimeoutStr = "DiscoverableTimeout";
+    dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pTimeoutStr );
+    dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
+                                      DBUS_TYPE_UINT32_AS_STRING, &varIt );
+    dbus_uint32_t nTimeout = 0;
+    dbus_message_iter_append_basic( &varIt, DBUS_TYPE_UINT32, &nTimeout );
+    dbus_message_iter_close_container( &it, &varIt );
+    dbus_connection_send( pConnection, pMsg, NULL ); // async send - why not ?
+    dbus_message_unref( pMsg );
 
-    DBusGProxy* aAdapter = bluezGetDefaultAdapter( pConnection );
-    if ( aAdapter == NULL )
-    {
-        dbus_g_connection_unref( aConnection );
-        return;
-    }
+    // set discoverable value
+    pMsg = pAdapter->getMethodCall( "SetProperty" );
+    dbus_message_iter_init_append( pMsg, &it );
+    const char *pDiscoverableStr = "Discoverable";
+    dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pDiscoverableStr );
+    dbus_message_iter_open_container( &it, DBUS_TYPE_VARIANT,
+                                      DBUS_TYPE_BOOLEAN_AS_STRING, &varIt );
+    dbus_bool_t bValue = bDiscoverable;
+    dbus_message_iter_append_basic( &varIt, DBUS_TYPE_BOOLEAN, &bValue );
+    dbus_message_iter_close_container( &it, &varIt ); // async send - why not ?
+    dbus_connection_send( pConnection, pMsg, NULL );
+    dbus_message_unref( pMsg );
+}
 
-    GHashTable* aProperties;
-    aResult = dbus_g_proxy_call( aAdapter, "GetProperties", &aError,
-                                G_TYPE_INVALID,
-                                DBUS_TYPE_G_STRING_ANY_HASHTABLE, &aProperties,
-                                G_TYPE_INVALID);
+#endif // LINUX_BLUETOOTH
 
-    if ( !aResult || aError )
-    {
-        SAL_WARN( "sdremote.bluetooth", "GetProperties failed" );
-        if ( aError )
-        {
-            g_error_free( aError );
-            SAL_WARN( "sdremote.bluetooth", "with error " << aError->message );
-        }
+BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
+  : meWasDiscoverable( UNKNOWN ),
+    mpImpl( NULL ),
+    mpCommunicators( pCommunicators )
+{
+#ifdef LINUX_BLUETOOTH
+    mpImpl = new BluetoothServerImpl();
+#endif
+}
+
+BluetoothServer::~BluetoothServer()
+{
+}
+
+void BluetoothServer::ensureDiscoverable()
+{
+#ifdef LINUX_BLUETOOTH
+    // Push it all across into our mainloop
+    if( !spServer )
         return;
-    }
+    GSource *pIdle = g_idle_source_new();
+    g_source_set_callback( pIdle, ensureDiscoverable_cb, NULL, NULL );
+    g_source_set_priority( pIdle, G_PRIORITY_DEFAULT );
+    g_source_attach( pIdle, spServer->mpImpl->mpContext );
+    g_source_unref( pIdle );
+#endif
+}
 
-    gboolean aPowered = g_value_get_boolean( (GValue*) g_hash_table_lookup(
-                aProperties, "Powered" ) );
+void BluetoothServer::restoreDiscoverable()
+{
+#ifdef LINUX_BLUETOOTH
+    // Push it all across into our mainloop
+    if( !spServer )
+        return;
+    GSource *pIdle = g_idle_source_new();
+    g_source_set_callback( pIdle, restoreDiscoverable_cb, NULL, NULL );
+    g_source_set_priority( pIdle, G_PRIORITY_DEFAULT_IDLE );
+    g_source_attach( pIdle, spServer->mpImpl->mpContext );
+    g_source_unref( pIdle );
+#endif
+}
 
-    g_hash_table_unref( aProperties );
-    if ( !aPowered )
-    {
-        SAL_INFO( "sdremote.bluetooth", "Bluetooth adapter not powered, returning" );
-        g_object_unref( G_OBJECT( aAdapter ));
+void BluetoothServer::doEnsureDiscoverable()
+{
+    if (!spServer->mpImpl->mpConnection ||
+        spServer->meWasDiscoverable != UNKNOWN )
         return;
-    }
 
-    GValue aTimeout = G_VALUE_INIT;
-    g_value_init( &aTimeout, G_TYPE_UINT );
-    g_value_set_uint( &aTimeout, 0 );
-    aResult = dbus_g_proxy_call( aAdapter, "SetProperty", &aError,
-                                G_TYPE_STRING, "DiscoverableTimeout",
-                                 G_TYPE_VALUE, &aTimeout, G_TYPE_INVALID, G_TYPE_INVALID);
-    if ( !aResult || aError )
-    {
-        SAL_WARN( "sdremote.bluetooth", "SetProperty(DiscoverableTimeout) failed" );
-        if ( aError )
-        {
-            g_error_free( aError );
-            SAL_WARN( "sdremote.bluetooth", "with error " << aError->message );
-        }
+#ifdef LINUX_BLUETOOTH
+    // Find out if we are discoverable already ...
+    DBusObject *pAdapter = spServer->mpImpl->getAdapter();
+    if( !pAdapter )
         return;
-    }
 
-    GValue bDiscoverableGValue = G_VALUE_INIT;
-    g_value_init( &bDiscoverableGValue, G_TYPE_BOOLEAN );
-    g_value_set_boolean( &bDiscoverableGValue, bDiscoverable );
-    aResult = dbus_g_proxy_call( aAdapter, "SetProperty", &aError,
-                                G_TYPE_STRING, "Discoverable",
-                                 G_TYPE_VALUE, &bDiscoverableGValue, G_TYPE_INVALID, G_TYPE_INVALID);
-    if ( !aResult || aError )
+    bool bDiscoverable;
+    if( getBooleanProperty( spServer->mpImpl->mpConnection, pAdapter,
+                            "Discoverable", &bDiscoverable ) )
     {
-        SAL_WARN( "sdremote.bluetooth", "SetProperty(Discoverable) failed" );
-        if ( aError )
-        {
-            g_error_free( aError );
-            SAL_WARN( "sdremote.bluetooth", "with error " << aError->message );
-        }
-        return;
+        spServer->meWasDiscoverable = bDiscoverable ? DISCOVERABLE : NOT_DISCOVERABLE;
+        if( !bDiscoverable )
+            setDiscoverable( spServer->mpImpl->mpConnection, pAdapter, true );
     }
 
-    g_object_unref( G_OBJECT( aAdapter ));
-    dbus_g_connection_unref( aConnection );
-#else // defined(LINUX) && defined(ENABLE_DBUS)
-    (void) bDiscoverable; // avoid warnings
+    delete pAdapter;
 #endif
 }
 
-void BluetoothServer::addCommunicator( Communicator* pCommunicator )
+void BluetoothServer::doRestoreDiscoverable()
 {
-    mpCommunicators->push_back( pCommunicator );
+    if( spServer->meWasDiscoverable == NOT_DISCOVERABLE )
+    {
+#ifdef LINUX_BLUETOOTH
+        DBusObject *pAdapter = spServer->mpImpl->getAdapter();
+        if( !pAdapter )
+            return;
+        setDiscoverable( spServer->mpImpl->mpConnection, pAdapter, false );
+        delete pAdapter;
+#endif
+    }
+    spServer->meWasDiscoverable = UNKNOWN;
 }
 
 void SAL_CALL BluetoothServer::run()
@@ -602,14 +645,15 @@ void SAL_CALL BluetoothServer::run()
     if( !pConnection )
         return;
 
-    DBusObject *pService = bluezGetDefaultAdapter( pConnection, "org.bluez.Service" );
-    if( !pService )
+    mpImpl->mpService = bluezGetDefaultService( pConnection );
+    if( !mpImpl->mpService )
     {
         dbus_connection_unref( pConnection );
         return;
     }
 
-    if( !bluezRegisterServiceRecord( pConnection, pService, bluetooth_service_record ) )
+    if( !bluezRegisterServiceRecord( pConnection, mpImpl->mpService,
+                                     bluetooth_service_record ) )
         return;
 
     int nSocket = bluezCreateListeningSocket();
@@ -641,6 +685,8 @@ void SAL_CALL BluetoothServer::run()
     else
         SAL_WARN( "sdremote.bluetooth", "failed to poll for incoming dbus signals" );
 
+    mpImpl->mpConnection = pConnection;
+
     while( !mpImpl->mbExitMainloop )
     {
         aDBusFD.revents = 0;
@@ -669,6 +715,10 @@ void SAL_CALL BluetoothServer::run()
         }
     }
 
+    g_main_context_unref( mpImpl->mpContext );
+    mpImpl->mpConnection = NULL;
+    mpImpl->mpContext = NULL;
+
 #elif defined(WIN32)
     WORD wVersionRequested;
     WSADATA wsaData;
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.hxx b/sd/source/ui/remotecontrol/BluetoothServer.hxx
index b922d60..24b8dec 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.hxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.hxx
@@ -28,15 +28,15 @@ namespace sd
         /// restore the state of discoverability from before ensureDiscoverable
         static void restoreDiscoverable();
 
-        void addCommunicator( Communicator* pCommunicator );
+        // called by C / idle callbacks
+        static void doEnsureDiscoverable();
+        static void doRestoreDiscoverable();
 
+        void addCommunicator( Communicator* pCommunicator );
     private:
         BluetoothServer( std::vector<Communicator*>* pCommunicators );
         ~BluetoothServer();
 
-        bool isDiscoverable();
-        void setDiscoverable( bool bDiscoverable );
-
         enum { UNKNOWN, DISCOVERABLE, NOT_DISCOVERABLE } meWasDiscoverable;
         static BluetoothServer *spServer;
 
commit 7848b97462a088521986ba200ee2fd55982667bb
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Feb 18 11:30:54 2013 +0000

    sdremote: switch to a non-blocking socket, and polling glib mainloop.
    
    Conflicts:
    
    	sd/source/ui/remotecontrol/BluetoothServer.cxx
    
    Change-Id: I84c0a522fe16fbc8fc86a8e4bccb84aec0a1acd1
    (cherry picked from commit 0d89d814055d5c267a2cc57e302a23e9f0b521e3)
    
    Signed-off-by: Thorsten Behrens <tbehrens at suse.com>

diff --git a/sd/source/ui/remotecontrol/BluetoothServer.cxx b/sd/source/ui/remotecontrol/BluetoothServer.cxx
index 2ccfc87..5229e9d 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.cxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.cxx
@@ -15,9 +15,15 @@
 #include <sal/log.hxx>
 
 #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
+#  define LINUX_BLUETOOTH
+#endif
+
+#ifdef LINUX_BLUETOOTH
   #include <glib.h>
   #include <dbus/dbus.h>
   #include <dbus/dbus-glib.h>
+  #include <errno.h>
+  #include <fcntl.h>
   #include <sys/unistd.h>
   #include <sys/socket.h>
   #include <bluetooth/bluetooth.h>
@@ -75,7 +81,13 @@
 
 using namespace sd;
 
-#if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
+#ifdef LINUX_BLUETOOTH
+
+struct sd::BluetoothServerImpl {
+    // the glib mainloop running in the thread
+    GMainContext *mpContext;
+    volatile bool mbExitMainloop;
+};
 
 struct DBusObject {
     OString maBusName;
@@ -230,6 +242,13 @@ bluezCreateListeningSocket()
         return -1;
     }
 
+    // set non-blocking behaviour ...
+    if( fcntl( nSocket, F_SETFL, O_NONBLOCK) < 0 )
+    {
+        close( nSocket );
+        return -1;
+    }
+
     return nSocket;
 }
 
@@ -386,8 +405,15 @@ void incomingCallback( void *userRefCon,
 
 BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
   : meWasDiscoverable( UNKNOWN ),
+    mpImpl( NULL ),
     mpCommunicators( pCommunicators )
 {
+#ifdef LINUX_BLUETOOTH
+    g_type_init();
+    mpImpl = new BluetoothServerImpl();
+    mpImpl->mpContext = g_main_context_new();
+    mpImpl->mbExitMainloop = false;
+#endif
 }
 
 BluetoothServer::~BluetoothServer()
@@ -569,10 +595,9 @@ void BluetoothServer::addCommunicator( Communicator* pCommunicator )
 
 void SAL_CALL BluetoothServer::run()
 {
-    SAL_INFO( "sdremote.bluetooth", "BluetoothServer::execute called" );
-#if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
-    g_type_init();
+    SAL_INFO( "sdremote.bluetooth", "BluetoothServer::run called" );
 
+#ifdef LINUX_BLUETOOTH
     DBusConnection *pConnection = dbusConnectToNameOnBus();
     if( !pConnection )
         return;
@@ -587,8 +612,8 @@ void SAL_CALL BluetoothServer::run()
     if( !bluezRegisterServiceRecord( pConnection, pService, bluetooth_service_record ) )
         return;
 
-    int aSocket = bluezCreateListeningSocket();
-    if( aSocket < 0 )
+    int nSocket = bluezCreateListeningSocket();
+    if( nSocket < 0 )
         return;
 
     // ---------------- Socket code ----------------
@@ -596,22 +621,51 @@ void SAL_CALL BluetoothServer::run()
     sockaddr_rc aRemoteAddr;
     socklen_t  aRemoteAddrLen = sizeof(aRemoteAddr);
 
-    // FIXME: use a glib main-loop [!] ...
-    // FIXME: fixme ! ...
-    while ( true )
+    // Avoid using GSources where we can
+
+    // poll on our socket
+    GPollFD aSocketFD;
+    aSocketFD.fd = nSocket;
+    aSocketFD.events = G_IO_IN | G_IO_PRI;
+    g_main_context_add_poll( mpImpl->mpContext, &aSocketFD, G_PRIORITY_DEFAULT );
+
+    // also poll on our dbus connection
+    int fd = -1;
+    GPollFD aDBusFD;
+    if( dbus_connection_get_unix_fd( pConnection, &fd ) && fd >= 0 )
     {
-        int bSocket;
-        SAL_INFO( "sdremote.bluetooth", "waiting on accept" );
-        if ( (bSocket = accept(aSocket, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) < 0 )
+        aDBusFD.fd = fd;
+        aDBusFD.events = G_IO_IN | G_IO_PRI;
+        g_main_context_add_poll( mpImpl->mpContext, &aDBusFD, G_PRIORITY_DEFAULT );
+    }
+    else
+        SAL_WARN( "sdremote.bluetooth", "failed to poll for incoming dbus signals" );
+
+    while( !mpImpl->mbExitMainloop )
+    {
+        aDBusFD.revents = 0;
+        aSocketFD.revents = 0;
+        g_main_context_iteration( mpImpl->mpContext, TRUE );
+
+        SAL_INFO( "sdremote.bluetooth", "main-loop spin "
+                  << aDBusFD.revents << " " << aSocketFD.revents );
+        if( aDBusFD.revents )
+            dbus_connection_read_write_dispatch( pConnection, 0 );
+
+        if( aSocketFD.revents )
         {
-            SAL_WARN( "sdremote.bluetooth", "accept failed with error" << bSocket );
-            close( aSocket );
-            return;
-        } else {
-            SAL_INFO( "sdremote.bluetooth", "connection accepted" );
-            Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( bSocket) );
-            mpCommunicators->push_back( pCommunicator );
-            pCommunicator->launch();
+            int nClient;
+            SAL_INFO( "sdremote.bluetooth", "performing accept" );
+            if ( ( nClient = accept( nSocket, (sockaddr*) &aRemoteAddr, &aRemoteAddrLen)) < 0 &&
+                 errno != EAGAIN )
+            {
+                SAL_WARN( "sdremote.bluetooth", "accept failed with errno " << errno );
+            } else {
+                SAL_INFO( "sdremote.bluetooth", "connection accepted " << nClient );
+                Communicator* pCommunicator = new Communicator( new BufferedStreamSocket( nClient ) );
+                mpCommunicators->push_back( pCommunicator );
+                pCommunicator->launch();
+            }
         }
     }
 
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.hxx b/sd/source/ui/remotecontrol/BluetoothServer.hxx
index 5b986fa..b922d60 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.hxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.hxx
@@ -16,6 +16,7 @@ namespace sd
 {
     class Communicator;
 
+    struct BluetoothServerImpl;
     class BluetoothServer:
         public osl::Thread
     {
@@ -39,7 +40,9 @@ namespace sd
         enum { UNKNOWN, DISCOVERABLE, NOT_DISCOVERABLE } meWasDiscoverable;
         static BluetoothServer *spServer;
 
+        BluetoothServerImpl *mpImpl;
         virtual void SAL_CALL run();
+
         std::vector<Communicator*>* mpCommunicators;
     };
 }
commit 84f1c87936fa13ea937cd02ec79a3b29ed26c5d1
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Feb 18 10:55:31 2013 +0000

    sdremote: re-write SDP registration to use raw dbus-1 not dbus-glib.
    
    Conflicts:
    
    	sd/source/ui/remotecontrol/BluetoothServer.cxx
    
    Change-Id: I65ff5e603b6719df69b3c2aef7ff438ad54d23e2
    (cherry picked from commit 5a90716b802d281c111e1f4f43f3fefded2c1f81)
    
    Signed-off-by: Thorsten Behrens <tbehrens at suse.com>

diff --git a/sd/source/ui/remotecontrol/BluetoothServer.cxx b/sd/source/ui/remotecontrol/BluetoothServer.cxx
index d140c1e..2ccfc87 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.cxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.cxx
@@ -16,6 +16,7 @@
 
 #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
   #include <glib.h>
+  #include <dbus/dbus.h>
   #include <dbus/dbus-glib.h>
   #include <sys/unistd.h>
   #include <sys/socket.h>
@@ -75,46 +76,163 @@
 using namespace sd;
 
 #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
-DBusGProxy* bluezGetDefaultAdapter( DBusGConnection* aConnection,
-                                    const gchar* aInterfaceType = "org.bluez.Adapter" )
+
+struct DBusObject {
+    OString maBusName;
+    OString maPath;
+    OString maInterface;
+
+    DBusObject( const char *pBusName, const char *pPath, const char *pInterface )
+        : maBusName( pBusName ), maPath( pPath ), maInterface( pInterface )
+    { }
+
+    DBusMessage *getMethodCall( const char *pName )
+    {
+        return dbus_message_new_method_call( maBusName.getStr(), maPath.getStr(),
+                                             maInterface.getStr(), pName );
+    }
+};
+
+static DBusConnection *
+dbusConnectToNameOnBus()
 {
-    GError *aError = NULL;
+    DBusError aError;
+    DBusConnection *pConnection;
 
-    DBusGProxy *aManager = NULL;
-    aManager = dbus_g_proxy_new_for_name( aConnection, "org.bluez", "/",
-                                          "org.bluez.Manager" );
+    dbus_error_init( &aError );
 
-    if ( aManager == NULL )
+    pConnection = dbus_bus_get( DBUS_BUS_SYSTEM, &aError );
+    if( !pConnection || dbus_error_is_set( &aError ))
     {
-        SAL_WARN( "sdremote.bluetooth", "getting org.bluez.Manager failed" );
-        dbus_g_connection_unref( aConnection );
+        SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus: " << aError.message );
+        dbus_error_free( &aError );
         return NULL;
     }
 
-    gboolean aResult;
-    DBusGObjectPath* aAdapterPath = NULL;
-    aResult = dbus_g_proxy_call( aManager, "DefaultAdapter", &aError,
-                                 G_TYPE_INVALID,
-                                 DBUS_TYPE_G_OBJECT_PATH, &aAdapterPath,
-                                 G_TYPE_INVALID);
+    return pConnection;
+}
 
-    g_object_unref( G_OBJECT( aManager ));
-    if ( !aResult || aError )
+static DBusObject *
+bluezGetDefaultAdapter( DBusConnection *pConnection,
+                        const gchar* pInterfaceType = "org.bluez.Adapter" )
+{
+    DBusMessage *pMsg;
+    DBusMessageIter it;
+    DBusPendingCall *pPending;
+
+    pMsg = DBusObject( "org.bluez", "/", "org.bluez.Manager" ).getMethodCall( "DefaultAdapter" );
+    if( !pMsg || !dbus_connection_send_with_reply( pConnection, pMsg, &pPending,
+                                                   -1 /* default timeout */ ) )
     {
-        SAL_WARN( "sdremote.bluetooth", "getting DefaultAdapter path failed" );
-        if ( aError )
-            g_error_free( aError );
+        SAL_WARN( "sdremote.bluetooth", "Memory allocation failed on message" );
+        dbus_message_unref( pMsg );
+        return NULL;
+    }
+    dbus_connection_flush( pConnection );
+    dbus_message_unref( pMsg );
+
+    dbus_pending_call_block( pPending ); // block for reply
+
+    pMsg = dbus_pending_call_steal_reply( pPending );
+    if( !pMsg || !dbus_message_iter_init( pMsg, &it ) )
+    {
+        SAL_WARN( "sdremote.bluetooth", "no valid reply / timeout" );
+        dbus_pending_call_unref( pPending );
         return NULL;
     }
+    dbus_pending_call_unref( pPending );
 
-    DBusGProxy *aAdapter = NULL;
-    aAdapter = dbus_g_proxy_new_for_name( aConnection, "org.bluez",
-                                          aAdapterPath, aInterfaceType );
-    g_free( aAdapterPath );
 
-    SAL_INFO( "sdremote.bluetooth", "DefaultAdapter retrieved" );
-    return aAdapter;
+    if( DBUS_TYPE_OBJECT_PATH != dbus_message_iter_get_arg_type( &it ) )
+        SAL_WARN( "sdremote.bluetooth", "invalid type of reply to DefaultAdapter: '"
+                  << dbus_message_iter_get_arg_type( &it ) << "'" );
+    else
+    {
+        const char *pObjectPath = NULL;
+        dbus_message_iter_get_basic( &it, &pObjectPath );
+        SAL_INFO( "sdremote.bluetooth", "DefaultAdapter retrieved: '"
+                  << pObjectPath << "' '" << pInterfaceType << "'" );
+        return new DBusObject( "org.bluez", pObjectPath, pInterfaceType );
+    }
+    dbus_message_unref( pMsg );
+
+    return NULL;
 }
+
+static bool
+bluezRegisterServiceRecord( DBusConnection *pConnection, DBusObject *pAdapter,
+                            const char *pServiceRecord )
+{
+    DBusMessage *pMsg;
+    DBusMessageIter it;
+    DBusPendingCall *pPending;
+
+    pMsg = pAdapter->getMethodCall( "AddRecord" );
+    dbus_message_iter_init_append( pMsg, &it );
+    dbus_message_iter_append_basic( &it, DBUS_TYPE_STRING, &pServiceRecord );
+
+    if(!dbus_connection_send_with_reply( pConnection, pMsg, &pPending,
+                                         -1 /* default timeout */ ) )
+    if( !dbus_connection_send( pConnection, pMsg, NULL ) )
+    {
+        SAL_WARN( "sdremote.bluetooth", "failed to send service record" );
+        return false;
+    }
+    dbus_connection_flush( pConnection );
+    dbus_message_unref( pMsg );
+
+    dbus_pending_call_block( pPending ); // block for reply
+
+    pMsg = dbus_pending_call_steal_reply( pPending );
+    if( !pMsg || !dbus_message_iter_init( pMsg, &it ) ||
+        dbus_message_iter_get_arg_type( &it ) != DBUS_TYPE_UINT32 )
+    {
+        SAL_WARN( "sdremote.bluetooth", "SDP registration failed" );
+        return false;
+    }
+
+    // We ignore the uint de-registration handle we get back:
+    // bluez will clean us up automatically on exit
+
+    dbus_pending_call_unref( pPending );
+
+    return true;
+}
+
+static int
+bluezCreateListeningSocket()
+{
+    int nSocket;
+
+    if( ( nSocket = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM ) ) < 0 )
+    {
+        SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << nSocket );
+        return -1;
+    }
+
+    sockaddr_rc aAddr;
+    aAddr.rc_family = AF_BLUETOOTH;
+    // BDADDR_ANY is broken, so use memset to set to 0.
+    memset( &aAddr.rc_bdaddr, 0, sizeof( aAddr.rc_bdaddr ) );
+    aAddr.rc_channel = 5;
+
+    int a;
+    if ( ( a = bind( nSocket, (sockaddr*) &aAddr, sizeof(aAddr) ) ) < 0 ) {
+        SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a );
+        close( nSocket );
+        return -1;
+    }
+
+    if ( ( a = listen( nSocket, 1 ) ) < 0 )
+    {
+        SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a );
+        close( nSocket );
+        return -1;
+    }
+
+    return nSocket;
+}
+
 #endif // defined(LINUX) && defined(ENABLE_DBUS)
 
 #if defined(MACOSX)
@@ -299,7 +417,7 @@ void BluetoothServer::restoreDiscoverable()
 
 bool BluetoothServer::isDiscoverable()
 {
-#if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
+#if 0 // (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
     SAL_INFO( "sdremote.bluetooth", "BluetoothServer::isDiscoverable called" );
     g_type_init();
     gboolean aResult;
@@ -315,7 +433,7 @@ bool BluetoothServer::isDiscoverable()
         return false;
     }
 
-    DBusGProxy* aAdapter = bluezGetDefaultAdapter( aConnection );
+    DBusGProxy* aAdapter = bluezGetDefaultAdapter( pConnection );
     if ( aAdapter == NULL )
     {
         dbus_g_connection_unref( aConnection );
@@ -352,8 +470,8 @@ bool BluetoothServer::isDiscoverable()
 
 void BluetoothServer::setDiscoverable( bool bDiscoverable )
 {
-#if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
-    SAL_INFO( "sdremote.bluetooth", "BluetoothServer::isDiscoverable called" );
+#if 0 // (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
+    SAL_INFO( "sdremote.bluetooth", "BluetoothServer::setDiscoverable called" );
     g_type_init();
     gboolean aResult;
 
@@ -368,7 +486,7 @@ void BluetoothServer::setDiscoverable( bool bDiscoverable )
         return;
     }
 
-    DBusGProxy* aAdapter = bluezGetDefaultAdapter( aConnection );
+    DBusGProxy* aAdapter = bluezGetDefaultAdapter( pConnection );
     if ( aAdapter == NULL )
     {
         dbus_g_connection_unref( aConnection );
@@ -455,72 +573,31 @@ void SAL_CALL BluetoothServer::run()
 #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
     g_type_init();
 
-    GError *aError = NULL;
-
-    DBusGConnection *aConnection = NULL;
-    aConnection = dbus_g_bus_get( DBUS_BUS_SYSTEM, &aError );
-
-    if ( aError != NULL ) {
-        SAL_WARN( "sdremote.bluetooth", "failed to get dbus system bus" );
-        g_error_free (aError);
-        return;
-    }
-
-    DBusGProxy* aAdapter = bluezGetDefaultAdapter( aConnection, "org.bluez.Service" );
-    if ( aAdapter == NULL )
-    {
-        SAL_WARN( "sdremote.bluetooth", "failed to retrieve default adapter" );
-        dbus_g_connection_unref( aConnection );
+    DBusConnection *pConnection = dbusConnectToNameOnBus();
+    if( !pConnection )
         return;
-    }
 
-    // Add the record -- the handle can be used to release it again, but we
-    // don't bother as the record is automatically released when LO exits.
-    guint aHandle;
-    gboolean aResult = dbus_g_proxy_call( aAdapter, "AddRecord", &aError,
-                                G_TYPE_STRING, bluetooth_service_record,
-                                G_TYPE_INVALID,
-                                G_TYPE_UINT, &aHandle,
-                                G_TYPE_INVALID);
-
-    g_object_unref( G_OBJECT( aAdapter ));
-    dbus_g_connection_unref( aConnection );
-    if ( !aResult)
+    DBusObject *pService = bluezGetDefaultAdapter( pConnection, "org.bluez.Service" );
+    if( !pService )
     {
-        SAL_WARN( "sdremote.bluetooth", "SDP registration failed" );
+        dbus_connection_unref( pConnection );
         return;
     }
 
-    // ---------------- Socket code
-    int aSocket;
-    if ( (aSocket = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM )) < 0 )
-    {
-        SAL_WARN( "sdremote.bluetooth", "failed to open bluetooth socket with error " << aSocket );
+    if( !bluezRegisterServiceRecord( pConnection, pService, bluetooth_service_record ) )
         return;
-    }
 
-    sockaddr_rc aAddr;
-    aAddr.rc_family = AF_BLUETOOTH;
-    // BDADDR_ANY is broken, so use memset to set to 0.
-    memset( &aAddr.rc_bdaddr, 0, sizeof( aAddr.rc_bdaddr ) );
-    aAddr.rc_channel = 5;
-
-    int a;
-    if ( ( a = bind( aSocket, (sockaddr*) &aAddr, sizeof(aAddr) ) ) < 0 ) {
-        SAL_WARN( "sdremote.bluetooth", "bind failed with error" << a );
-        close( aSocket );
+    int aSocket = bluezCreateListeningSocket();
+    if( aSocket < 0 )
         return;
-    }
 
-    if ( ( a = listen( aSocket, 1 ) ) < 0 )
-    {
-        SAL_WARN( "sdremote.bluetooth", "listen failed with error" << a );
-        close( aSocket );
-        return;
-    }
+    // ---------------- Socket code ----------------
 
     sockaddr_rc aRemoteAddr;
     socklen_t  aRemoteAddrLen = sizeof(aRemoteAddr);
+
+    // FIXME: use a glib main-loop [!] ...
+    // FIXME: fixme ! ...
     while ( true )
     {
         int bSocket;
commit 943fd58a4fce2a1009060f2f8907e806983721e7
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Feb 18 09:24:23 2013 +0000

    improve bluetooth discoverability toggling API.
    
    Change-Id: I289d43fcb173b64b01183a41f780bc74d2ba0abe
    (cherry picked from commit 21979643e47e503a20113b1e8e98814717c71ac5)
    
    Signed-off-by: Thorsten Behrens <tbehrens at suse.com>

diff --git a/sd/source/ui/dlg/RemoteDialog.cxx b/sd/source/ui/dlg/RemoteDialog.cxx
index fd60895..f9cff1b 100644
--- a/sd/source/ui/dlg/RemoteDialog.cxx
+++ b/sd/source/ui/dlg/RemoteDialog.cxx
@@ -22,22 +22,12 @@ RemoteDialog::RemoteDialog( Window *pWindow ) :
     ModalDialog( pWindow, SdResId( DLG_PAIR_REMOTE ) ),
     mButtonConnect(     this, SdResId( BTN_CONNECT ) ),
     mButtonCancel(      this, SdResId( BTN_CANCEL ) ),
-    mClientBox(         this, NULL, SdResId( LB_SERVERS ) ),
-    mPreviouslyDiscoverable()
+    mClientBox(         this, NULL, SdResId( LB_SERVERS ) )
 {
-    (void) mPreviouslyDiscoverable; // avoid warnings about unused member
-
     FreeResource();
 
 #ifdef ENABLE_SDREMOTE
-
-#ifdef ENABLE_SDREMOTE_BLUETOOTH
-    mPreviouslyDiscoverable = RemoteServer::isBluetoothDiscoverable();
-    if ( !mPreviouslyDiscoverable )
-        RemoteServer::setBluetoothDiscoverable( true );
-#else
-	RemoteServer::setBluetoothDiscoverable( false );
-#endif
+    RemoteServer::ensureDiscoverable();
 
     vector<ClientInfo*> aClients( RemoteServer::getClients() );
 
@@ -80,12 +70,7 @@ IMPL_LINK_NOARG(RemoteDialog, HandleConnectButton)
 
 IMPL_LINK_NOARG( RemoteDialog, CloseHdl )
 {
-#if defined(ENABLE_SDREMOTE) && defined(ENABLE_SDREMOTE_BLUETOOTH)
-    if ( !mPreviouslyDiscoverable )
-    {
-        RemoteServer::setBluetoothDiscoverable( false );
-    }
-#endif
+    RemoteServer::restoreDiscoverable();
     Close();
     return 0;
 }
diff --git a/sd/source/ui/dlg/RemoteDialog.hxx b/sd/source/ui/dlg/RemoteDialog.hxx
index bc4831b..882b9c2 100644
--- a/sd/source/ui/dlg/RemoteDialog.hxx
+++ b/sd/source/ui/dlg/RemoteDialog.hxx
@@ -27,8 +27,6 @@ private:
     OKButton        mButtonConnect;
     CancelButton    mButtonCancel;
     ClientBox       mClientBox;
-    // Whether discoverability was enabled befor the dialog started.
-    bool            mPreviouslyDiscoverable;
 
     DECL_DLLPRIVATE_LINK( HandleConnectButton, void * );
     DECL_LINK( CloseHdl, void * );
diff --git a/sd/source/ui/inc/RemoteServer.hxx b/sd/source/ui/inc/RemoteServer.hxx
index 740465c..f209561 100644
--- a/sd/source/ui/inc/RemoteServer.hxx
+++ b/sd/source/ui/inc/RemoteServer.hxx
@@ -66,8 +66,10 @@ namespace sd
             SD_DLLPUBLIC static sal_Bool connectClient( ClientInfo *pClient,
                                                         rtl::OUString aPin );
 
-            SD_DLLPUBLIC static bool isBluetoothDiscoverable();
-            SD_DLLPUBLIC static void setBluetoothDiscoverable( bool aDiscoverable );
+            /// ensure that discoverability (eg. for Bluetooth) is enabled
+            SD_DLLPUBLIC static void ensureDiscoverable();
+            /// restore the state of discoverability from before ensureDiscoverable
+            SD_DLLPUBLIC static void restoreDiscoverable();
 
             // For the communicator
             static void removeCommunicator( Communicator* pCommunicator );
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.cxx b/sd/source/ui/remotecontrol/BluetoothServer.cxx
index 4d94866..d140c1e 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.cxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.cxx
@@ -267,7 +267,8 @@ void incomingCallback( void *userRefCon,
 
 
 BluetoothServer::BluetoothServer( std::vector<Communicator*>* pCommunicators )
-  : mpCommunicators( pCommunicators )
+  : meWasDiscoverable( UNKNOWN ),
+    mpCommunicators( pCommunicators )
 {
 }
 
@@ -275,6 +276,27 @@ BluetoothServer::~BluetoothServer()
 {
 }
 
+
+void BluetoothServer::ensureDiscoverable()
+{
+     if( !spServer || spServer->meWasDiscoverable != UNKNOWN )
+        return;
+
+     bool bDiscoverable = spServer->isDiscoverable();
+     spServer->meWasDiscoverable = bDiscoverable ? DISCOVERABLE : NOT_DISCOVERABLE;
+     spServer->setDiscoverable( true );
+}
+
+void BluetoothServer::restoreDiscoverable()
+{
+     if(!spServer)
+        return;
+
+     if ( spServer->meWasDiscoverable == NOT_DISCOVERABLE )
+         spServer->setDiscoverable( false );
+     spServer->meWasDiscoverable = UNKNOWN;
+}
+
 bool BluetoothServer::isDiscoverable()
 {
 #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
@@ -328,7 +350,7 @@ bool BluetoothServer::isDiscoverable()
 #endif
 }
 
-void BluetoothServer::setDiscoverable( bool aDiscoverable )
+void BluetoothServer::setDiscoverable( bool bDiscoverable )
 {
 #if (defined(LINUX) && !defined(__FreeBSD_kernel__)) && defined(ENABLE_DBUS)
     SAL_INFO( "sdremote.bluetooth", "BluetoothServer::isDiscoverable called" );
@@ -398,12 +420,12 @@ void BluetoothServer::setDiscoverable( bool aDiscoverable )
         return;
     }
 
-    GValue aDiscoverableGValue = G_VALUE_INIT;
-    g_value_init( &aDiscoverableGValue, G_TYPE_BOOLEAN );
-    g_value_set_boolean( &aDiscoverableGValue, aDiscoverable );
+    GValue bDiscoverableGValue = G_VALUE_INIT;
+    g_value_init( &bDiscoverableGValue, G_TYPE_BOOLEAN );
+    g_value_set_boolean( &bDiscoverableGValue, bDiscoverable );
     aResult = dbus_g_proxy_call( aAdapter, "SetProperty", &aError,
                                 G_TYPE_STRING, "Discoverable",
-                                 G_TYPE_VALUE, &aDiscoverableGValue, G_TYPE_INVALID, G_TYPE_INVALID);
+                                 G_TYPE_VALUE, &bDiscoverableGValue, G_TYPE_INVALID, G_TYPE_INVALID);
     if ( !aResult || aError )
     {
         SAL_WARN( "sdremote.bluetooth", "SetProperty(Discoverable) failed" );
@@ -418,7 +440,7 @@ void BluetoothServer::setDiscoverable( bool aDiscoverable )
     g_object_unref( G_OBJECT( aAdapter ));
     dbus_g_connection_unref( aConnection );
 #else // defined(LINUX) && defined(ENABLE_DBUS)
-    (void) aDiscoverable; // avoid warnings
+    (void) bDiscoverable; // avoid warnings
 #endif
 }
 
diff --git a/sd/source/ui/remotecontrol/BluetoothServer.hxx b/sd/source/ui/remotecontrol/BluetoothServer.hxx
index d8c9879..5b986fa 100644
--- a/sd/source/ui/remotecontrol/BluetoothServer.hxx
+++ b/sd/source/ui/remotecontrol/BluetoothServer.hxx
@@ -22,18 +22,25 @@ namespace sd
     public:
         static void setup( std::vector<Communicator*>* pCommunicators );
 
-        static bool isDiscoverable();
-        static void setDiscoverable( bool aDiscoverable );
+        /// ensure that Bluetooth discoverability is on
+        static void ensureDiscoverable();
+        /// restore the state of discoverability from before ensureDiscoverable
+        static void restoreDiscoverable();
+
         void addCommunicator( Communicator* pCommunicator );
 
     private:
         BluetoothServer( std::vector<Communicator*>* pCommunicators );
         ~BluetoothServer();
+
+        bool isDiscoverable();
+        void setDiscoverable( bool bDiscoverable );
+
+        enum { UNKNOWN, DISCOVERABLE, NOT_DISCOVERABLE } meWasDiscoverable;
         static BluetoothServer *spServer;
 
         virtual void SAL_CALL run();
         std::vector<Communicator*>* mpCommunicators;
-
     };
 }
 
diff --git a/sd/source/ui/remotecontrol/Server.cxx b/sd/source/ui/remotecontrol/Server.cxx
index 9989ed0..561dac1 100644
--- a/sd/source/ui/remotecontrol/Server.cxx
+++ b/sd/source/ui/remotecontrol/Server.cxx
@@ -318,21 +318,19 @@ void SdDLL::RegisterRemotes()
     sd::DiscoveryService::setup();
 }
 
-bool RemoteServer::isBluetoothDiscoverable()
+void RemoteServer::ensureDiscoverable()
 {
+    // FIXME: we could also enable listening on our WiFi
+    // socket here to significantly reduce the attack surface.
 #ifdef ENABLE_SDREMOTE_BLUETOOTH
-    return BluetoothServer::isDiscoverable();
-#else
-    return false;
+    BluetoothServer::ensureDiscoverable();
 #endif
 }
 
-void RemoteServer::setBluetoothDiscoverable( bool aDiscoverable )
+void RemoteServer::restoreDiscoverable()
 {
 #ifdef ENABLE_SDREMOTE_BLUETOOTH
-    BluetoothServer::setDiscoverable( aDiscoverable );
-#else
-    (void) aDiscoverable;
+    BluetoothServer::restoreDiscoverable();
 #endif
 }
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list