Coverage Report

Created: 2025-08-03 06:57

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