Coverage Report

Created: 2026-06-10 07:04

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