Files
fastfetch/src/detection/bluetoothradio/bluetoothradio_linux.c
T
2026-05-28 15:58:08 +08:00

154 lines
4.7 KiB
C

#include "bluetoothradio.h"
#include "common/strutil.h"
#ifdef FF_HAVE_DBUS
#include "common/dbus.h"
#include "common/io.h"
/* Example dbus reply:
array [
dict entry(
string "Address"
variant string "XX:XX:XX:XX:XX:XX"
)
dict entry(
string "Name"
variant string "xxxxxxxx"
)
dict entry(
string "Powered"
variant boolean true
)
dict entry(
string "PowerState"
variant string "on"
)
dict entry(
string "Manufacturer"
variant uint16 2
)
dict entry(
string "Version"
variant byte 12
)
]
*/
static const char* detectBluetoothProperty(FFBluetoothRadioResult* device, FFDBusData* dbus, DBusMessageIter* iter) {
if (dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) {
return "Expected dict entry";
}
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if (dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) {
return "Expected dict entry key to be a string";
}
const char* deviceProperty;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty);
dbus->lib->ffdbus_message_iter_next(&dictIter);
if (ffStrEquals(deviceProperty, "Address")) {
ffDBusGetString(dbus, &dictIter, &device->address);
} else if (ffStrEquals(deviceProperty, "Alias")) {
ffDBusGetString(dbus, &dictIter, &device->name);
} else if (ffStrEquals(deviceProperty, "Manufacturer")) {
uint64_t vendorId;
if (ffDBusGetUint(dbus, &dictIter, &vendorId)) {
ffStrbufSetStatic(&device->vendor, ffBluetoothRadioGetVendor((uint32_t) vendorId));
}
} else if (ffStrEquals(deviceProperty, "Version")) {
uint64_t version;
if (ffDBusGetUint(dbus, &dictIter, &version)) {
device->lmpVersion = (int32_t) version;
}
} else if (ffStrEquals(deviceProperty, "Powered")) {
ffDBusGetBool(dbus, &dictIter, &device->enabled);
} else if (ffStrEquals(deviceProperty, "Discoverable")) {
ffDBusGetBool(dbus, &dictIter, &device->discoverable);
} else if (ffStrEquals(deviceProperty, "Pairable")) {
ffDBusGetBool(dbus, &dictIter, &device->connectable);
}
return NULL;
}
static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const char* hciName, FFDBusData* dbus) {
char objPath[300];
snprintf(objPath, sizeof(objPath), "/org/bluez/%s", hciName);
DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1", NULL);
if (!properties) {
return "Failed to call org.freedesktop.DBus.Properties.GetAll";
}
DBusMessageIter rootIter;
if (!dbus->lib->ffdbus_message_iter_init(properties, &rootIter)) {
dbus->lib->ffdbus_message_unref(properties);
return "Failed to get root iterator of org.freedesktop.DBus.Properties.GetAll";
}
if (dbus->lib->ffdbus_message_iter_get_arg_type(&rootIter) != DBUS_TYPE_ARRAY) {
dbus->lib->ffdbus_message_unref(properties);
return "Expected array";
}
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(&rootIter, &arrayIter);
do {
detectBluetoothProperty(device, dbus, &arrayIter);
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
dbus->lib->ffdbus_message_unref(properties);
return NULL;
}
static const char* detectBluetooth(FFlist* devices) {
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/bluetooth");
if (dirp == NULL) {
return "Failed to open /sys/class/bluetooth";
}
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
if (error) {
return error;
}
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_name[0] == '.') {
continue;
}
if (strchr(entry->d_name, ':') != NULL) { // ignore connected devices
continue;
}
FFBluetoothRadioResult* device = FF_LIST_ADD(FFBluetoothRadioResult, *devices);
ffStrbufInit(&device->name);
ffStrbufInit(&device->address);
ffStrbufInitStatic(&device->vendor, "Unknown");
device->lmpVersion = INT_MIN;
device->lmpSubversion = INT_MIN;
device->enabled = false;
detectBluetoothRoot(device, entry->d_name, &dbus);
}
return NULL;
}
#endif
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */) {
#ifdef FF_HAVE_DBUS
return detectBluetooth(devices);
#else
FF_UNUSED(devices)
return "Fastfetch was compiled without DBus support";
#endif
}