From 5b45748c5dc9c2d1718b6219e30a64e07e5ca313 Mon Sep 17 00:00:00 2001 From: Muhammad Asif Date: Mon, 19 May 2025 22:22:08 +0200 Subject: ayatana-indicator-bluetooth: add initial pairing agent Co-authored-by: Robert Tari Signed-off-by: Muhammad Asif --- src/bluetooth.vala | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/bluetooth.vala') diff --git a/src/bluetooth.vala b/src/bluetooth.vala index 0cc5432..da7c176 100644 --- a/src/bluetooth.vala +++ b/src/bluetooth.vala @@ -52,4 +52,8 @@ public interface Bluetooth: Object /* Try to connect/disconnect a particular device. The device_key argument comes from the Device struct */ public abstract void set_device_connected (uint device_key, bool connected); + + public abstract string get_device_name (ObjectPath path); + + public abstract void add_agent (string path); } -- cgit v1.2.3 From 568f6aa32e290b4e37b61dfd9985ae81a08e2892 Mon Sep 17 00:00:00 2001 From: Muhammad Asif Date: Tue, 24 Jun 2025 00:19:48 +0500 Subject: agent: use signals to register agent to BlueZ Signed-off-by: Muhammad Asif --- src/bluetooth.vala | 2 ++ src/bluez.vala | 2 +- src/service.vala | 12 ++++++++---- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/bluetooth.vala') diff --git a/src/bluetooth.vala b/src/bluetooth.vala index da7c176..9b2f9d5 100644 --- a/src/bluetooth.vala +++ b/src/bluetooth.vala @@ -55,5 +55,7 @@ public interface Bluetooth: Object public abstract string get_device_name (ObjectPath path); + public signal void agent_manager_ready (); + public abstract void add_agent (string path); } diff --git a/src/bluez.vala b/src/bluez.vala index fabee5f..6d08004 100644 --- a/src/bluez.vala +++ b/src/bluez.vala @@ -122,7 +122,7 @@ public class Bluez: Bluetooth, Object { manager = bus.get_proxy_sync (BLUEZ_BUSNAME, "/"); agent_manager = bus.get_proxy_sync (BLUEZ_BUSNAME, "/org/bluez"); - add_agent ("/agent"); + agent_manager_ready (); // Find the adapters and watch for changes manager.interfaces_added.connect ((object_path, interfaces_and_properties) => { diff --git a/src/service.vala b/src/service.vala index b79056e..e651811 100644 --- a/src/service.vala +++ b/src/service.vala @@ -29,7 +29,7 @@ public class Service: Object private MainLoop loop; private SimpleActionGroup actions; private HashTable profiles; - private Bluetooth bluez; + private Bluetooth bluetooth; private DBusConnection connection; private uint exported_action_id; private const string OBJECT_PATH = "/org/ayatana/indicator/bluetooth"; @@ -50,10 +50,10 @@ public class Service: Object } } - public Service (Bluetooth bluetooth) + public Service (Bluetooth bluetooth_service) { actions = new SimpleActionGroup (); - bluez = bluetooth; + bluetooth = bluetooth_service; profiles = new HashTable (str_hash, str_equal); profiles.insert ("phone", new Phone (bluetooth, actions)); @@ -83,6 +83,10 @@ public class Service: Object null, null); + bluetooth.agent_manager_ready.connect (() => { + bluetooth.add_agent ("/agent"); + }); + loop = new MainLoop (null, false); loop.run (); @@ -97,7 +101,7 @@ public class Service: Object { try { - connection.register_object ("/agent", new Agent (bluez)); + connection.register_object ("/agent", new Agent (bluetooth)); } catch (GLib.IOError pError) { -- cgit v1.2.3 From 36d77944f2e7707eefd60ea208c6f4bc55a3f961 Mon Sep 17 00:00:00 2001 From: Muhammad Date: Tue, 10 Mar 2026 01:37:25 +0500 Subject: agent: add proper support for AuthorizeService Signed-off-by: Muhammad --- src/agent.vala | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/bluetooth.vala | 6 ++++++ src/bluez.vala | 26 ++++++++++++++++++++++ src/device.vala | 5 ++++- 4 files changed, 98 insertions(+), 2 deletions(-) (limited to 'src/bluetooth.vala') diff --git a/src/agent.vala b/src/agent.vala index 9e568a4..16ce6a2 100644 --- a/src/agent.vala +++ b/src/agent.vala @@ -1,9 +1,12 @@ [DBus (name = "org.bluez.Agent1")] public class Agent: Object { + // These actions and menus are exposed on their relevant paths by service.vala public GLib.Menu menu; public GLib.SimpleActionGroup actions; private GLib.SimpleAction pin_action; + + // These paths are set by service.vala public string menu_path; public string actions_path; @@ -102,8 +105,66 @@ public class Agent: Object return accepted; } - public void AuthorizeService (GLib.ObjectPath object, string uuid) throws GLib.DBusError, GLib.IOError + public void AuthorizeService (GLib.ObjectPath object, string uuid) throws RejectedError, GLib.DBusError, GLib.IOError { + bool authorized = false; + bool trusted = false; + + string header = "Allow %s to connect?".printf (bluetooth.get_device_name (object)); + string body = "Allow the Bluetooth device to access a Bluetooth service?"; + + notification = new Notify.Notification (header, body, "bluetooth-active"); + notification.closed.connect (() => { + authorized = false; + notification = null; + + if (loop.is_running ()) { + loop.quit (); + } + }); + + if (AyatanaCommon.utils_is_lomiri ()) { + notification.set_hint ("x-lomiri-snap-decisions", true); + } + + notification.add_action ("trust_and_authorize", "Trust and authorize", (notif, action) => { + loop.quit (); + notification = null; + + trusted = true; + authorized = true; + }); + + notification.add_action ("authorize", "Authorize", (notif, action) => { + loop.quit (); + notification = null; + + authorized = true; + }); + + notification.add_action ("reject", "Do not authorize", (notif, action) => { + loop.quit (); + notification = null; + }); + + try { + notification.show (); + } + catch (Error e) { + warning ("Panic: Failed showing notification: %s", e.message); + } + + loop.run (); + + // Once the loop quits, we can see if we want to set the 'Trusted' property in BlueZ + if (trusted) { + Device device = bluetooth.get_device (object); + bluetooth.set_device_trusted (device.id, trusted); + } + + if (!authorized) { + throw new RejectedError.ERROR ("Rejected by user"); + } } public void RequestConfirmation (GLib.ObjectPath object, uint32 passkey) throws RejectedError, GLib.DBusError, GLib.IOError diff --git a/src/bluetooth.vala b/src/bluetooth.vala index 9b2f9d5..47c6f8e 100644 --- a/src/bluetooth.vala +++ b/src/bluetooth.vala @@ -46,6 +46,9 @@ public interface Bluetooth: Object /* Get a list of the Device structs that we know about */ public abstract List get_devices (); + /* Get a Device from its DBus path */ + public abstract Device get_device (ObjectPath path); + /* Emitted when one or more of the devices is added, removed, or changed */ public signal void devices_changed (); @@ -53,6 +56,9 @@ public interface Bluetooth: Object The device_key argument comes from the Device struct */ public abstract void set_device_connected (uint device_key, bool connected); + /* Sets whether or not a device is trusted (allowed to connect without authorization) */ + public abstract void set_device_trusted (uint device_key, bool trusted); + public abstract string get_device_name (ObjectPath path); public signal void agent_manager_ready (); diff --git a/src/bluez.vala b/src/bluez.vala index 8d481f2..353b1a2 100644 --- a/src/bluez.vala +++ b/src/bluez.vala @@ -325,6 +325,10 @@ public class Bluez: Bluetooth, Object v = device_proxy.get_cached_property ("Connected"); var is_connected = (v != null) && v.get_boolean (); + // look up whether the device is trusted + v = device_proxy.get_cached_property ("Trusted"); + var is_trusted = (v != null) && v.get_boolean (); + // derive the uuid-related attributes we care about v = device_proxy.get_cached_property ("UUIDs"); uint16[] uuids = {}; @@ -344,6 +348,7 @@ public class Bluez: Bluetooth, Object icon, true, is_connected, + is_trusted, supports_browsing, supports_file_transfer)); @@ -415,6 +420,19 @@ public class Bluez: Bluetooth, Object } } + public void set_device_trusted (uint id, bool trusted) + { + var device = id_to_device.lookup (id); + var path = id_to_path.lookup (id); + var proxy = (path != null) ? path_to_device_proxy.lookup (path) : null; + + if ((device != null) + && (device.is_trusted != trusted)) + { + proxy.trusted = trusted; + } + } + public void try_set_discoverable (bool b) { if (discoverable != b) @@ -440,6 +458,11 @@ public class Bluez: Bluetooth, Object return id_to_device.get_values(); } + public Device get_device (ObjectPath path) + { + return id_to_device.lookup(path_to_id.lookup(path)); + } + public bool supported { get; protected set; default = false; } public bool discoverable { get; protected set; default = false; } public bool enabled { get; protected set; default = false; } @@ -509,6 +532,9 @@ private interface BluezDevice : DBusProxy { [DBus (name = "Disconnect")] public abstract void disconnect_() throws DBusError, IOError; + + [DBus (name = "Trusted")] + public abstract bool trusted { get; set; } } [DBus (name = "org.bluez.AgentManager1")] diff --git a/src/device.vala b/src/device.vala index 51bec03..e984a35 100644 --- a/src/device.vala +++ b/src/device.vala @@ -46,10 +46,11 @@ public class Device: Object public Icon icon { get; construct; } public bool is_connectable { get; construct; } public bool is_connected { get; construct; } + public bool is_trusted { get; construct; } public bool supports_browsing { get; construct; } public bool supports_file_transfer { get; construct; } public string print() { - return @"{id:$id, name:$name, address:$address, icon:$(icon.to_string()), device_type:$device_type, is_connectable:$is_connectable, is_connected:$is_connected, supports_browsing:$supports_browsing, supports_file_transfer:$supports_file_transfer}"; + return @"{id:$id, name:$name, address:$address, icon:$(icon.to_string()), device_type:$device_type, is_connectable:$is_connectable, is_connected:$is_connected, is_trusted:$is_trusted, supports_browsing:$supports_browsing, supports_file_transfer:$supports_file_transfer}"; } public Device (uint id, @@ -59,6 +60,7 @@ public class Device: Object Icon icon, bool is_connectable, bool is_connected, + bool is_trusted, bool supports_browsing, bool supports_file_transfer) { @@ -69,6 +71,7 @@ public class Device: Object icon: icon, is_connectable: is_connectable, is_connected: is_connected, + is_trusted: is_trusted, supports_browsing: supports_browsing, supports_file_transfer: supports_file_transfer); } -- cgit v1.2.3