Coverage Report

Created: 2026-01-09 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupd/fwupd-report.c
Line
Count
Source
1
/*
2
 * Copyright 2022 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-enums-private.h"
15
#include "fwupd-json-array.h"
16
#include "fwupd-report.h"
17
18
/**
19
 * FwupdReport:
20
 *
21
 * A firmware report from a vendor.
22
 *
23
 * This is the LVFS formatted report that the fwupd user consumes, NOT the thing that gets uploaded.
24
 *
25
 * See also: [class@FwupdRelease]
26
 */
27
28
typedef struct {
29
  guint64 created;
30
  gchar *version_old;
31
  gchar *vendor;
32
  guint32 vendor_id;
33
  gchar *device_name;
34
  gchar *distro_id;
35
  gchar *distro_version;
36
  GHashTable *metadata;
37
  gchar *distro_variant;
38
  gchar *remote_id;
39
  FwupdReportFlags flags;
40
} FwupdReportPrivate;
41
42
enum { PROP_0, PROP_FLAGS, PROP_LAST };
43
44
static void
45
fwupd_report_codec_iface_init(FwupdCodecInterface *iface);
46
47
0
G_DEFINE_TYPE_EXTENDED(FwupdReport,
48
0
           fwupd_report,
49
0
           G_TYPE_OBJECT,
50
0
           0,
51
0
           G_ADD_PRIVATE(FwupdReport)
52
0
         G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fwupd_report_codec_iface_init));
53
0
54
0
#define GET_PRIVATE(o) (fwupd_report_get_instance_private(o))
55
56
/**
57
 * fwupd_report_get_created:
58
 * @self: a #FwupdReport
59
 *
60
 * Gets when the report was created.
61
 *
62
 * Returns: UTC timestamp in UNIX format, or 0 if unset
63
 *
64
 * Since: 1.8.8
65
 **/
66
guint64
67
fwupd_report_get_created(FwupdReport *self)
68
0
{
69
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
70
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), 0);
71
0
  return priv->created;
72
0
}
73
74
/**
75
 * fwupd_report_set_created:
76
 * @self: a #FwupdReport
77
 * @created: UTC timestamp in UNIX format
78
 *
79
 * Sets when the report was created.
80
 *
81
 * Since: 1.8.8
82
 **/
83
void
84
fwupd_report_set_created(FwupdReport *self, guint64 created)
85
0
{
86
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
87
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
88
0
  priv->created = created;
89
0
}
90
91
/**
92
 * fwupd_report_get_version_old:
93
 * @self: a #FwupdReport
94
 *
95
 * Gets the old version, i.e. what the upser was upgrading *from*.
96
 *
97
 * Returns: the version, or %NULL if unset
98
 *
99
 * Since: 1.8.8
100
 **/
101
const gchar *
102
fwupd_report_get_version_old(FwupdReport *self)
103
0
{
104
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
105
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
106
0
  return priv->version_old;
107
0
}
108
109
/**
110
 * fwupd_report_set_version_old:
111
 * @self: a #FwupdReport
112
 * @version_old: (nullable): the version, e.g. `1.2.3`
113
 *
114
 * Sets the old version, i.e. what the upser was upgrading *from*.
115
 *
116
 * Since: 1.8.8
117
 **/
118
void
119
fwupd_report_set_version_old(FwupdReport *self, const gchar *version_old)
120
0
{
121
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
122
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
123
124
  /* not changed */
125
0
  if (g_strcmp0(priv->version_old, version_old) == 0)
126
0
    return;
127
128
0
  g_free(priv->version_old);
129
0
  priv->version_old = g_strdup(version_old);
130
0
}
131
132
/**
133
 * fwupd_report_get_vendor:
134
 * @self: a #FwupdReport
135
 *
136
 * Gets the vendor that uploaded the test result.
137
 *
138
 * Returns: the test vendor, or %NULL if unset
139
 *
140
 * Since: 1.8.8
141
 **/
142
const gchar *
143
fwupd_report_get_vendor(FwupdReport *self)
144
0
{
145
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
146
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
147
0
  return priv->vendor;
148
0
}
149
150
/**
151
 * fwupd_report_set_vendor:
152
 * @self: a #FwupdReport
153
 * @vendor: (nullable): the vendor name
154
 *
155
 * Sets the vendor that uploaded the test result.
156
 *
157
 * Since: 1.8.8
158
 **/
159
void
160
fwupd_report_set_vendor(FwupdReport *self, const gchar *vendor)
161
0
{
162
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
163
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
164
165
  /* not changed */
166
0
  if (g_strcmp0(priv->vendor, vendor) == 0)
167
0
    return;
168
169
0
  g_free(priv->vendor);
170
0
  priv->vendor = g_strdup(vendor);
171
0
}
172
173
/**
174
 * fwupd_report_get_vendor_id:
175
 * @self: a #FwupdReport
176
 *
177
 * Gets the vendor identifier. The mapping is only known on the remote server, and this can be
178
 * useful to filter on different QA teams that work for the same OEM.
179
 *
180
 * Returns: the vendor ID, or 0 if unset
181
 *
182
 * Since: 1.8.8
183
 **/
184
guint32
185
fwupd_report_get_vendor_id(FwupdReport *self)
186
0
{
187
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
188
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), 0);
189
0
  return priv->vendor_id;
190
0
}
191
192
/**
193
 * fwupd_report_set_vendor_id:
194
 * @self: a #FwupdReport
195
 * @vendor_id: the vendor ID, or 0
196
 *
197
 * Sets the vendor identifier. The mapping is only known on the remote server, and this can be
198
 * useful to filter on different QA teams that work for the same OEM.
199
 *
200
 * Since: 1.8.8
201
 **/
202
void
203
fwupd_report_set_vendor_id(FwupdReport *self, guint32 vendor_id)
204
0
{
205
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
206
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
207
0
  priv->vendor_id = vendor_id;
208
0
}
209
210
/**
211
 * fwupd_report_get_device_name:
212
 * @self: a #FwupdReport
213
 *
214
 * Gets the name of the device the update was performed on.
215
 *
216
 * Returns: the name, or %NULL if unset
217
 *
218
 * Since: 1.8.8
219
 **/
220
const gchar *
221
fwupd_report_get_device_name(FwupdReport *self)
222
0
{
223
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
224
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
225
0
  return priv->device_name;
226
0
}
227
228
/**
229
 * fwupd_report_set_device_name:
230
 * @self: a #FwupdReport
231
 * @device_name: (nullable): the name, e.g. `LENOVO ThinkPad P1 Gen 3`
232
 *
233
 * Sets the name of the device the update was performed on.
234
 *
235
 * Since: 1.8.8
236
 **/
237
void
238
fwupd_report_set_device_name(FwupdReport *self, const gchar *device_name)
239
0
{
240
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
241
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
242
243
  /* not changed */
244
0
  if (g_strcmp0(priv->device_name, device_name) == 0)
245
0
    return;
246
247
0
  g_free(priv->device_name);
248
0
  priv->device_name = g_strdup(device_name);
249
0
}
250
251
/**
252
 * fwupd_report_get_distro_id:
253
 * @self: a #FwupdReport
254
 *
255
 * Gets the distribution name.
256
 *
257
 * Returns: the name, or %NULL if unset
258
 *
259
 * Since: 1.8.8
260
 **/
261
const gchar *
262
fwupd_report_get_distro_id(FwupdReport *self)
263
0
{
264
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
265
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
266
0
  return priv->distro_id;
267
0
}
268
269
/**
270
 * fwupd_report_set_distro_id:
271
 * @self: a #FwupdReport
272
 * @distro_id: (nullable): the name, e.g. `fedora`
273
 *
274
 * Sets the distribution name.
275
 *
276
 * Since: 1.8.8
277
 **/
278
void
279
fwupd_report_set_distro_id(FwupdReport *self, const gchar *distro_id)
280
0
{
281
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
282
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
283
284
  /* not changed */
285
0
  if (g_strcmp0(priv->distro_id, distro_id) == 0)
286
0
    return;
287
288
0
  g_free(priv->distro_id);
289
0
  priv->distro_id = g_strdup(distro_id);
290
0
}
291
292
/**
293
 * fwupd_report_get_distro_variant:
294
 * @self: a #FwupdReport
295
 *
296
 * Gets the distribution variant.
297
 *
298
 * Returns: variant, or %NULL if unset
299
 *
300
 * Since: 1.8.8
301
 **/
302
const gchar *
303
fwupd_report_get_distro_variant(FwupdReport *self)
304
0
{
305
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
306
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
307
0
  return priv->distro_variant;
308
0
}
309
310
/**
311
 * fwupd_report_set_distro_variant:
312
 * @self: a #FwupdReport
313
 * @distro_variant: (nullable): the variant, e.g. `workstation`
314
 *
315
 * Sets the distribution variant.
316
 *
317
 * Since: 1.8.8
318
 **/
319
void
320
fwupd_report_set_distro_variant(FwupdReport *self, const gchar *distro_variant)
321
0
{
322
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
323
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
324
325
  /* not changed */
326
0
  if (g_strcmp0(priv->distro_variant, distro_variant) == 0)
327
0
    return;
328
329
0
  g_free(priv->distro_variant);
330
0
  priv->distro_variant = g_strdup(distro_variant);
331
0
}
332
333
/**
334
 * fwupd_report_get_remote_id:
335
 * @self: a #FwupdReport
336
 *
337
 * Gets the remote ID.
338
 *
339
 * Returns: ID, or %NULL if unset
340
 *
341
 * Since: 1.9.3
342
 **/
343
const gchar *
344
fwupd_report_get_remote_id(FwupdReport *self)
345
0
{
346
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
347
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
348
0
  return priv->remote_id;
349
0
}
350
351
/**
352
 * fwupd_report_set_remote_id:
353
 * @self: a #FwupdReport
354
 * @remote_id: (nullable): the remote, e.g. `lvfs`
355
 *
356
 * Sets the remote ID.
357
 *
358
 * Since: 1.9.3
359
 **/
360
void
361
fwupd_report_set_remote_id(FwupdReport *self, const gchar *remote_id)
362
0
{
363
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
364
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
365
366
  /* not changed */
367
0
  if (g_strcmp0(priv->remote_id, remote_id) == 0)
368
0
    return;
369
370
0
  g_free(priv->remote_id);
371
0
  priv->remote_id = g_strdup(remote_id);
372
0
}
373
374
/**
375
 * fwupd_report_get_distro_version:
376
 * @self: a #FwupdReport
377
 *
378
 * Gets the distribution version.
379
 *
380
 * Returns: a string, or %NULL if unset
381
 *
382
 * Since: 1.8.8
383
 **/
384
const gchar *
385
fwupd_report_get_distro_version(FwupdReport *self)
386
0
{
387
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
388
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
389
0
  return priv->distro_version;
390
0
}
391
392
/**
393
 * fwupd_report_set_distro_version:
394
 * @self: a #FwupdReport
395
 * @distro_version: (nullable): a string
396
 *
397
 * Sets the distribution version.
398
 *
399
 * Since: 1.8.8
400
 **/
401
void
402
fwupd_report_set_distro_version(FwupdReport *self, const gchar *distro_version)
403
0
{
404
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
405
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
406
407
  /* not changed */
408
0
  if (g_strcmp0(priv->distro_version, distro_version) == 0)
409
0
    return;
410
411
0
  g_free(priv->distro_version);
412
0
  priv->distro_version = g_strdup(distro_version);
413
0
}
414
415
/**
416
 * fwupd_report_get_metadata:
417
 * @self: a #FwupdReport
418
 *
419
 * Gets the report metadata.
420
 *
421
 * Returns: (transfer none): the metadata, which may be empty
422
 *
423
 * Since: 1.8.8
424
 **/
425
GHashTable *
426
fwupd_report_get_metadata(FwupdReport *self)
427
0
{
428
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
429
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
430
0
  return priv->metadata;
431
0
}
432
433
/**
434
 * fwupd_report_add_metadata_item:
435
 * @self: a #FwupdReport
436
 * @key: (not nullable): the key
437
 * @value: (not nullable): the value
438
 *
439
 * Sets a report metadata item.
440
 *
441
 * Since: 1.8.8
442
 **/
443
void
444
fwupd_report_add_metadata_item(FwupdReport *self, const gchar *key, const gchar *value)
445
0
{
446
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
447
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
448
0
  g_return_if_fail(key != NULL);
449
0
  g_return_if_fail(value != NULL);
450
0
  g_hash_table_insert(priv->metadata, g_strdup(key), g_strdup(value));
451
0
}
452
453
/**
454
 * fwupd_report_get_metadata_item:
455
 * @self: a #FwupdReport
456
 * @key: (not nullable): the key
457
 *
458
 * Gets a report metadata item.
459
 *
460
 * Returns: the value, or %NULL if unset
461
 *
462
 * Since: 1.8.8
463
 **/
464
const gchar *
465
fwupd_report_get_metadata_item(FwupdReport *self, const gchar *key)
466
0
{
467
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
468
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), NULL);
469
0
  g_return_val_if_fail(key != NULL, NULL);
470
0
  return g_hash_table_lookup(priv->metadata, key);
471
0
}
472
473
static void
474
fwupd_report_add_variant(FwupdCodec *codec, GVariantBuilder *builder, FwupdCodecFlags flags)
475
0
{
476
0
  FwupdReport *self = FWUPD_REPORT(codec);
477
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
478
479
0
  if (priv->distro_id != NULL) {
480
0
    g_variant_builder_add(builder,
481
0
              "{sv}",
482
0
              FWUPD_RESULT_KEY_DISTRO_ID,
483
0
              g_variant_new_string(priv->distro_id));
484
0
  }
485
0
  if (priv->distro_variant != NULL) {
486
0
    g_variant_builder_add(builder,
487
0
              "{sv}",
488
0
              FWUPD_RESULT_KEY_DISTRO_VARIANT,
489
0
              g_variant_new_string(priv->distro_variant));
490
0
  }
491
0
  if (priv->distro_version != NULL) {
492
0
    g_variant_builder_add(builder,
493
0
              "{sv}",
494
0
              FWUPD_RESULT_KEY_DISTRO_VERSION,
495
0
              g_variant_new_string(priv->distro_version));
496
0
  }
497
0
  if (priv->vendor != NULL) {
498
0
    g_variant_builder_add(builder,
499
0
              "{sv}",
500
0
              FWUPD_RESULT_KEY_VENDOR,
501
0
              g_variant_new_string(priv->vendor));
502
0
  }
503
0
  if (priv->device_name != NULL) {
504
0
    g_variant_builder_add(builder,
505
0
              "{sv}",
506
0
              FWUPD_RESULT_KEY_DEVICE_NAME,
507
0
              g_variant_new_string(priv->device_name));
508
0
  }
509
0
  if (priv->created != 0) {
510
0
    g_variant_builder_add(builder,
511
0
              "{sv}",
512
0
              FWUPD_RESULT_KEY_CREATED,
513
0
              g_variant_new_uint64(priv->created));
514
0
  }
515
0
  if (priv->version_old != NULL) {
516
0
    g_variant_builder_add(builder,
517
0
              "{sv}",
518
0
              FWUPD_RESULT_KEY_VERSION_OLD,
519
0
              g_variant_new_string(priv->version_old));
520
0
  }
521
0
  if (priv->vendor_id > 0) {
522
0
    g_variant_builder_add(builder,
523
0
              "{sv}",
524
0
              FWUPD_RESULT_KEY_VENDOR_ID,
525
0
              g_variant_new_uint32(priv->vendor_id));
526
0
  }
527
0
  if (priv->remote_id != NULL) {
528
0
    g_variant_builder_add(builder,
529
0
              "{sv}",
530
0
              FWUPD_RESULT_KEY_REMOTE_ID,
531
0
              g_variant_new_string(priv->remote_id));
532
0
  }
533
0
  if (g_hash_table_size(priv->metadata) > 0) {
534
0
    g_variant_builder_add(builder,
535
0
              "{sv}",
536
0
              FWUPD_RESULT_KEY_METADATA,
537
0
              fwupd_hash_kv_to_variant(priv->metadata));
538
0
  }
539
0
  if (priv->flags > 0) {
540
0
    g_variant_builder_add(builder,
541
0
              "{sv}",
542
0
              FWUPD_RESULT_KEY_FLAGS,
543
0
              g_variant_new_uint64(priv->flags));
544
0
  }
545
0
}
546
547
static void
548
fwupd_report_from_key_value(FwupdReport *self, const gchar *key, GVariant *value)
549
0
{
550
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
551
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DISTRO_ID) == 0) {
552
0
    fwupd_report_set_distro_id(self, g_variant_get_string(value, NULL));
553
0
    return;
554
0
  }
555
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DISTRO_VARIANT) == 0) {
556
0
    fwupd_report_set_distro_variant(self, g_variant_get_string(value, NULL));
557
0
    return;
558
0
  }
559
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DISTRO_VERSION) == 0) {
560
0
    fwupd_report_set_distro_version(self, g_variant_get_string(value, NULL));
561
0
    return;
562
0
  }
563
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR) == 0) {
564
0
    fwupd_report_set_vendor(self, g_variant_get_string(value, NULL));
565
0
    return;
566
0
  }
567
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR_ID) == 0) {
568
0
    fwupd_report_set_vendor_id(self, g_variant_get_uint32(value));
569
0
    return;
570
0
  }
571
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DEVICE_NAME) == 0) {
572
0
    fwupd_report_set_device_name(self, g_variant_get_string(value, NULL));
573
0
    return;
574
0
  }
575
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_CREATED) == 0) {
576
0
    fwupd_report_set_created(self, g_variant_get_uint64(value));
577
0
    return;
578
0
  }
579
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION_OLD) == 0) {
580
0
    fwupd_report_set_version_old(self, g_variant_get_string(value, NULL));
581
0
    return;
582
0
  }
583
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_REMOTE_ID) == 0) {
584
0
    fwupd_report_set_remote_id(self, g_variant_get_string(value, NULL));
585
0
    return;
586
0
  }
587
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_FLAGS) == 0) {
588
0
    fwupd_report_set_flags(self, g_variant_get_uint64(value));
589
0
    return;
590
0
  }
591
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_METADATA) == 0) {
592
0
    g_hash_table_unref(priv->metadata);
593
0
    priv->metadata = fwupd_variant_to_hash_kv(value);
594
0
    return;
595
0
  }
596
0
}
597
598
static void
599
fwupd_report_add_json(FwupdCodec *codec, FwupdJsonObject *json_obj, FwupdCodecFlags flags)
600
0
{
601
0
  FwupdReport *self = FWUPD_REPORT(codec);
602
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
603
0
  g_autoptr(GList) keys = NULL;
604
605
0
  if (priv->device_name != NULL) {
606
0
    fwupd_json_object_add_string(json_obj,
607
0
               FWUPD_RESULT_KEY_DEVICE_NAME,
608
0
               priv->device_name);
609
0
  }
610
0
  if (priv->distro_id != NULL)
611
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_DISTRO_ID, priv->distro_id);
612
0
  if (priv->distro_variant != NULL) {
613
0
    fwupd_json_object_add_string(json_obj,
614
0
               FWUPD_RESULT_KEY_DISTRO_VARIANT,
615
0
               priv->distro_variant);
616
0
  }
617
0
  if (priv->distro_version != NULL) {
618
0
    fwupd_json_object_add_string(json_obj,
619
0
               FWUPD_RESULT_KEY_DISTRO_VERSION,
620
0
               priv->distro_version);
621
0
  }
622
0
  if (priv->version_old != NULL) {
623
0
    fwupd_json_object_add_string(json_obj,
624
0
               FWUPD_RESULT_KEY_VERSION_OLD,
625
0
               priv->version_old);
626
0
  }
627
0
  if (priv->vendor != NULL)
628
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
629
0
  if (priv->remote_id != NULL)
630
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
631
0
  if (priv->vendor_id > 0) {
632
0
    fwupd_json_object_add_integer(json_obj,
633
0
                FWUPD_RESULT_KEY_VENDOR_ID,
634
0
                priv->vendor_id);
635
0
  }
636
637
0
  if (priv->flags != FWUPD_REPORT_FLAG_NONE) {
638
0
    g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
639
0
    for (guint i = 0; i < 64; i++) {
640
0
      const gchar *tmp;
641
0
      if ((priv->flags & ((guint64)1 << i)) == 0)
642
0
        continue;
643
0
      tmp = fwupd_report_flag_to_string((guint64)1 << i);
644
0
      fwupd_json_array_add_string(json_arr, tmp);
645
0
    }
646
0
    fwupd_json_object_add_array(json_obj, FWUPD_RESULT_KEY_FLAGS, json_arr);
647
0
  }
648
649
  /* metadata */
650
0
  keys = g_hash_table_get_keys(priv->metadata);
651
0
  for (GList *l = keys; l != NULL; l = l->next) {
652
0
    const gchar *key = l->data;
653
0
    const gchar *value = g_hash_table_lookup(priv->metadata, key);
654
0
    fwupd_json_object_add_string(json_obj, key, value);
655
0
  }
656
0
}
657
658
static void
659
fwupd_report_string_append_flags(GString *str, guint idt, const gchar *key, guint64 report_flags)
660
0
{
661
0
  g_autoptr(GString) tmp = g_string_new("");
662
0
  for (guint i = 0; i < 64; i++) {
663
0
    if ((report_flags & ((guint64)1 << i)) == 0)
664
0
      continue;
665
0
    g_string_append_printf(tmp, "%s|", fwupd_report_flag_to_string((guint64)1 << i));
666
0
  }
667
0
  if (tmp->len == 0) {
668
0
    g_string_append(tmp, fwupd_report_flag_to_string(0));
669
0
  } else {
670
0
    g_string_truncate(tmp, tmp->len - 1);
671
0
  }
672
0
  fwupd_codec_string_append(str, idt, key, tmp->str);
673
0
}
674
675
static void
676
fwupd_report_add_string(FwupdCodec *codec, guint idt, GString *str)
677
0
{
678
0
  FwupdReport *self = FWUPD_REPORT(codec);
679
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
680
0
  g_autoptr(GList) keys = NULL;
681
682
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DEVICE_NAME, priv->device_name);
683
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DISTRO_ID, priv->distro_id);
684
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DISTRO_VARIANT, priv->distro_variant);
685
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DISTRO_VERSION, priv->distro_version);
686
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VERSION_OLD, priv->version_old);
687
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
688
0
  fwupd_codec_string_append_int(str, idt, FWUPD_RESULT_KEY_VENDOR_ID, priv->vendor_id);
689
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
690
0
  fwupd_report_string_append_flags(str, idt, FWUPD_RESULT_KEY_FLAGS, priv->flags);
691
692
  /* metadata */
693
0
  keys = g_hash_table_get_keys(priv->metadata);
694
0
  for (GList *l = keys; l != NULL; l = l->next) {
695
0
    const gchar *key = l->data;
696
0
    const gchar *value = g_hash_table_lookup(priv->metadata, key);
697
0
    fwupd_codec_string_append(str, idt, key, value);
698
0
  }
699
0
}
700
701
/**
702
 * fwupd_report_get_flags:
703
 * @self: a #FwupdReport
704
 *
705
 * Gets the report flags.
706
 *
707
 * Returns: report flags, or 0 if unset
708
 *
709
 * Since: 1.9.1
710
 **/
711
guint64
712
fwupd_report_get_flags(FwupdReport *self)
713
0
{
714
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
715
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), 0);
716
0
  return priv->flags;
717
0
}
718
719
/**
720
 * fwupd_report_set_flags:
721
 * @self: a #FwupdReport
722
 * @flags: report flags, e.g. %FWUPD_REPORT_FLAG_FROM_OEM
723
 *
724
 * Sets the report flags.
725
 *
726
 * Since: 1.9.1
727
 **/
728
void
729
fwupd_report_set_flags(FwupdReport *self, guint64 flags)
730
0
{
731
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
732
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
733
0
  if (priv->flags == flags)
734
0
    return;
735
0
  priv->flags = flags;
736
0
  g_object_notify(G_OBJECT(self), "flags");
737
0
}
738
739
/**
740
 * fwupd_report_add_flag:
741
 * @self: a #FwupdReport
742
 * @flag: the #FwupdReportFlags
743
 *
744
 * Adds a specific report flag to the report.
745
 *
746
 * Since: 1.9.1
747
 **/
748
void
749
fwupd_report_add_flag(FwupdReport *self, FwupdReportFlags flag)
750
0
{
751
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
752
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
753
0
  if (flag == 0)
754
0
    return;
755
0
  if ((priv->flags & flag) > 0)
756
0
    return;
757
0
  priv->flags |= flag;
758
0
  g_object_notify(G_OBJECT(self), "flags");
759
0
}
760
761
/**
762
 * fwupd_report_remove_flag:
763
 * @self: a #FwupdReport
764
 * @flag: a report flag
765
 *
766
 * Removes a specific report flag from the report.
767
 *
768
 * Since: 1.9.1
769
 **/
770
void
771
fwupd_report_remove_flag(FwupdReport *self, FwupdReportFlags flag)
772
0
{
773
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
774
0
  g_return_if_fail(FWUPD_IS_REPORT(self));
775
0
  if (flag == 0)
776
0
    return;
777
0
  if ((priv->flags & flag) == 0)
778
0
    return;
779
0
  priv->flags &= ~flag;
780
0
  g_object_notify(G_OBJECT(self), "flags");
781
0
}
782
783
/**
784
 * fwupd_report_has_flag:
785
 * @self: a #FwupdReport
786
 * @flag: a report flag
787
 *
788
 * Finds if the report has a specific report flag.
789
 *
790
 * Returns: %TRUE if the flag is set
791
 *
792
 * Since: 1.9.1
793
 **/
794
gboolean
795
fwupd_report_has_flag(FwupdReport *self, FwupdReportFlags flag)
796
0
{
797
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
798
0
  g_return_val_if_fail(FWUPD_IS_REPORT(self), FALSE);
799
0
  return (priv->flags & flag) > 0;
800
0
}
801
802
static void
803
fwupd_report_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
804
0
{
805
0
  FwupdReport *self = FWUPD_REPORT(object);
806
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
807
0
  switch (prop_id) {
808
0
  case PROP_FLAGS:
809
0
    g_value_set_uint64(value, priv->flags);
810
0
    break;
811
0
  default:
812
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
813
0
    break;
814
0
  }
815
0
}
816
817
static void
818
fwupd_report_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
819
0
{
820
0
  FwupdReport *self = FWUPD_REPORT(object);
821
0
  switch (prop_id) {
822
0
  case PROP_FLAGS:
823
0
    fwupd_report_set_flags(self, g_value_get_uint64(value));
824
0
    break;
825
0
  default:
826
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
827
0
    break;
828
0
  }
829
0
}
830
831
static void
832
fwupd_report_init(FwupdReport *self)
833
0
{
834
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
835
0
  priv->metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
836
0
}
837
838
static void
839
fwupd_report_finalize(GObject *object)
840
0
{
841
0
  FwupdReport *self = FWUPD_REPORT(object);
842
0
  FwupdReportPrivate *priv = GET_PRIVATE(self);
843
844
0
  g_free(priv->vendor);
845
0
  g_free(priv->device_name);
846
0
  g_free(priv->distro_id);
847
0
  g_free(priv->distro_version);
848
0
  g_free(priv->distro_variant);
849
0
  g_free(priv->remote_id);
850
0
  g_free(priv->version_old);
851
0
  g_hash_table_unref(priv->metadata);
852
853
0
  G_OBJECT_CLASS(fwupd_report_parent_class)->finalize(object);
854
0
}
855
856
static void
857
fwupd_report_class_init(FwupdReportClass *klass)
858
0
{
859
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
860
0
  GParamSpec *pspec;
861
862
0
  object_class->finalize = fwupd_report_finalize;
863
0
  object_class->get_property = fwupd_report_get_property;
864
0
  object_class->set_property = fwupd_report_set_property;
865
866
  /**
867
   * FwupdReport:flags:
868
   *
869
   * The report flags.
870
   *
871
   * Since: 1.9.1
872
   */
873
0
  pspec = g_param_spec_uint64("flags",
874
0
            NULL,
875
0
            NULL,
876
0
            FWUPD_REPORT_FLAG_NONE,
877
0
            FWUPD_REPORT_FLAG_UNKNOWN,
878
0
            FWUPD_REPORT_FLAG_NONE,
879
0
            G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
880
0
  g_object_class_install_property(object_class, PROP_FLAGS, pspec);
881
0
}
882
883
static void
884
fwupd_report_from_variant_iter(FwupdCodec *codec, GVariantIter *iter)
885
0
{
886
0
  FwupdReport *self = FWUPD_REPORT(codec);
887
0
  GVariant *value;
888
0
  const gchar *key;
889
0
  while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
890
0
    fwupd_report_from_key_value(self, key, value);
891
0
    g_variant_unref(value);
892
0
  }
893
0
}
894
895
static void
896
fwupd_report_codec_iface_init(FwupdCodecInterface *iface)
897
0
{
898
0
  iface->add_string = fwupd_report_add_string;
899
0
  iface->add_json = fwupd_report_add_json;
900
0
  iface->add_variant = fwupd_report_add_variant;
901
0
  iface->from_variant_iter = fwupd_report_from_variant_iter;
902
0
}
903
904
/**
905
 * fwupd_report_new:
906
 *
907
 * Creates a new report.
908
 *
909
 * Returns: a new #FwupdReport
910
 *
911
 * Since: 1.8.8
912
 **/
913
FwupdReport *
914
fwupd_report_new(void)
915
0
{
916
0
  FwupdReport *self;
917
0
  self = g_object_new(FWUPD_TYPE_REPORT, NULL);
918
0
  return FWUPD_REPORT(self);
919
0
}