Coverage Report

Created: 2025-07-01 07:09

/src/fwupd/libfwupd/fwupd-device.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2015 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#include "config.h"
8
9
#include <gio/gio.h>
10
#include <string.h>
11
12
#include "fwupd-codec.h"
13
#include "fwupd-common-private.h"
14
#include "fwupd-device-private.h"
15
#include "fwupd-enums-private.h"
16
#include "fwupd-error.h"
17
18
/**
19
 * FwupdDevice:
20
 *
21
 * A physical device on the host with optionally updatable firmware.
22
 *
23
 * See also: [class@FwupdRelease]
24
 */
25
26
static void
27
fwupd_device_finalize(GObject *object);
28
29
typedef struct {
30
  gchar *id;
31
  gchar *parent_id;
32
  gchar *composite_id;
33
  guint64 created;
34
  guint64 modified;
35
  guint64 flags;
36
  guint64 request_flags;
37
  guint64 problems;
38
  GPtrArray *guids;  /* (nullable) (element-type utf-8) */
39
  GPtrArray *vendor_ids;   /* (nullable) (element-type utf-8) */
40
  GPtrArray *protocols;  /* (nullable) (element-type utf-8) */
41
  GPtrArray *instance_ids; /* (nullable) (element-type utf-8) */
42
  GPtrArray *icons;  /* (nullable) (element-type utf-8) */
43
  GPtrArray *issues;   /* (nullable) (element-type utf-8) */
44
  gchar *name;
45
  gchar *serial;
46
  gchar *summary;
47
  gchar *branch;
48
  gchar *vendor;
49
  gchar *homepage;
50
  gchar *plugin;
51
  gchar *version;
52
  gchar *version_lowest;
53
  gchar *version_bootloader;
54
  FwupdVersionFormat version_format;
55
  guint64 version_raw;
56
  guint64 version_build_date;
57
  guint64 version_lowest_raw;
58
  guint64 version_bootloader_raw;
59
  GPtrArray *checksums; /* (nullable) (element-type utf-8) */
60
  GPtrArray *children;  /* (nullable) (element-type FuDevice) */
61
  guint32 flashes_left;
62
  guint32 battery_level;
63
  guint32 battery_threshold;
64
  guint32 install_duration;
65
  FwupdUpdateState update_state;
66
  gchar *update_error;
67
  FwupdStatus status;
68
  guint percentage;
69
  GPtrArray *releases; /* (nullable) (element-type FwupdRelease) */
70
  FwupdDevice *parent; /* noref */
71
} FwupdDevicePrivate;
72
73
enum {
74
  PROP_0,
75
  PROP_ID,
76
  PROP_VERSION,
77
  PROP_VERSION_FORMAT,
78
  PROP_FLAGS,
79
  PROP_REQUEST_FLAGS,
80
  PROP_STATUS,
81
  PROP_PERCENTAGE,
82
  PROP_PARENT,
83
  PROP_UPDATE_STATE,
84
  PROP_UPDATE_ERROR,
85
  PROP_BATTERY_LEVEL,
86
  PROP_BATTERY_THRESHOLD,
87
  PROP_PROBLEMS,
88
  PROP_LAST
89
};
90
91
static void
92
fwupd_device_codec_iface_init(FwupdCodecInterface *iface);
93
94
G_DEFINE_TYPE_EXTENDED(FwupdDevice,
95
           fwupd_device,
96
           G_TYPE_OBJECT,
97
           0,
98
           G_ADD_PRIVATE(FwupdDevice)
99
         G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fwupd_device_codec_iface_init));
100
101
0
#define GET_PRIVATE(o) (fwupd_device_get_instance_private(o))
102
103
0
#define FWUPD_BATTERY_THRESHOLD_DEFAULT 10 /* % */
104
105
static void
106
fwupd_device_ensure_checksums(FwupdDevice *self)
107
0
{
108
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
109
0
  if (priv->checksums == NULL)
110
0
    priv->checksums = g_ptr_array_new_with_free_func(g_free);
111
0
}
112
113
/**
114
 * fwupd_device_get_checksums:
115
 * @self: a #FwupdDevice
116
 *
117
 * Gets the device checksums.
118
 *
119
 * Returns: (element-type utf8) (transfer none): the checksums, which may be empty
120
 *
121
 * Since: 0.9.3
122
 **/
123
GPtrArray *
124
fwupd_device_get_checksums(FwupdDevice *self)
125
0
{
126
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
127
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
128
0
  fwupd_device_ensure_checksums(self);
129
0
  return priv->checksums;
130
0
}
131
132
/**
133
 * fwupd_device_has_checksum:
134
 * @self: a #FwupdDevice
135
 * @checksum: (not nullable): the device checksum
136
 *
137
 * Finds out if the device has this specific checksum.
138
 *
139
 * Returns: %TRUE if the checksum name is found
140
 *
141
 * Since: 1.8.7
142
 **/
143
gboolean
144
fwupd_device_has_checksum(FwupdDevice *self, const gchar *checksum)
145
0
{
146
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
147
148
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
149
0
  g_return_val_if_fail(checksum != NULL, FALSE);
150
151
0
  if (priv->checksums == NULL)
152
0
    return FALSE;
153
0
  for (guint i = 0; i < priv->checksums->len; i++) {
154
0
    const gchar *checksum_tmp = g_ptr_array_index(priv->checksums, i);
155
0
    if (g_strcmp0(checksum, checksum_tmp) == 0)
156
0
      return TRUE;
157
0
  }
158
0
  return FALSE;
159
0
}
160
161
/**
162
 * fwupd_device_add_checksum:
163
 * @self: a #FwupdDevice
164
 * @checksum: (not nullable): the device checksum
165
 *
166
 * Adds a device checksum.
167
 *
168
 * Since: 0.9.3
169
 **/
170
void
171
fwupd_device_add_checksum(FwupdDevice *self, const gchar *checksum)
172
0
{
173
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
174
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
175
0
  g_return_if_fail(checksum != NULL);
176
177
0
  if (fwupd_device_has_checksum(self, checksum))
178
0
    return;
179
0
  fwupd_device_ensure_checksums(self);
180
0
  g_ptr_array_add(priv->checksums, g_strdup(checksum));
181
0
}
182
183
static void
184
fwupd_device_ensure_issues(FwupdDevice *self)
185
0
{
186
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
187
0
  if (priv->issues == NULL)
188
0
    priv->issues = g_ptr_array_new_with_free_func(g_free);
189
0
}
190
191
/**
192
 * fwupd_device_get_issues:
193
 * @self: a #FwupdDevice
194
 *
195
 * Gets the list of issues currently affecting this device.
196
 *
197
 * Returns: (element-type utf8) (transfer none): the issues, which may be empty
198
 *
199
 * Since: 1.7.6
200
 **/
201
GPtrArray *
202
fwupd_device_get_issues(FwupdDevice *self)
203
0
{
204
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
205
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
206
0
  fwupd_device_ensure_issues(self);
207
0
  return priv->issues;
208
0
}
209
210
/**
211
 * fwupd_device_add_issue:
212
 * @self: a #FwupdDevice
213
 * @issue: (not nullable): the update issue, e.g. `CVE-2019-12345`
214
 *
215
 * Adds an current issue to this device.
216
 *
217
 * Since: 1.7.6
218
 **/
219
void
220
fwupd_device_add_issue(FwupdDevice *self, const gchar *issue)
221
0
{
222
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
223
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
224
0
  g_return_if_fail(issue != NULL);
225
226
0
  fwupd_device_ensure_issues(self);
227
0
  for (guint i = 0; i < priv->issues->len; i++) {
228
0
    const gchar *issue_tmp = g_ptr_array_index(priv->issues, i);
229
0
    if (g_strcmp0(issue_tmp, issue) == 0)
230
0
      return;
231
0
  }
232
0
  g_ptr_array_add(priv->issues, g_strdup(issue));
233
0
}
234
235
static void
236
fwupd_device_ensure_children(FwupdDevice *self)
237
0
{
238
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
239
0
  if (priv->children == NULL)
240
0
    priv->children = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
241
0
}
242
243
/**
244
 * fwupd_device_get_children:
245
 * @self: a #FwupdDevice
246
 *
247
 * Gets the device children. These can only be assigned using fwupd_device_set_parent().
248
 *
249
 * Returns: (element-type FwupdDevice) (transfer none): the children, which may be empty
250
 *
251
 * Since: 1.3.7
252
 **/
253
GPtrArray *
254
fwupd_device_get_children(FwupdDevice *self)
255
0
{
256
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
257
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
258
0
  fwupd_device_ensure_children(self);
259
0
  return priv->children;
260
0
}
261
262
/**
263
 * fwupd_device_get_summary:
264
 * @self: a #FwupdDevice
265
 *
266
 * Gets the device summary.
267
 *
268
 * Returns: the device summary, or %NULL if unset
269
 *
270
 * Since: 0.9.3
271
 **/
272
const gchar *
273
fwupd_device_get_summary(FwupdDevice *self)
274
0
{
275
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
276
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
277
0
  return priv->summary;
278
0
}
279
280
/**
281
 * fwupd_device_set_summary:
282
 * @self: a #FwupdDevice
283
 * @summary: (nullable): the device one line summary
284
 *
285
 * Sets the device summary.
286
 *
287
 * Since: 0.9.3
288
 **/
289
void
290
fwupd_device_set_summary(FwupdDevice *self, const gchar *summary)
291
0
{
292
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
293
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
294
295
  /* not changed */
296
0
  if (g_strcmp0(priv->summary, summary) == 0)
297
0
    return;
298
299
0
  g_free(priv->summary);
300
0
  priv->summary = g_strdup(summary);
301
0
}
302
303
/**
304
 * fwupd_device_get_branch:
305
 * @self: a #FwupdDevice
306
 *
307
 * Gets the current device branch.
308
 *
309
 * Returns: the device branch, or %NULL if unset
310
 *
311
 * Since: 1.5.0
312
 **/
313
const gchar *
314
fwupd_device_get_branch(FwupdDevice *self)
315
0
{
316
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
317
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
318
0
  return priv->branch;
319
0
}
320
321
/**
322
 * fwupd_device_set_branch:
323
 * @self: a #FwupdDevice
324
 * @branch: (nullable): the device one line branch
325
 *
326
 * Sets the current device branch.
327
 *
328
 * Since: 1.5.0
329
 **/
330
void
331
fwupd_device_set_branch(FwupdDevice *self, const gchar *branch)
332
0
{
333
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
334
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
335
336
  /* not changed */
337
0
  if (g_strcmp0(priv->branch, branch) == 0)
338
0
    return;
339
340
0
  g_free(priv->branch);
341
0
  priv->branch = g_strdup(branch);
342
0
}
343
344
/**
345
 * fwupd_device_get_serial:
346
 * @self: a #FwupdDevice
347
 *
348
 * Gets the serial number for the device.
349
 *
350
 * Returns: a string value, or %NULL if never set.
351
 *
352
 * Since: 1.1.2
353
 **/
354
const gchar *
355
fwupd_device_get_serial(FwupdDevice *self)
356
0
{
357
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
358
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
359
0
  return priv->serial;
360
0
}
361
362
/**
363
 * fwupd_device_set_serial:
364
 * @self: a #FwupdDevice
365
 * @serial: (nullable): the device serial number
366
 *
367
 * Sets the serial number for the device.
368
 *
369
 * Since: 1.1.2
370
 **/
371
void
372
fwupd_device_set_serial(FwupdDevice *self, const gchar *serial)
373
0
{
374
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
375
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
376
377
  /* not changed */
378
0
  if (g_strcmp0(priv->serial, serial) == 0)
379
0
    return;
380
381
0
  g_free(priv->serial);
382
0
  priv->serial = g_strdup(serial);
383
0
}
384
385
/**
386
 * fwupd_device_get_id:
387
 * @self: a #FwupdDevice
388
 *
389
 * Gets the ID.
390
 *
391
 * Returns: the ID, or %NULL if unset
392
 *
393
 * Since: 0.9.3
394
 **/
395
const gchar *
396
fwupd_device_get_id(FwupdDevice *self)
397
0
{
398
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
399
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
400
0
  return priv->id;
401
0
}
402
403
/**
404
 * fwupd_device_set_id:
405
 * @self: a #FwupdDevice
406
 * @id: (nullable): the device ID, usually a SHA1 hash
407
 *
408
 * Sets the ID.
409
 *
410
 * Since: 0.9.3
411
 **/
412
void
413
fwupd_device_set_id(FwupdDevice *self, const gchar *id)
414
0
{
415
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
416
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
417
418
  /* not changed */
419
0
  if (g_strcmp0(priv->id, id) == 0)
420
0
    return;
421
422
  /* sanity check */
423
0
  if (!fwupd_device_id_is_valid(id)) {
424
0
    g_critical("%s is not a valid device ID", id);
425
0
    return;
426
0
  }
427
428
0
  g_free(priv->id);
429
0
  priv->id = g_strdup(id);
430
0
  g_object_notify(G_OBJECT(self), "id");
431
0
}
432
433
/**
434
 * fwupd_device_get_parent_id:
435
 * @self: a #FwupdDevice
436
 *
437
 * Gets the parent ID.
438
 *
439
 * Returns: the parent ID, or %NULL if unset
440
 *
441
 * Since: 1.0.8
442
 **/
443
const gchar *
444
fwupd_device_get_parent_id(FwupdDevice *self)
445
0
{
446
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
447
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
448
0
  return priv->parent_id;
449
0
}
450
451
/**
452
 * fwupd_device_set_parent_id:
453
 * @self: a #FwupdDevice
454
 * @parent_id: (nullable): the device ID, usually a SHA1 hash
455
 *
456
 * Sets the parent ID.
457
 *
458
 * Since: 1.0.8
459
 **/
460
void
461
fwupd_device_set_parent_id(FwupdDevice *self, const gchar *parent_id)
462
0
{
463
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
464
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
465
466
  /* not changed */
467
0
  if (g_strcmp0(priv->parent_id, parent_id) == 0)
468
0
    return;
469
470
  /* sanity check */
471
0
  if (parent_id != NULL && !fwupd_device_id_is_valid(parent_id)) {
472
0
    g_critical("%s is not a valid device ID", parent_id);
473
0
    return;
474
0
  }
475
476
0
  g_free(priv->parent_id);
477
0
  priv->parent_id = g_strdup(parent_id);
478
0
}
479
480
/**
481
 * fwupd_device_get_composite_id:
482
 * @self: a #FwupdDevice
483
 *
484
 * Gets the composite ID, falling back to the device ID if unset.
485
 *
486
 * The composite ID will be the same value for all parent, child and sibling
487
 * devices.
488
 *
489
 * Returns: (nullable): the composite ID
490
 *
491
 * Since: 1.6.0
492
 **/
493
const gchar *
494
fwupd_device_get_composite_id(FwupdDevice *self)
495
0
{
496
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
497
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
498
0
  if (priv->composite_id != NULL)
499
0
    return priv->composite_id;
500
0
  return priv->id;
501
0
}
502
503
/**
504
 * fwupd_device_set_composite_id:
505
 * @self: a #FwupdDevice
506
 * @composite_id: (nullable): a device ID
507
 *
508
 * Sets the composite ID, which is usually a SHA1 hash of a grandparent or
509
 * parent device.
510
 *
511
 * Since: 1.6.0
512
 **/
513
void
514
fwupd_device_set_composite_id(FwupdDevice *self, const gchar *composite_id)
515
0
{
516
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
517
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
518
519
  /* not changed */
520
0
  if (g_strcmp0(priv->composite_id, composite_id) == 0)
521
0
    return;
522
523
  /* sanity check */
524
0
  if (!fwupd_device_id_is_valid(composite_id)) {
525
0
    g_critical("%s is not a valid device ID", composite_id);
526
0
    return;
527
0
  }
528
529
0
  g_free(priv->composite_id);
530
0
  priv->composite_id = g_strdup(composite_id);
531
0
}
532
533
/**
534
 * fwupd_device_get_parent:
535
 * @self: a #FwupdDevice
536
 *
537
 * Gets the parent.
538
 *
539
 * Returns: (transfer none): the parent device, or %NULL if unset
540
 *
541
 * Since: 1.0.8
542
 **/
543
FwupdDevice *
544
fwupd_device_get_parent(FwupdDevice *self)
545
0
{
546
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
547
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
548
0
  return priv->parent;
549
0
}
550
551
/**
552
 * fwupd_device_get_root:
553
 * @self: a #FwupdDevice
554
 *
555
 * Gets the device root.
556
 *
557
 * Returns: (transfer none): the root device, or %NULL if unset
558
 *
559
 * Since: 1.7.4
560
 **/
561
FwupdDevice *
562
fwupd_device_get_root(FwupdDevice *self)
563
0
{
564
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
565
0
  while (1) {
566
0
    FwupdDevicePrivate *priv = GET_PRIVATE(self);
567
0
    if (priv->parent == NULL)
568
0
      break;
569
0
    self = priv->parent;
570
0
  }
571
0
  return self;
572
0
}
573
574
/**
575
 * fwupd_device_set_parent:
576
 * @self: a #FwupdDevice
577
 * @parent: (nullable): another #FwupdDevice
578
 *
579
 * Sets the parent. Only used internally.
580
 *
581
 * Since: 1.0.8
582
 **/
583
void
584
fwupd_device_set_parent(FwupdDevice *self, FwupdDevice *parent)
585
0
{
586
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
587
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
588
0
  g_return_if_fail(self != parent);
589
590
0
  if (priv->parent != NULL)
591
0
    g_object_remove_weak_pointer(G_OBJECT(priv->parent), (gpointer *)&priv->parent);
592
0
  if (parent != NULL)
593
0
    g_object_add_weak_pointer(G_OBJECT(parent), (gpointer *)&priv->parent);
594
0
  priv->parent = parent;
595
596
  /* this is what goes over D-Bus */
597
0
  fwupd_device_set_parent_id(self, parent != NULL ? fwupd_device_get_id(parent) : NULL);
598
0
}
599
600
static void
601
fwupd_device_child_finalized_cb(gpointer data, GObject *where_the_object_was)
602
0
{
603
0
  FwupdDevice *self = FWUPD_DEVICE(data);
604
0
  g_critical("FuDevice child %p was finalized while still having parent %s [%s]!",
605
0
       where_the_object_was,
606
0
       fwupd_device_get_name(self),
607
0
       fwupd_device_get_id(self));
608
0
}
609
610
/**
611
 * fwupd_device_add_child:
612
 * @self: a #FwupdDevice
613
 * @child: (not nullable): Another #FwupdDevice
614
 *
615
 * Adds a child device. An child device is logically linked to the primary
616
 * device in some way.
617
 *
618
 * NOTE: You should never call this function from user code, it is for daemon
619
 * use only. Only use fwupd_device_set_parent() to set up a logical tree.
620
 *
621
 * Since: 1.5.1
622
 **/
623
void
624
fwupd_device_add_child(FwupdDevice *self, FwupdDevice *child)
625
0
{
626
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
627
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
628
0
  g_return_if_fail(FWUPD_IS_DEVICE(child));
629
0
  g_return_if_fail(self != child);
630
631
  /* add if the child does not already exist */
632
0
  fwupd_device_ensure_children(self);
633
0
  for (guint i = 0; i < priv->children->len; i++) {
634
0
    FwupdDevice *devtmp = g_ptr_array_index(priv->children, i);
635
0
    if (devtmp == child)
636
0
      return;
637
0
  }
638
0
  g_object_weak_ref(G_OBJECT(child), fwupd_device_child_finalized_cb, self);
639
0
  g_ptr_array_add(priv->children, g_object_ref(child));
640
0
}
641
642
/**
643
 * fwupd_device_remove_child:
644
 * @self: a #FwupdDevice
645
 * @child: Another #FwupdDevice
646
 *
647
 * Removes a child device.
648
 *
649
 * NOTE: You should never call this function from user code, it is for daemon
650
 * use only.
651
 *
652
 * Since: 1.6.2
653
 **/
654
void
655
fwupd_device_remove_child(FwupdDevice *self, FwupdDevice *child)
656
0
{
657
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
658
659
  /* remove if the child exists */
660
0
  if (priv->children == NULL)
661
0
    return;
662
0
  for (guint i = 0; i < priv->children->len; i++) {
663
0
    FwupdDevice *child_tmp = g_ptr_array_index(priv->children, i);
664
0
    if (child_tmp == child) {
665
0
      g_object_weak_unref(G_OBJECT(child), fwupd_device_child_finalized_cb, self);
666
0
      g_ptr_array_remove_index(priv->children, i);
667
0
      return;
668
0
    }
669
0
  }
670
0
}
671
672
/**
673
 * fwupd_device_remove_children:
674
 * @self: a #FwupdDevice
675
 *
676
 * Removes all child devices.
677
 *
678
 * NOTE: You should never call this function from user code, it is for daemon
679
 * use only.
680
 *
681
 * Since: 2.0.0
682
 **/
683
void
684
fwupd_device_remove_children(FwupdDevice *self)
685
0
{
686
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
687
688
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
689
690
0
  if (priv->children == NULL)
691
0
    return;
692
0
  for (guint i = 0; i < priv->children->len; i++) {
693
0
    FwupdDevice *child = g_ptr_array_index(priv->children, i);
694
0
    g_object_weak_unref(G_OBJECT(child), fwupd_device_child_finalized_cb, self);
695
0
  }
696
0
  g_ptr_array_set_size(priv->children, 0);
697
0
}
698
699
static void
700
fwupd_device_ensure_guids(FwupdDevice *self)
701
0
{
702
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
703
0
  if (priv->guids == NULL)
704
0
    priv->guids = g_ptr_array_new_with_free_func(g_free);
705
0
}
706
707
/**
708
 * fwupd_device_get_guids:
709
 * @self: a #FwupdDevice
710
 *
711
 * Gets the GUIDs.
712
 *
713
 * Returns: (element-type utf8) (transfer none): the GUIDs
714
 *
715
 * Since: 0.9.3
716
 **/
717
GPtrArray *
718
fwupd_device_get_guids(FwupdDevice *self)
719
0
{
720
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
721
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
722
0
  fwupd_device_ensure_guids(self);
723
0
  return priv->guids;
724
0
}
725
726
/**
727
 * fwupd_device_has_guid:
728
 * @self: a #FwupdDevice
729
 * @guid: (not nullable): the GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad`
730
 *
731
 * Finds out if the device has this specific GUID.
732
 *
733
 * Returns: %TRUE if the GUID is found
734
 *
735
 * Since: 0.9.3
736
 **/
737
gboolean
738
fwupd_device_has_guid(FwupdDevice *self, const gchar *guid)
739
0
{
740
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
741
742
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
743
0
  g_return_val_if_fail(guid != NULL, FALSE);
744
745
0
  if (priv->guids == NULL)
746
0
    return FALSE;
747
0
  for (guint i = 0; i < priv->guids->len; i++) {
748
0
    const gchar *guid_tmp = g_ptr_array_index(priv->guids, i);
749
0
    if (g_strcmp0(guid, guid_tmp) == 0)
750
0
      return TRUE;
751
0
  }
752
0
  return FALSE;
753
0
}
754
755
/**
756
 * fwupd_device_add_guid:
757
 * @self: a #FwupdDevice
758
 * @guid: the GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad`
759
 *
760
 * Adds the GUID if it does not already exist.
761
 *
762
 * Since: 0.9.3
763
 **/
764
void
765
fwupd_device_add_guid(FwupdDevice *self, const gchar *guid)
766
0
{
767
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
768
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
769
0
  g_return_if_fail(guid != NULL);
770
0
  if (fwupd_device_has_guid(self, guid))
771
0
    return;
772
0
  fwupd_device_ensure_guids(self);
773
0
  g_ptr_array_add(priv->guids, g_strdup(guid));
774
0
}
775
776
/**
777
 * fwupd_device_get_guid_default:
778
 * @self: a #FwupdDevice
779
 *
780
 * Gets the default GUID.
781
 *
782
 * Returns: the GUID, or %NULL if unset
783
 *
784
 * Since: 0.9.3
785
 **/
786
const gchar *
787
fwupd_device_get_guid_default(FwupdDevice *self)
788
0
{
789
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
790
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
791
0
  if (priv->guids == NULL || priv->guids->len == 0)
792
0
    return NULL;
793
0
  return g_ptr_array_index(priv->guids, 0);
794
0
}
795
796
static void
797
fwupd_device_ensure_instance_ids(FwupdDevice *self)
798
0
{
799
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
800
0
  if (priv->instance_ids == NULL)
801
0
    priv->instance_ids = g_ptr_array_new_with_free_func(g_free);
802
0
}
803
804
/**
805
 * fwupd_device_get_instance_ids:
806
 * @self: a #FwupdDevice
807
 *
808
 * Gets the instance IDs.
809
 *
810
 * Returns: (element-type utf8) (transfer none): the instance IDs
811
 *
812
 * Since: 1.2.5
813
 **/
814
GPtrArray *
815
fwupd_device_get_instance_ids(FwupdDevice *self)
816
0
{
817
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
818
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
819
0
  fwupd_device_ensure_instance_ids(self);
820
0
  return priv->instance_ids;
821
0
}
822
823
/**
824
 * fwupd_device_has_instance_id:
825
 * @self: a #FwupdDevice
826
 * @instance_id: (not nullable): the instance ID, e.g. `PCI\VEN_10EC&DEV_525A`
827
 *
828
 * Finds out if the device has this specific instance ID.
829
 *
830
 * Returns: %TRUE if the instance ID is found
831
 *
832
 * Since: 1.2.5
833
 **/
834
gboolean
835
fwupd_device_has_instance_id(FwupdDevice *self, const gchar *instance_id)
836
0
{
837
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
838
839
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
840
0
  g_return_val_if_fail(instance_id != NULL, FALSE);
841
842
0
  if (priv->instance_ids == NULL)
843
0
    return FALSE;
844
0
  for (guint i = 0; i < priv->instance_ids->len; i++) {
845
0
    const gchar *instance_id_tmp = g_ptr_array_index(priv->instance_ids, i);
846
0
    if (g_strcmp0(instance_id, instance_id_tmp) == 0)
847
0
      return TRUE;
848
0
  }
849
0
  return FALSE;
850
0
}
851
852
/**
853
 * fwupd_device_add_instance_id:
854
 * @self: a #FwupdDevice
855
 * @instance_id: (not nullable): the instance ID, e.g. `PCI\VEN_10EC&DEV_525A`
856
 *
857
 * Adds the instance ID if it does not already exist.
858
 *
859
 * Since: 1.2.5
860
 **/
861
void
862
fwupd_device_add_instance_id(FwupdDevice *self, const gchar *instance_id)
863
0
{
864
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
865
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
866
0
  g_return_if_fail(instance_id != NULL);
867
0
  if (fwupd_device_has_instance_id(self, instance_id))
868
0
    return;
869
0
  fwupd_device_ensure_instance_ids(self);
870
0
  g_ptr_array_add(priv->instance_ids, g_strdup(instance_id));
871
0
}
872
873
static void
874
fwupd_device_ensure_icons(FwupdDevice *self)
875
0
{
876
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
877
0
  if (priv->icons == NULL)
878
0
    priv->icons = g_ptr_array_new_with_free_func(g_free);
879
0
}
880
881
/**
882
 * fwupd_device_get_icons:
883
 * @self: a #FwupdDevice
884
 *
885
 * Gets the icon names to use for the device.
886
 *
887
 * NOTE: Icons specified without a full path are stock icons and should
888
 * be loaded from the users icon theme.
889
 *
890
 * Returns: (element-type utf8) (transfer none): an array of icon names
891
 *
892
 * Since: 0.9.8
893
 **/
894
GPtrArray *
895
fwupd_device_get_icons(FwupdDevice *self)
896
0
{
897
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
898
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
899
0
  fwupd_device_ensure_icons(self);
900
0
  return priv->icons;
901
0
}
902
903
/**
904
 * fwupd_device_has_icon:
905
 * @self: a #FwupdDevice
906
 * @icon: the icon name, e.g. `input-mouse` or `/usr/share/icons/foo.png`
907
 *
908
 * Finds out if the device has this specific icon.
909
 *
910
 * Returns: %TRUE if the icon name is found
911
 *
912
 * Since: 1.6.2
913
 **/
914
gboolean
915
fwupd_device_has_icon(FwupdDevice *self, const gchar *icon)
916
0
{
917
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
918
0
  if (priv->icons == NULL)
919
0
    return FALSE;
920
0
  for (guint i = 0; i < priv->icons->len; i++) {
921
0
    const gchar *icon_tmp = g_ptr_array_index(priv->icons, i);
922
0
    if (g_strcmp0(icon, icon_tmp) == 0)
923
0
      return TRUE;
924
0
  }
925
0
  return FALSE;
926
0
}
927
928
/**
929
 * fwupd_device_add_icon:
930
 * @self: a #FwupdDevice
931
 * @icon: (not nullable): the icon name, e.g. `input-mouse` or `/usr/share/icons/foo.png`
932
 *
933
 * Adds the icon name if it does not already exist.
934
 *
935
 * Since: 0.9.8
936
 **/
937
void
938
fwupd_device_add_icon(FwupdDevice *self, const gchar *icon)
939
0
{
940
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
941
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
942
0
  g_return_if_fail(icon != NULL);
943
0
  if (fwupd_device_has_icon(self, icon))
944
0
    return;
945
0
  fwupd_device_ensure_icons(self);
946
0
  g_ptr_array_add(priv->icons, g_strdup(icon));
947
0
}
948
949
/**
950
 * fwupd_device_get_name:
951
 * @self: a #FwupdDevice
952
 *
953
 * Gets the device name.
954
 *
955
 * Returns: the device name, or %NULL if unset
956
 *
957
 * Since: 0.9.3
958
 **/
959
const gchar *
960
fwupd_device_get_name(FwupdDevice *self)
961
0
{
962
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
963
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
964
0
  return priv->name;
965
0
}
966
967
/**
968
 * fwupd_device_set_name:
969
 * @self: a #FwupdDevice
970
 * @name: (nullable): the device name, e.g. `ColorHug2`
971
 *
972
 * Sets the device name.
973
 *
974
 * Since: 0.9.3
975
 **/
976
void
977
fwupd_device_set_name(FwupdDevice *self, const gchar *name)
978
0
{
979
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
980
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
981
982
  /* not changed */
983
0
  if (g_strcmp0(priv->name, name) == 0)
984
0
    return;
985
986
0
  g_free(priv->name);
987
0
  priv->name = g_strdup(name);
988
0
}
989
990
/**
991
 * fwupd_device_get_vendor:
992
 * @self: a #FwupdDevice
993
 *
994
 * Gets the device vendor.
995
 *
996
 * Returns: the device vendor, or %NULL if unset
997
 *
998
 * Since: 0.9.3
999
 **/
1000
const gchar *
1001
fwupd_device_get_vendor(FwupdDevice *self)
1002
0
{
1003
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1004
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
1005
0
  return priv->vendor;
1006
0
}
1007
1008
/**
1009
 * fwupd_device_set_vendor:
1010
 * @self: a #FwupdDevice
1011
 * @vendor: (nullable): the vendor
1012
 *
1013
 * Sets the device vendor.
1014
 *
1015
 * Since: 0.9.3
1016
 **/
1017
void
1018
fwupd_device_set_vendor(FwupdDevice *self, const gchar *vendor)
1019
0
{
1020
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1021
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1022
1023
  /* not changed */
1024
0
  if (g_strcmp0(priv->vendor, vendor) == 0)
1025
0
    return;
1026
1027
0
  g_free(priv->vendor);
1028
0
  priv->vendor = g_strdup(vendor);
1029
0
}
1030
1031
static void
1032
fwupd_device_ensure_vendor_ids(FwupdDevice *self)
1033
0
{
1034
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1035
0
  if (priv->vendor_ids == NULL)
1036
0
    priv->vendor_ids = g_ptr_array_new_with_free_func(g_free);
1037
0
}
1038
1039
/**
1040
 * fwupd_device_get_vendor_ids:
1041
 * @self: a #FwupdDevice
1042
 *
1043
 * Gets the device vendor ID.
1044
 *
1045
 * Returns: (element-type utf8) (transfer none): the device vendor ID
1046
 *
1047
 * Since: 1.5.5
1048
 **/
1049
GPtrArray *
1050
fwupd_device_get_vendor_ids(FwupdDevice *self)
1051
0
{
1052
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1053
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
1054
0
  fwupd_device_ensure_vendor_ids(self);
1055
0
  return priv->vendor_ids;
1056
0
}
1057
1058
/**
1059
 * fwupd_device_has_vendor_id:
1060
 * @self: a #FwupdDevice
1061
 * @vendor_id: (not nullable): the vendor ID, e.g. 'USB:0x1234'
1062
 *
1063
 * Finds out if the device has this specific vendor ID.
1064
 *
1065
 * Returns: %TRUE if the vendor ID is found
1066
 *
1067
 * Since: 1.5.5
1068
 **/
1069
gboolean
1070
fwupd_device_has_vendor_id(FwupdDevice *self, const gchar *vendor_id)
1071
0
{
1072
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1073
1074
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
1075
0
  g_return_val_if_fail(vendor_id != NULL, FALSE);
1076
1077
0
  if (priv->vendor_ids == NULL)
1078
0
    return FALSE;
1079
0
  for (guint i = 0; i < priv->vendor_ids->len; i++) {
1080
0
    const gchar *vendor_id_tmp = g_ptr_array_index(priv->vendor_ids, i);
1081
0
    if (g_strcmp0(vendor_id, vendor_id_tmp) == 0)
1082
0
      return TRUE;
1083
0
  }
1084
0
  return FALSE;
1085
0
}
1086
1087
/**
1088
 * fwupd_device_add_vendor_id:
1089
 * @self: a #FwupdDevice
1090
 * @vendor_id: (not nullable): the ID, e.g. 'USB:0x1234'
1091
 *
1092
 * Adds a device vendor ID.
1093
 *
1094
 * Since: 1.5.5
1095
 **/
1096
void
1097
fwupd_device_add_vendor_id(FwupdDevice *self, const gchar *vendor_id)
1098
0
{
1099
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1100
1101
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1102
0
  g_return_if_fail(vendor_id != NULL);
1103
1104
0
  if (fwupd_device_has_vendor_id(self, vendor_id))
1105
0
    return;
1106
0
  fwupd_device_ensure_vendor_ids(self);
1107
0
  g_ptr_array_add(priv->vendor_ids, g_strdup(vendor_id));
1108
0
}
1109
1110
/**
1111
 * fwupd_device_get_version:
1112
 * @self: a #FwupdDevice
1113
 *
1114
 * Gets the device version.
1115
 *
1116
 * Returns: the device version, or %NULL if unset
1117
 *
1118
 * Since: 0.9.3
1119
 **/
1120
const gchar *
1121
fwupd_device_get_version(FwupdDevice *self)
1122
0
{
1123
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1124
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
1125
0
  return priv->version;
1126
0
}
1127
1128
/**
1129
 * fwupd_device_set_version:
1130
 * @self: a #FwupdDevice
1131
 * @version: (nullable): the device version, e.g. `1.2.3`
1132
 *
1133
 * Sets the device version.
1134
 *
1135
 * Since: 0.9.3
1136
 **/
1137
void
1138
fwupd_device_set_version(FwupdDevice *self, const gchar *version)
1139
0
{
1140
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1141
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1142
1143
  /* not changed */
1144
0
  if (g_strcmp0(priv->version, version) == 0)
1145
0
    return;
1146
1147
0
  g_free(priv->version);
1148
0
  priv->version = g_strdup(version);
1149
0
  g_object_notify(G_OBJECT(self), "version");
1150
0
}
1151
1152
/**
1153
 * fwupd_device_get_version_lowest:
1154
 * @self: a #FwupdDevice
1155
 *
1156
 * Gets the lowest version of firmware the device will accept.
1157
 *
1158
 * Returns: the device version_lowest, or %NULL if unset
1159
 *
1160
 * Since: 0.9.3
1161
 **/
1162
const gchar *
1163
fwupd_device_get_version_lowest(FwupdDevice *self)
1164
0
{
1165
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1166
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
1167
0
  return priv->version_lowest;
1168
0
}
1169
1170
/**
1171
 * fwupd_device_set_version_lowest:
1172
 * @self: a #FwupdDevice
1173
 * @version_lowest: (nullable): the version
1174
 *
1175
 * Sets the lowest version of firmware the device will accept.
1176
 *
1177
 * Since: 0.9.3
1178
 **/
1179
void
1180
fwupd_device_set_version_lowest(FwupdDevice *self, const gchar *version_lowest)
1181
0
{
1182
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1183
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1184
1185
  /* not changed */
1186
0
  if (g_strcmp0(priv->version_lowest, version_lowest) == 0)
1187
0
    return;
1188
1189
0
  g_free(priv->version_lowest);
1190
0
  priv->version_lowest = g_strdup(version_lowest);
1191
0
}
1192
1193
/**
1194
 * fwupd_device_get_version_lowest_raw:
1195
 * @self: a #FwupdDevice
1196
 *
1197
 * Gets the lowest version of firmware the device will accept in raw format.
1198
 *
1199
 * Returns: integer version number, or %0 if unset
1200
 *
1201
 * Since: 1.4.0
1202
 **/
1203
guint64
1204
fwupd_device_get_version_lowest_raw(FwupdDevice *self)
1205
0
{
1206
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1207
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1208
0
  return priv->version_lowest_raw;
1209
0
}
1210
1211
/**
1212
 * fwupd_device_set_version_lowest_raw:
1213
 * @self: a #FwupdDevice
1214
 * @version_lowest_raw: the raw hardware version
1215
 *
1216
 * Sets the raw lowest version number from the hardware before converted to a string.
1217
 *
1218
 * Since: 1.4.0
1219
 **/
1220
void
1221
fwupd_device_set_version_lowest_raw(FwupdDevice *self, guint64 version_lowest_raw)
1222
0
{
1223
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1224
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1225
0
  priv->version_lowest_raw = version_lowest_raw;
1226
0
}
1227
1228
/**
1229
 * fwupd_device_get_version_bootloader:
1230
 * @self: a #FwupdDevice
1231
 *
1232
 * Gets the version of the bootloader.
1233
 *
1234
 * Returns: the device version_bootloader, or %NULL if unset
1235
 *
1236
 * Since: 0.9.3
1237
 **/
1238
const gchar *
1239
fwupd_device_get_version_bootloader(FwupdDevice *self)
1240
0
{
1241
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1242
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
1243
0
  return priv->version_bootloader;
1244
0
}
1245
1246
/**
1247
 * fwupd_device_set_version_bootloader:
1248
 * @self: a #FwupdDevice
1249
 * @version_bootloader: (nullable): the version
1250
 *
1251
 * Sets the bootloader version.
1252
 *
1253
 * Since: 0.9.3
1254
 **/
1255
void
1256
fwupd_device_set_version_bootloader(FwupdDevice *self, const gchar *version_bootloader)
1257
0
{
1258
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1259
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1260
1261
  /* not changed */
1262
0
  if (g_strcmp0(priv->version_bootloader, version_bootloader) == 0)
1263
0
    return;
1264
1265
0
  g_free(priv->version_bootloader);
1266
0
  priv->version_bootloader = g_strdup(version_bootloader);
1267
0
}
1268
1269
/**
1270
 * fwupd_device_get_version_bootloader_raw:
1271
 * @self: a #FwupdDevice
1272
 *
1273
 * Gets the bootloader version of firmware the device will accept in raw format.
1274
 *
1275
 * Returns: integer version number, or %0 if unset
1276
 *
1277
 * Since: 1.4.0
1278
 **/
1279
guint64
1280
fwupd_device_get_version_bootloader_raw(FwupdDevice *self)
1281
0
{
1282
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1283
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1284
0
  return priv->version_bootloader_raw;
1285
0
}
1286
1287
/**
1288
 * fwupd_device_set_version_bootloader_raw:
1289
 * @self: a #FwupdDevice
1290
 * @version_bootloader_raw: the raw hardware version
1291
 *
1292
 * Sets the raw bootloader version number from the hardware before converted to a string.
1293
 *
1294
 * Since: 1.4.0
1295
 **/
1296
void
1297
fwupd_device_set_version_bootloader_raw(FwupdDevice *self, guint64 version_bootloader_raw)
1298
0
{
1299
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1300
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1301
0
  priv->version_bootloader_raw = version_bootloader_raw;
1302
0
}
1303
1304
/**
1305
 * fwupd_device_get_flashes_left:
1306
 * @self: a #FwupdDevice
1307
 *
1308
 * Gets the number of flash cycles left on the device
1309
 *
1310
 * Returns: the flash cycles left, or %NULL if unset
1311
 *
1312
 * Since: 0.9.3
1313
 **/
1314
guint32
1315
fwupd_device_get_flashes_left(FwupdDevice *self)
1316
0
{
1317
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1318
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1319
0
  return priv->flashes_left;
1320
0
}
1321
1322
/**
1323
 * fwupd_device_set_flashes_left:
1324
 * @self: a #FwupdDevice
1325
 * @flashes_left: the description
1326
 *
1327
 * Sets the number of flash cycles left on the device
1328
 *
1329
 * Since: 0.9.3
1330
 **/
1331
void
1332
fwupd_device_set_flashes_left(FwupdDevice *self, guint32 flashes_left)
1333
0
{
1334
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1335
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1336
0
  priv->flashes_left = flashes_left;
1337
0
}
1338
1339
/**
1340
 * fwupd_device_get_battery_level:
1341
 * @self: a #FwupdDevice
1342
 *
1343
 * Returns the battery level.
1344
 *
1345
 * Returns: value in percent
1346
 *
1347
 * Since: 1.8.1
1348
 **/
1349
guint32
1350
fwupd_device_get_battery_level(FwupdDevice *self)
1351
0
{
1352
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1353
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), G_MAXUINT);
1354
0
  return priv->battery_level;
1355
0
}
1356
1357
/**
1358
 * fwupd_device_set_battery_level:
1359
 * @self: a #FwupdDevice
1360
 * @battery_level: the percentage value
1361
 *
1362
 * Sets the battery level, or %FWUPD_BATTERY_LEVEL_INVALID.
1363
 *
1364
 * Setting this allows fwupd to show a warning if the device change is too low
1365
 * to perform the update.
1366
 *
1367
 * Since: 1.8.1
1368
 **/
1369
void
1370
fwupd_device_set_battery_level(FwupdDevice *self, guint32 battery_level)
1371
0
{
1372
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1373
1374
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1375
0
  g_return_if_fail(battery_level <= FWUPD_BATTERY_LEVEL_INVALID);
1376
1377
0
  if (priv->battery_level == battery_level)
1378
0
    return;
1379
0
  priv->battery_level = battery_level;
1380
0
  g_object_notify(G_OBJECT(self), "battery-level");
1381
0
}
1382
1383
/**
1384
 * fwupd_device_get_battery_threshold:
1385
 * @self: a #FwupdDevice
1386
 *
1387
 * Returns the battery threshold under which a firmware update cannot be
1388
 * performed.
1389
 *
1390
 * If fwupd_device_set_battery_threshold() has not been used, a default value is
1391
 * used instead.
1392
 *
1393
 * Returns: value in percent
1394
 *
1395
 * Since: 1.8.1
1396
 **/
1397
guint32
1398
fwupd_device_get_battery_threshold(FwupdDevice *self)
1399
0
{
1400
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1401
1402
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FWUPD_BATTERY_LEVEL_INVALID);
1403
1404
  /* default value */
1405
0
  if (priv->battery_threshold == FWUPD_BATTERY_LEVEL_INVALID)
1406
0
    return FWUPD_BATTERY_THRESHOLD_DEFAULT;
1407
1408
0
  return priv->battery_threshold;
1409
0
}
1410
1411
/**
1412
 * fwupd_device_set_battery_threshold:
1413
 * @self: a #FwupdDevice
1414
 * @battery_threshold: the percentage value
1415
 *
1416
 * Sets the battery level, or %FWUPD_BATTERY_LEVEL_INVALID for the default.
1417
 *
1418
 * Setting this allows fwupd to show a warning if the device change is too low
1419
 * to perform the update.
1420
 *
1421
 * Since: 1.8.1
1422
 **/
1423
void
1424
fwupd_device_set_battery_threshold(FwupdDevice *self, guint32 battery_threshold)
1425
0
{
1426
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1427
1428
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1429
0
  g_return_if_fail(battery_threshold <= FWUPD_BATTERY_LEVEL_INVALID);
1430
1431
0
  if (priv->battery_threshold == battery_threshold)
1432
0
    return;
1433
0
  priv->battery_threshold = battery_threshold;
1434
0
  g_object_notify(G_OBJECT(self), "battery-threshold");
1435
0
}
1436
1437
/**
1438
 * fwupd_device_get_install_duration:
1439
 * @self: a #FwupdDevice
1440
 *
1441
 * Gets the time estimate for firmware installation (in seconds)
1442
 *
1443
 * Returns: the estimated time to flash this device (or 0 if unset)
1444
 *
1445
 * Since: 1.1.3
1446
 **/
1447
guint32
1448
fwupd_device_get_install_duration(FwupdDevice *self)
1449
0
{
1450
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1451
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1452
0
  return priv->install_duration;
1453
0
}
1454
1455
/**
1456
 * fwupd_device_set_install_duration:
1457
 * @self: a #FwupdDevice
1458
 * @duration: the amount of time
1459
 *
1460
 * Sets the time estimate for firmware installation (in seconds)
1461
 *
1462
 * Since: 1.1.3
1463
 **/
1464
void
1465
fwupd_device_set_install_duration(FwupdDevice *self, guint32 duration)
1466
0
{
1467
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1468
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1469
0
  priv->install_duration = duration;
1470
0
}
1471
1472
/**
1473
 * fwupd_device_get_plugin:
1474
 * @self: a #FwupdDevice
1475
 *
1476
 * Gets the plugin that created the device.
1477
 *
1478
 * Returns: the plugin name, or %NULL if unset
1479
 *
1480
 * Since: 1.0.0
1481
 **/
1482
const gchar *
1483
fwupd_device_get_plugin(FwupdDevice *self)
1484
0
{
1485
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1486
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
1487
0
  return priv->plugin;
1488
0
}
1489
1490
/**
1491
 * fwupd_device_set_plugin:
1492
 * @self: a #FwupdDevice
1493
 * @plugin: (nullable): the plugin name, e.g. `hughski_colorhug`
1494
 *
1495
 * Sets the plugin that created the device.
1496
 *
1497
 * Since: 1.0.0
1498
 **/
1499
void
1500
fwupd_device_set_plugin(FwupdDevice *self, const gchar *plugin)
1501
0
{
1502
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1503
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1504
1505
  /* not changed */
1506
0
  if (g_strcmp0(priv->plugin, plugin) == 0)
1507
0
    return;
1508
1509
0
  g_free(priv->plugin);
1510
0
  priv->plugin = g_strdup(plugin);
1511
0
}
1512
1513
static void
1514
fwupd_device_ensure_protocols(FwupdDevice *self)
1515
0
{
1516
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1517
0
  if (priv->protocols == NULL)
1518
0
    priv->protocols = g_ptr_array_new_with_free_func(g_free);
1519
0
}
1520
1521
/**
1522
 * fwupd_device_get_protocols:
1523
 * @self: a #FwupdDevice
1524
 *
1525
 * Gets the device protocol names.
1526
 *
1527
 * Returns: (element-type utf8) (transfer none): the device protocol names
1528
 *
1529
 * Since: 1.5.8
1530
 **/
1531
GPtrArray *
1532
fwupd_device_get_protocols(FwupdDevice *self)
1533
0
{
1534
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1535
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
1536
0
  fwupd_device_ensure_protocols(self);
1537
0
  return priv->protocols;
1538
0
}
1539
1540
/**
1541
 * fwupd_device_has_protocol:
1542
 * @self: a #FwupdDevice
1543
 * @protocol: (not nullable): the protocol name, e.g. `com.hughski.colorhug`
1544
 *
1545
 * Finds out if the device has this specific protocol name.
1546
 *
1547
 * Returns: %TRUE if the protocol name is found
1548
 *
1549
 * Since: 1.5.8
1550
 **/
1551
gboolean
1552
fwupd_device_has_protocol(FwupdDevice *self, const gchar *protocol)
1553
0
{
1554
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1555
1556
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
1557
0
  g_return_val_if_fail(protocol != NULL, FALSE);
1558
1559
0
  if (priv->protocols == NULL)
1560
0
    return FALSE;
1561
0
  for (guint i = 0; i < priv->protocols->len; i++) {
1562
0
    const gchar *protocol_tmp = g_ptr_array_index(priv->protocols, i);
1563
0
    if (g_strcmp0(protocol, protocol_tmp) == 0)
1564
0
      return TRUE;
1565
0
  }
1566
0
  return FALSE;
1567
0
}
1568
1569
/**
1570
 * fwupd_device_add_protocol:
1571
 * @self: a #FwupdDevice
1572
 * @protocol: (not nullable): the protocol name, e.g. `com.hughski.colorhug`
1573
 *
1574
 * Adds a device protocol name.
1575
 *
1576
 * Since: 1.5.8
1577
 **/
1578
void
1579
fwupd_device_add_protocol(FwupdDevice *self, const gchar *protocol)
1580
0
{
1581
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1582
1583
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1584
0
  g_return_if_fail(protocol != NULL);
1585
1586
0
  if (fwupd_device_has_protocol(self, protocol))
1587
0
    return;
1588
0
  fwupd_device_ensure_protocols(self);
1589
0
  g_ptr_array_add(priv->protocols, g_strdup(protocol));
1590
0
}
1591
1592
/**
1593
 * fwupd_device_get_flags:
1594
 * @self: a #FwupdDevice
1595
 *
1596
 * Gets device flags.
1597
 *
1598
 * Returns: device flags, or 0 if unset
1599
 *
1600
 * Since: 0.9.3
1601
 **/
1602
guint64
1603
fwupd_device_get_flags(FwupdDevice *self)
1604
0
{
1605
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1606
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1607
0
  return priv->flags;
1608
0
}
1609
1610
/**
1611
 * fwupd_device_set_flags:
1612
 * @self: a #FwupdDevice
1613
 * @flags: device flags, e.g. %FWUPD_DEVICE_FLAG_REQUIRE_AC
1614
 *
1615
 * Sets device flags.
1616
 *
1617
 * Since: 0.9.3
1618
 **/
1619
void
1620
fwupd_device_set_flags(FwupdDevice *self, guint64 flags)
1621
0
{
1622
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1623
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1624
0
  if (priv->flags == flags)
1625
0
    return;
1626
0
  priv->flags = flags;
1627
0
  g_object_notify(G_OBJECT(self), "flags");
1628
0
}
1629
1630
/**
1631
 * fwupd_device_add_flag:
1632
 * @self: a #FwupdDevice
1633
 * @flag: the #FwupdDeviceFlags
1634
 *
1635
 * Adds a specific device flag to the device.
1636
 *
1637
 * Since: 0.9.3
1638
 **/
1639
void
1640
fwupd_device_add_flag(FwupdDevice *self, FwupdDeviceFlags flag)
1641
0
{
1642
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1643
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1644
0
  if (flag == 0)
1645
0
    return;
1646
0
  if ((priv->flags | flag) == priv->flags)
1647
0
    return;
1648
0
  priv->flags |= flag;
1649
0
  g_object_notify(G_OBJECT(self), "flags");
1650
0
}
1651
1652
/**
1653
 * fwupd_device_remove_flag:
1654
 * @self: a #FwupdDevice
1655
 * @flag: the #FwupdDeviceFlags
1656
 *
1657
 * Removes a specific device flag from the device.
1658
 *
1659
 * Since: 0.9.3
1660
 **/
1661
void
1662
fwupd_device_remove_flag(FwupdDevice *self, FwupdDeviceFlags flag)
1663
0
{
1664
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1665
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1666
0
  if (flag == 0)
1667
0
    return;
1668
0
  if ((priv->flags & flag) == 0)
1669
0
    return;
1670
0
  priv->flags &= ~flag;
1671
0
  g_object_notify(G_OBJECT(self), "flags");
1672
0
}
1673
1674
/**
1675
 * fwupd_device_has_flag:
1676
 * @self: a #FwupdDevice
1677
 * @flag: the #FwupdDeviceFlags
1678
 *
1679
 * Finds if the device has a specific device flag.
1680
 *
1681
 * Returns: %TRUE if the flag is set
1682
 *
1683
 * Since: 0.9.3
1684
 **/
1685
gboolean
1686
fwupd_device_has_flag(FwupdDevice *self, FwupdDeviceFlags flag)
1687
0
{
1688
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1689
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
1690
0
  return (priv->flags & flag) > 0;
1691
0
}
1692
1693
/**
1694
 * fwupd_device_get_problems:
1695
 * @self: a #FwupdDevice
1696
 *
1697
 * Gets device problems.
1698
 *
1699
 * Returns: device problems, or 0 if unset
1700
 *
1701
 * Since: 1.8.1
1702
 **/
1703
guint64
1704
fwupd_device_get_problems(FwupdDevice *self)
1705
0
{
1706
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1707
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1708
0
  return priv->problems;
1709
0
}
1710
1711
/**
1712
 * fwupd_device_set_problems:
1713
 * @self: a #FwupdDevice
1714
 * @problems: device problems, e.g. %FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
1715
 *
1716
 * Sets device problems.
1717
 *
1718
 * Since: 1.8.1
1719
 **/
1720
void
1721
fwupd_device_set_problems(FwupdDevice *self, guint64 problems)
1722
0
{
1723
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1724
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1725
0
  if (priv->problems == problems)
1726
0
    return;
1727
0
  priv->problems = problems;
1728
0
  g_object_notify(G_OBJECT(self), "problems");
1729
0
}
1730
1731
/**
1732
 * fwupd_device_add_problem:
1733
 * @self: a #FwupdDevice
1734
 * @problem: the #FwupdDeviceProblem, e.g. #FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
1735
 *
1736
 * Adds a specific device problem kind to the device.
1737
 *
1738
 * Since: 1.8.1
1739
 **/
1740
void
1741
fwupd_device_add_problem(FwupdDevice *self, FwupdDeviceProblem problem)
1742
0
{
1743
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1744
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1745
0
  if (problem == FWUPD_DEVICE_PROBLEM_NONE)
1746
0
    return;
1747
0
  if (fwupd_device_has_problem(self, problem))
1748
0
    return;
1749
0
  priv->problems |= problem;
1750
0
  g_object_notify(G_OBJECT(self), "problems");
1751
0
}
1752
1753
/**
1754
 * fwupd_device_remove_problem:
1755
 * @self: a #FwupdDevice
1756
 * @problem: the #FwupdDeviceProblem, e.g. #FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW
1757
 *
1758
 * Removes a specific device problem kind from the device.
1759
 *
1760
 * Since: 1.8.1
1761
 **/
1762
void
1763
fwupd_device_remove_problem(FwupdDevice *self, FwupdDeviceProblem problem)
1764
0
{
1765
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1766
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1767
0
  if (problem == FWUPD_DEVICE_PROBLEM_NONE)
1768
0
    return;
1769
0
  if (!fwupd_device_has_problem(self, problem))
1770
0
    return;
1771
0
  priv->problems &= ~problem;
1772
0
  g_object_notify(G_OBJECT(self), "problems");
1773
0
}
1774
1775
/**
1776
 * fwupd_device_has_problem:
1777
 * @self: a #FwupdDevice
1778
 * @problem: the #FwupdDeviceProblem
1779
 *
1780
 * Finds if the device has a specific device problem kind.
1781
 *
1782
 * Returns: %TRUE if the problem is set
1783
 *
1784
 * Since: 1.8.1
1785
 **/
1786
gboolean
1787
fwupd_device_has_problem(FwupdDevice *self, FwupdDeviceProblem problem)
1788
0
{
1789
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1790
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
1791
0
  return (priv->problems & problem) > 0;
1792
0
}
1793
1794
/**
1795
 * fwupd_device_get_request_flags:
1796
 * @self: a #FwupdDevice
1797
 *
1798
 * Gets device request flags.
1799
 *
1800
 * Returns: device request flags, or 0 if unset
1801
 *
1802
 * Since: 1.9.10
1803
 **/
1804
guint64
1805
fwupd_device_get_request_flags(FwupdDevice *self)
1806
0
{
1807
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1808
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1809
0
  return priv->request_flags;
1810
0
}
1811
1812
/**
1813
 * fwupd_device_set_request_flags:
1814
 * @self: a #FwupdDevice
1815
 * @request_flags: device request flags, e.g. %FWUPD_DEVICE_REQUEST_FLAG_REQUIRE_AC
1816
 *
1817
 * Sets device request flags.
1818
 *
1819
 * Since: 1.9.10
1820
 **/
1821
void
1822
fwupd_device_set_request_flags(FwupdDevice *self, guint64 request_flags)
1823
0
{
1824
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1825
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1826
0
  if (priv->request_flags == request_flags)
1827
0
    return;
1828
0
  priv->request_flags = request_flags;
1829
0
  g_object_notify(G_OBJECT(self), "request-flags");
1830
0
}
1831
1832
/**
1833
 * fwupd_device_add_request_flag:
1834
 * @self: a #FwupdDevice
1835
 * @request_flag: the #FwupdRequestFlags
1836
 *
1837
 * Adds a specific device request flag to the device.
1838
 *
1839
 * Since: 1.9.10
1840
 **/
1841
void
1842
fwupd_device_add_request_flag(FwupdDevice *self, FwupdRequestFlags request_flag)
1843
0
{
1844
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1845
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1846
0
  if (request_flag == 0)
1847
0
    return;
1848
0
  if ((priv->request_flags | request_flag) == priv->request_flags)
1849
0
    return;
1850
0
  priv->request_flags |= request_flag;
1851
0
  g_object_notify(G_OBJECT(self), "request-flags");
1852
0
}
1853
1854
/**
1855
 * fwupd_device_remove_request_flag:
1856
 * @self: a #FwupdDevice
1857
 * @request_flag: the #FwupdRequestFlags
1858
 *
1859
 * Removes a specific device request flag from the device.
1860
 *
1861
 * Since: 1.9.10
1862
 **/
1863
void
1864
fwupd_device_remove_request_flag(FwupdDevice *self, FwupdRequestFlags request_flag)
1865
0
{
1866
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1867
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1868
0
  if (request_flag == 0)
1869
0
    return;
1870
0
  if ((priv->request_flags & request_flag) == 0)
1871
0
    return;
1872
0
  priv->request_flags &= ~request_flag;
1873
0
  g_object_notify(G_OBJECT(self), "request-flags");
1874
0
}
1875
1876
/**
1877
 * fwupd_device_has_request_flag:
1878
 * @self: a #FwupdDevice
1879
 * @request_flag: the #FwupdRequestFlags
1880
 *
1881
 * Finds if the device has a specific device request flag.
1882
 *
1883
 * Returns: %TRUE if the request_flag is set
1884
 *
1885
 * Since: 1.9.10
1886
 **/
1887
gboolean
1888
fwupd_device_has_request_flag(FwupdDevice *self, FwupdRequestFlags request_flag)
1889
0
{
1890
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1891
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
1892
0
  return (priv->request_flags & request_flag) > 0;
1893
0
}
1894
1895
/**
1896
 * fwupd_device_get_created:
1897
 * @self: a #FwupdDevice
1898
 *
1899
 * Gets when the device was created.
1900
 *
1901
 * Returns: the UNIX time, or 0 if unset
1902
 *
1903
 * Since: 0.9.3
1904
 **/
1905
guint64
1906
fwupd_device_get_created(FwupdDevice *self)
1907
0
{
1908
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1909
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1910
0
  return priv->created;
1911
0
}
1912
1913
/**
1914
 * fwupd_device_set_created:
1915
 * @self: a #FwupdDevice
1916
 * @created: the UNIX time
1917
 *
1918
 * Sets when the device was created.
1919
 *
1920
 * Since: 0.9.3
1921
 **/
1922
void
1923
fwupd_device_set_created(FwupdDevice *self, guint64 created)
1924
0
{
1925
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1926
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1927
0
  priv->created = created;
1928
0
}
1929
1930
/**
1931
 * fwupd_device_get_modified:
1932
 * @self: a #FwupdDevice
1933
 *
1934
 * Gets when the device was modified.
1935
 *
1936
 * Returns: the UNIX time, or 0 if unset
1937
 *
1938
 * Since: 0.9.3
1939
 **/
1940
guint64
1941
fwupd_device_get_modified(FwupdDevice *self)
1942
0
{
1943
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1944
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
1945
0
  return priv->modified;
1946
0
}
1947
1948
/**
1949
 * fwupd_device_set_modified:
1950
 * @self: a #FwupdDevice
1951
 * @modified: the UNIX time
1952
 *
1953
 * Sets when the device was modified.
1954
 *
1955
 * Since: 0.9.3
1956
 **/
1957
void
1958
fwupd_device_set_modified(FwupdDevice *self, guint64 modified)
1959
0
{
1960
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1961
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1962
0
  priv->modified = modified;
1963
0
}
1964
1965
/**
1966
 * fwupd_device_incorporate:
1967
 * @self: a #FwupdDevice
1968
 * @donor: Another #FwupdDevice
1969
 *
1970
 * Copy all properties from the donor object if they have not already been set.
1971
 *
1972
 * Since: 1.1.0
1973
 **/
1974
void
1975
fwupd_device_incorporate(FwupdDevice *self, FwupdDevice *donor)
1976
0
{
1977
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
1978
0
  FwupdDevicePrivate *priv_donor = GET_PRIVATE(donor);
1979
1980
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
1981
0
  g_return_if_fail(FWUPD_IS_DEVICE(donor));
1982
1983
0
  fwupd_device_add_flag(self, priv_donor->flags);
1984
0
  fwupd_device_add_request_flag(self, priv_donor->request_flags);
1985
0
  fwupd_device_add_problem(self, priv_donor->problems);
1986
0
  if (priv->created == 0)
1987
0
    fwupd_device_set_created(self, priv_donor->created);
1988
0
  if (priv->modified == 0)
1989
0
    fwupd_device_set_modified(self, priv_donor->modified);
1990
0
  if (priv->version_build_date == 0)
1991
0
    fwupd_device_set_version_build_date(self, priv_donor->version_build_date);
1992
0
  if (priv->flashes_left == 0)
1993
0
    fwupd_device_set_flashes_left(self, priv_donor->flashes_left);
1994
0
  if (priv->battery_level == FWUPD_BATTERY_LEVEL_INVALID)
1995
0
    fwupd_device_set_battery_level(self, priv_donor->battery_level);
1996
0
  if (priv->battery_threshold == FWUPD_BATTERY_LEVEL_INVALID)
1997
0
    fwupd_device_set_battery_threshold(self, priv_donor->battery_threshold);
1998
0
  if (priv->install_duration == 0)
1999
0
    fwupd_device_set_install_duration(self, priv_donor->install_duration);
2000
0
  if (priv->update_state == FWUPD_UPDATE_STATE_UNKNOWN)
2001
0
    fwupd_device_set_update_state(self, priv_donor->update_state);
2002
0
  if (priv->id == NULL)
2003
0
    fwupd_device_set_id(self, priv_donor->id);
2004
0
  if (priv->parent_id == NULL)
2005
0
    fwupd_device_set_parent_id(self, priv_donor->parent_id);
2006
0
  if (priv->composite_id == NULL)
2007
0
    fwupd_device_set_composite_id(self, priv_donor->composite_id);
2008
0
  if (priv->name == NULL)
2009
0
    fwupd_device_set_name(self, priv_donor->name);
2010
0
  if (priv->serial == NULL)
2011
0
    fwupd_device_set_serial(self, priv_donor->serial);
2012
0
  if (priv->summary == NULL)
2013
0
    fwupd_device_set_summary(self, priv_donor->summary);
2014
0
  if (priv->branch == NULL)
2015
0
    fwupd_device_set_branch(self, priv_donor->branch);
2016
0
  if (priv->vendor == NULL)
2017
0
    fwupd_device_set_vendor(self, priv_donor->vendor);
2018
0
  if (priv_donor->vendor_ids != NULL) {
2019
0
    for (guint i = 0; i < priv_donor->vendor_ids->len; i++) {
2020
0
      const gchar *tmp = g_ptr_array_index(priv_donor->vendor_ids, i);
2021
0
      fwupd_device_add_vendor_id(self, tmp);
2022
0
    }
2023
0
  }
2024
0
  if (priv->plugin == NULL)
2025
0
    fwupd_device_set_plugin(self, priv_donor->plugin);
2026
0
  if (priv_donor->protocols != NULL) {
2027
0
    for (guint i = 0; i < priv_donor->protocols->len; i++) {
2028
0
      const gchar *tmp = g_ptr_array_index(priv_donor->protocols, i);
2029
0
      fwupd_device_add_protocol(self, tmp);
2030
0
    }
2031
0
  }
2032
0
  if (priv->update_error == NULL)
2033
0
    fwupd_device_set_update_error(self, priv_donor->update_error);
2034
0
  if (priv->version == NULL)
2035
0
    fwupd_device_set_version(self, priv_donor->version);
2036
0
  if (priv->version_lowest == NULL)
2037
0
    fwupd_device_set_version_lowest(self, priv_donor->version_lowest);
2038
0
  if (priv->version_bootloader == NULL)
2039
0
    fwupd_device_set_version_bootloader(self, priv_donor->version_bootloader);
2040
0
  if (priv->version_format == FWUPD_VERSION_FORMAT_UNKNOWN)
2041
0
    fwupd_device_set_version_format(self, priv_donor->version_format);
2042
0
  if (priv->version_raw == 0)
2043
0
    fwupd_device_set_version_raw(self, priv_donor->version_raw);
2044
0
  if (priv->version_lowest_raw == 0)
2045
0
    fwupd_device_set_version_lowest_raw(self, priv_donor->version_lowest_raw);
2046
0
  if (priv->version_bootloader_raw == 0)
2047
0
    fwupd_device_set_version_bootloader_raw(self, priv_donor->version_bootloader_raw);
2048
0
  if (priv_donor->guids != NULL) {
2049
0
    for (guint i = 0; i < priv_donor->guids->len; i++) {
2050
0
      const gchar *tmp = g_ptr_array_index(priv_donor->guids, i);
2051
0
      fwupd_device_add_guid(self, tmp);
2052
0
    }
2053
0
  }
2054
0
  if (priv_donor->instance_ids != NULL) {
2055
0
    for (guint i = 0; i < priv_donor->instance_ids->len; i++) {
2056
0
      const gchar *tmp = g_ptr_array_index(priv_donor->instance_ids, i);
2057
0
      fwupd_device_add_instance_id(self, tmp);
2058
0
    }
2059
0
  }
2060
0
  if (priv_donor->icons != NULL) {
2061
0
    for (guint i = 0; i < priv_donor->icons->len; i++) {
2062
0
      const gchar *tmp = g_ptr_array_index(priv_donor->icons, i);
2063
0
      fwupd_device_add_icon(self, tmp);
2064
0
    }
2065
0
  }
2066
0
  if (priv_donor->checksums != NULL) {
2067
0
    for (guint i = 0; i < priv_donor->checksums->len; i++) {
2068
0
      const gchar *tmp = g_ptr_array_index(priv_donor->checksums, i);
2069
0
      fwupd_device_add_checksum(self, tmp);
2070
0
    }
2071
0
  }
2072
0
  if (priv_donor->releases != NULL) {
2073
0
    for (guint i = 0; i < priv_donor->releases->len; i++) {
2074
0
      FwupdRelease *tmp = g_ptr_array_index(priv_donor->releases, i);
2075
0
      fwupd_device_add_release(self, tmp);
2076
0
    }
2077
0
  }
2078
0
}
2079
2080
static void
2081
fwupd_device_add_variant(FwupdCodec *codec, GVariantBuilder *builder, FwupdCodecFlags flags)
2082
0
{
2083
0
  FwupdDevice *self = FWUPD_DEVICE(codec);
2084
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2085
2086
0
  if (priv->id != NULL) {
2087
0
    g_variant_builder_add(builder,
2088
0
              "{sv}",
2089
0
              FWUPD_RESULT_KEY_DEVICE_ID,
2090
0
              g_variant_new_string(priv->id));
2091
0
  }
2092
0
  if (priv->parent_id != NULL) {
2093
0
    g_variant_builder_add(builder,
2094
0
              "{sv}",
2095
0
              FWUPD_RESULT_KEY_PARENT_DEVICE_ID,
2096
0
              g_variant_new_string(priv->parent_id));
2097
0
  }
2098
0
  if (priv->composite_id != NULL) {
2099
0
    g_variant_builder_add(builder,
2100
0
              "{sv}",
2101
0
              FWUPD_RESULT_KEY_COMPOSITE_ID,
2102
0
              g_variant_new_string(priv->composite_id));
2103
0
  }
2104
0
  if (priv->guids != NULL && priv->guids->len > 0) {
2105
0
    const gchar *const *tmp = (const gchar *const *)priv->guids->pdata;
2106
0
    g_variant_builder_add(builder,
2107
0
              "{sv}",
2108
0
              FWUPD_RESULT_KEY_GUID,
2109
0
              g_variant_new_strv(tmp, priv->guids->len));
2110
0
  }
2111
0
  if (priv->icons != NULL && priv->icons->len > 0) {
2112
0
    const gchar *const *tmp = (const gchar *const *)priv->icons->pdata;
2113
0
    g_variant_builder_add(builder,
2114
0
              "{sv}",
2115
0
              FWUPD_RESULT_KEY_ICON,
2116
0
              g_variant_new_strv(tmp, priv->icons->len));
2117
0
  }
2118
0
  if (priv->name != NULL) {
2119
0
    g_variant_builder_add(builder,
2120
0
              "{sv}",
2121
0
              FWUPD_RESULT_KEY_NAME,
2122
0
              g_variant_new_string(priv->name));
2123
0
  }
2124
0
  if (priv->vendor != NULL) {
2125
0
    g_variant_builder_add(builder,
2126
0
              "{sv}",
2127
0
              FWUPD_RESULT_KEY_VENDOR,
2128
0
              g_variant_new_string(priv->vendor));
2129
0
  }
2130
0
  if (priv->vendor_ids != NULL && priv->vendor_ids->len > 0) {
2131
0
    g_autoptr(GString) str = g_string_new(NULL);
2132
0
    for (guint i = 0; i < priv->vendor_ids->len; i++) {
2133
0
      const gchar *tmp = g_ptr_array_index(priv->vendor_ids, i);
2134
0
      g_string_append_printf(str, "%s|", tmp);
2135
0
    }
2136
0
    if (str->len > 0)
2137
0
      g_string_truncate(str, str->len - 1);
2138
0
    g_variant_builder_add(builder,
2139
0
              "{sv}",
2140
0
              FWUPD_RESULT_KEY_VENDOR_ID,
2141
0
              g_variant_new_string(str->str));
2142
0
  }
2143
0
  if (priv->flags > 0) {
2144
0
    g_variant_builder_add(builder,
2145
0
              "{sv}",
2146
0
              FWUPD_RESULT_KEY_FLAGS,
2147
0
              g_variant_new_uint64(priv->flags));
2148
0
  }
2149
0
  if (priv->request_flags > 0) {
2150
0
    g_variant_builder_add(builder,
2151
0
              "{sv}",
2152
0
              FWUPD_RESULT_KEY_REQUEST_FLAGS,
2153
0
              g_variant_new_uint64(priv->request_flags));
2154
0
  }
2155
0
  if (priv->problems > 0) {
2156
0
    g_variant_builder_add(builder,
2157
0
              "{sv}",
2158
0
              FWUPD_RESULT_KEY_PROBLEMS,
2159
0
              g_variant_new_uint64(priv->problems));
2160
0
  }
2161
0
  if (priv->created > 0) {
2162
0
    g_variant_builder_add(builder,
2163
0
              "{sv}",
2164
0
              FWUPD_RESULT_KEY_CREATED,
2165
0
              g_variant_new_uint64(priv->created));
2166
0
  }
2167
0
  if (priv->modified > 0) {
2168
0
    g_variant_builder_add(builder,
2169
0
              "{sv}",
2170
0
              FWUPD_RESULT_KEY_MODIFIED,
2171
0
              g_variant_new_uint64(priv->modified));
2172
0
  }
2173
0
  if (priv->version_build_date > 0) {
2174
0
    g_variant_builder_add(builder,
2175
0
              "{sv}",
2176
0
              FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
2177
0
              g_variant_new_uint64(priv->version_build_date));
2178
0
  }
2179
2180
0
  if (priv->summary != NULL) {
2181
0
    g_variant_builder_add(builder,
2182
0
              "{sv}",
2183
0
              FWUPD_RESULT_KEY_SUMMARY,
2184
0
              g_variant_new_string(priv->summary));
2185
0
  }
2186
0
  if (priv->branch != NULL) {
2187
0
    g_variant_builder_add(builder,
2188
0
              "{sv}",
2189
0
              FWUPD_RESULT_KEY_BRANCH,
2190
0
              g_variant_new_string(priv->branch));
2191
0
  }
2192
0
  if (priv->checksums != NULL && priv->checksums->len > 0) {
2193
0
    g_autoptr(GString) str = g_string_new("");
2194
0
    for (guint i = 0; i < priv->checksums->len; i++) {
2195
0
      const gchar *checksum = g_ptr_array_index(priv->checksums, i);
2196
0
      g_string_append_printf(str, "%s,", checksum);
2197
0
    }
2198
0
    if (str->len > 0)
2199
0
      g_string_truncate(str, str->len - 1);
2200
0
    g_variant_builder_add(builder,
2201
0
              "{sv}",
2202
0
              FWUPD_RESULT_KEY_CHECKSUM,
2203
0
              g_variant_new_string(str->str));
2204
0
  }
2205
0
  if (priv->plugin != NULL) {
2206
0
    g_variant_builder_add(builder,
2207
0
              "{sv}",
2208
0
              FWUPD_RESULT_KEY_PLUGIN,
2209
0
              g_variant_new_string(priv->plugin));
2210
0
  }
2211
0
  if (priv->protocols != NULL && priv->protocols->len > 0) {
2212
0
    g_autoptr(GString) str = g_string_new(NULL);
2213
0
    for (guint i = 0; i < priv->protocols->len; i++) {
2214
0
      const gchar *tmp = g_ptr_array_index(priv->protocols, i);
2215
0
      g_string_append_printf(str, "%s|", tmp);
2216
0
    }
2217
0
    if (str->len > 0)
2218
0
      g_string_truncate(str, str->len - 1);
2219
0
    g_variant_builder_add(builder,
2220
0
              "{sv}",
2221
0
              FWUPD_RESULT_KEY_PROTOCOL,
2222
0
              g_variant_new_string(str->str));
2223
0
  }
2224
0
  if (priv->issues != NULL && priv->issues->len > 0) {
2225
0
    g_autofree const gchar **strv = g_new0(const gchar *, priv->issues->len + 1);
2226
0
    for (guint i = 0; i < priv->issues->len; i++)
2227
0
      strv[i] = (const gchar *)g_ptr_array_index(priv->issues, i);
2228
0
    g_variant_builder_add(builder,
2229
0
              "{sv}",
2230
0
              FWUPD_RESULT_KEY_ISSUES,
2231
0
              g_variant_new_strv(strv, -1));
2232
0
  }
2233
0
  if (priv->version != NULL) {
2234
0
    g_variant_builder_add(builder,
2235
0
              "{sv}",
2236
0
              FWUPD_RESULT_KEY_VERSION,
2237
0
              g_variant_new_string(priv->version));
2238
0
  }
2239
0
  if (priv->version_lowest != NULL) {
2240
0
    g_variant_builder_add(builder,
2241
0
              "{sv}",
2242
0
              FWUPD_RESULT_KEY_VERSION_LOWEST,
2243
0
              g_variant_new_string(priv->version_lowest));
2244
0
  }
2245
0
  if (priv->version_bootloader != NULL) {
2246
0
    g_variant_builder_add(builder,
2247
0
              "{sv}",
2248
0
              FWUPD_RESULT_KEY_VERSION_BOOTLOADER,
2249
0
              g_variant_new_string(priv->version_bootloader));
2250
0
  }
2251
0
  if (priv->version_raw > 0) {
2252
0
    g_variant_builder_add(builder,
2253
0
              "{sv}",
2254
0
              FWUPD_RESULT_KEY_VERSION_RAW,
2255
0
              g_variant_new_uint64(priv->version_raw));
2256
0
  }
2257
0
  if (priv->version_lowest_raw > 0) {
2258
0
    g_variant_builder_add(builder,
2259
0
              "{sv}",
2260
0
              FWUPD_RESULT_KEY_VERSION_LOWEST_RAW,
2261
0
              g_variant_new_uint64(priv->version_lowest_raw));
2262
0
  }
2263
0
  if (priv->version_bootloader_raw > 0) {
2264
0
    g_variant_builder_add(builder,
2265
0
              "{sv}",
2266
0
              FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW,
2267
0
              g_variant_new_uint64(priv->version_raw));
2268
0
  }
2269
0
  if (priv->flashes_left > 0) {
2270
0
    g_variant_builder_add(builder,
2271
0
              "{sv}",
2272
0
              FWUPD_RESULT_KEY_FLASHES_LEFT,
2273
0
              g_variant_new_uint32(priv->flashes_left));
2274
0
  }
2275
0
  if (priv->battery_level != FWUPD_BATTERY_LEVEL_INVALID) {
2276
0
    g_variant_builder_add(builder,
2277
0
              "{sv}",
2278
0
              FWUPD_RESULT_KEY_BATTERY_LEVEL,
2279
0
              g_variant_new_uint32(priv->battery_level));
2280
0
  }
2281
0
  if (priv->battery_threshold != FWUPD_BATTERY_LEVEL_INVALID) {
2282
0
    g_variant_builder_add(builder,
2283
0
              "{sv}",
2284
0
              FWUPD_RESULT_KEY_BATTERY_THRESHOLD,
2285
0
              g_variant_new_uint32(priv->battery_threshold));
2286
0
  }
2287
0
  if (priv->install_duration > 0) {
2288
0
    g_variant_builder_add(builder,
2289
0
              "{sv}",
2290
0
              FWUPD_RESULT_KEY_INSTALL_DURATION,
2291
0
              g_variant_new_uint32(priv->install_duration));
2292
0
  }
2293
0
  if (priv->update_error != NULL) {
2294
0
    g_variant_builder_add(builder,
2295
0
              "{sv}",
2296
0
              FWUPD_RESULT_KEY_UPDATE_ERROR,
2297
0
              g_variant_new_string(priv->update_error));
2298
0
  }
2299
0
  if (priv->update_state != FWUPD_UPDATE_STATE_UNKNOWN) {
2300
0
    g_variant_builder_add(builder,
2301
0
              "{sv}",
2302
0
              FWUPD_RESULT_KEY_UPDATE_STATE,
2303
0
              g_variant_new_uint32(priv->update_state));
2304
0
  }
2305
0
  if (priv->status != FWUPD_STATUS_UNKNOWN) {
2306
0
    g_variant_builder_add(builder,
2307
0
              "{sv}",
2308
0
              FWUPD_RESULT_KEY_STATUS,
2309
0
              g_variant_new_uint32(priv->status));
2310
0
  }
2311
0
  if (priv->percentage != 0) {
2312
0
    g_variant_builder_add(builder,
2313
0
              "{sv}",
2314
0
              FWUPD_RESULT_KEY_PERCENTAGE,
2315
0
              g_variant_new_uint32(priv->percentage));
2316
0
  }
2317
0
  if (priv->version_format != FWUPD_VERSION_FORMAT_UNKNOWN) {
2318
0
    g_variant_builder_add(builder,
2319
0
              "{sv}",
2320
0
              FWUPD_RESULT_KEY_VERSION_FORMAT,
2321
0
              g_variant_new_uint32(priv->version_format));
2322
0
  }
2323
0
  if (priv->instance_ids != NULL && (flags & FWUPD_CODEC_FLAG_TRUSTED) > 0) {
2324
0
    if (priv->serial != NULL) {
2325
0
      g_variant_builder_add(builder,
2326
0
                "{sv}",
2327
0
                FWUPD_RESULT_KEY_SERIAL,
2328
0
                g_variant_new_string(priv->serial));
2329
0
    }
2330
0
    if (priv->instance_ids->len > 0) {
2331
0
      const gchar *const *tmp = (const gchar *const *)priv->instance_ids->pdata;
2332
0
      g_variant_builder_add(builder,
2333
0
                "{sv}",
2334
0
                FWUPD_RESULT_KEY_INSTANCE_IDS,
2335
0
                g_variant_new_strv(tmp, priv->instance_ids->len));
2336
0
    }
2337
0
  }
2338
2339
  /* create an array with all the metadata in */
2340
0
  if (priv->releases != NULL && priv->releases->len > 0) {
2341
0
    g_autofree GVariant **children = NULL;
2342
0
    children = g_new0(GVariant *, priv->releases->len);
2343
0
    for (guint i = 0; i < priv->releases->len; i++) {
2344
0
      FwupdRelease *release = g_ptr_array_index(priv->releases, i);
2345
0
      children[i] =
2346
0
          fwupd_codec_to_variant(FWUPD_CODEC(release), FWUPD_CODEC_FLAG_NONE);
2347
0
    }
2348
0
    g_variant_builder_add(
2349
0
        builder,
2350
0
        "{sv}",
2351
0
        FWUPD_RESULT_KEY_RELEASE,
2352
0
        g_variant_new_array(G_VARIANT_TYPE("a{sv}"), children, priv->releases->len));
2353
0
  }
2354
0
}
2355
2356
static void
2357
fwupd_device_from_key_value(FwupdDevice *self, const gchar *key, GVariant *value)
2358
0
{
2359
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_RELEASE) == 0) {
2360
0
    GVariantIter iter;
2361
0
    GVariant *child;
2362
0
    g_variant_iter_init(&iter, value);
2363
0
    while ((child = g_variant_iter_next_value(&iter))) {
2364
0
      g_autoptr(FwupdRelease) release = fwupd_release_new();
2365
0
      if (fwupd_codec_from_variant(FWUPD_CODEC(release), child, NULL))
2366
0
        fwupd_device_add_release(self, release);
2367
0
      g_variant_unref(child);
2368
0
    }
2369
0
    return;
2370
0
  }
2371
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DEVICE_ID) == 0) {
2372
0
    fwupd_device_set_id(self, g_variant_get_string(value, NULL));
2373
0
    return;
2374
0
  }
2375
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_PARENT_DEVICE_ID) == 0) {
2376
0
    fwupd_device_set_parent_id(self, g_variant_get_string(value, NULL));
2377
0
    return;
2378
0
  }
2379
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_COMPOSITE_ID) == 0) {
2380
0
    fwupd_device_set_composite_id(self, g_variant_get_string(value, NULL));
2381
0
    return;
2382
0
  }
2383
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_FLAGS) == 0) {
2384
0
    fwupd_device_set_flags(self, g_variant_get_uint64(value));
2385
0
    return;
2386
0
  }
2387
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_PROBLEMS) == 0) {
2388
0
    fwupd_device_set_problems(self, g_variant_get_uint64(value));
2389
0
    return;
2390
0
  }
2391
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_REQUEST_FLAGS) == 0) {
2392
0
    fwupd_device_set_request_flags(self, g_variant_get_uint64(value));
2393
0
    return;
2394
0
  }
2395
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_CREATED) == 0) {
2396
0
    fwupd_device_set_created(self, g_variant_get_uint64(value));
2397
0
    return;
2398
0
  }
2399
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_MODIFIED) == 0) {
2400
0
    fwupd_device_set_modified(self, g_variant_get_uint64(value));
2401
0
    return;
2402
0
  }
2403
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_BUILD_DATE) == 0) {
2404
0
    fwupd_device_set_version_build_date(self, g_variant_get_uint64(value));
2405
0
    return;
2406
0
  }
2407
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_GUID) == 0) {
2408
0
    g_autofree const gchar **guids = g_variant_get_strv(value, NULL);
2409
0
    for (guint i = 0; guids != NULL && guids[i] != NULL; i++)
2410
0
      fwupd_device_add_guid(self, guids[i]);
2411
0
    return;
2412
0
  }
2413
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_INSTANCE_IDS) == 0) {
2414
0
    g_autofree const gchar **instance_ids = g_variant_get_strv(value, NULL);
2415
0
    for (guint i = 0; instance_ids != NULL && instance_ids[i] != NULL; i++)
2416
0
      fwupd_device_add_instance_id(self, instance_ids[i]);
2417
0
    return;
2418
0
  }
2419
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_ICON) == 0) {
2420
0
    g_autofree const gchar **icons = g_variant_get_strv(value, NULL);
2421
0
    for (guint i = 0; icons != NULL && icons[i] != NULL; i++)
2422
0
      fwupd_device_add_icon(self, icons[i]);
2423
0
    return;
2424
0
  }
2425
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME) == 0) {
2426
0
    fwupd_device_set_name(self, g_variant_get_string(value, NULL));
2427
0
    return;
2428
0
  }
2429
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR) == 0) {
2430
0
    fwupd_device_set_vendor(self, g_variant_get_string(value, NULL));
2431
0
    return;
2432
0
  }
2433
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR_ID) == 0) {
2434
0
    g_auto(GStrv) vendor_ids = NULL;
2435
0
    vendor_ids = g_strsplit(g_variant_get_string(value, NULL), "|", -1);
2436
0
    for (guint i = 0; vendor_ids[i] != NULL; i++)
2437
0
      fwupd_device_add_vendor_id(self, vendor_ids[i]);
2438
0
    return;
2439
0
  }
2440
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_SERIAL) == 0) {
2441
0
    fwupd_device_set_serial(self, g_variant_get_string(value, NULL));
2442
0
    return;
2443
0
  }
2444
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_SUMMARY) == 0) {
2445
0
    fwupd_device_set_summary(self, g_variant_get_string(value, NULL));
2446
0
    return;
2447
0
  }
2448
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_BRANCH) == 0) {
2449
0
    fwupd_device_set_branch(self, g_variant_get_string(value, NULL));
2450
0
    return;
2451
0
  }
2452
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_CHECKSUM) == 0) {
2453
0
    const gchar *checksums = g_variant_get_string(value, NULL);
2454
0
    if (checksums != NULL) {
2455
0
      g_auto(GStrv) split = g_strsplit(checksums, ",", -1);
2456
0
      for (guint i = 0; split[i] != NULL; i++)
2457
0
        fwupd_device_add_checksum(self, split[i]);
2458
0
    }
2459
0
    return;
2460
0
  }
2461
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_PLUGIN) == 0) {
2462
0
    fwupd_device_set_plugin(self, g_variant_get_string(value, NULL));
2463
0
    return;
2464
0
  }
2465
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_PROTOCOL) == 0) {
2466
0
    g_auto(GStrv) protocols = NULL;
2467
0
    protocols = g_strsplit(g_variant_get_string(value, NULL), "|", -1);
2468
0
    for (guint i = 0; protocols[i] != NULL; i++)
2469
0
      fwupd_device_add_protocol(self, protocols[i]);
2470
0
    return;
2471
0
  }
2472
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_ISSUES) == 0) {
2473
0
    g_autofree const gchar **strv = g_variant_get_strv(value, NULL);
2474
0
    for (guint i = 0; strv[i] != NULL; i++)
2475
0
      fwupd_device_add_issue(self, strv[i]);
2476
0
    return;
2477
0
  }
2478
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION) == 0) {
2479
0
    fwupd_device_set_version(self, g_variant_get_string(value, NULL));
2480
0
    return;
2481
0
  }
2482
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_LOWEST) == 0) {
2483
0
    fwupd_device_set_version_lowest(self, g_variant_get_string(value, NULL));
2484
0
    return;
2485
0
  }
2486
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_BOOTLOADER) == 0) {
2487
0
    fwupd_device_set_version_bootloader(self, g_variant_get_string(value, NULL));
2488
0
    return;
2489
0
  }
2490
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_FLASHES_LEFT) == 0) {
2491
0
    fwupd_device_set_flashes_left(self, g_variant_get_uint32(value));
2492
0
    return;
2493
0
  }
2494
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_BATTERY_LEVEL) == 0) {
2495
0
    fwupd_device_set_battery_level(self, g_variant_get_uint32(value));
2496
0
    return;
2497
0
  }
2498
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_BATTERY_THRESHOLD) == 0) {
2499
0
    fwupd_device_set_battery_threshold(self, g_variant_get_uint32(value));
2500
0
    return;
2501
0
  }
2502
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) {
2503
0
    fwupd_device_set_install_duration(self, g_variant_get_uint32(value));
2504
0
    return;
2505
0
  }
2506
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_ERROR) == 0) {
2507
0
    fwupd_device_set_update_error(self, g_variant_get_string(value, NULL));
2508
0
    return;
2509
0
  }
2510
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_STATE) == 0) {
2511
0
    fwupd_device_set_update_state(self, g_variant_get_uint32(value));
2512
0
    return;
2513
0
  }
2514
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_STATUS) == 0) {
2515
0
    fwupd_device_set_status(self, g_variant_get_uint32(value));
2516
0
    return;
2517
0
  }
2518
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_PERCENTAGE) == 0) {
2519
0
    fwupd_device_set_percentage(self, g_variant_get_uint32(value));
2520
0
    return;
2521
0
  }
2522
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_FORMAT) == 0) {
2523
0
    fwupd_device_set_version_format(self, g_variant_get_uint32(value));
2524
0
    return;
2525
0
  }
2526
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_RAW) == 0) {
2527
0
    fwupd_device_set_version_raw(self, g_variant_get_uint64(value));
2528
0
    return;
2529
0
  }
2530
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_LOWEST_RAW) == 0) {
2531
0
    fwupd_device_set_version_lowest_raw(self, g_variant_get_uint64(value));
2532
0
    return;
2533
0
  }
2534
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW) == 0) {
2535
0
    fwupd_device_set_version_bootloader_raw(self, g_variant_get_uint64(value));
2536
0
    return;
2537
0
  }
2538
0
}
2539
2540
static void
2541
fwupd_device_string_append_flags(GString *str, guint idt, const gchar *key, guint64 device_flags)
2542
0
{
2543
0
  g_autoptr(GString) tmp = g_string_new("");
2544
0
  for (guint i = 0; i < 64; i++) {
2545
0
    if ((device_flags & ((guint64)1 << i)) == 0)
2546
0
      continue;
2547
0
    g_string_append_printf(tmp, "%s|", fwupd_device_flag_to_string((guint64)1 << i));
2548
0
  }
2549
0
  if (tmp->len == 0) {
2550
0
    g_string_append(tmp, fwupd_device_flag_to_string(0));
2551
0
  } else {
2552
0
    g_string_truncate(tmp, tmp->len - 1);
2553
0
  }
2554
0
  fwupd_codec_string_append(str, idt, key, tmp->str);
2555
0
}
2556
2557
static void
2558
fwupd_device_string_append_request_flags(GString *str,
2559
           guint idt,
2560
           const gchar *key,
2561
           guint64 request_flags)
2562
0
{
2563
0
  g_autoptr(GString) tmp = g_string_new("");
2564
0
  for (guint i = 0; i < 64; i++) {
2565
0
    if ((request_flags & ((guint64)1 << i)) == 0)
2566
0
      continue;
2567
0
    g_string_append_printf(tmp, "%s|", fwupd_request_flag_to_string((guint64)1 << i));
2568
0
  }
2569
0
  if (tmp->len == 0) {
2570
0
    g_string_append(tmp, fwupd_request_flag_to_string(0));
2571
0
  } else {
2572
0
    g_string_truncate(tmp, tmp->len - 1);
2573
0
  }
2574
0
  fwupd_codec_string_append(str, idt, key, tmp->str);
2575
0
}
2576
2577
static void
2578
fwupd_device_string_append_problems(GString *str,
2579
            guint idt,
2580
            const gchar *key,
2581
            guint64 device_problems)
2582
0
{
2583
0
  g_autoptr(GString) tmp = g_string_new("");
2584
0
  for (guint i = 0; i < 64; i++) {
2585
0
    if ((device_problems & ((guint64)1 << i)) == 0)
2586
0
      continue;
2587
0
    g_string_append_printf(tmp, "%s|", fwupd_device_problem_to_string((guint64)1 << i));
2588
0
  }
2589
0
  if (tmp->len == 0) {
2590
0
    g_string_append(tmp, fwupd_device_problem_to_string(0));
2591
0
  } else {
2592
0
    g_string_truncate(tmp, tmp->len - 1);
2593
0
  }
2594
0
  fwupd_codec_string_append(str, idt, key, tmp->str);
2595
0
}
2596
2597
/**
2598
 * fwupd_device_get_update_state:
2599
 * @self: a #FwupdDevice
2600
 *
2601
 * Gets the update state.
2602
 *
2603
 * Returns: the update state, or %FWUPD_UPDATE_STATE_UNKNOWN if unset
2604
 *
2605
 * Since: 0.9.8
2606
 **/
2607
FwupdUpdateState
2608
fwupd_device_get_update_state(FwupdDevice *self)
2609
0
{
2610
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2611
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FWUPD_UPDATE_STATE_UNKNOWN);
2612
0
  return priv->update_state;
2613
0
}
2614
2615
/**
2616
 * fwupd_device_set_update_state:
2617
 * @self: a #FwupdDevice
2618
 * @update_state: the state, e.g. %FWUPD_UPDATE_STATE_PENDING
2619
 *
2620
 * Sets the update state.
2621
 *
2622
 * Since: 0.9.8
2623
 **/
2624
void
2625
fwupd_device_set_update_state(FwupdDevice *self, FwupdUpdateState update_state)
2626
0
{
2627
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2628
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2629
0
  if (priv->update_state == update_state)
2630
0
    return;
2631
0
  priv->update_state = update_state;
2632
0
  g_object_notify(G_OBJECT(self), "update-state");
2633
0
}
2634
2635
/**
2636
 * fwupd_device_get_version_format:
2637
 * @self: a #FwupdDevice
2638
 *
2639
 * Gets the version format.
2640
 *
2641
 * Returns: the version format, or %FWUPD_VERSION_FORMAT_UNKNOWN if unset
2642
 *
2643
 * Since: 1.2.9
2644
 **/
2645
FwupdVersionFormat
2646
fwupd_device_get_version_format(FwupdDevice *self)
2647
0
{
2648
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2649
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FWUPD_VERSION_FORMAT_UNKNOWN);
2650
0
  return priv->version_format;
2651
0
}
2652
2653
/**
2654
 * fwupd_device_set_version_format:
2655
 * @self: a #FwupdDevice
2656
 * @version_format: the version format, e.g. %FWUPD_VERSION_FORMAT_NUMBER
2657
 *
2658
 * Sets the version format.
2659
 *
2660
 * Since: 1.2.9
2661
 **/
2662
void
2663
fwupd_device_set_version_format(FwupdDevice *self, FwupdVersionFormat version_format)
2664
0
{
2665
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2666
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2667
0
  priv->version_format = version_format;
2668
0
}
2669
2670
/**
2671
 * fwupd_device_get_version_raw:
2672
 * @self: a #FwupdDevice
2673
 *
2674
 * Gets the raw version number from the hardware before converted to a string.
2675
 *
2676
 * Returns: the hardware version, or 0 if unset
2677
 *
2678
 * Since: 1.3.6
2679
 **/
2680
guint64
2681
fwupd_device_get_version_raw(FwupdDevice *self)
2682
0
{
2683
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2684
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
2685
0
  return priv->version_raw;
2686
0
}
2687
2688
/**
2689
 * fwupd_device_set_version_raw:
2690
 * @self: a #FwupdDevice
2691
 * @version_raw: the raw hardware version
2692
 *
2693
 * Sets the raw version number from the hardware before converted to a string.
2694
 *
2695
 * Since: 1.3.6
2696
 **/
2697
void
2698
fwupd_device_set_version_raw(FwupdDevice *self, guint64 version_raw)
2699
0
{
2700
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2701
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2702
0
  priv->version_raw = version_raw;
2703
0
}
2704
2705
/**
2706
 * fwupd_device_get_version_build_date:
2707
 * @self: a #FwupdDevice
2708
 *
2709
 * Gets the date when the firmware was built.
2710
 *
2711
 * Returns: the UNIX time, or 0 if unset
2712
 *
2713
 * Since: 1.6.2
2714
 **/
2715
guint64
2716
fwupd_device_get_version_build_date(FwupdDevice *self)
2717
0
{
2718
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2719
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
2720
0
  return priv->version_build_date;
2721
0
}
2722
2723
/**
2724
 * fwupd_device_set_version_build_date:
2725
 * @self: a #FwupdDevice
2726
 * @version_build_date: the UNIX time
2727
 *
2728
 * Sets the date when the firmware was built.
2729
 *
2730
 * Since: 1.6.2
2731
 **/
2732
void
2733
fwupd_device_set_version_build_date(FwupdDevice *self, guint64 version_build_date)
2734
0
{
2735
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2736
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2737
0
  priv->version_build_date = version_build_date;
2738
0
}
2739
2740
/**
2741
 * fwupd_device_get_update_error:
2742
 * @self: a #FwupdDevice
2743
 *
2744
 * Gets the update error string.
2745
 *
2746
 * Returns: the update error string, or %NULL if unset
2747
 *
2748
 * Since: 0.9.8
2749
 **/
2750
const gchar *
2751
fwupd_device_get_update_error(FwupdDevice *self)
2752
0
{
2753
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2754
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
2755
0
  return priv->update_error;
2756
0
}
2757
2758
/**
2759
 * fwupd_device_set_update_error:
2760
 * @self: a #FwupdDevice
2761
 * @update_error: (nullable): the update error string
2762
 *
2763
 * Sets the update error string.
2764
 *
2765
 * Since: 0.9.8
2766
 **/
2767
void
2768
fwupd_device_set_update_error(FwupdDevice *self, const gchar *update_error)
2769
0
{
2770
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2771
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2772
2773
  /* not changed */
2774
0
  if (g_strcmp0(priv->update_error, update_error) == 0)
2775
0
    return;
2776
2777
0
  g_free(priv->update_error);
2778
0
  priv->update_error = g_strdup(update_error);
2779
0
  g_object_notify(G_OBJECT(self), "update-error");
2780
0
}
2781
2782
/**
2783
 * fwupd_device_get_release_default:
2784
 * @self: a #FwupdDevice
2785
 *
2786
 * Gets the default release for this device.
2787
 *
2788
 * Returns: (transfer none): the #FwupdRelease, or %NULL if not set
2789
 *
2790
 * Since: 0.9.8
2791
 **/
2792
FwupdRelease *
2793
fwupd_device_get_release_default(FwupdDevice *self)
2794
0
{
2795
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2796
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
2797
0
  if (priv->releases == NULL || priv->releases->len == 0)
2798
0
    return NULL;
2799
0
  return FWUPD_RELEASE(g_ptr_array_index(priv->releases, 0));
2800
0
}
2801
2802
static void
2803
fwupd_device_ensure_releases(FwupdDevice *self)
2804
0
{
2805
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2806
0
  if (priv->releases == NULL)
2807
0
    priv->releases = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
2808
0
}
2809
2810
/**
2811
 * fwupd_device_get_releases:
2812
 * @self: a #FwupdDevice
2813
 *
2814
 * Gets all the releases for this device.
2815
 *
2816
 * Returns: (transfer none) (element-type FwupdRelease): array of releases
2817
 *
2818
 * Since: 0.9.8
2819
 **/
2820
GPtrArray *
2821
fwupd_device_get_releases(FwupdDevice *self)
2822
0
{
2823
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2824
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), NULL);
2825
0
  fwupd_device_ensure_releases(self);
2826
0
  return priv->releases;
2827
0
}
2828
2829
/**
2830
 * fwupd_device_add_release:
2831
 * @self: a #FwupdDevice
2832
 * @release: (not nullable): a release
2833
 *
2834
 * Adds a release for this device.
2835
 *
2836
 * Since: 0.9.8
2837
 **/
2838
void
2839
fwupd_device_add_release(FwupdDevice *self, FwupdRelease *release)
2840
0
{
2841
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2842
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2843
0
  g_return_if_fail(FWUPD_IS_RELEASE(release));
2844
0
  fwupd_device_ensure_releases(self);
2845
0
  g_ptr_array_add(priv->releases, g_object_ref(release));
2846
0
}
2847
2848
/**
2849
 * fwupd_device_get_status:
2850
 * @self: a #FwupdDevice
2851
 *
2852
 * Returns what the device is currently doing.
2853
 *
2854
 * Returns: the status value, e.g. %FWUPD_STATUS_DEVICE_WRITE
2855
 *
2856
 * Since: 1.4.0
2857
 **/
2858
FwupdStatus
2859
fwupd_device_get_status(FwupdDevice *self)
2860
0
{
2861
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2862
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
2863
0
  return priv->status;
2864
0
}
2865
2866
/**
2867
 * fwupd_device_set_status:
2868
 * @self: a #FwupdDevice
2869
 * @status: the status value, e.g. %FWUPD_STATUS_DEVICE_WRITE
2870
 *
2871
 * Sets what the device is currently doing.
2872
 *
2873
 * Since: 1.4.0
2874
 **/
2875
void
2876
fwupd_device_set_status(FwupdDevice *self, FwupdStatus status)
2877
0
{
2878
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2879
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2880
0
  if (priv->status == status)
2881
0
    return;
2882
0
  priv->status = status;
2883
0
  g_object_notify(G_OBJECT(self), "status");
2884
0
}
2885
2886
/**
2887
 * fwupd_device_get_percentage:
2888
 * @self: a #FwupdDevice
2889
 *
2890
 * Returns the percentage completion of the device.
2891
 *
2892
 * Returns: the percentage value
2893
 *
2894
 * Since: 1.8.11
2895
 **/
2896
guint
2897
fwupd_device_get_percentage(FwupdDevice *self)
2898
0
{
2899
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2900
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), 0);
2901
0
  return priv->percentage;
2902
0
}
2903
2904
/**
2905
 * fwupd_device_set_percentage:
2906
 * @self: a #FwupdDevice
2907
 * @percentage: the percentage value
2908
 *
2909
 * Sets the percentage completion of the device.
2910
 *
2911
 * Since: 1.8.11
2912
 **/
2913
void
2914
fwupd_device_set_percentage(FwupdDevice *self, guint percentage)
2915
0
{
2916
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2917
0
  g_return_if_fail(FWUPD_IS_DEVICE(self));
2918
0
  if (priv->percentage == percentage)
2919
0
    return;
2920
0
  priv->percentage = percentage;
2921
0
  g_object_notify(G_OBJECT(self), "percentage");
2922
0
}
2923
2924
static void
2925
fwupd_device_string_append_update_state(GString *str,
2926
          guint idt,
2927
          const gchar *key,
2928
          FwupdUpdateState value)
2929
0
{
2930
0
  if (value == FWUPD_UPDATE_STATE_UNKNOWN)
2931
0
    return;
2932
0
  fwupd_codec_string_append(str, idt, key, fwupd_update_state_to_string(value));
2933
0
}
2934
2935
static void
2936
fwupd_device_add_json(FwupdCodec *codec, JsonBuilder *builder, FwupdCodecFlags flags)
2937
0
{
2938
0
  FwupdDevice *self = FWUPD_DEVICE(codec);
2939
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
2940
2941
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_NAME, priv->name);
2942
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_DEVICE_ID, priv->id);
2943
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_PARENT_DEVICE_ID, priv->parent_id);
2944
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_COMPOSITE_ID, priv->composite_id);
2945
0
  if ((flags & FWUPD_CODEC_FLAG_TRUSTED) > 0 && priv->instance_ids != NULL &&
2946
0
      priv->instance_ids->len > 0) {
2947
0
    json_builder_set_member_name(builder, FWUPD_RESULT_KEY_INSTANCE_IDS);
2948
0
    json_builder_begin_array(builder);
2949
0
    for (guint i = 0; i < priv->instance_ids->len; i++) {
2950
0
      const gchar *instance_id = g_ptr_array_index(priv->instance_ids, i);
2951
0
      json_builder_add_string_value(builder, instance_id);
2952
0
    }
2953
0
    json_builder_end_array(builder);
2954
0
  }
2955
0
  if (priv->guids != NULL && priv->guids->len > 0) {
2956
0
    json_builder_set_member_name(builder, FWUPD_RESULT_KEY_GUID);
2957
0
    json_builder_begin_array(builder);
2958
0
    for (guint i = 0; i < priv->guids->len; i++) {
2959
0
      const gchar *guid = g_ptr_array_index(priv->guids, i);
2960
0
      json_builder_add_string_value(builder, guid);
2961
0
    }
2962
0
    json_builder_end_array(builder);
2963
0
  }
2964
0
  if (flags & FWUPD_CODEC_FLAG_TRUSTED)
2965
0
    fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_SERIAL, priv->serial);
2966
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
2967
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_BRANCH, priv->branch);
2968
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
2969
0
  if (priv->protocols != NULL && priv->protocols->len > 0) {
2970
0
    json_builder_set_member_name(builder, "Protocols");
2971
0
    json_builder_begin_array(builder);
2972
0
    for (guint i = 0; i < priv->protocols->len; i++) {
2973
0
      const gchar *tmp = g_ptr_array_index(priv->protocols, i);
2974
0
      json_builder_add_string_value(builder, tmp);
2975
0
    }
2976
0
    json_builder_end_array(builder);
2977
0
  }
2978
0
  if (priv->issues != NULL && priv->issues->len > 0) {
2979
0
    json_builder_set_member_name(builder, FWUPD_RESULT_KEY_ISSUES);
2980
0
    json_builder_begin_array(builder);
2981
0
    for (guint i = 0; i < priv->issues->len; i++) {
2982
0
      const gchar *tmp = g_ptr_array_index(priv->issues, i);
2983
0
      json_builder_add_string_value(builder, tmp);
2984
0
    }
2985
0
    json_builder_end_array(builder);
2986
0
  }
2987
0
  if (priv->flags != FWUPD_DEVICE_FLAG_NONE) {
2988
0
    json_builder_set_member_name(builder, FWUPD_RESULT_KEY_FLAGS);
2989
0
    json_builder_begin_array(builder);
2990
0
    for (guint i = 0; i < 64; i++) {
2991
0
      const gchar *tmp;
2992
0
      if ((priv->flags & ((guint64)1 << i)) == 0)
2993
0
        continue;
2994
0
      tmp = fwupd_device_flag_to_string((guint64)1 << i);
2995
0
      json_builder_add_string_value(builder, tmp);
2996
0
    }
2997
0
    json_builder_end_array(builder);
2998
0
  }
2999
0
  if (priv->request_flags != FWUPD_REQUEST_FLAG_NONE) {
3000
0
    json_builder_set_member_name(builder, FWUPD_RESULT_KEY_REQUEST_FLAGS);
3001
0
    json_builder_begin_array(builder);
3002
0
    for (guint i = 0; i < 64; i++) {
3003
0
      const gchar *tmp;
3004
0
      if ((priv->request_flags & ((guint64)1 << i)) == 0)
3005
0
        continue;
3006
0
      tmp = fwupd_request_flag_to_string((guint64)1 << i);
3007
0
      json_builder_add_string_value(builder, tmp);
3008
0
    }
3009
0
    json_builder_end_array(builder);
3010
0
  }
3011
0
  if (priv->problems != FWUPD_DEVICE_PROBLEM_NONE) {
3012
0
    json_builder_set_member_name(builder, FWUPD_RESULT_KEY_PROBLEMS);
3013
0
    json_builder_begin_array(builder);
3014
0
    for (guint i = 0; i < 64; i++) {
3015
0
      const gchar *tmp;
3016
0
      if ((priv->problems & ((guint64)1 << i)) == 0)
3017
0
        continue;
3018
0
      tmp = fwupd_device_problem_to_string((guint64)1 << i);
3019
0
      json_builder_add_string_value(builder, tmp);
3020
0
    }
3021
0
    json_builder_end_array(builder);
3022
0
  }
3023
0
  if (priv->checksums != NULL && priv->checksums->len > 0) {
3024
0
    json_builder_set_member_name(builder, "Checksums");
3025
0
    json_builder_begin_array(builder);
3026
0
    for (guint i = 0; i < priv->checksums->len; i++) {
3027
0
      const gchar *checksum = g_ptr_array_index(priv->checksums, i);
3028
0
      json_builder_add_string_value(builder, checksum);
3029
0
    }
3030
0
    json_builder_end_array(builder);
3031
0
  }
3032
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
3033
0
  if (priv->vendor_ids != NULL && priv->vendor_ids->len > 0) {
3034
0
    json_builder_set_member_name(builder, "VendorIds");
3035
0
    json_builder_begin_array(builder);
3036
0
    for (guint i = 0; i < priv->vendor_ids->len; i++) {
3037
0
      const gchar *tmp = g_ptr_array_index(priv->vendor_ids, i);
3038
0
      json_builder_add_string_value(builder, tmp);
3039
0
    }
3040
0
    json_builder_end_array(builder);
3041
0
  }
3042
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_VERSION, priv->version);
3043
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_VERSION_LOWEST, priv->version_lowest);
3044
0
  fwupd_codec_json_append(builder,
3045
0
        FWUPD_RESULT_KEY_VERSION_BOOTLOADER,
3046
0
        priv->version_bootloader);
3047
0
  fwupd_codec_json_append(builder,
3048
0
        FWUPD_RESULT_KEY_VERSION_FORMAT,
3049
0
        fwupd_version_format_to_string(priv->version_format));
3050
0
  if (priv->flashes_left > 0) {
3051
0
    fwupd_codec_json_append_int(builder,
3052
0
              FWUPD_RESULT_KEY_FLASHES_LEFT,
3053
0
              priv->flashes_left);
3054
0
  }
3055
0
  if (priv->battery_level != FWUPD_BATTERY_LEVEL_INVALID) {
3056
0
    fwupd_codec_json_append_int(builder,
3057
0
              FWUPD_RESULT_KEY_BATTERY_LEVEL,
3058
0
              priv->battery_level);
3059
0
  }
3060
0
  if (priv->battery_threshold != FWUPD_BATTERY_LEVEL_INVALID) {
3061
0
    fwupd_codec_json_append_int(builder,
3062
0
              FWUPD_RESULT_KEY_BATTERY_THRESHOLD,
3063
0
              priv->battery_threshold);
3064
0
  }
3065
0
  if (priv->version_raw > 0) {
3066
0
    fwupd_codec_json_append_int(builder,
3067
0
              FWUPD_RESULT_KEY_VERSION_RAW,
3068
0
              priv->version_raw);
3069
0
  }
3070
0
  if (priv->version_lowest_raw > 0)
3071
0
    fwupd_codec_json_append_int(builder,
3072
0
              FWUPD_RESULT_KEY_VERSION_LOWEST_RAW,
3073
0
              priv->version_lowest_raw);
3074
0
  if (priv->version_bootloader_raw > 0)
3075
0
    fwupd_codec_json_append_int(builder,
3076
0
              FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW,
3077
0
              priv->version_bootloader_raw);
3078
0
  if (priv->version_build_date > 0) {
3079
0
    fwupd_codec_json_append_int(builder,
3080
0
              FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
3081
0
              priv->version_build_date);
3082
0
  }
3083
0
  if (priv->icons != NULL && priv->icons->len > 0) {
3084
0
    json_builder_set_member_name(builder, "Icons");
3085
0
    json_builder_begin_array(builder);
3086
0
    for (guint i = 0; i < priv->icons->len; i++) {
3087
0
      const gchar *icon = g_ptr_array_index(priv->icons, i);
3088
0
      json_builder_add_string_value(builder, icon);
3089
0
    }
3090
0
    json_builder_end_array(builder);
3091
0
  }
3092
0
  if (priv->install_duration > 0) {
3093
0
    fwupd_codec_json_append_int(builder,
3094
0
              FWUPD_RESULT_KEY_INSTALL_DURATION,
3095
0
              priv->install_duration);
3096
0
  }
3097
0
  if (priv->created > 0)
3098
0
    fwupd_codec_json_append_int(builder, FWUPD_RESULT_KEY_CREATED, priv->created);
3099
0
  if (priv->modified > 0)
3100
0
    fwupd_codec_json_append_int(builder, FWUPD_RESULT_KEY_MODIFIED, priv->modified);
3101
0
  if (priv->update_state > 0) {
3102
0
    fwupd_codec_json_append_int(builder,
3103
0
              FWUPD_RESULT_KEY_UPDATE_STATE,
3104
0
              priv->update_state);
3105
0
  }
3106
0
  if (priv->status > 0)
3107
0
    fwupd_codec_json_append_int(builder, FWUPD_RESULT_KEY_STATUS, priv->status);
3108
0
  if (priv->percentage > 0)
3109
0
    fwupd_codec_json_append_int(builder, FWUPD_RESULT_KEY_PERCENTAGE, priv->percentage);
3110
0
  fwupd_codec_json_append(builder, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error);
3111
0
  if (priv->releases != NULL && priv->releases->len > 0)
3112
0
    fwupd_codec_array_to_json(priv->releases, "Releases", builder, flags);
3113
0
}
3114
3115
static gboolean
3116
fwupd_device_from_json(FwupdCodec *codec, JsonNode *json_node, GError **error)
3117
0
{
3118
0
  FwupdDevice *self = FWUPD_DEVICE(codec);
3119
0
  JsonObject *obj;
3120
3121
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
3122
0
  g_return_val_if_fail(json_node != NULL, FALSE);
3123
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
3124
3125
  /* sanity check */
3126
0
  if (!JSON_NODE_HOLDS_OBJECT(json_node)) {
3127
0
    g_set_error_literal(error,
3128
0
            FWUPD_ERROR,
3129
0
            FWUPD_ERROR_INVALID_DATA,
3130
0
            "not JSON object");
3131
0
    return FALSE;
3132
0
  }
3133
0
  obj = json_node_get_object(json_node);
3134
3135
  /* this has to exist */
3136
0
  if (!json_object_has_member(obj, FWUPD_RESULT_KEY_DEVICE_ID)) {
3137
0
    g_set_error(error,
3138
0
          FWUPD_ERROR,
3139
0
          FWUPD_ERROR_INVALID_DATA,
3140
0
          "no %s property in object",
3141
0
          FWUPD_RESULT_KEY_DEVICE_ID);
3142
0
    return FALSE;
3143
0
  }
3144
0
  fwupd_device_set_id(self, json_object_get_string_member(obj, FWUPD_RESULT_KEY_DEVICE_ID));
3145
3146
  /* also optional */
3147
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_NAME)) {
3148
0
    const gchar *tmp =
3149
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_NAME, NULL);
3150
0
    fwupd_device_set_name(self, tmp);
3151
0
  }
3152
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_PARENT_DEVICE_ID)) {
3153
0
    const gchar *tmp =
3154
0
        json_object_get_string_member_with_default(obj,
3155
0
                     FWUPD_RESULT_KEY_PARENT_DEVICE_ID,
3156
0
                     NULL);
3157
0
    fwupd_device_set_parent_id(self, tmp);
3158
0
  }
3159
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_COMPOSITE_ID)) {
3160
0
    const gchar *tmp =
3161
0
        json_object_get_string_member_with_default(obj,
3162
0
                     FWUPD_RESULT_KEY_COMPOSITE_ID,
3163
0
                     NULL);
3164
0
    fwupd_device_set_composite_id(self, tmp);
3165
0
  }
3166
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_PROTOCOL)) {
3167
0
    const gchar *tmp =
3168
0
        json_object_get_string_member_with_default(obj,
3169
0
                     FWUPD_RESULT_KEY_PROTOCOL,
3170
0
                     NULL);
3171
0
    fwupd_device_add_protocol(self, tmp);
3172
0
  }
3173
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_SERIAL)) {
3174
0
    const gchar *tmp =
3175
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_SERIAL, NULL);
3176
0
    fwupd_device_set_serial(self, tmp);
3177
0
  }
3178
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_SUMMARY)) {
3179
0
    const gchar *tmp =
3180
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_SUMMARY, NULL);
3181
0
    fwupd_device_set_summary(self, tmp);
3182
0
  }
3183
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_BRANCH)) {
3184
0
    const gchar *tmp =
3185
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_BRANCH, NULL);
3186
0
    fwupd_device_set_branch(self, tmp);
3187
0
  }
3188
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_PLUGIN)) {
3189
0
    const gchar *tmp =
3190
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_PLUGIN, NULL);
3191
0
    fwupd_device_set_plugin(self, tmp);
3192
0
  }
3193
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VENDOR)) {
3194
0
    const gchar *tmp =
3195
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_VENDOR, NULL);
3196
0
    fwupd_device_set_vendor(self, tmp);
3197
0
  }
3198
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VENDOR_ID)) {
3199
0
    const gchar *tmp =
3200
0
        json_object_get_string_member_with_default(obj,
3201
0
                     FWUPD_RESULT_KEY_VENDOR_ID,
3202
0
                     NULL);
3203
0
    if (tmp != NULL) {
3204
0
      g_auto(GStrv) split = g_strsplit(tmp, "|", -1);
3205
0
      for (guint i = 0; split[i] != NULL; i++)
3206
0
        fwupd_device_add_vendor_id(self, split[i]);
3207
0
    }
3208
0
  }
3209
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION)) {
3210
0
    const gchar *tmp =
3211
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_VERSION, NULL);
3212
0
    fwupd_device_set_version(self, tmp);
3213
0
  }
3214
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_LOWEST)) {
3215
0
    const gchar *tmp =
3216
0
        json_object_get_string_member_with_default(obj,
3217
0
                     FWUPD_RESULT_KEY_VERSION_LOWEST,
3218
0
                     NULL);
3219
0
    fwupd_device_set_version_lowest(self, tmp);
3220
0
  }
3221
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_BOOTLOADER)) {
3222
0
    const gchar *tmp =
3223
0
        json_object_get_string_member_with_default(obj,
3224
0
                     FWUPD_RESULT_KEY_VERSION_BOOTLOADER,
3225
0
                     NULL);
3226
0
    fwupd_device_set_version_bootloader(self, tmp);
3227
0
  }
3228
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_FORMAT)) {
3229
0
    const gchar *tmp =
3230
0
        json_object_get_string_member_with_default(obj,
3231
0
                     FWUPD_RESULT_KEY_VERSION_FORMAT,
3232
0
                     NULL);
3233
0
    fwupd_device_set_version_format(self, fwupd_version_format_from_string(tmp));
3234
0
  }
3235
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_FLASHES_LEFT)) {
3236
0
    gint64 tmp =
3237
0
        json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_FLASHES_LEFT, 0);
3238
0
    fwupd_device_set_flashes_left(self, tmp);
3239
0
  }
3240
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_BATTERY_LEVEL)) {
3241
0
    gint64 tmp =
3242
0
        json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_BATTERY_LEVEL, 0);
3243
0
    fwupd_device_set_battery_level(self, tmp);
3244
0
  }
3245
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_BATTERY_THRESHOLD)) {
3246
0
    gint64 tmp =
3247
0
        json_object_get_int_member_with_default(obj,
3248
0
                  FWUPD_RESULT_KEY_BATTERY_THRESHOLD,
3249
0
                  0);
3250
0
    fwupd_device_set_battery_threshold(self, tmp);
3251
0
  }
3252
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_RAW)) {
3253
0
    gint64 tmp =
3254
0
        json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_VERSION_RAW, 0);
3255
0
    fwupd_device_set_version_raw(self, tmp);
3256
0
  }
3257
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_LOWEST_RAW)) {
3258
0
    gint64 tmp =
3259
0
        json_object_get_int_member_with_default(obj,
3260
0
                  FWUPD_RESULT_KEY_VERSION_LOWEST_RAW,
3261
0
                  0);
3262
0
    fwupd_device_set_version_lowest_raw(self, tmp);
3263
0
  }
3264
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW)) {
3265
0
    gint64 tmp =
3266
0
        json_object_get_int_member_with_default(obj,
3267
0
                  FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW,
3268
0
                  0);
3269
0
    fwupd_device_set_version_bootloader_raw(self, tmp);
3270
0
  }
3271
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_VERSION_BUILD_DATE)) {
3272
0
    gint64 tmp =
3273
0
        json_object_get_int_member_with_default(obj,
3274
0
                  FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
3275
0
                  0);
3276
0
    fwupd_device_set_version_build_date(self, tmp);
3277
0
  }
3278
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_INSTALL_DURATION)) {
3279
0
    gint64 tmp =
3280
0
        json_object_get_int_member_with_default(obj,
3281
0
                  FWUPD_RESULT_KEY_INSTALL_DURATION,
3282
0
                  0);
3283
0
    fwupd_device_set_install_duration(self, tmp);
3284
0
  }
3285
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_CREATED)) {
3286
0
    gint64 tmp =
3287
0
        json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_CREATED, 0);
3288
0
    fwupd_device_set_created(self, tmp);
3289
0
  }
3290
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_MODIFIED)) {
3291
0
    gint64 tmp =
3292
0
        json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_MODIFIED, 0);
3293
0
    fwupd_device_set_modified(self, tmp);
3294
0
  }
3295
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_UPDATE_STATE)) {
3296
0
    const gchar *tmp =
3297
0
        json_object_get_string_member_with_default(obj,
3298
0
                     FWUPD_RESULT_KEY_UPDATE_STATE,
3299
0
                     NULL);
3300
0
    fwupd_device_set_update_state(self, fwupd_update_state_from_string(tmp));
3301
0
  }
3302
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_STATUS)) {
3303
0
    const gchar *tmp =
3304
0
        json_object_get_string_member_with_default(obj, FWUPD_RESULT_KEY_STATUS, NULL);
3305
0
    fwupd_device_set_status(self, fwupd_status_from_string(tmp));
3306
0
  }
3307
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_PERCENTAGE)) {
3308
0
    gint64 tmp =
3309
0
        json_object_get_int_member_with_default(obj, FWUPD_RESULT_KEY_PERCENTAGE, 0);
3310
0
    fwupd_device_set_percentage(self, tmp);
3311
0
  }
3312
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_UPDATE_ERROR)) {
3313
0
    const gchar *tmp =
3314
0
        json_object_get_string_member_with_default(obj,
3315
0
                     FWUPD_RESULT_KEY_UPDATE_ERROR,
3316
0
                     NULL);
3317
0
    fwupd_device_set_update_error(self, tmp);
3318
0
  }
3319
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_INSTANCE_IDS)) {
3320
0
    JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_INSTANCE_IDS);
3321
0
    for (guint i = 0; i < json_array_get_length(array); i++)
3322
0
      fwupd_device_add_instance_id(self, json_array_get_string_element(array, i));
3323
0
  }
3324
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_GUID)) {
3325
0
    JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_GUID);
3326
0
    for (guint i = 0; i < json_array_get_length(array); i++)
3327
0
      fwupd_device_add_guid(self, json_array_get_string_element(array, i));
3328
0
  }
3329
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_ISSUES)) {
3330
0
    JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_ISSUES);
3331
0
    for (guint i = 0; i < json_array_get_length(array); i++)
3332
0
      fwupd_device_add_issue(self, json_array_get_string_element(array, i));
3333
0
  }
3334
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_FLAGS)) {
3335
0
    JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_FLAGS);
3336
0
    for (guint i = 0; i < json_array_get_length(array); i++) {
3337
0
      const gchar *tmp = json_array_get_string_element(array, i);
3338
0
      fwupd_device_add_flag(self, fwupd_device_flag_from_string(tmp));
3339
0
    }
3340
0
  }
3341
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_PROBLEMS)) {
3342
0
    JsonArray *array = json_object_get_array_member(obj, FWUPD_RESULT_KEY_PROBLEMS);
3343
0
    for (guint i = 0; i < json_array_get_length(array); i++) {
3344
0
      const gchar *tmp = json_array_get_string_element(array, i);
3345
0
      fwupd_device_add_problem(self, fwupd_device_problem_from_string(tmp));
3346
0
    }
3347
0
  }
3348
0
  if (json_object_has_member(obj, FWUPD_RESULT_KEY_REQUEST_FLAGS)) {
3349
0
    JsonArray *array =
3350
0
        json_object_get_array_member(obj, FWUPD_RESULT_KEY_REQUEST_FLAGS);
3351
0
    for (guint i = 0; i < json_array_get_length(array); i++) {
3352
0
      const gchar *tmp = json_array_get_string_element(array, i);
3353
0
      fwupd_device_add_request_flag(self, fwupd_request_flag_from_string(tmp));
3354
0
    }
3355
0
  }
3356
0
  if (json_object_has_member(obj, "VendorIds")) {
3357
0
    JsonArray *array = json_object_get_array_member(obj, "VendorIds");
3358
0
    for (guint i = 0; i < json_array_get_length(array); i++)
3359
0
      fwupd_device_add_vendor_id(self, json_array_get_string_element(array, i));
3360
0
  }
3361
0
  if (json_object_has_member(obj, "Protocols")) {
3362
0
    JsonArray *array = json_object_get_array_member(obj, "Protocols");
3363
0
    for (guint i = 0; i < json_array_get_length(array); i++)
3364
0
      fwupd_device_add_protocol(self, json_array_get_string_element(array, i));
3365
0
  }
3366
0
  if (json_object_has_member(obj, "Icons")) {
3367
0
    JsonArray *array = json_object_get_array_member(obj, "Icons");
3368
0
    for (guint i = 0; i < json_array_get_length(array); i++)
3369
0
      fwupd_device_add_icon(self, json_array_get_string_element(array, i));
3370
0
  }
3371
0
  if (json_object_has_member(obj, "Checksums")) {
3372
0
    JsonArray *array = json_object_get_array_member(obj, "Checksums");
3373
0
    for (guint i = 0; i < json_array_get_length(array); i++)
3374
0
      fwupd_device_add_checksum(self, json_array_get_string_element(array, i));
3375
0
  }
3376
3377
  /* success */
3378
0
  return TRUE;
3379
0
}
3380
3381
static gchar *
3382
fwupd_device_verstr_raw(guint64 value_raw)
3383
0
{
3384
0
  if (value_raw > 0xffffffff) {
3385
0
    return g_strdup_printf("0x%08x%08x",
3386
0
               (guint)(value_raw >> 32),
3387
0
               (guint)(value_raw & 0xffffffff));
3388
0
  }
3389
0
  return g_strdup_printf("0x%08x", (guint)value_raw);
3390
0
}
3391
3392
typedef struct {
3393
  gchar *guid;
3394
  gchar *instance_id;
3395
} FwupdDeviceGuidHelper;
3396
3397
static void
3398
fwupd_device_guid_helper_new(FwupdDeviceGuidHelper *helper)
3399
0
{
3400
0
  g_free(helper->guid);
3401
0
  g_free(helper->instance_id);
3402
0
  g_free(helper);
3403
0
}
3404
3405
static FwupdDeviceGuidHelper *
3406
fwupd_device_guid_helper_array_find(GPtrArray *array, const gchar *guid)
3407
0
{
3408
0
  for (guint i = 0; i < array->len; i++) {
3409
0
    FwupdDeviceGuidHelper *helper = g_ptr_array_index(array, i);
3410
0
    if (g_strcmp0(helper->guid, guid) == 0)
3411
0
      return helper;
3412
0
  }
3413
0
  return NULL;
3414
0
}
3415
3416
static void
3417
fwupd_device_add_string(FwupdCodec *codec, guint idt, GString *str)
3418
0
{
3419
0
  FwupdDevice *self = FWUPD_DEVICE(codec);
3420
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
3421
0
  g_autoptr(GPtrArray) guid_helpers = NULL;
3422
3423
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DEVICE_ID, priv->id);
3424
0
  if (g_strcmp0(priv->composite_id, priv->parent_id) != 0) {
3425
0
    fwupd_codec_string_append(str,
3426
0
            idt,
3427
0
            FWUPD_RESULT_KEY_PARENT_DEVICE_ID,
3428
0
            priv->parent_id);
3429
0
  }
3430
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_COMPOSITE_ID, priv->composite_id);
3431
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_NAME, priv->name);
3432
0
  if (priv->status != FWUPD_STATUS_UNKNOWN) {
3433
0
    fwupd_codec_string_append(str,
3434
0
            idt,
3435
0
            FWUPD_RESULT_KEY_STATUS,
3436
0
            fwupd_status_to_string(priv->status));
3437
0
  }
3438
0
  fwupd_codec_string_append_int(str, idt, FWUPD_RESULT_KEY_PERCENTAGE, priv->percentage);
3439
3440
  /* show instance IDs optionally mapped to GUIDs, and also "standalone" GUIDs */
3441
0
  guid_helpers = g_ptr_array_new_with_free_func((GDestroyNotify)fwupd_device_guid_helper_new);
3442
0
  if (priv->instance_ids != NULL) {
3443
0
    for (guint i = 0; i < priv->instance_ids->len; i++) {
3444
0
      FwupdDeviceGuidHelper *helper = g_new0(FwupdDeviceGuidHelper, 1);
3445
0
      const gchar *instance_id = g_ptr_array_index(priv->instance_ids, i);
3446
0
      helper->guid = fwupd_guid_hash_string(instance_id);
3447
0
      helper->instance_id = g_strdup(instance_id);
3448
0
      g_ptr_array_add(guid_helpers, helper);
3449
0
    }
3450
0
  }
3451
0
  if (priv->guids != NULL) {
3452
0
    for (guint i = 0; i < priv->guids->len; i++) {
3453
0
      const gchar *guid = g_ptr_array_index(priv->guids, i);
3454
0
      if (fwupd_device_guid_helper_array_find(guid_helpers, guid) == NULL) {
3455
0
        FwupdDeviceGuidHelper *helper = g_new0(FwupdDeviceGuidHelper, 1);
3456
0
        helper->guid = g_strdup(guid);
3457
0
        g_ptr_array_add(guid_helpers, helper);
3458
0
      }
3459
0
    }
3460
0
  }
3461
0
  for (guint i = 0; i < guid_helpers->len; i++) {
3462
0
    FwupdDeviceGuidHelper *helper = g_ptr_array_index(guid_helpers, i);
3463
0
    g_autoptr(GString) tmp = g_string_new(helper->guid);
3464
0
    if (helper->instance_id != NULL)
3465
0
      g_string_append_printf(tmp, " ← %s", helper->instance_id);
3466
0
    if (!fwupd_device_has_guid(self, helper->guid))
3467
0
      g_string_append(tmp, " ⚠");
3468
0
    fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_GUID, tmp->str);
3469
0
  }
3470
3471
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_SERIAL, priv->serial);
3472
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
3473
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_BRANCH, priv->branch);
3474
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
3475
0
  if (priv->protocols != NULL) {
3476
0
    for (guint i = 0; i < priv->protocols->len; i++) {
3477
0
      const gchar *tmp = g_ptr_array_index(priv->protocols, i);
3478
0
      fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_PROTOCOL, tmp);
3479
0
    }
3480
0
  }
3481
0
  if (priv->issues != NULL) {
3482
0
    for (guint i = 0; i < priv->issues->len; i++) {
3483
0
      const gchar *tmp = g_ptr_array_index(priv->issues, i);
3484
0
      fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_ISSUES, tmp);
3485
0
    }
3486
0
  }
3487
0
  fwupd_device_string_append_flags(str, idt, FWUPD_RESULT_KEY_FLAGS, priv->flags);
3488
0
  if (priv->problems != FWUPD_DEVICE_PROBLEM_NONE) {
3489
0
    fwupd_device_string_append_problems(str,
3490
0
                idt,
3491
0
                FWUPD_RESULT_KEY_PROBLEMS,
3492
0
                priv->problems);
3493
0
  }
3494
0
  if (priv->request_flags > 0) {
3495
0
    fwupd_device_string_append_request_flags(str,
3496
0
               idt,
3497
0
               FWUPD_RESULT_KEY_REQUEST_FLAGS,
3498
0
               priv->request_flags);
3499
0
  }
3500
0
  if (priv->checksums != NULL) {
3501
0
    for (guint i = 0; i < priv->checksums->len; i++) {
3502
0
      const gchar *checksum = g_ptr_array_index(priv->checksums, i);
3503
0
      g_autofree gchar *checksum_display =
3504
0
          fwupd_checksum_format_for_display(checksum);
3505
0
      fwupd_codec_string_append(str,
3506
0
              idt,
3507
0
              FWUPD_RESULT_KEY_CHECKSUM,
3508
0
              checksum_display);
3509
0
    }
3510
0
  }
3511
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
3512
0
  if (priv->vendor_ids != NULL) {
3513
0
    for (guint i = 0; i < priv->vendor_ids->len; i++) {
3514
0
      const gchar *tmp = g_ptr_array_index(priv->vendor_ids, i);
3515
0
      fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VENDOR_ID, tmp);
3516
0
    }
3517
0
  }
3518
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VERSION, priv->version);
3519
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VERSION_LOWEST, priv->version_lowest);
3520
0
  fwupd_codec_string_append(str,
3521
0
          idt,
3522
0
          FWUPD_RESULT_KEY_VERSION_BOOTLOADER,
3523
0
          priv->version_bootloader);
3524
0
  fwupd_codec_string_append(str,
3525
0
          idt,
3526
0
          FWUPD_RESULT_KEY_VERSION_FORMAT,
3527
0
          fwupd_version_format_to_string(priv->version_format));
3528
0
  if (priv->flashes_left < 2) {
3529
0
    fwupd_codec_string_append_int(str,
3530
0
                idt,
3531
0
                FWUPD_RESULT_KEY_FLASHES_LEFT,
3532
0
                priv->flashes_left);
3533
0
  }
3534
0
  if (priv->battery_level != FWUPD_BATTERY_LEVEL_INVALID) {
3535
0
    fwupd_codec_string_append_int(str,
3536
0
                idt,
3537
0
                FWUPD_RESULT_KEY_BATTERY_LEVEL,
3538
0
                priv->battery_level);
3539
0
  }
3540
0
  if (priv->battery_threshold != FWUPD_BATTERY_LEVEL_INVALID) {
3541
0
    fwupd_codec_string_append_int(str,
3542
0
                idt,
3543
0
                FWUPD_RESULT_KEY_BATTERY_THRESHOLD,
3544
0
                priv->battery_threshold);
3545
0
  }
3546
0
  if (priv->version_raw > 0) {
3547
0
    g_autofree gchar *tmp = fwupd_device_verstr_raw(priv->version_raw);
3548
0
    fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VERSION_RAW, tmp);
3549
0
  }
3550
0
  if (priv->version_lowest_raw > 0) {
3551
0
    g_autofree gchar *tmp = fwupd_device_verstr_raw(priv->version_lowest_raw);
3552
0
    fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VERSION_LOWEST_RAW, tmp);
3553
0
  }
3554
0
  fwupd_codec_string_append_time(str,
3555
0
               idt,
3556
0
               FWUPD_RESULT_KEY_VERSION_BUILD_DATE,
3557
0
               priv->version_build_date);
3558
0
  if (priv->version_bootloader_raw > 0) {
3559
0
    g_autofree gchar *tmp = fwupd_device_verstr_raw(priv->version_bootloader_raw);
3560
0
    fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VERSION_BOOTLOADER_RAW, tmp);
3561
0
  }
3562
0
  if (priv->icons != NULL && priv->icons->len > 0) {
3563
0
    g_autoptr(GString) tmp = g_string_new(NULL);
3564
0
    for (guint i = 0; i < priv->icons->len; i++) {
3565
0
      const gchar *icon = g_ptr_array_index(priv->icons, i);
3566
0
      g_string_append_printf(tmp, "%s,", icon);
3567
0
    }
3568
0
    if (tmp->len > 1)
3569
0
      g_string_truncate(tmp, tmp->len - 1);
3570
0
    fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_ICON, tmp->str);
3571
0
  }
3572
0
  fwupd_codec_string_append_int(str,
3573
0
              idt,
3574
0
              FWUPD_RESULT_KEY_INSTALL_DURATION,
3575
0
              priv->install_duration);
3576
0
  fwupd_codec_string_append_time(str, idt, FWUPD_RESULT_KEY_CREATED, priv->created);
3577
0
  fwupd_codec_string_append_time(str, idt, FWUPD_RESULT_KEY_MODIFIED, priv->modified);
3578
0
  fwupd_device_string_append_update_state(str,
3579
0
            idt,
3580
0
            FWUPD_RESULT_KEY_UPDATE_STATE,
3581
0
            priv->update_state);
3582
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_UPDATE_ERROR, priv->update_error);
3583
0
  if (priv->releases != NULL) {
3584
0
    for (guint i = 0; i < priv->releases->len; i++) {
3585
0
      FwupdRelease *release = g_ptr_array_index(priv->releases, i);
3586
0
      fwupd_codec_add_string(FWUPD_CODEC(release), idt, str);
3587
0
    }
3588
0
  }
3589
0
}
3590
3591
static void
3592
fwupd_device_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
3593
0
{
3594
0
  FwupdDevice *self = FWUPD_DEVICE(object);
3595
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
3596
0
  switch (prop_id) {
3597
0
  case PROP_ID:
3598
0
    g_value_set_string(value, priv->id);
3599
0
    break;
3600
0
  case PROP_VERSION:
3601
0
    g_value_set_string(value, priv->version);
3602
0
    break;
3603
0
  case PROP_VERSION_FORMAT:
3604
0
    g_value_set_uint(value, priv->version_format);
3605
0
    break;
3606
0
  case PROP_FLAGS:
3607
0
    g_value_set_uint64(value, priv->flags);
3608
0
    break;
3609
0
  case PROP_PROBLEMS:
3610
0
    g_value_set_uint64(value, priv->problems);
3611
0
    break;
3612
0
  case PROP_REQUEST_FLAGS:
3613
0
    g_value_set_uint64(value, priv->request_flags);
3614
0
    break;
3615
0
  case PROP_UPDATE_ERROR:
3616
0
    g_value_set_string(value, priv->update_error);
3617
0
    break;
3618
0
  case PROP_STATUS:
3619
0
    g_value_set_uint(value, priv->status);
3620
0
    break;
3621
0
  case PROP_PERCENTAGE:
3622
0
    g_value_set_uint(value, priv->percentage);
3623
0
    break;
3624
0
  case PROP_PARENT:
3625
0
    g_value_set_object(value, priv->parent);
3626
0
    break;
3627
0
  case PROP_UPDATE_STATE:
3628
0
    g_value_set_uint(value, priv->update_state);
3629
0
    break;
3630
0
  case PROP_BATTERY_LEVEL:
3631
0
    g_value_set_uint(value, priv->battery_level);
3632
0
    break;
3633
0
  case PROP_BATTERY_THRESHOLD:
3634
0
    g_value_set_uint(value, priv->battery_threshold);
3635
0
    break;
3636
0
  default:
3637
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
3638
0
    break;
3639
0
  }
3640
0
}
3641
3642
static void
3643
fwupd_device_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
3644
0
{
3645
0
  FwupdDevice *self = FWUPD_DEVICE(object);
3646
0
  switch (prop_id) {
3647
0
  case PROP_VERSION:
3648
0
    fwupd_device_set_version(self, g_value_get_string(value));
3649
0
    break;
3650
0
  case PROP_ID:
3651
0
    fwupd_device_set_id(self, g_value_get_string(value));
3652
0
    break;
3653
0
  case PROP_VERSION_FORMAT:
3654
0
    fwupd_device_set_version_format(self, g_value_get_uint(value));
3655
0
    break;
3656
0
  case PROP_FLAGS:
3657
0
    fwupd_device_set_flags(self, g_value_get_uint64(value));
3658
0
    break;
3659
0
  case PROP_PROBLEMS:
3660
0
    fwupd_device_set_problems(self, g_value_get_uint64(value));
3661
0
    break;
3662
0
  case PROP_REQUEST_FLAGS:
3663
0
    fwupd_device_set_request_flags(self, g_value_get_uint64(value));
3664
0
    break;
3665
0
  case PROP_UPDATE_ERROR:
3666
0
    fwupd_device_set_update_error(self, g_value_get_string(value));
3667
0
    break;
3668
0
  case PROP_STATUS:
3669
0
    fwupd_device_set_status(self, g_value_get_uint(value));
3670
0
    break;
3671
0
  case PROP_PERCENTAGE:
3672
0
    fwupd_device_set_percentage(self, g_value_get_uint(value));
3673
0
    break;
3674
0
  case PROP_PARENT:
3675
0
    fwupd_device_set_parent(self, g_value_get_object(value));
3676
0
    break;
3677
0
  case PROP_UPDATE_STATE:
3678
0
    fwupd_device_set_update_state(self, g_value_get_uint(value));
3679
0
    break;
3680
0
  case PROP_BATTERY_LEVEL:
3681
0
    fwupd_device_set_battery_level(self, g_value_get_uint(value));
3682
0
    break;
3683
0
  case PROP_BATTERY_THRESHOLD:
3684
0
    fwupd_device_set_battery_threshold(self, g_value_get_uint(value));
3685
0
    break;
3686
0
  default:
3687
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
3688
0
    break;
3689
0
  }
3690
0
}
3691
3692
static void
3693
fwupd_device_class_init(FwupdDeviceClass *klass)
3694
0
{
3695
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
3696
0
  GParamSpec *pspec;
3697
3698
0
  object_class->finalize = fwupd_device_finalize;
3699
0
  object_class->get_property = fwupd_device_get_property;
3700
0
  object_class->set_property = fwupd_device_set_property;
3701
3702
  /**
3703
   * FwupdDevice:version:
3704
   *
3705
   * The device version.
3706
   *
3707
   * Since: 1.8.15
3708
   */
3709
0
  pspec = g_param_spec_string("version",
3710
0
            NULL,
3711
0
            NULL,
3712
0
            NULL,
3713
0
            G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3714
0
  g_object_class_install_property(object_class, PROP_VERSION, pspec);
3715
3716
  /**
3717
   * FwupdDevice:id:
3718
   *
3719
   * The device ID.
3720
   *
3721
   * Since: 2.0.0
3722
   */
3723
0
  pspec =
3724
0
      g_param_spec_string("id", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3725
0
  g_object_class_install_property(object_class, PROP_ID, pspec);
3726
3727
  /**
3728
   * FwupdDevice:version-format:
3729
   *
3730
   * The version format of the device.
3731
   *
3732
   * Since: 1.2.9
3733
   */
3734
0
  pspec = g_param_spec_uint("version-format",
3735
0
          NULL,
3736
0
          NULL,
3737
0
          FWUPD_VERSION_FORMAT_UNKNOWN,
3738
0
          FWUPD_VERSION_FORMAT_LAST,
3739
0
          FWUPD_VERSION_FORMAT_UNKNOWN,
3740
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3741
0
  g_object_class_install_property(object_class, PROP_VERSION_FORMAT, pspec);
3742
3743
  /**
3744
   * FwupdDevice:flags:
3745
   *
3746
   * The device flags.
3747
   *
3748
   * Since: 0.9.3
3749
   */
3750
0
  pspec = g_param_spec_uint64("flags",
3751
0
            NULL,
3752
0
            NULL,
3753
0
            FWUPD_DEVICE_FLAG_NONE,
3754
0
            FWUPD_DEVICE_FLAG_UNKNOWN,
3755
0
            FWUPD_DEVICE_FLAG_NONE,
3756
0
            G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3757
0
  g_object_class_install_property(object_class, PROP_FLAGS, pspec);
3758
3759
  /**
3760
   * FwupdDevice:problems:
3761
   *
3762
   * The problems with the device that the user could fix, e.g. "lid open".
3763
   *
3764
   * Since: 1.8.1
3765
   */
3766
0
  pspec = g_param_spec_uint64("problems",
3767
0
            NULL,
3768
0
            NULL,
3769
0
            FWUPD_DEVICE_PROBLEM_NONE,
3770
0
            FWUPD_DEVICE_PROBLEM_UNKNOWN,
3771
0
            FWUPD_DEVICE_PROBLEM_NONE,
3772
0
            G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3773
0
  g_object_class_install_property(object_class, PROP_PROBLEMS, pspec);
3774
3775
  /**
3776
   * FwupdDevice:request-flags:
3777
   *
3778
   * The device request flags.
3779
   *
3780
   * Since: 1.9.10
3781
   */
3782
0
  pspec = g_param_spec_uint64("request-flags",
3783
0
            NULL,
3784
0
            NULL,
3785
0
            FWUPD_REQUEST_FLAG_NONE,
3786
0
            FWUPD_REQUEST_FLAG_UNKNOWN,
3787
0
            FWUPD_REQUEST_FLAG_NONE,
3788
0
            G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3789
0
  g_object_class_install_property(object_class, PROP_REQUEST_FLAGS, pspec);
3790
3791
  /**
3792
   * FwupdDevice:status:
3793
   *
3794
   * The current device status.
3795
   *
3796
   * Since: 1.4.0
3797
   */
3798
0
  pspec = g_param_spec_uint("status",
3799
0
          NULL,
3800
0
          NULL,
3801
0
          FWUPD_STATUS_UNKNOWN,
3802
0
          FWUPD_STATUS_LAST,
3803
0
          FWUPD_STATUS_UNKNOWN,
3804
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3805
0
  g_object_class_install_property(object_class, PROP_STATUS, pspec);
3806
3807
  /**
3808
   * FwupdDevice:percentage:
3809
   *
3810
   * The current device percentage.
3811
   *
3812
   * Since: 1.8.11
3813
   */
3814
0
  pspec = g_param_spec_uint("percentage",
3815
0
          NULL,
3816
0
          NULL,
3817
0
          0,
3818
0
          100,
3819
0
          0,
3820
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3821
0
  g_object_class_install_property(object_class, PROP_PERCENTAGE, pspec);
3822
3823
  /**
3824
   * FwupdDevice:parent:
3825
   *
3826
   * The device parent.
3827
   *
3828
   * Since: 1.0.8
3829
   */
3830
0
  pspec = g_param_spec_object("parent",
3831
0
            NULL,
3832
0
            NULL,
3833
0
            FWUPD_TYPE_DEVICE,
3834
0
            G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME);
3835
0
  g_object_class_install_property(object_class, PROP_PARENT, pspec);
3836
3837
  /**
3838
   * FwupdDevice:update-state:
3839
   *
3840
   * The device update state.
3841
   *
3842
   * Since: 0.9.8
3843
   */
3844
0
  pspec = g_param_spec_uint("update-state",
3845
0
          NULL,
3846
0
          NULL,
3847
0
          FWUPD_UPDATE_STATE_UNKNOWN,
3848
0
          FWUPD_UPDATE_STATE_LAST,
3849
0
          FWUPD_UPDATE_STATE_UNKNOWN,
3850
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3851
0
  g_object_class_install_property(object_class, PROP_UPDATE_STATE, pspec);
3852
3853
  /**
3854
   * FwupdDevice:update-error:
3855
   *
3856
   * The device update error.
3857
   *
3858
   * Since: 0.9.8
3859
   */
3860
0
  pspec = g_param_spec_string("update-error",
3861
0
            NULL,
3862
0
            NULL,
3863
0
            NULL,
3864
0
            G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3865
0
  g_object_class_install_property(object_class, PROP_UPDATE_ERROR, pspec);
3866
3867
  /**
3868
   * FwupdDevice:battery-level:
3869
   *
3870
   * The device battery level in percent.
3871
   *
3872
   * Since: 1.5.8
3873
   */
3874
0
  pspec = g_param_spec_uint("battery-level",
3875
0
          NULL,
3876
0
          NULL,
3877
0
          0,
3878
0
          FWUPD_BATTERY_LEVEL_INVALID,
3879
0
          FWUPD_BATTERY_LEVEL_INVALID,
3880
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3881
0
  g_object_class_install_property(object_class, PROP_BATTERY_LEVEL, pspec);
3882
3883
  /**
3884
   * FwupdDevice:battery-threshold:
3885
   *
3886
   * The device battery threshold in percent.
3887
   *
3888
   * Since: 1.5.8
3889
   */
3890
0
  pspec = g_param_spec_uint("battery-threshold",
3891
0
          NULL,
3892
0
          NULL,
3893
0
          0,
3894
0
          FWUPD_BATTERY_LEVEL_INVALID,
3895
0
          FWUPD_BATTERY_LEVEL_INVALID,
3896
0
          G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
3897
0
  g_object_class_install_property(object_class, PROP_BATTERY_THRESHOLD, pspec);
3898
0
}
3899
3900
static void
3901
fwupd_device_init(FwupdDevice *self)
3902
0
{
3903
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
3904
0
  priv->battery_level = FWUPD_BATTERY_LEVEL_INVALID;
3905
0
  priv->battery_threshold = FWUPD_BATTERY_LEVEL_INVALID;
3906
0
}
3907
3908
static void
3909
fwupd_device_finalize(GObject *object)
3910
0
{
3911
0
  FwupdDevice *self = FWUPD_DEVICE(object);
3912
0
  FwupdDevicePrivate *priv = GET_PRIVATE(self);
3913
3914
0
  if (priv->parent != NULL)
3915
0
    g_object_remove_weak_pointer(G_OBJECT(priv->parent), (gpointer *)&priv->parent);
3916
0
  if (priv->children != NULL) {
3917
0
    for (guint i = 0; i < priv->children->len; i++) {
3918
0
      FwupdDevice *child = g_ptr_array_index(priv->children, i);
3919
0
      g_object_weak_unref(G_OBJECT(child), fwupd_device_child_finalized_cb, self);
3920
0
    }
3921
0
  }
3922
3923
0
  g_free(priv->id);
3924
0
  g_free(priv->parent_id);
3925
0
  g_free(priv->composite_id);
3926
0
  g_free(priv->name);
3927
0
  g_free(priv->serial);
3928
0
  g_free(priv->summary);
3929
0
  g_free(priv->branch);
3930
0
  g_free(priv->vendor);
3931
0
  g_free(priv->plugin);
3932
0
  g_free(priv->update_error);
3933
0
  g_free(priv->version);
3934
0
  g_free(priv->version_lowest);
3935
0
  g_free(priv->version_bootloader);
3936
0
  if (priv->guids != NULL)
3937
0
    g_ptr_array_unref(priv->guids);
3938
0
  if (priv->vendor_ids != NULL)
3939
0
    g_ptr_array_unref(priv->vendor_ids);
3940
0
  if (priv->protocols != NULL)
3941
0
    g_ptr_array_unref(priv->protocols);
3942
0
  if (priv->instance_ids != NULL)
3943
0
    g_ptr_array_unref(priv->instance_ids);
3944
0
  if (priv->icons != NULL)
3945
0
    g_ptr_array_unref(priv->icons);
3946
0
  if (priv->checksums != NULL)
3947
0
    g_ptr_array_unref(priv->checksums);
3948
0
  if (priv->children != NULL)
3949
0
    g_ptr_array_unref(priv->children);
3950
0
  if (priv->releases != NULL)
3951
0
    g_ptr_array_unref(priv->releases);
3952
0
  if (priv->issues != NULL)
3953
0
    g_ptr_array_unref(priv->issues);
3954
3955
0
  G_OBJECT_CLASS(fwupd_device_parent_class)->finalize(object);
3956
0
}
3957
3958
static void
3959
fwupd_device_from_variant_iter(FwupdCodec *codec, GVariantIter *iter)
3960
0
{
3961
0
  FwupdDevice *self = FWUPD_DEVICE(codec);
3962
0
  GVariant *value;
3963
0
  const gchar *key;
3964
0
  while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
3965
0
    fwupd_device_from_key_value(self, key, value);
3966
0
    g_variant_unref(value);
3967
0
  }
3968
0
}
3969
3970
static void
3971
fwupd_device_codec_iface_init(FwupdCodecInterface *iface)
3972
0
{
3973
0
  iface->add_string = fwupd_device_add_string;
3974
0
  iface->add_json = fwupd_device_add_json;
3975
0
  iface->from_json = fwupd_device_from_json;
3976
0
  iface->add_variant = fwupd_device_add_variant;
3977
0
  iface->from_variant_iter = fwupd_device_from_variant_iter;
3978
0
}
3979
3980
/**
3981
 * fwupd_device_array_ensure_parents:
3982
 * @devices: (not nullable) (element-type FwupdDevice): devices
3983
 *
3984
 * Sets the parent object on all devices in the array using the parent ID.
3985
 *
3986
 * Since: 1.3.7
3987
 **/
3988
void
3989
fwupd_device_array_ensure_parents(GPtrArray *devices)
3990
0
{
3991
0
  g_autoptr(GHashTable) devices_by_id = NULL;
3992
3993
0
  g_return_if_fail(devices != NULL);
3994
3995
  /* create hash of ID->FwupdDevice */
3996
0
  devices_by_id = g_hash_table_new(g_str_hash, g_str_equal);
3997
0
  for (guint i = 0; i < devices->len; i++) {
3998
0
    FwupdDevice *dev = g_ptr_array_index(devices, i);
3999
0
    if (fwupd_device_get_id(dev) == NULL)
4000
0
      continue;
4001
0
    g_hash_table_insert(devices_by_id,
4002
0
            (gpointer)fwupd_device_get_id(dev),
4003
0
            (gpointer)dev);
4004
0
  }
4005
4006
  /* set the parent on each child */
4007
0
  for (guint i = 0; i < devices->len; i++) {
4008
0
    FwupdDevice *dev = g_ptr_array_index(devices, i);
4009
0
    const gchar *parent_id = fwupd_device_get_parent_id(dev);
4010
0
    if (parent_id != NULL) {
4011
0
      FwupdDevice *dev_tmp;
4012
0
      dev_tmp = g_hash_table_lookup(devices_by_id, parent_id);
4013
0
      if (dev_tmp != NULL)
4014
0
        fwupd_device_set_parent(dev, dev_tmp);
4015
0
    }
4016
0
  }
4017
0
}
4018
4019
/**
4020
 * fwupd_device_compare:
4021
 * @self1: (not nullable): a device
4022
 * @self2: (not nullable): a different device
4023
 *
4024
 * Comparison function for comparing two device objects.
4025
 *
4026
 * Returns: negative, 0 or positive
4027
 *
4028
 * Since: 1.1.1
4029
 **/
4030
gint
4031
fwupd_device_compare(FwupdDevice *self1, FwupdDevice *self2)
4032
0
{
4033
0
  FwupdDevicePrivate *priv1 = GET_PRIVATE(self1);
4034
0
  FwupdDevicePrivate *priv2 = GET_PRIVATE(self2);
4035
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self1), 0);
4036
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self2), 0);
4037
0
  return g_strcmp0(priv1->id, priv2->id);
4038
0
}
4039
4040
/**
4041
 * fwupd_device_match_flags:
4042
 * @include: #FwupdDeviceFlags, or %FWUPD_DEVICE_FLAG_NONE
4043
 * @exclude: #FwupdDeviceFlags, or %FWUPD_DEVICE_FLAG_NONE
4044
 *
4045
 * Check if the device flags match.
4046
 *
4047
 * Returns: %TRUE if the device flags match
4048
 *
4049
 * Since: 1.9.3
4050
 **/
4051
gboolean
4052
fwupd_device_match_flags(FwupdDevice *self, FwupdDeviceFlags include, FwupdDeviceFlags exclude)
4053
0
{
4054
0
  g_return_val_if_fail(FWUPD_IS_DEVICE(self), FALSE);
4055
4056
0
  for (guint i = 0; i < 64; i++) {
4057
0
    FwupdDeviceFlags flag = 1LLU << i;
4058
0
    if ((include & flag) > 0) {
4059
0
      if (!fwupd_device_has_flag(self, flag))
4060
0
        return FALSE;
4061
0
    }
4062
0
    if ((exclude & flag) > 0) {
4063
0
      if (fwupd_device_has_flag(self, flag))
4064
0
        return FALSE;
4065
0
    }
4066
0
  }
4067
0
  return TRUE;
4068
0
}
4069
4070
/**
4071
 * fwupd_device_array_filter_flags:
4072
 * @devices: (not nullable) (element-type FwupdDevice): devices
4073
 * @include: #FwupdDeviceFlags, or %FWUPD_DEVICE_FLAG_NONE
4074
 * @exclude: #FwupdDeviceFlags, or %FWUPD_DEVICE_FLAG_NONE
4075
 * @error: (nullable): optional return location for an error
4076
 *
4077
 * Creates an array of new devices that match using fwupd_device_match_flags().
4078
 *
4079
 * Returns: (transfer container) (element-type FwupdDevice): devices
4080
 *
4081
 * Since: 1.9.3
4082
 **/
4083
GPtrArray *
4084
fwupd_device_array_filter_flags(GPtrArray *devices,
4085
        FwupdDeviceFlags include,
4086
        FwupdDeviceFlags exclude,
4087
        GError **error)
4088
0
{
4089
0
  g_autoptr(GPtrArray) devices_filtered =
4090
0
      g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
4091
4092
0
  g_return_val_if_fail(devices != NULL, NULL);
4093
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
4094
4095
0
  for (guint i = 0; i < devices->len; i++) {
4096
0
    FwupdDevice *device = g_ptr_array_index(devices, i);
4097
0
    if (!fwupd_device_match_flags(device, include, exclude))
4098
0
      continue;
4099
0
    g_ptr_array_add(devices_filtered, g_object_ref(device));
4100
0
  }
4101
0
  if (devices_filtered->len == 0) {
4102
0
    g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "no devices");
4103
0
    return NULL;
4104
0
  }
4105
0
  return g_steal_pointer(&devices_filtered);
4106
0
}
4107
4108
/**
4109
 * fwupd_device_new:
4110
 *
4111
 * Creates a new device.
4112
 *
4113
 * Returns: a new #FwupdDevice
4114
 *
4115
 * Since: 0.9.3
4116
 **/
4117
FwupdDevice *
4118
fwupd_device_new(void)
4119
0
{
4120
0
  FwupdDevice *self;
4121
0
  self = g_object_new(FWUPD_TYPE_DEVICE, NULL);
4122
0
  return FWUPD_DEVICE(self);
4123
0
}