fix styling issues
This commit is contained in:
@@ -1,29 +1,57 @@
|
||||
#include "connection/dbus/bluetooth.hpp"
|
||||
#include "services/notificationController.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// ---------------------------------------------------------------------------
|
||||
const std::string agent_introspection_xml = R"(
|
||||
<node>
|
||||
<interface name="org.bluez.Agent1">
|
||||
<method name="Release"/>
|
||||
<method name="RequestPinCode">
|
||||
<arg type="o" name="device" direction="in"/>
|
||||
<arg type="s" name="pincode" direction="out"/>
|
||||
</method>
|
||||
<method name="DisplayPinCode">
|
||||
<arg type="o" name="device" direction="in"/>
|
||||
<arg type="s" name="pincode" direction="in"/>
|
||||
</method>
|
||||
<method name="RequestPasskey">
|
||||
<arg type="o" name="device" direction="in"/>
|
||||
<arg type="u" name="passkey" direction="out"/>
|
||||
</method>
|
||||
<method name="DisplayPasskey">
|
||||
<arg type="o" name="device" direction="in"/>
|
||||
<arg type="u" name="passkey" direction="in"/>
|
||||
<arg type="q" name="entered" direction="in"/>
|
||||
</method>
|
||||
<method name="RequestConfirmation">
|
||||
<arg type="o" name="device" direction="in"/>
|
||||
<arg type="u" name="passkey" direction="in"/>
|
||||
</method>
|
||||
<method name="RequestAuthorization">
|
||||
<arg type="o" name="device" direction="in"/>
|
||||
</method>
|
||||
<method name="AuthorizeService">
|
||||
<arg type="o" name="device" direction="in"/>
|
||||
<arg type="s" name="uuid" direction="in"/>
|
||||
</method>
|
||||
<method name="Cancel"/>
|
||||
</interface>
|
||||
</node>
|
||||
)";
|
||||
|
||||
BluetoothController::BluetoothController() {
|
||||
connect_system_async(sigc::mem_fun(*this, &BluetoothController::onBusConnected));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Signal accessors
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
sigc::signal<void(bool)> &BluetoothController::signalPoweredChanged() { return m_powered_signal; }
|
||||
sigc::signal<void(bool)> &BluetoothController::signalDiscoveringChanged() { return m_discovering_signal; }
|
||||
sigc::signal<void(const BluetoothDevice &)> &BluetoothController::signalDeviceAdded() { return m_device_added_signal; }
|
||||
sigc::signal<void(const std::string &)> &BluetoothController::signalDeviceRemoved() { return m_device_removed_signal; }
|
||||
sigc::signal<void(const BluetoothDevice &)> &BluetoothController::signalDeviceChanged() { return m_device_changed_signal; }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Queries
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
bool BluetoothController::isPowered() const { return m_powered; }
|
||||
bool BluetoothController::isDiscovering() const { return m_discovering; }
|
||||
|
||||
@@ -46,10 +74,6 @@ std::vector<BluetoothDevice> BluetoothController::getPairedDevices() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Adapter control
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void BluetoothController::setPowered(bool powered) {
|
||||
spdlog::info("Bluetooth: setting powered to {}", powered);
|
||||
setDbusProperty(m_adapter_path, "org.bluez.Adapter1", "Powered",
|
||||
@@ -70,10 +94,6 @@ void BluetoothController::stopDiscovery() {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Device actions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void BluetoothController::pairDevice(const std::string &object_path) {
|
||||
spdlog::info("Bluetooth: pairing device {}", object_path);
|
||||
auto it = m_device_proxies.find(object_path);
|
||||
@@ -139,6 +159,8 @@ void BluetoothController::onBusConnected(const Glib::RefPtr<Gio::AsyncResult> &r
|
||||
|
||||
enumerateObjects();
|
||||
}
|
||||
|
||||
registerAgent();
|
||||
} catch (const Glib::Error &ex) {
|
||||
spdlog::error("Bluetooth DBus Connection Error: {}", ex.what());
|
||||
}
|
||||
@@ -452,3 +474,292 @@ void BluetoothController::setDbusProperty(const std::string &object_path,
|
||||
spdlog::error("Error setting {}.{}: {}", interface, property, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Agent
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void BluetoothController::registerAgent() {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
try {
|
||||
auto node_info = Gio::DBus::NodeInfo::create_for_xml(agent_introspection_xml);
|
||||
auto interface_info = node_info->lookup_interface("org.bluez.Agent1");
|
||||
|
||||
Gio::DBus::InterfaceVTable vtable(
|
||||
sigc::mem_fun(*this, &BluetoothController::on_agent_method_call));
|
||||
|
||||
m_agent_id = connection->register_object("/org/bluez/agent", interface_info, vtable);
|
||||
|
||||
auto agent_manager = Gio::DBus::Proxy::create_sync(
|
||||
connection, "org.bluez", "/org/bluez", "org.bluez.AgentManager1");
|
||||
|
||||
if (agent_manager) {
|
||||
agent_manager->call(
|
||||
"RegisterAgent",
|
||||
Glib::VariantContainerBase::create_tuple(
|
||||
{Glib::Variant<Glib::ustring>::create("/org/bluez/agent"),
|
||||
Glib::Variant<Glib::ustring>::create("KeyboardDisplay")})); // Using KeyboardDisplay capacity
|
||||
|
||||
agent_manager->call(
|
||||
"RequestDefaultAgent",
|
||||
Glib::VariantContainerBase::create_tuple(
|
||||
{Glib::Variant<Glib::ustring>::create("/org/bluez/agent")}));
|
||||
|
||||
spdlog::info("Bluetooth Agent registered successfully");
|
||||
}
|
||||
} catch (const Glib::Error &ex) {
|
||||
spdlog::error("Bluetooth: Failed to register agent: {}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothController::on_agent_method_call(
|
||||
const Glib::RefPtr<Gio::DBus::Connection> &,
|
||||
const Glib::ustring &,
|
||||
const Glib::ustring &,
|
||||
const Glib::ustring &,
|
||||
const Glib::ustring &method_name,
|
||||
const Glib::VariantContainerBase ¶meters,
|
||||
const Glib::RefPtr<Gio::DBus::MethodInvocation> &invocation) {
|
||||
|
||||
if (method_name == "RequestConfirmation") {
|
||||
// Signature: (ou)
|
||||
std::string device_path = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::DBusObjectPathString>>(
|
||||
parameters.get_child(0)).get());
|
||||
|
||||
guint32 passkey = Glib::VariantBase::cast_dynamic<Glib::Variant<guint32>>(
|
||||
parameters.get_child(1)).get();
|
||||
|
||||
std::string device_name = device_path;
|
||||
if (m_devices.count(device_path)) {
|
||||
device_name = m_devices[device_path].name;
|
||||
if (device_name.empty())
|
||||
device_name = m_devices[device_path].address;
|
||||
}
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << std::setw(6) << std::setfill('0') << passkey;
|
||||
std::string passkey_str = ss.str();
|
||||
|
||||
NotifyMessage msg;
|
||||
msg.summary = "Bluetooth Pairing Request";
|
||||
msg.body = "Device '" + device_name + "' wants to pair.\nPasskey: " + passkey_str;
|
||||
msg.app_name = "Bar";
|
||||
msg.actions = {"Confirm", "Cancel"};
|
||||
msg.urgency = NotificationUrgency::CRITICAL;
|
||||
msg.expire_timeout = -1; // No timeout, requires user interaction
|
||||
|
||||
// Capture invocation to respond later
|
||||
// Note: invocation is a RefPtr, so copying it increases ref count
|
||||
msg.on_action = [invocation](const std::string &action) {
|
||||
if (action == "Confirm") {
|
||||
invocation->return_value(Glib::VariantContainerBase());
|
||||
} else {
|
||||
invocation->return_dbus_error("org.bluez.Error.Rejected", "Rejected by user");
|
||||
}
|
||||
};
|
||||
|
||||
NotificationController::getInstance()->showNotificationOnAllMonitors(msg);
|
||||
|
||||
} else if (method_name == "RequestAuthorization") {
|
||||
// Signature: (o)
|
||||
std::string device_path = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::DBusObjectPathString>>(
|
||||
parameters.get_child(0)).get());
|
||||
|
||||
std::string device_name = device_path;
|
||||
if (m_devices.count(device_path)) {
|
||||
device_name = m_devices[device_path].name;
|
||||
if (device_name.empty())
|
||||
device_name = m_devices[device_path].address;
|
||||
}
|
||||
|
||||
NotifyMessage msg;
|
||||
msg.summary = "Bluetooth Authorization Request";
|
||||
msg.body = "Device '" + device_name + "' requests authorization to connect.";
|
||||
msg.app_name = "Bar";
|
||||
msg.actions = {"Allow", "Deny"};
|
||||
msg.urgency = NotificationUrgency::CRITICAL;
|
||||
msg.expire_timeout = -1;
|
||||
|
||||
msg.on_action = [invocation](const std::string &action) {
|
||||
if (action == "Allow") {
|
||||
invocation->return_value(Glib::VariantContainerBase());
|
||||
} else {
|
||||
invocation->return_dbus_error("org.bluez.Error.Rejected", "Rejected by user");
|
||||
}
|
||||
};
|
||||
|
||||
NotificationController::getInstance()->showNotificationOnAllMonitors(msg);
|
||||
|
||||
} else if (method_name == "AuthorizeService") {
|
||||
// Signature: (os)
|
||||
std::string device_path = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::DBusObjectPathString>>(
|
||||
parameters.get_child(0)).get());
|
||||
std::string uuid = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(
|
||||
parameters.get_child(1)).get());
|
||||
|
||||
std::string device_name = device_path;
|
||||
if (m_devices.count(device_path)) {
|
||||
device_name = m_devices[device_path].name;
|
||||
if (device_name.empty())
|
||||
device_name = m_devices[device_path].address;
|
||||
}
|
||||
|
||||
NotifyMessage msg;
|
||||
msg.summary = "Bluetooth Service Authorization";
|
||||
msg.body = "Device '" + device_name + "' wants to access service: " + uuid;
|
||||
msg.app_name = "Bar";
|
||||
msg.actions = {"Allow", "Deny"};
|
||||
msg.urgency = NotificationUrgency::CRITICAL;
|
||||
msg.expire_timeout = -1;
|
||||
|
||||
msg.on_action = [invocation](const std::string &action) {
|
||||
if (action == "Allow") {
|
||||
invocation->return_value(Glib::VariantContainerBase());
|
||||
} else {
|
||||
invocation->return_dbus_error("org.bluez.Error.Rejected", "Rejected by user");
|
||||
}
|
||||
};
|
||||
|
||||
NotificationController::getInstance()->showNotificationOnAllMonitors(msg);
|
||||
|
||||
} else if (method_name == "DisplayPinCode") {
|
||||
// Signature: (os)
|
||||
std::string device_path = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::DBusObjectPathString>>(
|
||||
parameters.get_child(0)).get());
|
||||
std::string pincode = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::ustring>>(
|
||||
parameters.get_child(1)).get());
|
||||
|
||||
std::string device_name = device_path;
|
||||
if (m_devices.count(device_path)) {
|
||||
device_name = m_devices[device_path].name;
|
||||
if (device_name.empty())
|
||||
device_name = m_devices[device_path].address;
|
||||
}
|
||||
|
||||
NotifyMessage msg;
|
||||
msg.summary = "Bluetooth Pin Code";
|
||||
msg.body = "Pin code for device '" + device_name + "': " + pincode;
|
||||
msg.app_name = "Bar";
|
||||
msg.actions = {"Dismiss"};
|
||||
msg.urgency = NotificationUrgency::NORMAL;
|
||||
msg.expire_timeout = 0;
|
||||
|
||||
NotificationController::getInstance()->showNotificationOnAllMonitors(msg);
|
||||
invocation->return_value(Glib::VariantContainerBase());
|
||||
|
||||
} else if (method_name == "DisplayPasskey") {
|
||||
// Signature: (ouq)
|
||||
std::string device_path = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::DBusObjectPathString>>(
|
||||
parameters.get_child(0)).get());
|
||||
guint32 passkey = Glib::VariantBase::cast_dynamic<Glib::Variant<guint32>>(
|
||||
parameters.get_child(1)).get();
|
||||
guint16 entered = Glib::VariantBase::cast_dynamic<Glib::Variant<guint16>>(
|
||||
parameters.get_child(2)).get();
|
||||
|
||||
// Only show on first display (entered == 0) to avoid spam
|
||||
if (entered == 0) {
|
||||
std::string device_name = device_path;
|
||||
if (m_devices.count(device_path)) {
|
||||
device_name = m_devices[device_path].name;
|
||||
if (device_name.empty())
|
||||
device_name = m_devices[device_path].address;
|
||||
}
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << std::setw(6) << std::setfill('0') << passkey;
|
||||
std::string passkey_str = ss.str();
|
||||
|
||||
NotifyMessage msg;
|
||||
msg.summary = "Bluetooth Passkey";
|
||||
msg.body = "Type this passkey on '" + device_name + "': " + passkey_str;
|
||||
msg.app_name = "Bar";
|
||||
msg.actions = {"Dismiss"};
|
||||
msg.urgency = NotificationUrgency::CRITICAL;
|
||||
msg.expire_timeout = -1;
|
||||
|
||||
NotificationController::getInstance()->showNotificationOnAllMonitors(msg);
|
||||
}
|
||||
invocation->return_value(Glib::VariantContainerBase());
|
||||
|
||||
} else if (method_name == "RequestPinCode") {
|
||||
// Signature: (o) -> s
|
||||
std::string device_path = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::DBusObjectPathString>>(
|
||||
parameters.get_child(0)).get());
|
||||
|
||||
std::string device_name = device_path;
|
||||
if (m_devices.count(device_path)) {
|
||||
device_name = m_devices[device_path].name;
|
||||
if (device_name.empty())
|
||||
device_name = m_devices[device_path].address;
|
||||
}
|
||||
|
||||
NotifyMessage msg;
|
||||
msg.summary = "Bluetooth PIN Request";
|
||||
msg.body = "Enter PIN Code for '" + device_name + "'";
|
||||
msg.app_name = "Bar";
|
||||
msg.urgency = NotificationUrgency::CRITICAL;
|
||||
msg.expire_timeout = -1;
|
||||
msg.has_input = true;
|
||||
msg.input_placeholder = "PIN Code";
|
||||
|
||||
msg.on_input = [invocation](const std::string &input) {
|
||||
invocation->return_value(
|
||||
Glib::VariantContainerBase::create_tuple(
|
||||
{Glib::Variant<Glib::ustring>::create(input)}));
|
||||
};
|
||||
|
||||
NotificationController::getInstance()->showNotificationOnAllMonitors(msg);
|
||||
|
||||
} else if (method_name == "RequestPasskey") {
|
||||
// Signature: (o) -> u
|
||||
std::string device_path = static_cast<std::string>(
|
||||
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::DBusObjectPathString>>(
|
||||
parameters.get_child(0)).get());
|
||||
|
||||
std::string device_name = device_path;
|
||||
if (m_devices.count(device_path)) {
|
||||
device_name = m_devices[device_path].name;
|
||||
if (device_name.empty())
|
||||
device_name = m_devices[device_path].address;
|
||||
}
|
||||
|
||||
NotifyMessage msg;
|
||||
msg.summary = "Bluetooth Passkey Request";
|
||||
msg.body = "Enter Passkey for '" + device_name + "'";
|
||||
msg.app_name = "Bar";
|
||||
msg.urgency = NotificationUrgency::CRITICAL;
|
||||
msg.expire_timeout = -1;
|
||||
msg.has_input = true;
|
||||
msg.input_placeholder = "Passkey (0-999999)";
|
||||
|
||||
msg.on_input = [invocation](const std::string &input) {
|
||||
try {
|
||||
uint32_t passkey = std::stoul(input);
|
||||
invocation->return_value(
|
||||
Glib::VariantContainerBase::create_tuple(
|
||||
{Glib::Variant<guint32>::create(passkey)}));
|
||||
} catch (...) {
|
||||
invocation->return_dbus_error("org.bluez.Error.Failed", "Invalid passkey format");
|
||||
}
|
||||
};
|
||||
|
||||
NotificationController::getInstance()->showNotificationOnAllMonitors(msg);
|
||||
|
||||
} else if (method_name == "Cancel" || method_name == "Release") {
|
||||
// Just return
|
||||
invocation->return_value(Glib::VariantContainerBase());
|
||||
} else {
|
||||
// Not implemented
|
||||
invocation->return_dbus_error("org.bluez.Error.Rejected", "Not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user