Coverage Report

Created: 2026-07-16 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupd/fwupd-release.c
Line
Count
Source
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-enums-private.h"
15
#include "fwupd-error.h"
16
#include "fwupd-json-array.h"
17
#include "fwupd-release.h"
18
#include "fwupd-report.h"
19
#include "fwupd-variant.h"
20
21
/**
22
 * FwupdRelease:
23
 *
24
 * A firmware release with a specific version.
25
 *
26
 * Devices can have more than one release, and the releases are typically
27
 * ordered by their version.
28
 *
29
 * See also: [class@FwupdDevice]
30
 */
31
32
static void
33
fwupd_release_finalize(GObject *object);
34
35
typedef struct {
36
  GPtrArray *checksums;  /* (nullable) (element-type utf-8) */
37
  GPtrArray *tags;       /* (nullable) (element-type utf-8) */
38
  GPtrArray *categories; /* (nullable) (element-type utf-8) */
39
  GPtrArray *issues;     /* (nullable) (element-type utf-8) */
40
  GHashTable *metadata;  /* (nullable) (element-type utf-8 utf-8) */
41
  gchar *description;
42
  gchar *filename;
43
  gchar *protocol;
44
  gchar *homepage;
45
  gchar *details_url;
46
  gchar *source_url;
47
  gchar *sbom_url;
48
  gchar *appstream_id;
49
  gchar *id;
50
  gchar *detach_caption;
51
  gchar *detach_image;
52
  gchar *license;
53
  gchar *name;
54
  gchar *name_variant_suffix;
55
  gchar *summary;
56
  gchar *branch;
57
  GPtrArray *locations; /* (nullable) (element-type utf-8) */
58
  gchar *vendor;
59
  gchar *version;
60
  gchar *remote_id;
61
  guint64 size;
62
  guint64 created;
63
  guint32 install_duration;
64
  FwupdReleaseFlags flags;
65
  FwupdReleaseUrgency urgency;
66
  gchar *update_message;
67
  gchar *update_image;
68
  GPtrArray *reports; /* (nullable) (element-type FwupdReport) */
69
} FwupdReleasePrivate;
70
71
enum { PROP_0, PROP_REMOTE_ID, PROP_LAST };
72
73
static void
74
fwupd_release_codec_iface_init(FwupdCodecInterface *iface);
75
76
0
G_DEFINE_TYPE_EXTENDED(FwupdRelease,
77
0
           fwupd_release,
78
0
           G_TYPE_OBJECT,
79
0
           0,
80
0
           G_ADD_PRIVATE(FwupdRelease)
81
0
         G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fwupd_release_codec_iface_init));
82
0
83
0
#define GET_PRIVATE(o) (fwupd_release_get_instance_private(o))
84
85
/**
86
 * fwupd_release_get_remote_id:
87
 * @self: a #FwupdRelease
88
 *
89
 * Gets the remote ID that can be used for downloading.
90
 *
91
 * Returns: the ID, or %NULL if unset
92
 *
93
 * Since: 0.9.3
94
 **/
95
const gchar *
96
fwupd_release_get_remote_id(FwupdRelease *self)
97
0
{
98
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
99
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
100
0
  return priv->remote_id;
101
0
}
102
103
/**
104
 * fwupd_release_set_remote_id:
105
 * @self: a #FwupdRelease
106
 * @remote_id: the release ID, e.g. `USB:foo`
107
 *
108
 * Sets the remote ID that can be used for downloading.
109
 *
110
 * Since: 0.9.3
111
 **/
112
void
113
fwupd_release_set_remote_id(FwupdRelease *self, const gchar *remote_id)
114
0
{
115
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
116
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
117
118
  /* not changed */
119
0
  if (g_strcmp0(priv->remote_id, remote_id) == 0)
120
0
    return;
121
122
0
  g_free(priv->remote_id);
123
0
  priv->remote_id = g_strdup(remote_id);
124
0
  g_object_notify(G_OBJECT(self), "remote-id");
125
0
}
126
127
/**
128
 * fwupd_release_get_version:
129
 * @self: a #FwupdRelease
130
 *
131
 * Gets the update version.
132
 *
133
 * Returns: the update version, or %NULL if unset
134
 *
135
 * Since: 0.9.3
136
 **/
137
const gchar *
138
fwupd_release_get_version(FwupdRelease *self)
139
0
{
140
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
141
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
142
0
  return priv->version;
143
0
}
144
145
/**
146
 * fwupd_release_set_version:
147
 * @self: a #FwupdRelease
148
 * @version: (nullable): the update version, e.g. `1.2.4`
149
 *
150
 * Sets the update version.
151
 *
152
 * Since: 0.9.3
153
 **/
154
void
155
fwupd_release_set_version(FwupdRelease *self, const gchar *version)
156
0
{
157
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
158
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
159
160
  /* not changed */
161
0
  if (g_strcmp0(priv->version, version) == 0)
162
0
    return;
163
164
0
  g_free(priv->version);
165
0
  priv->version = g_strdup(version);
166
0
}
167
168
/**
169
 * fwupd_release_get_filename:
170
 * @self: a #FwupdRelease
171
 *
172
 * Gets the update filename.
173
 *
174
 * Returns: the update filename, or %NULL if unset
175
 *
176
 * Since: 0.9.3
177
 **/
178
const gchar *
179
fwupd_release_get_filename(FwupdRelease *self)
180
0
{
181
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
182
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
183
0
  return priv->filename;
184
0
}
185
186
/**
187
 * fwupd_release_set_filename:
188
 * @self: a #FwupdRelease
189
 * @filename: (nullable): the update filename on disk
190
 *
191
 * Sets the update filename.
192
 *
193
 * Since: 0.9.3
194
 **/
195
void
196
fwupd_release_set_filename(FwupdRelease *self, const gchar *filename)
197
0
{
198
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
199
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
200
201
  /* not changed */
202
0
  if (g_strcmp0(priv->filename, filename) == 0)
203
0
    return;
204
205
0
  g_free(priv->filename);
206
0
  priv->filename = g_strdup(filename);
207
0
}
208
209
/**
210
 * fwupd_release_get_update_message:
211
 * @self: a #FwupdRelease
212
 *
213
 * Gets the update message.
214
 *
215
 * Returns: the update message, or %NULL if unset
216
 *
217
 * Since: 1.2.4
218
 **/
219
const gchar *
220
fwupd_release_get_update_message(FwupdRelease *self)
221
0
{
222
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
223
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
224
0
  return priv->update_message;
225
0
}
226
227
/**
228
 * fwupd_release_set_update_message:
229
 * @self: a #FwupdRelease
230
 * @update_message: (nullable): the update message string
231
 *
232
 * Sets the update message.
233
 *
234
 * Since: 1.2.4
235
 **/
236
void
237
fwupd_release_set_update_message(FwupdRelease *self, const gchar *update_message)
238
0
{
239
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
240
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
241
242
  /* not changed */
243
0
  if (g_strcmp0(priv->update_message, update_message) == 0)
244
0
    return;
245
246
0
  g_free(priv->update_message);
247
0
  priv->update_message = g_strdup(update_message);
248
0
}
249
250
/**
251
 * fwupd_release_get_update_image:
252
 * @self: a #FwupdRelease
253
 *
254
 * Gets the update image.
255
 *
256
 * Returns: the update image URL, or %NULL if unset
257
 *
258
 * Since: 1.4.5
259
 **/
260
const gchar *
261
fwupd_release_get_update_image(FwupdRelease *self)
262
0
{
263
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
264
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
265
0
  return priv->update_image;
266
0
}
267
268
/**
269
 * fwupd_release_set_update_image:
270
 * @self: a #FwupdRelease
271
 * @update_image: (nullable): the update image URL
272
 *
273
 * Sets the update image.
274
 *
275
 * Since: 1.4.5
276
 **/
277
void
278
fwupd_release_set_update_image(FwupdRelease *self, const gchar *update_image)
279
0
{
280
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
281
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
282
283
  /* not changed */
284
0
  if (g_strcmp0(priv->update_image, update_image) == 0)
285
0
    return;
286
287
0
  g_free(priv->update_image);
288
0
  priv->update_image = g_strdup(update_image);
289
0
}
290
291
/**
292
 * fwupd_release_get_protocol:
293
 * @self: a #FwupdRelease
294
 *
295
 * Gets the update protocol.
296
 *
297
 * Returns: the update protocol, or %NULL if unset
298
 *
299
 * Since: 1.2.2
300
 **/
301
const gchar *
302
fwupd_release_get_protocol(FwupdRelease *self)
303
0
{
304
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
305
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
306
0
  return priv->protocol;
307
0
}
308
309
/**
310
 * fwupd_release_set_protocol:
311
 * @self: a #FwupdRelease
312
 * @protocol: (nullable): the update protocol, e.g. `org.usb.dfu`
313
 *
314
 * Sets the update protocol.
315
 *
316
 * Since: 1.2.2
317
 **/
318
void
319
fwupd_release_set_protocol(FwupdRelease *self, const gchar *protocol)
320
0
{
321
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
322
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
323
324
  /* not changed */
325
0
  if (g_strcmp0(priv->protocol, protocol) == 0)
326
0
    return;
327
328
0
  g_free(priv->protocol);
329
0
  priv->protocol = g_strdup(protocol);
330
0
}
331
332
static void
333
fwupd_release_ensure_issues(FwupdRelease *self)
334
0
{
335
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
336
0
  if (priv->issues == NULL)
337
0
    priv->issues = g_ptr_array_new_with_free_func(g_free);
338
0
}
339
340
/**
341
 * fwupd_release_get_issues:
342
 * @self: a #FwupdRelease
343
 *
344
 * Gets the list of issues fixed in this release.
345
 *
346
 * Returns: (element-type utf8) (transfer none): the issues, which may be empty
347
 *
348
 * Since: 1.3.2
349
 **/
350
GPtrArray *
351
fwupd_release_get_issues(FwupdRelease *self)
352
0
{
353
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
354
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
355
0
  fwupd_release_ensure_issues(self);
356
0
  return priv->issues;
357
0
}
358
359
/**
360
 * fwupd_release_add_issue:
361
 * @self: a #FwupdRelease
362
 * @issue: (not nullable): the update issue, e.g. `CVE-2019-12345`
363
 *
364
 * Adds an resolved issue to this release.
365
 *
366
 * Since: 1.3.2
367
 **/
368
void
369
fwupd_release_add_issue(FwupdRelease *self, const gchar *issue)
370
0
{
371
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
372
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
373
0
  g_return_if_fail(issue != NULL);
374
0
  fwupd_release_ensure_issues(self);
375
0
  for (guint i = 0; i < priv->issues->len; i++) {
376
0
    const gchar *issue_tmp = g_ptr_array_index(priv->issues, i);
377
0
    if (g_strcmp0(issue_tmp, issue) == 0)
378
0
      return;
379
0
  }
380
0
  g_ptr_array_add(priv->issues, g_strdup(issue));
381
0
}
382
383
static void
384
fwupd_release_ensure_categories(FwupdRelease *self)
385
0
{
386
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
387
0
  if (priv->categories == NULL)
388
0
    priv->categories = g_ptr_array_new_with_free_func(g_free);
389
0
}
390
391
/**
392
 * fwupd_release_get_categories:
393
 * @self: a #FwupdRelease
394
 *
395
 * Gets the release categories.
396
 *
397
 * Returns: (element-type utf8) (transfer none): the categories, which may be empty
398
 *
399
 * Since: 1.2.7
400
 **/
401
GPtrArray *
402
fwupd_release_get_categories(FwupdRelease *self)
403
0
{
404
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
405
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
406
0
  fwupd_release_ensure_categories(self);
407
0
  return priv->categories;
408
0
}
409
410
/**
411
 * fwupd_release_add_category:
412
 * @self: a #FwupdRelease
413
 * @category: (not nullable): the update category, e.g. `X-EmbeddedController`
414
 *
415
 * Adds the update category.
416
 *
417
 * Since: 1.2.7
418
 **/
419
void
420
fwupd_release_add_category(FwupdRelease *self, const gchar *category)
421
0
{
422
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
423
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
424
0
  g_return_if_fail(category != NULL);
425
0
  if (fwupd_release_has_category(self, category))
426
0
    return;
427
0
  fwupd_release_ensure_categories(self);
428
0
  g_ptr_array_add(priv->categories, g_strdup(category));
429
0
}
430
431
/**
432
 * fwupd_release_has_category:
433
 * @self: a #FwupdRelease
434
 * @category: (not nullable): the update category, e.g. `X-EmbeddedController`
435
 *
436
 * Finds out if the release has the update category.
437
 *
438
 * Returns: %TRUE if the release matches
439
 *
440
 * Since: 1.2.7
441
 **/
442
gboolean
443
fwupd_release_has_category(FwupdRelease *self, const gchar *category)
444
0
{
445
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
446
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE);
447
0
  g_return_val_if_fail(category != NULL, FALSE);
448
0
  if (priv->categories == NULL)
449
0
    return FALSE;
450
0
  for (guint i = 0; i < priv->categories->len; i++) {
451
0
    const gchar *category_tmp = g_ptr_array_index(priv->categories, i);
452
0
    if (g_strcmp0(category_tmp, category) == 0)
453
0
      return TRUE;
454
0
  }
455
0
  return FALSE;
456
0
}
457
458
static void
459
fwupd_release_ensure_checksums(FwupdRelease *self)
460
0
{
461
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
462
0
  if (priv->checksums == NULL)
463
0
    priv->checksums = g_ptr_array_new_with_free_func(g_free);
464
0
}
465
466
/**
467
 * fwupd_release_get_checksums:
468
 * @self: a #FwupdRelease
469
 *
470
 * Gets the release container checksums.
471
 *
472
 * Returns: (element-type utf8) (transfer none): the checksums, which may be empty
473
 *
474
 * Since: 0.9.3
475
 **/
476
GPtrArray *
477
fwupd_release_get_checksums(FwupdRelease *self)
478
0
{
479
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
480
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
481
0
  fwupd_release_ensure_checksums(self);
482
0
  return priv->checksums;
483
0
}
484
485
/**
486
 * fwupd_release_add_checksum:
487
 * @self: a #FwupdRelease
488
 * @checksum: (not nullable): the update container checksum
489
 *
490
 * Sets the update checksum.
491
 *
492
 * Since: 0.9.3
493
 **/
494
void
495
fwupd_release_add_checksum(FwupdRelease *self, const gchar *checksum)
496
0
{
497
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
498
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
499
0
  g_return_if_fail(checksum != NULL);
500
0
  if (fwupd_release_has_checksum(self, checksum))
501
0
    return;
502
0
  fwupd_release_ensure_checksums(self);
503
0
  g_ptr_array_add(priv->checksums, g_strdup(checksum));
504
0
}
505
506
/**
507
 * fwupd_release_has_checksum:
508
 * @self: a #FwupdRelease
509
 * @checksum: (not nullable): the update checksum
510
 *
511
 * Finds out if the release has the update container checksum.
512
 *
513
 * Returns: %TRUE if the release matches
514
 *
515
 * Since: 1.2.6
516
 **/
517
gboolean
518
fwupd_release_has_checksum(FwupdRelease *self, const gchar *checksum)
519
0
{
520
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
521
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE);
522
0
  g_return_val_if_fail(checksum != NULL, FALSE);
523
0
  if (priv->checksums == NULL)
524
0
    return FALSE;
525
0
  for (guint i = 0; i < priv->checksums->len; i++) {
526
0
    const gchar *checksum_tmp = g_ptr_array_index(priv->checksums, i);
527
0
    if (g_strcmp0(checksum_tmp, checksum) == 0)
528
0
      return TRUE;
529
0
  }
530
0
  return FALSE;
531
0
}
532
533
static void
534
fwupd_release_ensure_tags(FwupdRelease *self)
535
0
{
536
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
537
0
  if (priv->tags == NULL)
538
0
    priv->tags = g_ptr_array_new_with_free_func(g_free);
539
0
}
540
541
/**
542
 * fwupd_release_get_tags:
543
 * @self: a #FwupdRelease
544
 *
545
 * Gets the release tags.
546
 *
547
 * Returns: (element-type utf8) (transfer none): the tags, which may be empty
548
 *
549
 * Since: 1.7.3
550
 **/
551
GPtrArray *
552
fwupd_release_get_tags(FwupdRelease *self)
553
0
{
554
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
555
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
556
0
  fwupd_release_ensure_tags(self);
557
0
  return priv->tags;
558
0
}
559
560
/**
561
 * fwupd_release_add_tag:
562
 * @self: a #FwupdRelease
563
 * @tag: (not nullable): the update tag, e.g. `vendor-factory-2021q1`
564
 *
565
 * Adds a specific release tag.
566
 *
567
 * Since: 1.7.3
568
 **/
569
void
570
fwupd_release_add_tag(FwupdRelease *self, const gchar *tag)
571
0
{
572
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
573
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
574
0
  g_return_if_fail(tag != NULL);
575
0
  if (fwupd_release_has_tag(self, tag))
576
0
    return;
577
0
  fwupd_release_ensure_tags(self);
578
0
  g_ptr_array_add(priv->tags, g_strdup(tag));
579
0
}
580
581
/**
582
 * fwupd_release_has_tag:
583
 * @self: a #FwupdRelease
584
 * @tag: (not nullable): the update tag, e.g. `vendor-factory-2021q1`
585
 *
586
 * Finds out if the release has a specific tag.
587
 *
588
 * Returns: %TRUE if the release matches
589
 *
590
 * Since: 1.7.3
591
 **/
592
gboolean
593
fwupd_release_has_tag(FwupdRelease *self, const gchar *tag)
594
0
{
595
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
596
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE);
597
0
  g_return_val_if_fail(tag != NULL, FALSE);
598
0
  if (priv->tags == NULL)
599
0
    return FALSE;
600
0
  for (guint i = 0; i < priv->tags->len; i++) {
601
0
    const gchar *tag_tmp = g_ptr_array_index(priv->tags, i);
602
0
    if (g_strcmp0(tag_tmp, tag) == 0)
603
0
      return TRUE;
604
0
  }
605
0
  return FALSE;
606
0
}
607
608
static void
609
fwupd_release_ensure_metadata(FwupdRelease *self)
610
0
{
611
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
612
0
  if (priv->metadata == NULL)
613
0
    priv->metadata = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
614
0
}
615
616
/**
617
 * fwupd_release_get_metadata:
618
 * @self: a #FwupdRelease
619
 *
620
 * Gets the release metadata.
621
 *
622
 * Returns: (transfer none): the metadata, which may be empty
623
 *
624
 * Since: 1.0.4
625
 **/
626
GHashTable *
627
fwupd_release_get_metadata(FwupdRelease *self)
628
0
{
629
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
630
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
631
0
  fwupd_release_ensure_metadata(self);
632
0
  return priv->metadata;
633
0
}
634
635
/**
636
 * fwupd_release_add_metadata_item:
637
 * @self: a #FwupdRelease
638
 * @key: (not nullable): the key
639
 * @value: (not nullable): the value
640
 *
641
 * Sets a release metadata item.
642
 *
643
 * Since: 1.0.4
644
 **/
645
void
646
fwupd_release_add_metadata_item(FwupdRelease *self, const gchar *key, const gchar *value)
647
0
{
648
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
649
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
650
0
  g_return_if_fail(key != NULL);
651
0
  g_return_if_fail(value != NULL);
652
0
  fwupd_release_ensure_metadata(self);
653
0
  g_hash_table_insert(priv->metadata, g_strdup(key), g_strdup(value));
654
0
}
655
656
/**
657
 * fwupd_release_add_metadata:
658
 * @self: a #FwupdRelease
659
 * @hash: (not nullable): the key-values
660
 *
661
 * Sets multiple release metadata items.
662
 *
663
 * Since: 1.0.4
664
 **/
665
void
666
fwupd_release_add_metadata(FwupdRelease *self, GHashTable *hash)
667
0
{
668
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
669
0
  g_autoptr(GList) keys = NULL;
670
671
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
672
0
  g_return_if_fail(hash != NULL);
673
674
  /* deep copy the whole map */
675
0
  fwupd_release_ensure_metadata(self);
676
0
  keys = g_list_sort(g_hash_table_get_keys(hash), (GCompareFunc)g_strcmp0);
677
0
  for (GList *l = keys; l != NULL; l = l->next) {
678
0
    const gchar *key = l->data;
679
0
    const gchar *value = g_hash_table_lookup(hash, key);
680
0
    g_hash_table_insert(priv->metadata, g_strdup(key), g_strdup(value));
681
0
  }
682
0
}
683
684
/**
685
 * fwupd_release_get_metadata_item:
686
 * @self: a #FwupdRelease
687
 * @key: (not nullable): the key
688
 *
689
 * Gets a release metadata item.
690
 *
691
 * Returns: the value, or %NULL if unset
692
 *
693
 * Since: 1.0.4
694
 **/
695
const gchar *
696
fwupd_release_get_metadata_item(FwupdRelease *self, const gchar *key)
697
0
{
698
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
699
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
700
0
  g_return_val_if_fail(key != NULL, NULL);
701
0
  if (priv->metadata == NULL)
702
0
    return NULL;
703
0
  return g_hash_table_lookup(priv->metadata, key);
704
0
}
705
706
static void
707
fwupd_release_ensure_locations(FwupdRelease *self)
708
0
{
709
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
710
0
  if (priv->locations == NULL)
711
0
    priv->locations = g_ptr_array_new_with_free_func(g_free);
712
0
}
713
714
/**
715
 * fwupd_release_get_locations:
716
 * @self: a #FwupdRelease
717
 *
718
 * Gets the update URI, i.e. where you can download the firmware from.
719
 *
720
 * Typically the first URI will be the main HTTP mirror, but all URIs may not
721
 * be valid HTTP URIs. For example, "ipns://QmSrPmba" is valid here.
722
 *
723
 * Returns: (element-type utf8) (transfer none): the URIs
724
 *
725
 * Since: 1.5.6
726
 **/
727
GPtrArray *
728
fwupd_release_get_locations(FwupdRelease *self)
729
0
{
730
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
731
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
732
0
  fwupd_release_ensure_locations(self);
733
0
  return priv->locations;
734
0
}
735
736
/**
737
 * fwupd_release_add_location:
738
 * @self: a #FwupdRelease
739
 * @location: (not nullable): the update URI
740
 *
741
 * Adds an update URI, i.e. where you can download the firmware from.
742
 *
743
 * Since: 1.5.6
744
 **/
745
void
746
fwupd_release_add_location(FwupdRelease *self, const gchar *location)
747
0
{
748
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
749
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
750
0
  g_return_if_fail(location != NULL);
751
0
  fwupd_release_ensure_locations(self);
752
0
  for (guint i = 0; i < priv->locations->len; i++) {
753
0
    const gchar *location_tmp = g_ptr_array_index(priv->locations, i);
754
0
    if (g_strcmp0(location_tmp, location) == 0)
755
0
      return;
756
0
  }
757
0
  g_ptr_array_add(priv->locations, g_strdup(location));
758
0
}
759
760
/**
761
 * fwupd_release_get_homepage:
762
 * @self: a #FwupdRelease
763
 *
764
 * Gets the update homepage.
765
 *
766
 * Returns: the update homepage, or %NULL if unset
767
 *
768
 * Since: 0.9.3
769
 **/
770
const gchar *
771
fwupd_release_get_homepage(FwupdRelease *self)
772
0
{
773
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
774
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
775
0
  return priv->homepage;
776
0
}
777
778
/**
779
 * fwupd_release_set_homepage:
780
 * @self: a #FwupdRelease
781
 * @homepage: (nullable): the URL
782
 *
783
 * Sets the update homepage URL.
784
 *
785
 * Since: 0.9.3
786
 **/
787
void
788
fwupd_release_set_homepage(FwupdRelease *self, const gchar *homepage)
789
0
{
790
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
791
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
792
793
  /* not changed */
794
0
  if (g_strcmp0(priv->homepage, homepage) == 0)
795
0
    return;
796
797
0
  g_free(priv->homepage);
798
0
  priv->homepage = g_strdup(homepage);
799
0
}
800
801
/**
802
 * fwupd_release_get_details_url:
803
 * @self: a #FwupdRelease
804
 *
805
 * Gets the URL for the online update notes.
806
 *
807
 * Returns: the update URL, or %NULL if unset
808
 *
809
 * Since: 1.2.4
810
 **/
811
const gchar *
812
fwupd_release_get_details_url(FwupdRelease *self)
813
0
{
814
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
815
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
816
0
  return priv->details_url;
817
0
}
818
819
/**
820
 * fwupd_release_set_details_url:
821
 * @self: a #FwupdRelease
822
 * @details_url: (nullable): the URL
823
 *
824
 * Sets the URL for the online update notes.
825
 *
826
 * Since: 1.2.4
827
 **/
828
void
829
fwupd_release_set_details_url(FwupdRelease *self, const gchar *details_url)
830
0
{
831
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
832
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
833
834
  /* not changed */
835
0
  if (g_strcmp0(priv->details_url, details_url) == 0)
836
0
    return;
837
838
0
  g_free(priv->details_url);
839
0
  priv->details_url = g_strdup(details_url);
840
0
}
841
842
/**
843
 * fwupd_release_get_source_url:
844
 * @self: a #FwupdRelease
845
 *
846
 * Gets the URL of the source code used to build this release.
847
 *
848
 * Returns: the update source_url, or %NULL if unset
849
 *
850
 * Since: 1.2.4
851
 **/
852
const gchar *
853
fwupd_release_get_source_url(FwupdRelease *self)
854
0
{
855
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
856
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
857
0
  return priv->source_url;
858
0
}
859
860
/**
861
 * fwupd_release_set_source_url:
862
 * @self: a #FwupdRelease
863
 * @source_url: (nullable): the URL
864
 *
865
 * Sets the URL of the source code used to build this release.
866
 *
867
 * Since: 1.2.4
868
 **/
869
void
870
fwupd_release_set_source_url(FwupdRelease *self, const gchar *source_url)
871
0
{
872
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
873
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
874
875
  /* not changed */
876
0
  if (g_strcmp0(priv->source_url, source_url) == 0)
877
0
    return;
878
879
0
  g_free(priv->source_url);
880
0
  priv->source_url = g_strdup(source_url);
881
0
}
882
883
/**
884
 * fwupd_release_set_sbom_url:
885
 * @self: a #FwupdRelease
886
 * @sbom_url: (nullable): the URL
887
 *
888
 * Sets the URL of the SBOM for this release.
889
 *
890
 * Since: 2.0.7
891
 **/
892
void
893
fwupd_release_set_sbom_url(FwupdRelease *self, const gchar *sbom_url)
894
0
{
895
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
896
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
897
898
  /* not changed */
899
0
  if (g_strcmp0(priv->sbom_url, sbom_url) == 0)
900
0
    return;
901
902
0
  g_free(priv->sbom_url);
903
0
  priv->sbom_url = g_strdup(sbom_url);
904
0
}
905
906
/**
907
 * fwupd_release_get_sbom_url:
908
 * @self: a #FwupdRelease
909
 *
910
 * Gets the URL of the SBOM for this release.
911
 *
912
 * Returns: a URL, or %NULL if unset
913
 *
914
 * Since: 2.0.7
915
 **/
916
const gchar *
917
fwupd_release_get_sbom_url(FwupdRelease *self)
918
0
{
919
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
920
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
921
0
  return priv->sbom_url;
922
0
}
923
924
/**
925
 * fwupd_release_get_description:
926
 * @self: a #FwupdRelease
927
 *
928
 * Gets the update description in AppStream markup format.
929
 *
930
 * Returns: the update description, or %NULL if unset
931
 *
932
 * Since: 0.9.3
933
 **/
934
const gchar *
935
fwupd_release_get_description(FwupdRelease *self)
936
0
{
937
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
938
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
939
0
  return priv->description;
940
0
}
941
942
/**
943
 * fwupd_release_set_description:
944
 * @self: a #FwupdRelease
945
 * @description: (nullable): the update description in AppStream markup format
946
 *
947
 * Sets the update description.
948
 *
949
 * Since: 0.9.3
950
 **/
951
void
952
fwupd_release_set_description(FwupdRelease *self, const gchar *description)
953
0
{
954
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
955
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
956
957
  /* not changed */
958
0
  if (g_strcmp0(priv->description, description) == 0)
959
0
    return;
960
961
0
  g_free(priv->description);
962
0
  priv->description = g_strdup(description);
963
0
}
964
965
/**
966
 * fwupd_release_get_appstream_id:
967
 * @self: a #FwupdRelease
968
 *
969
 * Gets the AppStream ID.
970
 *
971
 * Returns: the AppStream ID, or %NULL if unset
972
 *
973
 * Since: 0.9.3
974
 **/
975
const gchar *
976
fwupd_release_get_appstream_id(FwupdRelease *self)
977
0
{
978
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
979
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
980
0
  return priv->appstream_id;
981
0
}
982
983
/**
984
 * fwupd_release_set_appstream_id:
985
 * @self: a #FwupdRelease
986
 * @appstream_id: (nullable): the AppStream component ID, e.g. `org.hughski.ColorHug2.firmware`
987
 *
988
 * Sets the AppStream ID.
989
 *
990
 * Since: 0.9.3
991
 **/
992
void
993
fwupd_release_set_appstream_id(FwupdRelease *self, const gchar *appstream_id)
994
0
{
995
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
996
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
997
998
  /* not changed */
999
0
  if (g_strcmp0(priv->appstream_id, appstream_id) == 0)
1000
0
    return;
1001
1002
0
  g_free(priv->appstream_id);
1003
0
  priv->appstream_id = g_strdup(appstream_id);
1004
0
}
1005
1006
/**
1007
 * fwupd_release_get_id:
1008
 * @self: a #FwupdRelease
1009
 *
1010
 * Gets the release ID, which allows identifying the specific uploaded component.
1011
 *
1012
 * Returns: the ID, or %NULL if unset
1013
 *
1014
 * Since: 1.7.2
1015
 **/
1016
const gchar *
1017
fwupd_release_get_id(FwupdRelease *self)
1018
0
{
1019
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1020
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1021
0
  return priv->id;
1022
0
}
1023
1024
/**
1025
 * fwupd_release_set_id:
1026
 * @self: a #FwupdRelease
1027
 * @id: (nullable): the AppStream component ID, e.g. `component:1234`
1028
 *
1029
 * Sets the ID, which allows identifying the specific uploaded component.
1030
 *
1031
 * Since: 1.7.2
1032
 **/
1033
void
1034
fwupd_release_set_id(FwupdRelease *self, const gchar *id)
1035
0
{
1036
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1037
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1038
1039
  /* not changed */
1040
0
  if (g_strcmp0(priv->id, id) == 0)
1041
0
    return;
1042
1043
0
  g_free(priv->id);
1044
0
  priv->id = g_strdup(id);
1045
0
}
1046
1047
/**
1048
 * fwupd_release_get_detach_caption:
1049
 * @self: a #FwupdRelease
1050
 *
1051
 * Gets the optional text caption used to manually detach the device.
1052
 *
1053
 * Returns: the string caption, or %NULL if unset
1054
 *
1055
 * Since: 1.3.3
1056
 **/
1057
const gchar *
1058
fwupd_release_get_detach_caption(FwupdRelease *self)
1059
0
{
1060
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1061
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1062
0
  return priv->detach_caption;
1063
0
}
1064
1065
/**
1066
 * fwupd_release_set_detach_caption:
1067
 * @self: a #FwupdRelease
1068
 * @detach_caption: (nullable): string caption
1069
 *
1070
 * Sets the optional text caption used to manually detach the device.
1071
 *
1072
 * Since: 1.3.3
1073
 **/
1074
void
1075
fwupd_release_set_detach_caption(FwupdRelease *self, const gchar *detach_caption)
1076
0
{
1077
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1078
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1079
1080
  /* not changed */
1081
0
  if (g_strcmp0(priv->detach_caption, detach_caption) == 0)
1082
0
    return;
1083
1084
0
  g_free(priv->detach_caption);
1085
0
  priv->detach_caption = g_strdup(detach_caption);
1086
0
}
1087
1088
/**
1089
 * fwupd_release_get_detach_image:
1090
 * @self: a #FwupdRelease
1091
 *
1092
 * Gets the optional image used to manually detach the device.
1093
 *
1094
 * Returns: the URI, or %NULL if unset
1095
 *
1096
 * Since: 1.3.3
1097
 **/
1098
const gchar *
1099
fwupd_release_get_detach_image(FwupdRelease *self)
1100
0
{
1101
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1102
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1103
0
  return priv->detach_image;
1104
0
}
1105
1106
/**
1107
 * fwupd_release_set_detach_image:
1108
 * @self: a #FwupdRelease
1109
 * @detach_image: (nullable): a fully qualified URI
1110
 *
1111
 * Sets the optional image used to manually detach the device.
1112
 *
1113
 * Since: 1.3.3
1114
 **/
1115
void
1116
fwupd_release_set_detach_image(FwupdRelease *self, const gchar *detach_image)
1117
0
{
1118
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1119
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1120
1121
  /* not changed */
1122
0
  if (g_strcmp0(priv->detach_image, detach_image) == 0)
1123
0
    return;
1124
1125
0
  g_free(priv->detach_image);
1126
0
  priv->detach_image = g_strdup(detach_image);
1127
0
}
1128
1129
/**
1130
 * fwupd_release_get_size:
1131
 * @self: a #FwupdRelease
1132
 *
1133
 * Gets the update size.
1134
 *
1135
 * Returns: the update size in bytes, or 0 if unset
1136
 *
1137
 * Since: 0.9.3
1138
 **/
1139
guint64
1140
fwupd_release_get_size(FwupdRelease *self)
1141
0
{
1142
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1143
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
1144
0
  return priv->size;
1145
0
}
1146
1147
/**
1148
 * fwupd_release_set_size:
1149
 * @self: a #FwupdRelease
1150
 * @size: the update size in bytes
1151
 *
1152
 * Sets the update size.
1153
 *
1154
 * Since: 0.9.3
1155
 **/
1156
void
1157
fwupd_release_set_size(FwupdRelease *self, guint64 size)
1158
0
{
1159
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1160
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1161
0
  priv->size = size;
1162
0
}
1163
1164
/**
1165
 * fwupd_release_get_created:
1166
 * @self: a #FwupdRelease
1167
 *
1168
 * Gets when the update was created.
1169
 *
1170
 * Returns: UTC timestamp in UNIX format, or 0 if unset
1171
 *
1172
 * Since: 1.4.0
1173
 **/
1174
guint64
1175
fwupd_release_get_created(FwupdRelease *self)
1176
0
{
1177
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1178
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
1179
0
  return priv->created;
1180
0
}
1181
1182
/**
1183
 * fwupd_release_set_created:
1184
 * @self: a #FwupdRelease
1185
 * @created: UTC timestamp in UNIX format
1186
 *
1187
 * Sets when the update was created.
1188
 *
1189
 * Since: 1.4.0
1190
 **/
1191
void
1192
fwupd_release_set_created(FwupdRelease *self, guint64 created)
1193
0
{
1194
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1195
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1196
0
  priv->created = created;
1197
0
}
1198
1199
/**
1200
 * fwupd_release_get_summary:
1201
 * @self: a #FwupdRelease
1202
 *
1203
 * Gets the update summary.
1204
 *
1205
 * Returns: the update summary, or %NULL if unset
1206
 *
1207
 * Since: 0.9.3
1208
 **/
1209
const gchar *
1210
fwupd_release_get_summary(FwupdRelease *self)
1211
0
{
1212
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1213
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1214
0
  return priv->summary;
1215
0
}
1216
1217
/**
1218
 * fwupd_release_set_summary:
1219
 * @self: a #FwupdRelease
1220
 * @summary: (nullable): the update one line summary
1221
 *
1222
 * Sets the update summary.
1223
 *
1224
 * Since: 0.9.3
1225
 **/
1226
void
1227
fwupd_release_set_summary(FwupdRelease *self, const gchar *summary)
1228
0
{
1229
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1230
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1231
1232
  /* not changed */
1233
0
  if (g_strcmp0(priv->summary, summary) == 0)
1234
0
    return;
1235
1236
0
  g_free(priv->summary);
1237
0
  priv->summary = g_strdup(summary);
1238
0
}
1239
1240
/**
1241
 * fwupd_release_get_branch:
1242
 * @self: a #FwupdRelease
1243
 *
1244
 * Gets the update branch.
1245
 *
1246
 * Returns: the alternate branch, or %NULL if unset
1247
 *
1248
 * Since: 1.5.0
1249
 **/
1250
const gchar *
1251
fwupd_release_get_branch(FwupdRelease *self)
1252
0
{
1253
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1254
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1255
0
  return priv->branch;
1256
0
}
1257
1258
/**
1259
 * fwupd_release_set_branch:
1260
 * @self: a #FwupdRelease
1261
 * @branch: (nullable): the update one line branch
1262
 *
1263
 * Sets the alternate branch.
1264
 *
1265
 * Since: 1.5.0
1266
 **/
1267
void
1268
fwupd_release_set_branch(FwupdRelease *self, const gchar *branch)
1269
0
{
1270
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1271
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1272
1273
  /* not changed */
1274
0
  if (g_strcmp0(priv->branch, branch) == 0)
1275
0
    return;
1276
1277
0
  g_free(priv->branch);
1278
0
  priv->branch = g_strdup(branch);
1279
0
}
1280
1281
/**
1282
 * fwupd_release_get_vendor:
1283
 * @self: a #FwupdRelease
1284
 *
1285
 * Gets the update vendor.
1286
 *
1287
 * Returns: the update vendor, or %NULL if unset
1288
 *
1289
 * Since: 0.9.3
1290
 **/
1291
const gchar *
1292
fwupd_release_get_vendor(FwupdRelease *self)
1293
0
{
1294
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1295
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1296
0
  return priv->vendor;
1297
0
}
1298
1299
/**
1300
 * fwupd_release_set_vendor:
1301
 * @self: a #FwupdRelease
1302
 * @vendor: (nullable): the vendor name, e.g. `Hughski Limited`
1303
 *
1304
 * Sets the update vendor.
1305
 *
1306
 * Since: 0.9.3
1307
 **/
1308
void
1309
fwupd_release_set_vendor(FwupdRelease *self, const gchar *vendor)
1310
0
{
1311
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1312
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1313
1314
  /* not changed */
1315
0
  if (g_strcmp0(priv->vendor, vendor) == 0)
1316
0
    return;
1317
1318
0
  g_free(priv->vendor);
1319
0
  priv->vendor = g_strdup(vendor);
1320
0
}
1321
1322
/**
1323
 * fwupd_release_get_license:
1324
 * @self: a #FwupdRelease
1325
 *
1326
 * Gets the update license.
1327
 *
1328
 * Returns: the update license, or %NULL if unset
1329
 *
1330
 * Since: 0.9.3
1331
 **/
1332
const gchar *
1333
fwupd_release_get_license(FwupdRelease *self)
1334
0
{
1335
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1336
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1337
0
  return priv->license;
1338
0
}
1339
1340
/**
1341
 * fwupd_release_set_license:
1342
 * @self: a #FwupdRelease
1343
 * @license: (nullable): the update license.
1344
 *
1345
 * Sets the update license.
1346
 *
1347
 * Since: 0.9.3
1348
 **/
1349
void
1350
fwupd_release_set_license(FwupdRelease *self, const gchar *license)
1351
0
{
1352
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1353
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1354
1355
  /* not changed */
1356
0
  if (g_strcmp0(priv->license, license) == 0)
1357
0
    return;
1358
1359
0
  g_free(priv->license);
1360
0
  priv->license = g_strdup(license);
1361
0
}
1362
1363
/**
1364
 * fwupd_release_get_name:
1365
 * @self: a #FwupdRelease
1366
 *
1367
 * Gets the update name.
1368
 *
1369
 * Returns: the update name, or %NULL if unset
1370
 *
1371
 * Since: 0.9.3
1372
 **/
1373
const gchar *
1374
fwupd_release_get_name(FwupdRelease *self)
1375
0
{
1376
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1377
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1378
0
  return priv->name;
1379
0
}
1380
1381
/**
1382
 * fwupd_release_set_name:
1383
 * @self: a #FwupdRelease
1384
 * @name: (nullable): the update name.
1385
 *
1386
 * Sets the update name.
1387
 *
1388
 * Since: 0.9.3
1389
 **/
1390
void
1391
fwupd_release_set_name(FwupdRelease *self, const gchar *name)
1392
0
{
1393
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1394
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1395
1396
  /* not changed */
1397
0
  if (g_strcmp0(priv->name, name) == 0)
1398
0
    return;
1399
1400
0
  g_free(priv->name);
1401
0
  priv->name = g_strdup(name);
1402
0
}
1403
1404
/**
1405
 * fwupd_release_get_name_variant_suffix:
1406
 * @self: a #FwupdRelease
1407
 *
1408
 * Gets the update variant suffix.
1409
 *
1410
 * Returns: the update variant, or %NULL if unset
1411
 *
1412
 * Since: 1.3.2
1413
 **/
1414
const gchar *
1415
fwupd_release_get_name_variant_suffix(FwupdRelease *self)
1416
0
{
1417
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1418
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1419
0
  return priv->name_variant_suffix;
1420
0
}
1421
1422
/**
1423
 * fwupd_release_set_name_variant_suffix:
1424
 * @self: a #FwupdRelease
1425
 * @name_variant_suffix: (nullable): the description
1426
 *
1427
 * Sets the update variant suffix.
1428
 *
1429
 * Since: 1.3.2
1430
 **/
1431
void
1432
fwupd_release_set_name_variant_suffix(FwupdRelease *self, const gchar *name_variant_suffix)
1433
0
{
1434
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1435
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1436
1437
  /* not changed */
1438
0
  if (g_strcmp0(priv->name_variant_suffix, name_variant_suffix) == 0)
1439
0
    return;
1440
1441
0
  g_free(priv->name_variant_suffix);
1442
0
  priv->name_variant_suffix = g_strdup(name_variant_suffix);
1443
0
}
1444
1445
/**
1446
 * fwupd_release_get_flags:
1447
 * @self: a #FwupdRelease
1448
 *
1449
 * Gets the release flags.
1450
 *
1451
 * Returns: release flags, or 0 if unset
1452
 *
1453
 * Since: 1.2.6
1454
 **/
1455
FwupdReleaseFlags
1456
fwupd_release_get_flags(FwupdRelease *self)
1457
0
{
1458
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1459
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
1460
0
  return priv->flags;
1461
0
}
1462
1463
/**
1464
 * fwupd_release_set_flags:
1465
 * @self: a #FwupdRelease
1466
 * @flags: release flags, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD
1467
 *
1468
 * Sets the release flags.
1469
 *
1470
 * Since: 1.2.6
1471
 **/
1472
void
1473
fwupd_release_set_flags(FwupdRelease *self, FwupdReleaseFlags flags)
1474
0
{
1475
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1476
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1477
0
  priv->flags = flags;
1478
0
}
1479
1480
/**
1481
 * fwupd_release_add_flag:
1482
 * @self: a #FwupdRelease
1483
 * @flag: the #FwupdReleaseFlags
1484
 *
1485
 * Adds a specific release flag to the release.
1486
 *
1487
 * Since: 1.2.6
1488
 **/
1489
void
1490
fwupd_release_add_flag(FwupdRelease *self, FwupdReleaseFlags flag)
1491
0
{
1492
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1493
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1494
0
  priv->flags |= flag;
1495
0
}
1496
1497
/**
1498
 * fwupd_release_remove_flag:
1499
 * @self: a #FwupdRelease
1500
 * @flag: the #FwupdReleaseFlags
1501
 *
1502
 * Removes a specific release flag from the release.
1503
 *
1504
 * Since: 1.2.6
1505
 **/
1506
void
1507
fwupd_release_remove_flag(FwupdRelease *self, FwupdReleaseFlags flag)
1508
0
{
1509
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1510
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1511
0
  priv->flags &= ~flag;
1512
0
}
1513
1514
/**
1515
 * fwupd_release_has_flag:
1516
 * @self: a #FwupdRelease
1517
 * @flag: the #FwupdReleaseFlags
1518
 *
1519
 * Finds if the release has a specific release flag.
1520
 *
1521
 * Returns: %TRUE if the flag is set
1522
 *
1523
 * Since: 1.2.6
1524
 **/
1525
gboolean
1526
fwupd_release_has_flag(FwupdRelease *self, FwupdReleaseFlags flag)
1527
0
{
1528
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1529
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE);
1530
0
  return (priv->flags & flag) > 0;
1531
0
}
1532
1533
/**
1534
 * fwupd_release_get_urgency:
1535
 * @self: a #FwupdRelease
1536
 *
1537
 * Gets the release urgency.
1538
 *
1539
 * Returns: the release urgency, or 0 if unset
1540
 *
1541
 * Since: 1.4.0
1542
 **/
1543
FwupdReleaseUrgency
1544
fwupd_release_get_urgency(FwupdRelease *self)
1545
0
{
1546
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1547
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
1548
0
  return priv->urgency;
1549
0
}
1550
1551
/**
1552
 * fwupd_release_set_urgency:
1553
 * @self: a #FwupdRelease
1554
 * @urgency: the release urgency, e.g. %FWUPD_RELEASE_FLAG_TRUSTED_PAYLOAD
1555
 *
1556
 * Sets the release urgency.
1557
 *
1558
 * Since: 1.4.0
1559
 **/
1560
void
1561
fwupd_release_set_urgency(FwupdRelease *self, FwupdReleaseUrgency urgency)
1562
0
{
1563
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1564
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1565
0
  priv->urgency = urgency;
1566
0
}
1567
1568
/**
1569
 * fwupd_release_get_install_duration:
1570
 * @self: a #FwupdRelease
1571
 *
1572
 * Gets the time estimate for firmware installation (in seconds)
1573
 *
1574
 * Returns: the estimated time to flash this release (or 0 if unset)
1575
 *
1576
 * Since: 1.2.1
1577
 **/
1578
guint32
1579
fwupd_release_get_install_duration(FwupdRelease *self)
1580
0
{
1581
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1582
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), 0);
1583
0
  return priv->install_duration;
1584
0
}
1585
1586
static void
1587
fwupd_release_ensure_reports(FwupdRelease *self)
1588
0
{
1589
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1590
0
  if (priv->reports == NULL)
1591
0
    priv->reports = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
1592
0
}
1593
1594
/**
1595
 * fwupd_release_get_reports:
1596
 * @self: a #FwupdRelease
1597
 *
1598
 * Gets all the reports for this release.
1599
 *
1600
 * Returns: (transfer none) (element-type FwupdReport): array of reports
1601
 *
1602
 * Since: 1.8.8
1603
 **/
1604
GPtrArray *
1605
fwupd_release_get_reports(FwupdRelease *self)
1606
0
{
1607
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1608
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), NULL);
1609
0
  fwupd_release_ensure_reports(self);
1610
0
  return priv->reports;
1611
0
}
1612
1613
/**
1614
 * fwupd_release_add_report:
1615
 * @self: a #FwupdRelease
1616
 * @report: (not nullable): a #FwupdReport
1617
 *
1618
 * Adds a report for this release.
1619
 *
1620
 * Since: 1.8.8
1621
 **/
1622
void
1623
fwupd_release_add_report(FwupdRelease *self, FwupdReport *report)
1624
0
{
1625
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1626
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1627
0
  g_return_if_fail(FWUPD_IS_REPORT(report));
1628
0
  fwupd_release_ensure_reports(self);
1629
0
  g_ptr_array_add(priv->reports, g_object_ref(report));
1630
0
}
1631
1632
/**
1633
 * fwupd_release_set_install_duration:
1634
 * @self: a #FwupdRelease
1635
 * @duration: amount of time in seconds
1636
 *
1637
 * Sets the time estimate for firmware installation (in seconds)
1638
 *
1639
 * Since: 1.2.1
1640
 **/
1641
void
1642
fwupd_release_set_install_duration(FwupdRelease *self, guint32 duration)
1643
0
{
1644
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1645
0
  g_return_if_fail(FWUPD_IS_RELEASE(self));
1646
0
  priv->install_duration = duration;
1647
0
}
1648
1649
static void
1650
fwupd_release_add_variant(FwupdCodec *codec, GVariantBuilder *builder, FwupdCodecFlags flags)
1651
0
{
1652
0
  FwupdRelease *self = FWUPD_RELEASE(codec);
1653
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1654
1655
0
  if (priv->remote_id != NULL) {
1656
0
    g_variant_builder_add(builder,
1657
0
              "{sv}",
1658
0
              FWUPD_RESULT_KEY_REMOTE_ID,
1659
0
              g_variant_new_string(priv->remote_id));
1660
0
  }
1661
0
  if (priv->appstream_id != NULL) {
1662
0
    g_variant_builder_add(builder,
1663
0
              "{sv}",
1664
0
              FWUPD_RESULT_KEY_APPSTREAM_ID,
1665
0
              g_variant_new_string(priv->appstream_id));
1666
0
  }
1667
0
  if (priv->id != NULL) {
1668
0
    g_variant_builder_add(builder,
1669
0
              "{sv}",
1670
0
              FWUPD_RESULT_KEY_RELEASE_ID,
1671
0
              g_variant_new_string(priv->id));
1672
0
  }
1673
0
  if (priv->detach_caption != NULL) {
1674
0
    g_variant_builder_add(builder,
1675
0
              "{sv}",
1676
0
              FWUPD_RESULT_KEY_DETACH_CAPTION,
1677
0
              g_variant_new_string(priv->detach_caption));
1678
0
  }
1679
0
  if (priv->detach_image != NULL) {
1680
0
    g_variant_builder_add(builder,
1681
0
              "{sv}",
1682
0
              FWUPD_RESULT_KEY_DETACH_IMAGE,
1683
0
              g_variant_new_string(priv->detach_image));
1684
0
  }
1685
0
  if (priv->update_message != NULL) {
1686
0
    g_variant_builder_add(builder,
1687
0
              "{sv}",
1688
0
              FWUPD_RESULT_KEY_UPDATE_MESSAGE,
1689
0
              g_variant_new_string(priv->update_message));
1690
0
  }
1691
0
  if (priv->update_image != NULL) {
1692
0
    g_variant_builder_add(builder,
1693
0
              "{sv}",
1694
0
              FWUPD_RESULT_KEY_UPDATE_IMAGE,
1695
0
              g_variant_new_string(priv->update_image));
1696
0
  }
1697
0
  if (priv->filename != NULL) {
1698
0
    g_variant_builder_add(builder,
1699
0
              "{sv}",
1700
0
              FWUPD_RESULT_KEY_FILENAME,
1701
0
              g_variant_new_string(priv->filename));
1702
0
  }
1703
0
  if (priv->protocol != NULL) {
1704
0
    g_variant_builder_add(builder,
1705
0
              "{sv}",
1706
0
              FWUPD_RESULT_KEY_PROTOCOL,
1707
0
              g_variant_new_string(priv->protocol));
1708
0
  }
1709
0
  if (priv->license != NULL) {
1710
0
    g_variant_builder_add(builder,
1711
0
              "{sv}",
1712
0
              FWUPD_RESULT_KEY_LICENSE,
1713
0
              g_variant_new_string(priv->license));
1714
0
  }
1715
0
  if (priv->name != NULL) {
1716
0
    g_variant_builder_add(builder,
1717
0
              "{sv}",
1718
0
              FWUPD_RESULT_KEY_NAME,
1719
0
              g_variant_new_string(priv->name));
1720
0
  }
1721
0
  if (priv->name_variant_suffix != NULL) {
1722
0
    g_variant_builder_add(builder,
1723
0
              "{sv}",
1724
0
              FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX,
1725
0
              g_variant_new_string(priv->name_variant_suffix));
1726
0
  }
1727
0
  if (priv->size != 0) {
1728
0
    g_variant_builder_add(builder,
1729
0
              "{sv}",
1730
0
              FWUPD_RESULT_KEY_SIZE,
1731
0
              g_variant_new_uint64(priv->size));
1732
0
  }
1733
0
  if (priv->created != 0) {
1734
0
    g_variant_builder_add(builder,
1735
0
              "{sv}",
1736
0
              FWUPD_RESULT_KEY_CREATED,
1737
0
              g_variant_new_uint64(priv->created));
1738
0
  }
1739
0
  if (priv->summary != NULL) {
1740
0
    g_variant_builder_add(builder,
1741
0
              "{sv}",
1742
0
              FWUPD_RESULT_KEY_SUMMARY,
1743
0
              g_variant_new_string(priv->summary));
1744
0
  }
1745
0
  if (priv->branch != NULL) {
1746
0
    g_variant_builder_add(builder,
1747
0
              "{sv}",
1748
0
              FWUPD_RESULT_KEY_BRANCH,
1749
0
              g_variant_new_string(priv->branch));
1750
0
  }
1751
0
  if (priv->description != NULL) {
1752
0
    g_variant_builder_add(builder,
1753
0
              "{sv}",
1754
0
              FWUPD_RESULT_KEY_DESCRIPTION,
1755
0
              g_variant_new_string(priv->description));
1756
0
  }
1757
0
  if (priv->categories != NULL && priv->categories->len > 0) {
1758
0
    g_autofree const gchar **strv = g_new0(const gchar *, priv->categories->len + 1);
1759
0
    for (guint i = 0; i < priv->categories->len; i++)
1760
0
      strv[i] = (const gchar *)g_ptr_array_index(priv->categories, i);
1761
0
    g_variant_builder_add(builder,
1762
0
              "{sv}",
1763
0
              FWUPD_RESULT_KEY_CATEGORIES,
1764
0
              g_variant_new_strv(strv, -1));
1765
0
  }
1766
0
  if (priv->issues != NULL && priv->issues->len > 0) {
1767
0
    g_autofree const gchar **strv = g_new0(const gchar *, priv->issues->len + 1);
1768
0
    for (guint i = 0; i < priv->issues->len; i++)
1769
0
      strv[i] = (const gchar *)g_ptr_array_index(priv->issues, i);
1770
0
    g_variant_builder_add(builder,
1771
0
              "{sv}",
1772
0
              FWUPD_RESULT_KEY_ISSUES,
1773
0
              g_variant_new_strv(strv, -1));
1774
0
  }
1775
0
  if (priv->checksums != NULL && priv->checksums->len > 0) {
1776
0
    g_autoptr(GString) str = g_string_new("");
1777
0
    for (guint i = 0; i < priv->checksums->len; i++) {
1778
0
      const gchar *checksum = g_ptr_array_index(priv->checksums, i);
1779
0
      g_string_append_printf(str, "%s,", checksum);
1780
0
    }
1781
0
    if (str->len > 0)
1782
0
      g_string_truncate(str, str->len - 1);
1783
0
    g_variant_builder_add(builder,
1784
0
              "{sv}",
1785
0
              FWUPD_RESULT_KEY_CHECKSUM,
1786
0
              g_variant_new_string(str->str));
1787
0
  }
1788
0
  if (priv->locations != NULL && priv->locations->len > 0) {
1789
0
    g_variant_builder_add(
1790
0
        builder,
1791
0
        "{sv}",
1792
0
        FWUPD_RESULT_KEY_LOCATIONS,
1793
0
        g_variant_new_strv((const gchar *const *)priv->locations->pdata,
1794
0
               priv->locations->len));
1795
0
  }
1796
0
  if (priv->tags != NULL && priv->tags->len > 0) {
1797
0
    g_variant_builder_add(
1798
0
        builder,
1799
0
        "{sv}",
1800
0
        FWUPD_RESULT_KEY_TAGS,
1801
0
        g_variant_new_strv((const gchar *const *)priv->tags->pdata, priv->tags->len));
1802
0
  }
1803
0
  if (priv->homepage != NULL) {
1804
0
    g_variant_builder_add(builder,
1805
0
              "{sv}",
1806
0
              FWUPD_RESULT_KEY_HOMEPAGE,
1807
0
              g_variant_new_string(priv->homepage));
1808
0
  }
1809
0
  if (priv->details_url != NULL) {
1810
0
    g_variant_builder_add(builder,
1811
0
              "{sv}",
1812
0
              FWUPD_RESULT_KEY_DETAILS_URL,
1813
0
              g_variant_new_string(priv->details_url));
1814
0
  }
1815
0
  if (priv->source_url != NULL) {
1816
0
    g_variant_builder_add(builder,
1817
0
              "{sv}",
1818
0
              FWUPD_RESULT_KEY_SOURCE_URL,
1819
0
              g_variant_new_string(priv->source_url));
1820
0
  }
1821
0
  if (priv->sbom_url != NULL) {
1822
0
    g_variant_builder_add(builder,
1823
0
              "{sv}",
1824
0
              FWUPD_RESULT_KEY_SBOM_URL,
1825
0
              g_variant_new_string(priv->sbom_url));
1826
0
  }
1827
0
  if (priv->version != NULL) {
1828
0
    g_variant_builder_add(builder,
1829
0
              "{sv}",
1830
0
              FWUPD_RESULT_KEY_VERSION,
1831
0
              g_variant_new_string(priv->version));
1832
0
  }
1833
0
  if (priv->vendor != NULL) {
1834
0
    g_variant_builder_add(builder,
1835
0
              "{sv}",
1836
0
              FWUPD_RESULT_KEY_VENDOR,
1837
0
              g_variant_new_string(priv->vendor));
1838
0
  }
1839
0
  if (priv->flags != 0) {
1840
0
    g_variant_builder_add(builder,
1841
0
              "{sv}",
1842
0
              FWUPD_RESULT_KEY_TRUST_FLAGS,
1843
0
              g_variant_new_uint64(priv->flags));
1844
0
  }
1845
0
  if (priv->urgency != 0) {
1846
0
    g_variant_builder_add(builder,
1847
0
              "{sv}",
1848
0
              FWUPD_RESULT_KEY_URGENCY,
1849
0
              g_variant_new_uint32(priv->urgency));
1850
0
  }
1851
0
  if (priv->metadata != NULL && g_hash_table_size(priv->metadata) > 0) {
1852
0
    g_variant_builder_add(builder,
1853
0
              "{sv}",
1854
0
              FWUPD_RESULT_KEY_METADATA,
1855
0
              fwupd_variant_from_hash_kv(priv->metadata));
1856
0
  }
1857
0
  if (priv->install_duration > 0) {
1858
0
    g_variant_builder_add(builder,
1859
0
              "{sv}",
1860
0
              FWUPD_RESULT_KEY_INSTALL_DURATION,
1861
0
              g_variant_new_uint32(priv->install_duration));
1862
0
  }
1863
0
  if (priv->reports != NULL && priv->reports->len > 0) {
1864
0
    g_autofree GVariant **children = NULL;
1865
0
    children = g_new0(GVariant *, priv->reports->len);
1866
0
    for (guint i = 0; i < priv->reports->len; i++) {
1867
0
      FwupdReport *report = g_ptr_array_index(priv->reports, i);
1868
0
      children[i] = fwupd_codec_to_variant(FWUPD_CODEC(report), flags);
1869
0
    }
1870
0
    g_variant_builder_add(
1871
0
        builder,
1872
0
        "{sv}",
1873
0
        FWUPD_RESULT_KEY_REPORTS,
1874
0
        g_variant_new_array(G_VARIANT_TYPE("a{sv}"), children, priv->reports->len));
1875
0
  }
1876
0
}
1877
1878
static void
1879
fwupd_release_from_key_value(FwupdRelease *self, const gchar *key, GVariant *value)
1880
0
{
1881
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
1882
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_REMOTE_ID) == 0) {
1883
0
    fwupd_release_set_remote_id(self, fwupd_variant_get_string(value));
1884
0
    return;
1885
0
  }
1886
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) {
1887
0
    fwupd_release_set_appstream_id(self, fwupd_variant_get_string(value));
1888
0
    return;
1889
0
  }
1890
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_RELEASE_ID) == 0) {
1891
0
    fwupd_release_set_id(self, fwupd_variant_get_string(value));
1892
0
    return;
1893
0
  }
1894
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DETACH_CAPTION) == 0) {
1895
0
    fwupd_release_set_detach_caption(self, fwupd_variant_get_string(value));
1896
0
    return;
1897
0
  }
1898
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DETACH_IMAGE) == 0) {
1899
0
    fwupd_release_set_detach_image(self, fwupd_variant_get_string(value));
1900
0
    return;
1901
0
  }
1902
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_FILENAME) == 0) {
1903
0
    fwupd_release_set_filename(self, fwupd_variant_get_string(value));
1904
0
    return;
1905
0
  }
1906
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_PROTOCOL) == 0) {
1907
0
    fwupd_release_set_protocol(self, fwupd_variant_get_string(value));
1908
0
    return;
1909
0
  }
1910
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_LICENSE) == 0) {
1911
0
    fwupd_release_set_license(self, fwupd_variant_get_string(value));
1912
0
    return;
1913
0
  }
1914
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME) == 0) {
1915
0
    fwupd_release_set_name(self, fwupd_variant_get_string(value));
1916
0
    return;
1917
0
  }
1918
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX) == 0) {
1919
0
    fwupd_release_set_name_variant_suffix(self, fwupd_variant_get_string(value));
1920
0
    return;
1921
0
  }
1922
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_SIZE) == 0) {
1923
0
    fwupd_release_set_size(self, fwupd_variant_get_uint64(value));
1924
0
    return;
1925
0
  }
1926
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_CREATED) == 0) {
1927
0
    fwupd_release_set_created(self, fwupd_variant_get_uint64(value));
1928
0
    return;
1929
0
  }
1930
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_SUMMARY) == 0) {
1931
0
    fwupd_release_set_summary(self, fwupd_variant_get_string(value));
1932
0
    return;
1933
0
  }
1934
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_BRANCH) == 0) {
1935
0
    fwupd_release_set_branch(self, fwupd_variant_get_string(value));
1936
0
    return;
1937
0
  }
1938
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) {
1939
0
    fwupd_release_set_description(self, fwupd_variant_get_string(value));
1940
0
    return;
1941
0
  }
1942
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_CATEGORIES) == 0) {
1943
0
    g_autofree const gchar **strv = fwupd_variant_get_strv(value);
1944
0
    for (guint i = 0; strv != NULL && strv[i] != NULL; i++)
1945
0
      fwupd_release_add_category(self, strv[i]);
1946
0
    return;
1947
0
  }
1948
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_ISSUES) == 0) {
1949
0
    g_autofree const gchar **strv = fwupd_variant_get_strv(value);
1950
0
    for (guint i = 0; strv != NULL && strv[i] != NULL; i++)
1951
0
      fwupd_release_add_issue(self, strv[i]);
1952
0
    return;
1953
0
  }
1954
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_CHECKSUM) == 0) {
1955
0
    const gchar *str = fwupd_variant_get_string(value);
1956
0
    if (str != NULL) {
1957
0
      g_auto(GStrv) split = g_strsplit(str, ",", -1);
1958
0
      for (guint i = 0; split[i] != NULL; i++)
1959
0
        fwupd_release_add_checksum(self, split[i]);
1960
0
    }
1961
0
    return;
1962
0
  }
1963
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_LOCATIONS) == 0) {
1964
0
    g_autofree const gchar **strv = fwupd_variant_get_strv(value);
1965
0
    for (guint i = 0; strv != NULL && strv[i] != NULL; i++)
1966
0
      fwupd_release_add_location(self, strv[i]);
1967
0
    return;
1968
0
  }
1969
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_TAGS) == 0) {
1970
0
    g_autofree const gchar **strv = fwupd_variant_get_strv(value);
1971
0
    for (guint i = 0; strv != NULL && strv[i] != NULL; i++)
1972
0
      fwupd_release_add_tag(self, strv[i]);
1973
0
    return;
1974
0
  }
1975
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_URI) == 0) {
1976
0
    fwupd_release_add_location(self, fwupd_variant_get_string(value));
1977
0
    return;
1978
0
  }
1979
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_HOMEPAGE) == 0) {
1980
0
    fwupd_release_set_homepage(self, fwupd_variant_get_string(value));
1981
0
    return;
1982
0
  }
1983
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_DETAILS_URL) == 0) {
1984
0
    fwupd_release_set_details_url(self, fwupd_variant_get_string(value));
1985
0
    return;
1986
0
  }
1987
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_SOURCE_URL) == 0) {
1988
0
    fwupd_release_set_source_url(self, fwupd_variant_get_string(value));
1989
0
    return;
1990
0
  }
1991
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_SBOM_URL) == 0) {
1992
0
    fwupd_release_set_sbom_url(self, fwupd_variant_get_string(value));
1993
0
    return;
1994
0
  }
1995
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VERSION) == 0) {
1996
0
    fwupd_release_set_version(self, fwupd_variant_get_string(value));
1997
0
    return;
1998
0
  }
1999
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_VENDOR) == 0) {
2000
0
    fwupd_release_set_vendor(self, fwupd_variant_get_string(value));
2001
0
    return;
2002
0
  }
2003
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_TRUST_FLAGS) == 0) {
2004
0
    fwupd_release_set_flags(self, fwupd_variant_get_uint64(value));
2005
0
    return;
2006
0
  }
2007
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_URGENCY) == 0) {
2008
0
    fwupd_release_set_urgency(self, fwupd_variant_get_uint32(value));
2009
0
    return;
2010
0
  }
2011
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_INSTALL_DURATION) == 0) {
2012
0
    fwupd_release_set_install_duration(self, fwupd_variant_get_uint32(value));
2013
0
    return;
2014
0
  }
2015
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) {
2016
0
    fwupd_release_set_update_message(self, fwupd_variant_get_string(value));
2017
0
    return;
2018
0
  }
2019
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_UPDATE_IMAGE) == 0) {
2020
0
    fwupd_release_set_update_image(self, fwupd_variant_get_string(value));
2021
0
    return;
2022
0
  }
2023
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_METADATA) == 0) {
2024
0
    g_autoptr(GHashTable) hash = fwupd_variant_to_hash_kv(value);
2025
0
    if (hash != NULL) {
2026
0
      if (priv->metadata != NULL)
2027
0
        g_hash_table_unref(priv->metadata);
2028
0
      priv->metadata = g_steal_pointer(&hash);
2029
0
    }
2030
0
    return;
2031
0
  }
2032
0
  if (g_strcmp0(key, FWUPD_RESULT_KEY_REPORTS) == 0) {
2033
0
    GVariantIter iter;
2034
0
    GVariant *child;
2035
0
    g_variant_iter_init(&iter, value);
2036
0
    while ((child = g_variant_iter_next_value(&iter))) {
2037
0
      g_autoptr(FwupdReport) report = fwupd_report_new();
2038
0
      if (fwupd_codec_from_variant(FWUPD_CODEC(report), child, NULL))
2039
0
        fwupd_release_add_report(self, report);
2040
0
      g_variant_unref(child);
2041
0
    }
2042
0
    return;
2043
0
  }
2044
0
}
2045
2046
static void
2047
fwupd_release_string_append_flags(GString *str,
2048
          guint idt,
2049
          const gchar *key,
2050
          FwupdReleaseFlags release_flags)
2051
0
{
2052
0
  g_autoptr(GString) tmp = g_string_new("");
2053
0
  for (guint i = 0; i < 64; i++) {
2054
0
    if ((release_flags & ((guint64)1 << i)) == 0)
2055
0
      continue;
2056
0
    g_string_append_printf(tmp, "%s|", fwupd_release_flag_to_string((guint64)1 << i));
2057
0
  }
2058
0
  if (tmp->len == 0) {
2059
0
    g_string_append(tmp, fwupd_release_flag_to_string(0));
2060
0
  } else {
2061
0
    g_string_truncate(tmp, tmp->len - 1);
2062
0
  }
2063
0
  fwupd_codec_string_append(str, idt, key, tmp->str);
2064
0
}
2065
2066
static void
2067
fwupd_release_add_json(FwupdCodec *codec, FwupdJsonObject *json_obj, FwupdCodecFlags flags)
2068
0
{
2069
0
  FwupdRelease *self = FWUPD_RELEASE(codec);
2070
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
2071
2072
0
  if (priv->appstream_id != NULL) {
2073
0
    fwupd_json_object_add_string(json_obj,
2074
0
               FWUPD_RESULT_KEY_APPSTREAM_ID,
2075
0
               priv->appstream_id);
2076
0
  }
2077
0
  if (priv->id != NULL)
2078
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_RELEASE_ID, priv->id);
2079
0
  if (priv->remote_id != NULL)
2080
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
2081
0
  if (priv->name != NULL)
2082
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_NAME, priv->name);
2083
0
  if (priv->name_variant_suffix != NULL) {
2084
0
    fwupd_json_object_add_string(json_obj,
2085
0
               FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX,
2086
0
               priv->name_variant_suffix);
2087
0
  }
2088
0
  if (priv->summary != NULL)
2089
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
2090
0
  if (priv->description != NULL) {
2091
0
    fwupd_json_object_add_string(json_obj,
2092
0
               FWUPD_RESULT_KEY_DESCRIPTION,
2093
0
               priv->description);
2094
0
  }
2095
0
  if (priv->branch != NULL)
2096
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_BRANCH, priv->branch);
2097
0
  if (priv->version != NULL)
2098
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_VERSION, priv->version);
2099
0
  if (priv->filename != NULL)
2100
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_FILENAME, priv->filename);
2101
0
  if (priv->protocol != NULL)
2102
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol);
2103
0
  if (priv->categories != NULL && priv->categories->len > 0) {
2104
0
    g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
2105
0
    for (guint i = 0; i < priv->categories->len; i++) {
2106
0
      const gchar *tmp = g_ptr_array_index(priv->categories, i);
2107
0
      fwupd_json_array_add_string(json_arr, tmp);
2108
0
    }
2109
0
    fwupd_json_object_add_array(json_obj, FWUPD_RESULT_KEY_CATEGORIES, json_arr);
2110
0
  }
2111
0
  if (priv->issues != NULL && priv->issues->len > 0) {
2112
0
    g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
2113
0
    for (guint i = 0; i < priv->issues->len; i++) {
2114
0
      const gchar *tmp = g_ptr_array_index(priv->issues, i);
2115
0
      fwupd_json_array_add_string(json_arr, tmp);
2116
0
    }
2117
0
    fwupd_json_object_add_array(json_obj, FWUPD_RESULT_KEY_ISSUES, json_arr);
2118
0
  }
2119
0
  if (priv->checksums != NULL && priv->checksums->len > 0) {
2120
0
    g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
2121
0
    for (guint i = 0; i < priv->checksums->len; i++) {
2122
0
      const gchar *checksum = g_ptr_array_index(priv->checksums, i);
2123
0
      fwupd_json_array_add_string(json_arr, checksum);
2124
0
    }
2125
0
    fwupd_json_object_add_array(json_obj, FWUPD_RESULT_KEY_CHECKSUM, json_arr);
2126
0
  }
2127
0
  if (priv->tags != NULL && priv->tags->len > 0) {
2128
0
    g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
2129
0
    for (guint i = 0; i < priv->tags->len; i++) {
2130
0
      const gchar *tag = g_ptr_array_index(priv->tags, i);
2131
0
      fwupd_json_array_add_string(json_arr, tag);
2132
0
    }
2133
0
    fwupd_json_object_add_array(json_obj, FWUPD_RESULT_KEY_TAGS, json_arr);
2134
0
  }
2135
0
  if (priv->license != NULL)
2136
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_LICENSE, priv->license);
2137
0
  if (priv->size > 0)
2138
0
    fwupd_json_object_add_integer(json_obj, FWUPD_RESULT_KEY_SIZE, priv->size);
2139
0
  if (priv->created > 0)
2140
0
    fwupd_json_object_add_integer(json_obj, FWUPD_RESULT_KEY_CREATED, priv->created);
2141
0
  if (priv->locations != NULL && priv->locations->len > 0) {
2142
0
    g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
2143
0
    for (guint i = 0; i < priv->locations->len; i++) {
2144
0
      const gchar *location = g_ptr_array_index(priv->locations, i);
2145
0
      fwupd_json_array_add_string(json_arr, location);
2146
0
    }
2147
0
    fwupd_json_object_add_array(json_obj, FWUPD_RESULT_KEY_LOCATIONS, json_arr);
2148
0
  }
2149
0
  if (priv->homepage != NULL)
2150
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage);
2151
0
  if (priv->details_url != NULL) {
2152
0
    fwupd_json_object_add_string(json_obj,
2153
0
               FWUPD_RESULT_KEY_DETAILS_URL,
2154
0
               priv->details_url);
2155
0
  }
2156
0
  if (priv->source_url != NULL) {
2157
0
    fwupd_json_object_add_string(json_obj,
2158
0
               FWUPD_RESULT_KEY_SOURCE_URL,
2159
0
               priv->source_url);
2160
0
  }
2161
0
  if (priv->sbom_url != NULL)
2162
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_SBOM_URL, priv->sbom_url);
2163
0
  if (priv->urgency != FWUPD_RELEASE_URGENCY_UNKNOWN) {
2164
0
    fwupd_json_object_add_string(json_obj,
2165
0
               FWUPD_RESULT_KEY_URGENCY,
2166
0
               fwupd_release_urgency_to_string(priv->urgency));
2167
0
  }
2168
0
  if (priv->vendor != NULL)
2169
0
    fwupd_json_object_add_string(json_obj, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
2170
0
  if (priv->flags != FWUPD_RELEASE_FLAG_NONE) {
2171
0
    g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
2172
0
    for (guint i = 0; i < 64; i++) {
2173
0
      const gchar *tmp;
2174
0
      if ((priv->flags & ((guint64)1 << i)) == 0)
2175
0
        continue;
2176
0
      tmp = fwupd_release_flag_to_string((guint64)1 << i);
2177
0
      fwupd_json_array_add_string(json_arr, tmp);
2178
0
    }
2179
0
    fwupd_json_object_add_array(json_obj, FWUPD_RESULT_KEY_FLAGS, json_arr);
2180
0
  }
2181
0
  if (priv->install_duration > 0) {
2182
0
    fwupd_json_object_add_integer(json_obj,
2183
0
                FWUPD_RESULT_KEY_INSTALL_DURATION,
2184
0
                priv->install_duration);
2185
0
  }
2186
0
  if (priv->detach_caption != NULL) {
2187
0
    fwupd_json_object_add_string(json_obj,
2188
0
               FWUPD_RESULT_KEY_DETACH_CAPTION,
2189
0
               priv->detach_caption);
2190
0
  }
2191
0
  if (priv->detach_image != NULL) {
2192
0
    fwupd_json_object_add_string(json_obj,
2193
0
               FWUPD_RESULT_KEY_DETACH_IMAGE,
2194
0
               priv->detach_image);
2195
0
  }
2196
0
  if (priv->update_message != NULL) {
2197
0
    fwupd_json_object_add_string(json_obj,
2198
0
               FWUPD_RESULT_KEY_UPDATE_MESSAGE,
2199
0
               priv->update_message);
2200
0
  }
2201
0
  if (priv->update_image != NULL) {
2202
0
    fwupd_json_object_add_string(json_obj,
2203
0
               FWUPD_RESULT_KEY_UPDATE_IMAGE,
2204
0
               priv->update_image);
2205
0
  }
2206
2207
  /* metadata */
2208
0
  if (priv->metadata != NULL) {
2209
0
    g_autoptr(GList) keys =
2210
0
        g_list_sort(g_hash_table_get_keys(priv->metadata), (GCompareFunc)g_strcmp0);
2211
0
    for (GList *l = keys; l != NULL; l = l->next) {
2212
0
      const gchar *key = l->data;
2213
0
      const gchar *value = g_hash_table_lookup(priv->metadata, key);
2214
0
      fwupd_json_object_add_string(json_obj, key, value);
2215
0
    }
2216
0
  }
2217
2218
  /* reports */
2219
0
  if (priv->reports != NULL && priv->reports->len > 0)
2220
0
    fwupd_codec_array_to_json(priv->reports, "Reports", json_obj, flags);
2221
0
}
2222
2223
static void
2224
fwupd_release_add_string(FwupdCodec *codec, guint idt, GString *str)
2225
0
{
2226
0
  FwupdRelease *self = FWUPD_RELEASE(codec);
2227
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
2228
2229
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->appstream_id);
2230
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_RELEASE_ID, priv->id);
2231
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
2232
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_NAME, priv->name);
2233
0
  fwupd_codec_string_append(str,
2234
0
          idt,
2235
0
          FWUPD_RESULT_KEY_NAME_VARIANT_SUFFIX,
2236
0
          priv->name_variant_suffix);
2237
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
2238
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
2239
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_BRANCH, priv->branch);
2240
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VERSION, priv->version);
2241
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_FILENAME, priv->filename);
2242
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol);
2243
0
  if (priv->categories != NULL) {
2244
0
    for (guint i = 0; i < priv->categories->len; i++) {
2245
0
      const gchar *tmp = g_ptr_array_index(priv->categories, i);
2246
0
      fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_CATEGORIES, tmp);
2247
0
    }
2248
0
  }
2249
0
  if (priv->issues != NULL) {
2250
0
    for (guint i = 0; i < priv->issues->len; i++) {
2251
0
      const gchar *tmp = g_ptr_array_index(priv->issues, i);
2252
0
      fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_ISSUES, tmp);
2253
0
    }
2254
0
  }
2255
0
  if (priv->checksums != NULL) {
2256
0
    for (guint i = 0; i < priv->checksums->len; i++) {
2257
0
      const gchar *checksum = g_ptr_array_index(priv->checksums, i);
2258
0
      g_autofree gchar *checksum_display =
2259
0
          fwupd_checksum_format_for_display(checksum);
2260
0
      fwupd_codec_string_append(str,
2261
0
              idt,
2262
0
              FWUPD_RESULT_KEY_CHECKSUM,
2263
0
              checksum_display);
2264
0
    }
2265
0
  }
2266
0
  if (priv->tags != NULL) {
2267
0
    for (guint i = 0; i < priv->tags->len; i++) {
2268
0
      const gchar *tag = g_ptr_array_index(priv->tags, i);
2269
0
      fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_TAGS, tag);
2270
0
    }
2271
0
  }
2272
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_LICENSE, priv->license);
2273
0
  fwupd_codec_string_append_size(str, idt, FWUPD_RESULT_KEY_SIZE, priv->size);
2274
0
  fwupd_codec_string_append_time(str, idt, FWUPD_RESULT_KEY_CREATED, priv->created);
2275
0
  if (priv->locations != NULL) {
2276
0
    for (guint i = 0; i < priv->locations->len; i++) {
2277
0
      const gchar *location = g_ptr_array_index(priv->locations, i);
2278
0
      fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_URI, location);
2279
0
    }
2280
0
  }
2281
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_HOMEPAGE, priv->homepage);
2282
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DETAILS_URL, priv->details_url);
2283
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_SOURCE_URL, priv->source_url);
2284
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_SBOM_URL, priv->sbom_url);
2285
0
  if (priv->urgency != FWUPD_RELEASE_URGENCY_UNKNOWN) {
2286
0
    fwupd_codec_string_append(str,
2287
0
            idt,
2288
0
            FWUPD_RESULT_KEY_URGENCY,
2289
0
            fwupd_release_urgency_to_string(priv->urgency));
2290
0
  }
2291
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_VENDOR, priv->vendor);
2292
0
  fwupd_release_string_append_flags(str, idt, FWUPD_RESULT_KEY_FLAGS, priv->flags);
2293
0
  fwupd_codec_string_append_int(str,
2294
0
              idt,
2295
0
              FWUPD_RESULT_KEY_INSTALL_DURATION,
2296
0
              priv->install_duration);
2297
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DETACH_CAPTION, priv->detach_caption);
2298
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_DETACH_IMAGE, priv->detach_image);
2299
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->update_message);
2300
0
  fwupd_codec_string_append(str, idt, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->update_image);
2301
2302
  /* metadata */
2303
0
  if (priv->metadata != NULL) {
2304
0
    g_autoptr(GList) keys =
2305
0
        g_list_sort(g_hash_table_get_keys(priv->metadata), (GCompareFunc)g_strcmp0);
2306
0
    for (GList *l = keys; l != NULL; l = l->next) {
2307
0
      const gchar *key = l->data;
2308
0
      const gchar *value = g_hash_table_lookup(priv->metadata, key);
2309
0
      fwupd_codec_string_append(str, idt, key, value);
2310
0
    }
2311
0
  }
2312
0
  if (priv->reports != NULL) {
2313
0
    for (guint i = 0; i < priv->reports->len; i++) {
2314
0
      FwupdReport *report = g_ptr_array_index(priv->reports, i);
2315
0
      fwupd_codec_add_string(FWUPD_CODEC(report), idt, str);
2316
0
    }
2317
0
  }
2318
0
}
2319
2320
static void
2321
fwupd_release_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
2322
0
{
2323
0
  FwupdRelease *self = FWUPD_RELEASE(obj);
2324
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
2325
2326
0
  switch (prop_id) {
2327
0
  case PROP_REMOTE_ID:
2328
0
    g_value_set_string(value, priv->remote_id);
2329
0
    break;
2330
0
  default:
2331
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
2332
0
    break;
2333
0
  }
2334
0
}
2335
2336
static void
2337
fwupd_release_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec)
2338
0
{
2339
0
  FwupdRelease *self = FWUPD_RELEASE(obj);
2340
2341
0
  switch (prop_id) {
2342
0
  case PROP_REMOTE_ID:
2343
0
    fwupd_release_set_remote_id(self, g_value_get_string(value));
2344
0
    break;
2345
0
  default:
2346
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
2347
0
    break;
2348
0
  }
2349
0
}
2350
2351
static void
2352
fwupd_release_class_init(FwupdReleaseClass *klass)
2353
0
{
2354
0
  GParamSpec *pspec;
2355
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
2356
0
  object_class->finalize = fwupd_release_finalize;
2357
0
  object_class->get_property = fwupd_release_get_property;
2358
0
  object_class->set_property = fwupd_release_set_property;
2359
2360
  /**
2361
   * FwupdRelease:remote-id:
2362
   *
2363
   * The remote ID.
2364
   *
2365
   * Since: 1.8.0
2366
   */
2367
0
  pspec = g_param_spec_string("remote-id",
2368
0
            NULL,
2369
0
            NULL,
2370
0
            NULL,
2371
0
            G_PARAM_READWRITE | G_PARAM_STATIC_NAME);
2372
0
  g_object_class_install_property(object_class, PROP_REMOTE_ID, pspec);
2373
0
}
2374
2375
static void
2376
fwupd_release_init(FwupdRelease *self)
2377
0
{
2378
0
}
2379
2380
static void
2381
fwupd_release_finalize(GObject *object)
2382
0
{
2383
0
  FwupdRelease *self = FWUPD_RELEASE(object);
2384
0
  FwupdReleasePrivate *priv = GET_PRIVATE(self);
2385
2386
0
  g_free(priv->description);
2387
0
  g_free(priv->filename);
2388
0
  g_free(priv->protocol);
2389
0
  g_free(priv->appstream_id);
2390
0
  g_free(priv->id);
2391
0
  g_free(priv->detach_caption);
2392
0
  g_free(priv->detach_image);
2393
0
  g_free(priv->license);
2394
0
  g_free(priv->name);
2395
0
  g_free(priv->name_variant_suffix);
2396
0
  g_free(priv->summary);
2397
0
  g_free(priv->branch);
2398
0
  if (priv->locations != NULL)
2399
0
    g_ptr_array_unref(priv->locations);
2400
0
  g_free(priv->homepage);
2401
0
  g_free(priv->details_url);
2402
0
  g_free(priv->source_url);
2403
0
  g_free(priv->sbom_url);
2404
0
  g_free(priv->vendor);
2405
0
  g_free(priv->version);
2406
0
  g_free(priv->remote_id);
2407
0
  g_free(priv->update_message);
2408
0
  g_free(priv->update_image);
2409
0
  if (priv->categories != NULL)
2410
0
    g_ptr_array_unref(priv->categories);
2411
0
  if (priv->issues != NULL)
2412
0
    g_ptr_array_unref(priv->issues);
2413
0
  if (priv->checksums != NULL)
2414
0
    g_ptr_array_unref(priv->checksums);
2415
0
  if (priv->tags != NULL)
2416
0
    g_ptr_array_unref(priv->tags);
2417
0
  if (priv->reports != NULL)
2418
0
    g_ptr_array_unref(priv->reports);
2419
0
  if (priv->metadata != NULL)
2420
0
    g_hash_table_unref(priv->metadata);
2421
2422
0
  G_OBJECT_CLASS(fwupd_release_parent_class)->finalize(object);
2423
0
}
2424
2425
static void
2426
fwupd_release_from_variant_iter(FwupdCodec *codec, GVariantIter *iter)
2427
0
{
2428
0
  FwupdRelease *self = FWUPD_RELEASE(codec);
2429
0
  GVariant *value;
2430
0
  const gchar *key;
2431
0
  while (g_variant_iter_next(iter, "{&sv}", &key, &value)) {
2432
0
    fwupd_release_from_key_value(self, key, value);
2433
0
    g_variant_unref(value);
2434
0
  }
2435
0
}
2436
2437
static void
2438
fwupd_release_codec_iface_init(FwupdCodecInterface *iface)
2439
0
{
2440
0
  iface->add_string = fwupd_release_add_string;
2441
0
  iface->add_json = fwupd_release_add_json;
2442
0
  iface->add_variant = fwupd_release_add_variant;
2443
0
  iface->from_variant_iter = fwupd_release_from_variant_iter;
2444
0
}
2445
2446
/**
2447
 * fwupd_release_match_flags:
2448
 * @include: #FwupdReleaseFlags, or %FWUPD_RELEASE_FLAG_NONE
2449
 * @exclude: #FwupdReleaseFlags, or %FWUPD_RELEASE_FLAG_NONE
2450
 *
2451
 * Check if the release flags match.
2452
 *
2453
 * Returns: %TRUE if the release flags match
2454
 *
2455
 * Since: 1.9.3
2456
 **/
2457
gboolean
2458
fwupd_release_match_flags(FwupdRelease *self, FwupdReleaseFlags include, FwupdReleaseFlags exclude)
2459
0
{
2460
0
  g_return_val_if_fail(FWUPD_IS_RELEASE(self), FALSE);
2461
2462
0
  for (guint i = 0; i < 64; i++) {
2463
0
    FwupdReleaseFlags flag = 1LLU << i;
2464
0
    if ((include & flag) > 0) {
2465
0
      if (!fwupd_release_has_flag(self, flag))
2466
0
        return FALSE;
2467
0
    }
2468
0
    if ((exclude & flag) > 0) {
2469
0
      if (fwupd_release_has_flag(self, flag))
2470
0
        return FALSE;
2471
0
    }
2472
0
  }
2473
0
  return TRUE;
2474
0
}
2475
2476
/**
2477
 * fwupd_release_array_filter_flags:
2478
 * @rels: (not nullable) (element-type FwupdRelease): releases
2479
 * @include: #FwupdReleaseFlags, or %FWUPD_RELEASE_FLAG_NONE
2480
 * @exclude: #FwupdReleaseFlags, or %FWUPD_RELEASE_FLAG_NONE
2481
 * @error: (nullable): optional return location for an error
2482
 *
2483
 * Creates an array of new releases that match using fwupd_release_match_flags().
2484
 *
2485
 * Returns: (transfer container) (element-type FwupdRelease): releases
2486
 *
2487
 * Since: 1.9.3
2488
 **/
2489
GPtrArray *
2490
fwupd_release_array_filter_flags(GPtrArray *rels,
2491
         FwupdReleaseFlags include,
2492
         FwupdReleaseFlags exclude,
2493
         GError **error)
2494
0
{
2495
0
  g_autoptr(GPtrArray) rels_filtered =
2496
0
      g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref);
2497
2498
0
  g_return_val_if_fail(rels != NULL, NULL);
2499
0
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
2500
2501
0
  for (guint i = 0; i < rels->len; i++) {
2502
0
    FwupdRelease *rel = g_ptr_array_index(rels, i);
2503
0
    if (!fwupd_release_match_flags(rel, include, exclude))
2504
0
      continue;
2505
0
    g_ptr_array_add(rels_filtered, g_object_ref(rel));
2506
0
  }
2507
0
  if (rels_filtered->len == 0) {
2508
0
    g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOTHING_TO_DO, "no releases");
2509
0
    return NULL;
2510
0
  }
2511
0
  return g_steal_pointer(&rels_filtered);
2512
0
}
2513
2514
/**
2515
 * fwupd_release_new:
2516
 *
2517
 * Creates a new release.
2518
 *
2519
 * Returns: a new #FwupdRelease
2520
 *
2521
 * Since: 0.9.3
2522
 **/
2523
FwupdRelease *
2524
fwupd_release_new(void)
2525
0
{
2526
0
  FwupdRelease *self;
2527
0
  self = g_object_new(FWUPD_TYPE_RELEASE, NULL);
2528
0
  return FWUPD_RELEASE(self);
2529
0
}