master ohmu/fastfetch-openbsd / src / common / impl / dbus.c
ohmu  ·  2026-10-15
  1#include "common/dbus.h"
  2
  3#ifdef FF_HAVE_DBUS
  4
  5    #include "common/debug.h"
  6    #include "common/thread.h"
  7    #include "common/strutil.h"
  8
  9static bool loadLibSymbols(FFDBusLibrary* lib) {
 10    FF_LIBRARY_LOAD(dbus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4);
 11    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_bus_get, false)
 12    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_new_method_call, false)
 13    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_append_args, false)
 14    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_init, false)
 15    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_arg_type, false)
 16    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_basic, false)
 17    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_recurse, false)
 18    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_has_next, false)
 19    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false)
 20    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false)
 21    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false)
 22    FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_unref, false)
 23    dbus = nullptr; // don't auto dlclose
 24    return true;
 25}
 26
 27static const FFDBusLibrary* loadLib(void) {
 28    static FFDBusLibrary lib;
 29    static bool loaded = false;
 30    static bool loadSuccess = false;
 31
 32    if (!loaded) {
 33        loaded = true;
 34        loadSuccess = loadLibSymbols(&lib);
 35    }
 36
 37    return loadSuccess ? &lib : nullptr;
 38}
 39
 40const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data) {
 41    data->lib = loadLib();
 42    if (data->lib == nullptr) {
 43        FF_DEBUG("libdbus-1 could not be loaded");
 44        return "Failed to load DBus library";
 45    }
 46
 47    data->connection = data->lib->ffdbus_bus_get(busType, nullptr);
 48    if (data->connection == nullptr) {
 49        FF_DEBUG("dbus_bus_get(busType=%d) returned no connection", (int) busType);
 50        return "Failed to connect to DBus";
 51    }
 52
 53    return nullptr;
 54}
 55
 56void ffDBusDestroyData(FFDBusData* data) {
 57    if (data->connection != nullptr) {
 58        data->lib->ffdbus_connection_unref(data->connection);
 59        data->connection = nullptr;
 60    }
 61}
 62
 63bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result) {
 64    int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
 65
 66    if (argType == DBUS_TYPE_STRING || argType == DBUS_TYPE_OBJECT_PATH) {
 67        const char* value = nullptr;
 68        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
 69
 70        if (!ffStrSet(value)) {
 71            return false;
 72        }
 73
 74        ffStrbufAppendS(result, value);
 75        return true;
 76    }
 77
 78    if (argType == DBUS_TYPE_BYTE) {
 79        uint8_t value;
 80        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
 81        ffStrbufAppendC(result, (char) value);
 82        return true;
 83    }
 84
 85    if (argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) {
 86        return false;
 87    }
 88
 89    DBusMessageIter subIter;
 90    dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
 91
 92    if (argType == DBUS_TYPE_VARIANT) {
 93        return ffDBusGetString(dbus, &subIter, result);
 94    }
 95
 96    // At this point we have an array
 97
 98    int subArgType = dbus->lib->ffdbus_message_iter_get_arg_type(&subIter);
 99    if (subArgType == DBUS_TYPE_INVALID) {
100        return false;
101    }
102
103    if (subArgType == DBUS_TYPE_BYTE) {
104        while (true) {
105            uint8_t value;
106            dbus->lib->ffdbus_message_iter_get_basic(&subIter, &value);
107            ffStrbufAppendC(result, (char) value);
108
109            if (!dbus->lib->ffdbus_message_iter_next(&subIter)) {
110                break;
111            }
112        }
113
114        return true;
115    }
116
117    bool foundAValue = false;
118
119    while (true) {
120        if (ffDBusGetString(dbus, &subIter, result)) {
121            foundAValue = true;
122            ffStrbufAppendS(result, ", ");
123        }
124
125        if (!dbus->lib->ffdbus_message_iter_next(&subIter)) {
126            break;
127        } else {
128            continue;
129        }
130    }
131
132    if (foundAValue) {
133        ffStrbufSubstrBefore(result, result->length - 2);
134    }
135
136    return foundAValue;
137}
138
139bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result) {
140    int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
141
142    if (argType == DBUS_TYPE_BOOLEAN) {
143        dbus_bool_t value = 0;
144        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
145        *result = value != 0;
146        return true;
147    }
148
149    if (argType != DBUS_TYPE_VARIANT) {
150        return false;
151    }
152
153    DBusMessageIter subIter;
154    dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
155    return ffDBusGetBool(dbus, &subIter, result);
156}
157
158bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint64_t* result) {
159    int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
160
161    if (argType == DBUS_TYPE_BYTE) {
162        uint8_t value = 0;
163        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
164        *result = value;
165        return true;
166    }
167
168    if (argType == DBUS_TYPE_UINT16) {
169        uint16_t value = 0;
170        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
171        *result = value;
172        return true;
173    }
174
175    if (argType == DBUS_TYPE_UINT32) {
176        uint32_t value = 0;
177        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
178        *result = value;
179        return true;
180    }
181
182    if (argType == DBUS_TYPE_UINT64) {
183        dbus->lib->ffdbus_message_iter_get_basic(iter, result);
184        return true;
185    }
186
187    if (argType != DBUS_TYPE_VARIANT) {
188        return false;
189    }
190
191    DBusMessageIter subIter;
192    dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
193    return ffDBusGetUint(dbus, &subIter, result);
194}
195
196bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_t* result) {
197    int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
198
199    if (argType == DBUS_TYPE_INT16) {
200        int16_t value = 0;
201        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
202        *result = value;
203        return true;
204    }
205
206    if (argType == DBUS_TYPE_INT32) {
207        int32_t value = 0;
208        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
209        *result = value;
210        return true;
211    }
212
213    if (argType == DBUS_TYPE_INT64) {
214        dbus->lib->ffdbus_message_iter_get_basic(iter, result);
215        return true;
216    }
217
218    if (argType == DBUS_TYPE_BYTE) {
219        uint8_t value = 0;
220        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
221        *result = value;
222        return true;
223    }
224
225    if (argType == DBUS_TYPE_UINT16) {
226        uint16_t value = 0;
227        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
228        *result = (int32_t) value;
229        return true;
230    }
231
232    if (argType == DBUS_TYPE_UINT32) {
233        uint32_t value = 0;
234        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
235        *result = (int32_t) value;
236        return true;
237    }
238
239    if (argType == DBUS_TYPE_UINT64) {
240        uint64_t value = 0;
241        dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
242        if (value > INT64_MAX) {
243            return false;
244        }
245        *result = (int64_t) value;
246        return true;
247    }
248
249    if (argType != DBUS_TYPE_VARIANT) {
250        return false;
251    }
252
253    DBusMessageIter subIter;
254    dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
255    return ffDBusGetInt(dbus, &subIter, result);
256}
257
258DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2) {
259    DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
260    if (message == nullptr) {
261        return nullptr;
262    }
263
264    if (arg1) {
265        if (arg2) {
266            dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID);
267        } else {
268            dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID);
269        }
270    }
271
272    DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, nullptr);
273
274    dbus->lib->ffdbus_message_unref(message);
275
276    return reply;
277}
278
279DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property) {
280    DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
281    if (message == nullptr) {
282        return nullptr;
283    }
284
285    dbus->lib->ffdbus_message_append_args(message,
286        DBUS_TYPE_STRING,
287        &interface,
288        DBUS_TYPE_STRING,
289        &property,
290        DBUS_TYPE_INVALID);
291
292    DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, nullptr);
293
294    dbus->lib->ffdbus_message_unref(message);
295
296    return reply;
297}
298
299bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result) {
300    DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
301    if (reply == nullptr) {
302        return false;
303    }
304
305    DBusMessageIter rootIterator;
306    if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) {
307        dbus->lib->ffdbus_message_unref(reply);
308        return false;
309    }
310
311    bool ret = ffDBusGetString(dbus, &rootIterator, result);
312
313    dbus->lib->ffdbus_message_unref(reply);
314
315    return ret;
316}
317
318bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint64_t* result) {
319    DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
320    if (reply == nullptr) {
321        return false;
322    }
323
324    DBusMessageIter rootIterator;
325    if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) {
326        dbus->lib->ffdbus_message_unref(reply);
327        return false;
328    }
329
330    bool ret = ffDBusGetUint(dbus, &rootIterator, result);
331
332    dbus->lib->ffdbus_message_unref(reply);
333
334    return ret;
335}
336
337#endif // FF_HAVE_DBUS