diff options
| author | Muhammad Asif <thevancedgamer@mentallysanemainliners.org> | 2025-05-19 22:22:08 +0200 |
|---|---|---|
| committer | Muhammad <thevancedgamer@mentallysanemainliners.org> | 2025-06-23 23:56:57 +0500 |
| commit | 5b45748c5dc9c2d1718b6219e30a64e07e5ca313 (patch) | |
| tree | e97a51abc7a8e6226975740470a24c05abcb13ce /src | |
| parent | cd978f758a34f636a375383b1456f4a636a97be5 (diff) | |
| download | ayatana-indicator-bluetooth-5b45748c5dc9c2d1718b6219e30a64e07e5ca313.tar.gz ayatana-indicator-bluetooth-5b45748c5dc9c2d1718b6219e30a64e07e5ca313.tar.bz2 ayatana-indicator-bluetooth-5b45748c5dc9c2d1718b6219e30a64e07e5ca313.zip | |
ayatana-indicator-bluetooth: add initial pairing agent
Co-authored-by: Robert Tari <robert@tari.in>
Signed-off-by: Muhammad Asif <thevancedgamer@mentallysanemainliners.org>
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/agent.vala | 115 | ||||
| -rw-r--r-- | src/bluetooth.vala | 4 | ||||
| -rw-r--r-- | src/bluez.vala | 40 | ||||
| -rw-r--r-- | src/service.vala | 22 |
5 files changed, 190 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b0a1e2..d616baf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ vala_init(ayatana-indicator-bluetooth-service posix gio-2.0 gio-unix-2.0 + libnotify AyatanaCommon OPTIONS --ccode @@ -94,6 +95,14 @@ vala_add(ayatana-indicator-bluetooth-service phone desktop greeter + agent +) + +vala_add(ayatana-indicator-bluetooth-service + agent.vala + DEPENDS + bluetooth + device ) vala_finish(ayatana-indicator-bluetooth-service diff --git a/src/agent.vala b/src/agent.vala new file mode 100644 index 0000000..beb8f8b --- /dev/null +++ b/src/agent.vala @@ -0,0 +1,115 @@ +[DBus (name = "org.bluez.Agent1")] +public class Agent: Object +{ + private MainLoop loop; + private Bluetooth bluetooth; + + public Agent (Bluetooth bluez) + { + loop = new MainLoop (null, false); + bluetooth = bluez; + Notify.init ("ayatana-indicator-bluetooth"); + } + + private bool sendNotification (string device_name, string body) + { + bool accepted = false; + + Notify.Notification notification = new Notify.Notification (@"Pair with $device_name?", body, "bluetooth-active"); + bool bLomiri = AyatanaCommon.utils_is_lomiri (); + + if (bLomiri) + { + notification.set_hint ("x-lomiri-snap-decisions", true); + notification.set_hint ("x-lomiri-private-affirmative-tint", "true"); + } + + notification.add_action("yes_id", "Yes", (notif, action) => { + loop.quit (); + accepted = true; + }); + notification.add_action("no_id", "No", (notif, action) => { + loop.quit (); + accepted = false; + }); + + try + { + notification.show (); + } + catch (Error pError) + { + warning ("Panic: Failed showing notification: %s", pError.message); + } + + loop.run (); + + return accepted; + } + + public void AuthorizeService (GLib.ObjectPath object, string uuid) throws GLib.DBusError, GLib.IOError + { + } + + public void RequestConfirmation (GLib.ObjectPath object, uint32 passkey) throws RejectedError, GLib.DBusError, GLib.IOError + { + string body = "Are you sure you want to pair with passkey %06u?".printf (passkey); + bool confirmed = sendNotification (bluetooth.get_device_name (object), body); + + if (confirmed) { + return; + } else { + throw new RejectedError.ERROR ("Rejected by user"); + } + } + + public void RequestAuthorization (GLib.ObjectPath object) throws RejectedError, GLib.DBusError, GLib.IOError + { + bool authorized = sendNotification (bluetooth.get_device_name (object), "Are you sure you want to pair with this device?"); + + if (authorized) { + return; + } else { + throw new RejectedError.ERROR ("Rejected by user"); + } + } + + public string RequestPinCode (GLib.ObjectPath object) throws GLib.DBusError, GLib.IOError + { + return "123456"; + } + + public void DisplayPinCode (GLib.ObjectPath object, string pincode) throws GLib.DBusError, GLib.IOError + { + } + + public uint32 RequestPasskey (GLib.ObjectPath object) throws GLib.DBusError, GLib.IOError + { + return 123456; + } + + public void DisplayPasskey (GLib.ObjectPath object, uint32 passkey, uint16 entered) throws GLib.DBusError, GLib.IOError + { + } + + public void Cancel () throws GLib.DBusError, GLib.IOError + { + if (loop.is_running ()) { + loop.quit (); + } + } + + public void Release () throws GLib.DBusError, GLib.IOError + { + } +} + +[DBus (name = "org.bluez.Error.Cancelled")] +public errordomain CancelledError { + ERROR +} + +[DBus (name = "org.bluez.Error.Rejected")] +public errordomain RejectedError { + ERROR +} 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); } diff --git a/src/bluez.vala b/src/bluez.vala index 16e237a..fabee5f 100644 --- a/src/bluez.vala +++ b/src/bluez.vala @@ -55,6 +55,8 @@ public class Bluez: Bluetooth, Object /* maps our arbitrary unique id to a Bluetooth.Device struct for public consumption */ private HashTable<uint,Device> id_to_device; + private BluezAgentManager agent_manager; + public Bluez (KillSwitch? killswitch) { init_bluez_state_vars (); @@ -119,6 +121,8 @@ public class Bluez: Bluetooth, Object try { manager = bus.get_proxy_sync (BLUEZ_BUSNAME, "/"); + agent_manager = bus.get_proxy_sync (BLUEZ_BUSNAME, "/org/bluez"); + add_agent ("/agent"); // Find the adapters and watch for changes manager.interfaces_added.connect ((object_path, interfaces_and_properties) => { @@ -425,6 +429,12 @@ public class Bluez: Bluetooth, Object } } + public string get_device_name (ObjectPath path) + { + var device = id_to_device.lookup(path_to_id.lookup(path)); + return device.name; + } + public List<unowned Device> get_devices () { return id_to_device.get_values(); @@ -453,6 +463,27 @@ public class Bluez: Bluetooth, Object DBusCallFlags.NONE, -1); } } + + public void add_agent(string path) + { + try + { + agent_manager.register_agent (new GLib.ObjectPath(path), "DisplayYesNo"); + } + catch (GLib.Error pError) + { + warning ("Panic: Failed registering pairing agent: %s", pError.message); + } + + try + { + agent_manager.request_default_agent (new GLib.ObjectPath(path)); + } + catch (GLib.Error pError) + { + warning ("Panic: Failed getting default pairing agent: %s", pError.message); + } + } } [DBus (name = "org.freedesktop.DBus.ObjectManager")] @@ -479,3 +510,12 @@ private interface BluezDevice : DBusProxy { [DBus (name = "Disconnect")] public abstract void disconnect_() throws DBusError, IOError; } + +[DBus (name = "org.bluez.AgentManager1")] +private interface BluezAgentManager : DBusProxy { + [DBus (name = "RegisterAgent")] + public abstract void register_agent(GLib.ObjectPath object, string capabilities) throws DBusError, IOError; + + [DBus (name = "RequestDefaultAgent")] + public abstract void request_default_agent(GLib.ObjectPath object) throws DBusError, IOError; +} diff --git a/src/service.vala b/src/service.vala index 80ccea6..b79056e 100644 --- a/src/service.vala +++ b/src/service.vala @@ -29,6 +29,7 @@ public class Service: Object private MainLoop loop; private SimpleActionGroup actions; private HashTable<string,Profile> profiles; + private Bluetooth bluez; private DBusConnection connection; private uint exported_action_id; private const string OBJECT_PATH = "/org/ayatana/indicator/bluetooth"; @@ -52,6 +53,7 @@ public class Service: Object public Service (Bluetooth bluetooth) { actions = new SimpleActionGroup (); + bluez = bluetooth; profiles = new HashTable<string,Profile> (str_hash, str_equal); profiles.insert ("phone", new Phone (bluetooth, actions)); @@ -74,15 +76,35 @@ public class Service: Object null, on_name_lost); + var system_name_id = Bus.own_name (BusType.SYSTEM, + "org.ayatana.indicator.bluetooth", + BusNameOwnerFlags.NONE, + on_system_bus_acquired, + null, + null); + loop = new MainLoop (null, false); loop.run (); // cleanup unexport (); Bus.unown_name (own_name_id); + Bus.unown_name (system_name_id); return Posix.EXIT_SUCCESS; } + void on_system_bus_acquired (DBusConnection connection, string name) + { + try + { + connection.register_object ("/agent", new Agent (bluez)); + } + catch (GLib.IOError pError) + { + warning ("Panic: Failed registering pairing agent: %s", pError.message); + } + } + void on_bus_acquired (DBusConnection connection, string name) { debug (@"bus acquired: $name"); |
