aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMuhammad Asif <thevancedgamer@mentallysanemainliners.org>2025-05-19 22:22:08 +0200
committerMuhammad <thevancedgamer@mentallysanemainliners.org>2025-06-23 23:56:57 +0500
commit5b45748c5dc9c2d1718b6219e30a64e07e5ca313 (patch)
treee97a51abc7a8e6226975740470a24c05abcb13ce /src
parentcd978f758a34f636a375383b1456f4a636a97be5 (diff)
downloadayatana-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.txt9
-rw-r--r--src/agent.vala115
-rw-r--r--src/bluetooth.vala4
-rw-r--r--src/bluez.vala40
-rw-r--r--src/service.vala22
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");