diff --git a/dom/bluetooth/BluetoothCommon.h b/dom/bluetooth/BluetoothCommon.h index c7f5787bc43e..63628ae5e67c 100644 --- a/dom/bluetooth/BluetoothCommon.h +++ b/dom/bluetooth/BluetoothCommon.h @@ -18,6 +18,14 @@ #define USING_BLUETOOTH_NAMESPACE \ using namespace mozilla::dom::bluetooth; +#define LOCAL_AGENT_PATH "/B2G/bluetooth/agent" +#define REMOTE_AGENT_PATH "/B2G/bluetooth/remote_device_agent" + +// Bluetooth address format: xx:xx:xx:xx:xx:xx (or xx_xx_xx_xx_xx_xx) +#define BLUETOOTH_ADDRESS_LENGTH 17 + +#define DOM_BLUETOOTH_URL_PREF "dom.mozBluetooth.whitelist" + class nsCString; BEGIN_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/BluetoothService.h b/dom/bluetooth/BluetoothService.h index df9c59f9a2ef..85797cb9e2e4 100644 --- a/dom/bluetooth/BluetoothService.h +++ b/dom/bluetooth/BluetoothService.h @@ -209,6 +209,22 @@ public: RemoveReservedServicesInternal(const nsAString& aAdapterPath, const nsTArray& aServiceHandles) = 0; + virtual nsresult + CreatePairedDeviceInternal(const nsAString& aAdapterPath, + const nsAString& aAddress, + int aTimeout, + BluetoothReplyRunnable* aRunnable) = 0; + + virtual nsresult + RemoveDeviceInternal(const nsAString& aAdapterPath, + const nsAString& aObjectPath, + BluetoothReplyRunnable* aRunnable) = 0; + + virtual bool SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode) = 0; + virtual bool SetPasskeyInternal(const nsAString& aDeviceAddress, PRUint32 aPasskey) = 0; + virtual bool SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm) = 0; + virtual bool SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow) = 0; + /** * Due to the fact that some operations require multiple calls, a * CommandThread is created that can run blocking, platform-specific calls @@ -222,6 +238,7 @@ public: * */ nsCOMPtr mBluetoothCommandThread; + protected: BluetoothService() { diff --git a/dom/bluetooth/linux/BluetoothDBusService.cpp b/dom/bluetooth/linux/BluetoothDBusService.cpp index 11373e60c448..6919430eeb6b 100644 --- a/dom/bluetooth/linux/BluetoothDBusService.cpp +++ b/dom/bluetooth/linux/BluetoothDBusService.cpp @@ -28,7 +28,7 @@ #include "nsAutoPtr.h" #include "nsThreadUtils.h" #include "nsDebug.h" -#include "nsClassHashtable.h" +#include "nsDataHashtable.h" #include "mozilla/ipc/DBusThread.h" #include "mozilla/ipc/DBusUtils.h" #include "mozilla/ipc/RawDBusConnection.h" @@ -57,9 +57,11 @@ USING_BLUETOOTH_NAMESPACE #define LOG(args...) if (BTDEBUG) printf(args); #endif +#define B2G_AGENT_CAPABILITIES "DisplayYesNo" #define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager" #define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter" #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device" +#define DBUS_AGENT_IFACE BLUEZ_DBUS_BASE_IFC ".Agent" #define BLUEZ_DBUS_BASE_PATH "/org/bluez" #define BLUEZ_DBUS_BASE_IFC "org.bluez" #define BLUEZ_ERROR_IFC "org.bluez.Error" @@ -133,6 +135,8 @@ static const char* sBluetoothDBusSignals[] = * */ static nsAutoPtr gThreadConnection; +static nsDataHashtable sPairingReqTable; +static nsDataHashtable sAuthorizeReqTable; class DistributeBluetoothSignalTask : public nsRunnable { BluetoothSignal mSignal; @@ -155,7 +159,7 @@ public: } }; -bool +static bool IsDBusMessageError(DBusMessage* aMsg, DBusError* aErr, nsAString& aErrorStr) { if(aErr && dbus_error_is_set(aErr)) { @@ -187,7 +191,7 @@ IsDBusMessageError(DBusMessage* aMsg, DBusError* aErr, nsAString& aErrorStr) return false; } -void +static void DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable, const BluetoothValue& aValue, const nsAString& aErrorStr) { @@ -206,7 +210,7 @@ DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable, } } -void +static void UnpackObjectPathMessage(DBusMessage* aMsg, DBusError* aErr, BluetoothValue& aValue, nsAString& aErrorStr) { @@ -231,6 +235,300 @@ UnpackObjectPathMessage(DBusMessage* aMsg, DBusError* aErr, typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&); +static nsString +GetObjectPathFromAddress(const nsAString& aAdapterPath, + const nsAString& aDeviceAddress) +{ + // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1, + // and the adapter path would be the first part of the object path, accoring + // to the example above, it's /org/bluez/2906/hci0. + nsString devicePath(aAdapterPath); + devicePath.AppendLiteral("/dev_"); + devicePath.Append(aDeviceAddress); + devicePath.ReplaceChar(':', '_'); + return devicePath; +} + +static nsString +GetAddressFromObjectPath(const nsAString& aObjectPath) +{ + // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1, + // and the adapter path would be the first part of the object path, accoring + // to the example above, it's /org/bluez/2906/hci0. + nsString address(aObjectPath); + int addressHead = address.RFind("/") + 5; + + MOZ_ASSERT(addressHead + BLUETOOTH_ADDRESS_LENGTH == address.Length()); + + address.Cut(0, addressHead); + address.ReplaceChar('_', ':'); + + return address; +} + +static void +KeepDBusPairingMessage(const nsString& aDeviceAddress, DBusMessage* aMsg) +{ + sPairingReqTable.Put(aDeviceAddress, aMsg); + + // Increase ref count here because we need this message later. + // It'll be unrefed when set*Internal() is called. + dbus_message_ref(aMsg); +} + +static DBusHandlerResult +AgentEventFilter(DBusConnection *conn, DBusMessage *msg, void *data) +{ + if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) { + LOG("%s: agent handler not interested (not a method call).\n", __FUNCTION__); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + DBusError err; + dbus_error_init(&err); + + nsString signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(msg)); + nsString signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(msg)); + nsString errorStr; + BluetoothValue v; + InfallibleTArray parameters; + + // The following descriptions of each signal are retrieved from: + // + // http://maemo.org/api_refs/5.0/beta/bluez/agent.html + // + if (dbus_message_is_method_call(msg, DBUS_AGENT_IFACE, "Cancel")) { + // This method gets called to indicate that the agent request failed before a reply + // was returned. + + // Return directly + DBusMessage *reply = dbus_message_new_method_return(msg); + + if (!reply) { + errorStr.AssignLiteral("Memory can't be allocated for the message."); + } else { + dbus_connection_send(conn, reply, NULL); + dbus_message_unref(reply); + } + } else if (dbus_message_is_method_call(msg, DBUS_AGENT_IFACE, "Authorize")) { + // This method gets called when the service daemon needs to authorize a + // connection/service request. + char *objectPath; + const char *uuid; + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &objectPath, + DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_INVALID)) { + LOG("%s: Invalid arguments for Authorize() method", __FUNCTION__); + errorStr.AssignLiteral("Invalid arguments for Authorize() method"); + } else { + nsString deviceAddress = GetAddressFromObjectPath(NS_ConvertUTF8toUTF16(objectPath)); + + parameters.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Device"), deviceAddress)); + parameters.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("UUID"), + NS_ConvertUTF8toUTF16(uuid))); + + // Because we may have authorization request and pairing request from the + // same remote device at the same time, we need two tables to keep these messages. + sAuthorizeReqTable.Put(deviceAddress, msg); + + // Increase ref count here because we need this message later. + // It'll be unrefed when setAuthorizationInternal() is called. + dbus_message_ref(msg); + + v = parameters; + } + } else if (dbus_message_is_method_call(msg, DBUS_AGENT_IFACE, "RequestConfirmation")) { + // This method gets called when the service daemon needs to confirm a passkey for + // an authentication. + char *objectPath; + uint32_t passkey; + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &objectPath, + DBUS_TYPE_UINT32, &passkey, + DBUS_TYPE_INVALID)) { + LOG("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__); + errorStr.AssignLiteral("Invalid arguments for RequestConfirmation() method"); + } else { + nsString deviceAddress = GetAddressFromObjectPath(NS_ConvertUTF8toUTF16(objectPath)); + + parameters.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Device"), deviceAddress)); + parameters.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Passkey"), passkey)); + + KeepDBusPairingMessage(deviceAddress, msg); + + v = parameters; + } + } else if (dbus_message_is_method_call(msg, DBUS_AGENT_IFACE, "RequestPinCode")) { + // This method gets called when the service daemon needs to get the passkey for an + // authentication. The return value should be a string of 1-16 characters length. + // The string can be alphanumeric. + char *objectPath; + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &objectPath, + DBUS_TYPE_INVALID)) { + LOG("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__); + errorStr.AssignLiteral("Invalid arguments for RequestPinCode() method"); + } else { + nsString deviceAddress = GetAddressFromObjectPath(NS_ConvertUTF8toUTF16(objectPath)); + + parameters.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Device"), deviceAddress)); + + KeepDBusPairingMessage(deviceAddress, msg); + + v = parameters; + } + } else if (dbus_message_is_method_call(msg, DBUS_AGENT_IFACE, "RequestPasskey")) { + // This method gets called when the service daemon needs to get the passkey for an + // authentication. The return value should be a numeric value between 0-999999. + char *objectPath; + if (!dbus_message_get_args(msg, NULL, + DBUS_TYPE_OBJECT_PATH, &objectPath, + DBUS_TYPE_INVALID)) { + LOG("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__); + errorStr.AssignLiteral("Invalid arguments for RequestPasskey() method"); + } else { + nsString deviceAddress = GetAddressFromObjectPath(NS_ConvertUTF8toUTF16(objectPath)); + + parameters.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Device"), deviceAddress)); + + KeepDBusPairingMessage(deviceAddress, msg); + + v = parameters; + } + } else if (dbus_message_is_method_call(msg, DBUS_AGENT_IFACE, "Release")) { + // This method gets called when the service daemon unregisters the agent. An agent + // can use it to do cleanup tasks. There is no need to unregister the agent, because + // when this method gets called it has already been unregistered. + DBusMessage *reply = dbus_message_new_method_return(msg); + + if (!reply) { + errorStr.AssignLiteral("Memory can't be allocated for the message."); + } else { + dbus_connection_send(conn, reply, NULL); + dbus_message_unref(reply); + + // Do not send an notification to upper layer, too annoying. + return DBUS_HANDLER_RESULT_HANDLED; + } + } else { + LOG("agent handler %s: Unhandled event. Ignore.", __FUNCTION__); + } + + if (!errorStr.IsEmpty()) { + NS_WARNING(NS_ConvertUTF16toUTF8(errorStr).get()); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + BluetoothSignal signal(signalName, signalPath, v); + + nsRefPtr t = new DistributeBluetoothSignalTask(signal); + + if (NS_FAILED(NS_DispatchToMainThread(t))) { + NS_WARNING("Failed to dispatch to main thread!"); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static const DBusObjectPathVTable agentVtable = { + NULL, AgentEventFilter, NULL, NULL, NULL, NULL +}; + +// Local agent means agent for Adapter, not agent for Device. Some signals +// will be passed to local agent, some will be passed to device agent. +// For example, if a remote device would like to pair with us, then the +// signal will be passed to local agent. If we start pairing process with +// calling CreatePairedDevice, we'll get signal which should be passed to +// device agent. +static bool +RegisterLocalAgent(const char* adapterPath, + const char* agentPath, + const char* capabilities) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + if (!dbus_connection_register_object_path(gThreadConnection->GetConnection(), + agentPath, + &agentVtable, + NULL)) { + LOG("%s: Can't register object path %s for agent!", + __FUNCTION__, agentPath); + return false; + } + + DBusMessage* msg = + dbus_message_new_method_call("org.bluez", adapterPath, + DBUS_ADAPTER_IFACE, "RegisterAgent"); + if (!msg) { + LOG("%s: Can't allocate new method call for agent!", __FUNCTION__); + return false; + } + + if (!dbus_message_append_args(msg, + DBUS_TYPE_OBJECT_PATH, &agentPath, + DBUS_TYPE_STRING, &capabilities, + DBUS_TYPE_INVALID)) { + LOG("%s: Couldn't append arguments to dbus message.", __FUNCTION__); + return false; + } + + DBusError err; + dbus_error_init(&err); + + DBusMessage* reply = + dbus_connection_send_with_reply_and_block(gThreadConnection->GetConnection(), + msg, -1, &err); + dbus_message_unref(msg); + + if (!reply) { + if (dbus_error_is_set(&err)) { + if(!strcmp(err.name, "org.bluez.Error.AlreadyExists")) { + LOG_AND_FREE_DBUS_ERROR(&err); +#ifdef DEBUG + LOG("Agent already registered, still returning true"); +#endif + } else { + LOG_AND_FREE_DBUS_ERROR(&err); + LOG("%s: Can't register agent!", __FUNCTION__); + return false; + } + } + } else { + dbus_message_unref(reply); + } + + dbus_connection_flush(gThreadConnection->GetConnection()); + return true; +} + +static bool +RegisterAgent(const nsAString& aAdapterPath) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + if (!RegisterLocalAgent(NS_ConvertUTF16toUTF8(aAdapterPath).get(), + LOCAL_AGENT_PATH, + B2G_AGENT_CAPABILITIES)) { + return false; + } + + // There is no "RegisterAgent" function defined in device interface. + // When we call "CreatePairedDevice", it will do device agent registration for us. + // (See maemo.org/api_refs/5.0/beta/bluez/adapter.html) + if (!dbus_connection_register_object_path(gThreadConnection->GetConnection(), + REMOTE_AGENT_PATH, + &agentVtable, + NULL)) { + LOG("%s: Can't register object path %s for remote device agent!", + __FUNCTION__, REMOTE_AGENT_PATH); + + return false; + } + + return true; +} + void RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable, UnpackFunc aFunc) @@ -675,9 +973,20 @@ BluetoothDBusService::StartInternal() return NS_ERROR_FAILURE; } + sPairingReqTable.Init(); + sAuthorizeReqTable.Init(); + return NS_OK; } +PLDHashOperator +UnrefDBusMessages(const nsAString& key, DBusMessage* value, void* arg) +{ + dbus_message_unref(value); + + return PL_DHASH_NEXT; +} + nsresult BluetoothDBusService::StopInternal() { @@ -705,6 +1014,14 @@ BluetoothDBusService::StopInternal() mConnection = nullptr; gThreadConnection = nullptr; mBluetoothSignalObserverTable.Clear(); + + // unref stored DBusMessages before clear the hashtable + sPairingReqTable.EnumerateRead(UnrefDBusMessages, nullptr); + sPairingReqTable.Clear(); + + sAuthorizeReqTable.EnumerateRead(UnrefDBusMessages, nullptr); + sAuthorizeReqTable.Clear(); + StopDBus(); return NS_OK; } @@ -767,6 +1084,9 @@ public: // We have to manually attach the path to the rest of the elements v.get_ArrayOfBluetoothNamedValue().AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Path"), path)); + + RegisterAgent(path); + DispatchBluetoothReply(mRunnable, v, replyError); return NS_OK; @@ -783,6 +1103,7 @@ BluetoothDBusService::GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRun NS_ERROR("Bluetooth service not started yet!"); return NS_ERROR_FAILURE; } + NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!"); nsRefPtr runnable = aRunnable; @@ -1035,20 +1356,6 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType, return NS_OK; } -nsString -GetObjectPathFromAddress(const nsAString& aAdapterPath, - const nsAString& aDeviceAddress) -{ - // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1, - // and the adapter path would be the first part of the object path, accoring - // to the example above, it's /org/bluez/2906/hci0. - nsString devicePath(aAdapterPath); - devicePath.AppendLiteral("/dev_"); - devicePath.Append(aDeviceAddress); - devicePath.ReplaceChar(':', '_'); - return devicePath; -} - bool BluetoothDBusService::GetDevicePath(const nsAString& aAdapterPath, const nsAString& aDeviceAddress, @@ -1066,12 +1373,12 @@ BluetoothDBusService::GetDeviceServiceChannelInternal(const nsAString& aObjectPa // This is a blocking call, should not be run on main thread. MOZ_ASSERT(!NS_IsMainThread()); - const char* deviceObjectPath = NS_ConvertUTF16toUTF8(aObjectPath).get(); - const char* pattern = NS_ConvertUTF16toUTF8(aPattern).get(); + nsCString tempPattern = NS_ConvertUTF16toUTF8(aPattern); + const char* pattern = tempPattern.get(); DBusMessage *reply = dbus_func_args(gThreadConnection->GetConnection(), - deviceObjectPath, + NS_ConvertUTF16toUTF8(aObjectPath).get(), DBUS_DEVICE_IFACE, "GetServiceAttributeValue", DBUS_TYPE_STRING, &pattern, DBUS_TYPE_UINT16, &aAttributeId, @@ -1111,7 +1418,6 @@ BluetoothDBusService::AddReservedServicesInternal(const nsAString& aAdapterPath, MOZ_ASSERT(!NS_IsMainThread()); nsTArray ret; - const char* adapterPath = NS_ConvertUTF16toUTF8(aAdapterPath).get(); int length = aServices.Length(); if (length == 0) return ret; @@ -1119,7 +1425,7 @@ BluetoothDBusService::AddReservedServicesInternal(const nsAString& aAdapterPath, const uint32_t* services = aServices.Elements(); DBusMessage* reply = dbus_func_args(gThreadConnection->GetConnection(), - adapterPath, + NS_ConvertUTF16toUTF8(aAdapterPath).get(), DBUS_ADAPTER_IFACE, "AddReservedServiceRecords", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &services, length, DBUS_TYPE_INVALID); @@ -1156,3 +1462,212 @@ BluetoothDBusService::RemoveReservedServicesInternal(const nsAString& aAdapterPa dbus_message_unref(reply); return true; } + +nsresult +BluetoothDBusService::CreatePairedDeviceInternal(const nsAString& aAdapterPath, + const nsAString& aDeviceAddress, + int aTimeout, + BluetoothReplyRunnable* aRunnable) +{ + const char *capabilities = B2G_AGENT_CAPABILITIES; + const char *deviceAgentPath = REMOTE_AGENT_PATH; + + nsCString tempDeviceAddress = NS_ConvertUTF16toUTF8(aDeviceAddress); + const char *deviceAddress = tempDeviceAddress.get(); + + nsRefPtr runnable = aRunnable; + // Then send CreatePairedDevice, it will register a temp device agent then + // unregister it after pairing process is over + bool ret = dbus_func_args_async(mConnection, + aTimeout, + GetObjectPathCallback, + (void*)runnable, + NS_ConvertUTF16toUTF8(aAdapterPath).get(), + DBUS_ADAPTER_IFACE, + "CreatePairedDevice", + DBUS_TYPE_STRING, &deviceAddress, + DBUS_TYPE_OBJECT_PATH, &deviceAgentPath, + DBUS_TYPE_STRING, &capabilities, + DBUS_TYPE_INVALID); + + if (!ret) { + NS_WARNING("Could not start async function!"); + return NS_ERROR_FAILURE; + } + + runnable.forget(); + return NS_OK; +} + +nsresult +BluetoothDBusService::RemoveDeviceInternal(const nsAString& aAdapterPath, + const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) +{ + nsCString tempDeviceObjectPath = + NS_ConvertUTF16toUTF8(GetObjectPathFromAddress(aAdapterPath, aDeviceAddress)); + const char* deviceObjectPath = tempDeviceObjectPath.get(); + + nsRefPtr runnable = aRunnable; + + // We don't really care about how long it would take on removing a device, + // just to make sure that the value of timeout is reasonable. So, we use + // -1 for the timeout, which means a reasonable default timeout will be used. + bool ret = dbus_func_args_async(mConnection, + -1, + GetVoidCallback, + (void*)runnable, + NS_ConvertUTF16toUTF8(aAdapterPath).get(), + DBUS_ADAPTER_IFACE, + "RemoveDevice", + DBUS_TYPE_OBJECT_PATH, &deviceObjectPath, + DBUS_TYPE_INVALID); + if (!ret) { + NS_WARNING("Could not start async function!"); + return NS_ERROR_FAILURE; + } + + runnable.forget(); + return NS_OK; +} + +bool +BluetoothDBusService::SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode) +{ + DBusMessage *msg; + if (!sPairingReqTable.Get(aDeviceAddress, &msg)) { + LOG("%s: Couldn't get original request message.", __FUNCTION__); + return false; + } + + DBusMessage *reply = dbus_message_new_method_return(msg); + + if (!reply) { + LOG("%s: Memory can't be allocated for the message.", __FUNCTION__); + dbus_message_unref(msg); + return false; + } + + bool result; + + nsCString tempPinCode = NS_ConvertUTF16toUTF8(aPinCode); + const char* pinCode = tempPinCode.get(); + + if (!dbus_message_append_args(reply, + DBUS_TYPE_STRING, &pinCode, + DBUS_TYPE_INVALID)) { + LOG("%s: Couldn't append arguments to dbus message.", __FUNCTION__); + result = false; + } else { + result = dbus_connection_send(mConnection, reply, NULL); + } + + dbus_message_unref(msg); + dbus_message_unref(reply); + + sPairingReqTable.Remove(aDeviceAddress); + + return result; +} + +bool +BluetoothDBusService::SetPasskeyInternal(const nsAString& aDeviceAddress, PRUint32 aPasskey) +{ + DBusMessage *msg; + if (!sPairingReqTable.Get(aDeviceAddress, &msg)) { + LOG("%s: Couldn't get original request message.", __FUNCTION__); + return false; + } + + DBusMessage *reply = dbus_message_new_method_return(msg); + + if (!reply) { + LOG("%s: Memory can't be allocated for the message.", __FUNCTION__); + dbus_message_unref(msg); + return false; + } + + uint32_t passkey = aPasskey; + bool result; + + if (!dbus_message_append_args(reply, + DBUS_TYPE_UINT32, &passkey, + DBUS_TYPE_INVALID)) { + LOG("%s: Couldn't append arguments to dbus message.", __FUNCTION__); + result = false; + } else { + result = dbus_connection_send(mConnection, reply, NULL); + } + + dbus_message_unref(msg); + dbus_message_unref(reply); + + sPairingReqTable.Remove(aDeviceAddress); + + return result; +} + +bool +BluetoothDBusService::SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm) +{ + DBusMessage *msg; + if (!sPairingReqTable.Get(aDeviceAddress, &msg)) { + LOG("%s: Couldn't get original request message.", __FUNCTION__); + return false; + } + + DBusMessage *reply; + + if (aConfirm) { + reply = dbus_message_new_method_return(msg); + } else { + reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "User rejected confirmation"); + } + + if (!reply) { + LOG("%s: Memory can't be allocated for the message.", __FUNCTION__); + dbus_message_unref(msg); + return false; + } + + bool result = dbus_connection_send(mConnection, reply, NULL); + dbus_message_unref(msg); + dbus_message_unref(reply); + + sPairingReqTable.Remove(aDeviceAddress); + + return result; +} + +bool +BluetoothDBusService::SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow) +{ + DBusMessage *msg; + + if (!sAuthorizeReqTable.Get(aDeviceAddress, &msg)) { + LOG("%s: Couldn't get original request message.", __FUNCTION__); + return false; + } + + DBusMessage *reply; + + if (aAllow) { + reply = dbus_message_new_method_return(msg); + } else { + reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "Authorization rejected"); + } + + if (!reply) { + LOG("%s: Memory can't be allocated for the message.", __FUNCTION__); + dbus_message_unref(msg); + return false; + } + + bool result = dbus_connection_send(mConnection, reply, NULL); + dbus_message_unref(msg); + dbus_message_unref(reply); + + sAuthorizeReqTable.Remove(aDeviceAddress); + + return result; +} diff --git a/dom/bluetooth/linux/BluetoothDBusService.h b/dom/bluetooth/linux/BluetoothDBusService.h index 81f6d8d3d8ae..3e65c4cf3c5a 100644 --- a/dom/bluetooth/linux/BluetoothDBusService.h +++ b/dom/bluetooth/linux/BluetoothDBusService.h @@ -59,6 +59,29 @@ public: RemoveReservedServicesInternal(const nsAString& aAdapterPath, const nsTArray& aServiceHandles); + virtual nsresult + CreatePairedDeviceInternal(const nsAString& aAdapterPath, + const nsAString& aDeviceAddress, + int aTimeout, + BluetoothReplyRunnable* aRunnable); + + virtual nsresult + RemoveDeviceInternal(const nsAString& aAdapterPath, + const nsAString& aDeviceObjectPath, + BluetoothReplyRunnable* aRunnable); + + virtual bool + SetPinCodeInternal(const nsAString& aDeviceAddress, const nsAString& aPinCode); + + virtual bool + SetPasskeyInternal(const nsAString& aDeviceAddress, PRUint32 aPasskey); + + virtual bool + SetPairingConfirmationInternal(const nsAString& aDeviceAddress, bool aConfirm); + + virtual bool + SetAuthorizationInternal(const nsAString& aDeviceAddress, bool aAllow); + private: nsresult SendGetPropertyMessage(const nsAString& aPath, const char* aInterface,