Coverage Report

Created: 2025-06-22 06:29

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