Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
appstream/src/as-issue.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
348 lines (302 sloc)
7.67 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- | |
| * | |
| * Copyright (C) 2019-2022 Matthias Klumpp <matthias@tenstral.net> | |
| * | |
| * Licensed under the GNU Lesser General Public License Version 2.1 | |
| * | |
| * This library is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation, either version 2.1 of the license, or | |
| * (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public License | |
| * along with this library. If not, see <http://www.gnu.org/licenses/>. | |
| */ | |
| /** | |
| * SECTION:as-issue | |
| * @short_description: An issue resolved in a release. | |
| * @include: appstream.h | |
| * | |
| * Information about an issue that was resolved in a release. | |
| * | |
| * See also: #AsRelease | |
| */ | |
| #include "config.h" | |
| #include "as-issue-private.h" | |
| typedef struct | |
| { | |
| AsIssueKind kind; | |
| gchar *id; | |
| gchar *url; | |
| } AsIssuePrivate; | |
| G_DEFINE_TYPE_WITH_PRIVATE (AsIssue, as_issue, G_TYPE_OBJECT) | |
| #define GET_PRIVATE(o) (as_issue_get_instance_private (o)) | |
| /** | |
| * as_issue_kind_to_string: | |
| * @kind: the %AsIssueKind. | |
| * | |
| * Converts the enumerated value to an text representation. | |
| * | |
| * Returns: string version of @kind | |
| **/ | |
| const gchar* | |
| as_issue_kind_to_string (AsIssueKind kind) | |
| { | |
| if (kind == AS_ISSUE_KIND_GENERIC) | |
| return "generic"; | |
| if (kind == AS_ISSUE_KIND_CVE) | |
| return "cve"; | |
| return "unknown"; | |
| } | |
| /** | |
| * as_issue_kind_from_string: | |
| * @kind_str: the string. | |
| * | |
| * Converts the text representation to an enumerated value. | |
| * | |
| * Returns: a #AsIssueKind or %AS_ISSUE_KIND_UNKNOWN for unknown | |
| **/ | |
| AsIssueKind | |
| as_issue_kind_from_string (const gchar *kind_str) | |
| { | |
| if (kind_str == NULL) | |
| return AS_ISSUE_KIND_GENERIC; | |
| if (g_strcmp0 (kind_str, "") == 0) | |
| return AS_ISSUE_KIND_GENERIC; | |
| if (g_strcmp0 (kind_str, "cve") == 0) | |
| return AS_ISSUE_KIND_CVE; | |
| return AS_ISSUE_KIND_UNKNOWN; | |
| } | |
| static void | |
| as_issue_finalize (GObject *object) | |
| { | |
| AsIssue *issue = AS_ISSUE (object); | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| g_free (priv->id); | |
| g_free (priv->url); | |
| G_OBJECT_CLASS (as_issue_parent_class)->finalize (object); | |
| } | |
| static void | |
| as_issue_init (AsIssue *issue) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| priv->kind = AS_ISSUE_KIND_GENERIC; | |
| } | |
| static void | |
| as_issue_class_init (AsIssueClass *klass) | |
| { | |
| GObjectClass *object_class = G_OBJECT_CLASS (klass); | |
| object_class->finalize = as_issue_finalize; | |
| } | |
| /** | |
| * as_issue_get_kind: | |
| * @issue: a #AsIssue instance. | |
| * | |
| * Gets the issue type. | |
| * | |
| * Returns: the #AsIssueKind | |
| **/ | |
| AsIssueKind | |
| as_issue_get_kind (AsIssue *issue) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| return priv->kind; | |
| } | |
| /** | |
| * as_issue_set_kind: | |
| * @issue: a #AsIssue instance. | |
| * @kind: the #AsIssueKind, e.g. %AS_ISSUE_KIND_SHA256. | |
| * | |
| * Sets the issue type. | |
| **/ | |
| void | |
| as_issue_set_kind (AsIssue *issue, AsIssueKind kind) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| priv->kind = kind; | |
| } | |
| /** | |
| * as_issue_get_id: | |
| * @issue: a #AsIssue instance. | |
| * | |
| * Gets the issue ID (usually a bug number or CVE ID) | |
| * | |
| * Returns: the ID. | |
| **/ | |
| const gchar* | |
| as_issue_get_id (AsIssue *issue) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| return priv->id; | |
| } | |
| /** | |
| * as_issue_set_id: | |
| * @issue: a #AsIssue instance. | |
| * @id: the new ID. | |
| * | |
| * Sets the issue ID. | |
| **/ | |
| void | |
| as_issue_set_id (AsIssue *issue, const gchar *id) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| g_free (priv->id); | |
| priv->id = g_strdup (id); | |
| } | |
| /** | |
| * as_issue_get_url: | |
| * @issue: a #AsIssue instance. | |
| * | |
| * Gets the URL associacted with this issue, usually | |
| * referencing a bug report or issue description. | |
| * | |
| * Returns: the URL. | |
| **/ | |
| const gchar* | |
| as_issue_get_url (AsIssue *issue) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| /* we can synthesize an URL if the issue type is a CVE entry */ | |
| if ((priv->url == NULL) && (priv->kind == AS_ISSUE_KIND_CVE) && (priv->id != NULL)) | |
| priv->url = g_strdup_printf ("https://cve.mitre.org/cgi-bin/cvename.cgi?name=%s", priv->id); | |
| return priv->url; | |
| } | |
| /** | |
| * as_issue_set_url: | |
| * @issue: a #AsIssue instance. | |
| * @url: the new URL. | |
| * | |
| * Sets an URL describing this issue. | |
| **/ | |
| void | |
| as_issue_set_url (AsIssue *issue, const gchar *url) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| g_free (priv->url); | |
| priv->url = g_strdup (url); | |
| } | |
| /** | |
| * as_issue_load_from_xml: | |
| * @issue: a #AsIssue instance. | |
| * @ctx: the AppStream document context. | |
| * @node: the XML node. | |
| * @error: a #GError. | |
| * | |
| * Loads data from an XML node. | |
| **/ | |
| gboolean | |
| as_issue_load_from_xml (AsIssue *issue, AsContext *ctx, xmlNode *node, GError **error) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| g_autofree gchar *prop = NULL; | |
| prop = as_xml_get_prop_value (node, "type"); | |
| priv->kind = as_issue_kind_from_string (prop); | |
| if (priv->kind == AS_ISSUE_KIND_UNKNOWN) | |
| return FALSE; | |
| g_free (priv->id); | |
| priv->id = as_xml_get_node_value (node); | |
| g_free (priv->url); | |
| priv->url = as_xml_get_prop_value (node, "url"); | |
| return TRUE; | |
| } | |
| /** | |
| * as_issue_to_xml_node: | |
| * @issue: a #AsIssue instance. | |
| * @ctx: the AppStream document context. | |
| * @root: XML node to attach the new nodes to. | |
| * | |
| * Serializes the data to an XML node. | |
| **/ | |
| void | |
| as_issue_to_xml_node (AsIssue *issue, AsContext *ctx, xmlNode *root) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| xmlNode *n; | |
| if (priv->kind == AS_ISSUE_KIND_UNKNOWN) | |
| return; | |
| if (priv->id == NULL) | |
| return; | |
| n = as_xml_add_text_node (root, "issue", priv->id); | |
| if (priv->kind != AS_ISSUE_KIND_GENERIC) | |
| as_xml_add_text_prop (n, "type", as_issue_kind_to_string (priv->kind)); | |
| if (priv->url != NULL) { | |
| g_strstrip (priv->url); | |
| as_xml_add_text_prop (n, "url", priv->url); | |
| } | |
| } | |
| /** | |
| * as_issue_load_from_yaml: | |
| * @issue: a #AsIssue instance. | |
| * @ctx: the AppStream document context. | |
| * @node: the YAML node. | |
| * @error: a #GError. | |
| * | |
| * Loads data from a YAML field. | |
| **/ | |
| gboolean | |
| as_issue_load_from_yaml (AsIssue *issue, AsContext *ctx, GNode *node, GError **error) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| for (GNode *n = node->children; n != NULL; n = n->next) { | |
| const gchar *key = as_yaml_node_get_key (n); | |
| const gchar *value = as_yaml_node_get_value (n); | |
| if (G_UNLIKELY (value == NULL)) | |
| continue; /* there should be no key without value */ | |
| if (g_strcmp0 (key, "type") == 0) { | |
| priv->kind = as_issue_kind_from_string (value); | |
| } else if (g_strcmp0 (key, "id") == 0) { | |
| g_free (priv->id); | |
| priv->id = g_strdup (value); | |
| } else if (g_strcmp0 (key, "url") == 0) { | |
| g_free (priv->url); | |
| priv->url = g_strdup (value); | |
| } else { | |
| as_yaml_print_unknown ("issue", key); | |
| } | |
| } | |
| return TRUE; | |
| } | |
| /** | |
| * as_issue_emit_yaml: | |
| * @issue: a #AsIssue instance. | |
| * @ctx: the AppStream document context. | |
| * @emitter: The YAML emitter to emit data on. | |
| * | |
| * Emit YAML data for this object. | |
| **/ | |
| void | |
| as_issue_emit_yaml (AsIssue *issue, AsContext *ctx, yaml_emitter_t *emitter) | |
| { | |
| AsIssuePrivate *priv = GET_PRIVATE (issue); | |
| if (priv->kind == AS_ISSUE_KIND_UNKNOWN) | |
| return; | |
| if (priv->id == NULL) | |
| return; | |
| as_yaml_mapping_start (emitter); | |
| if (priv->kind != AS_ISSUE_KIND_GENERIC) | |
| as_yaml_emit_entry (emitter, "type", as_issue_kind_to_string (priv->kind)); | |
| if (priv->url != NULL) | |
| g_strstrip (priv->url); | |
| as_yaml_emit_entry (emitter, "id", priv->id); | |
| as_yaml_emit_entry (emitter, "url", priv->url); | |
| as_yaml_mapping_end (emitter); | |
| } | |
| /** | |
| * as_issue_new: | |
| * | |
| * Creates a new #AsIssue. | |
| * | |
| * Returns: (transfer full): an #AsIssue | |
| **/ | |
| AsIssue* | |
| as_issue_new (void) | |
| { | |
| AsIssue *issue; | |
| issue = g_object_new (AS_TYPE_ISSUE, NULL); | |
| return AS_ISSUE (issue); | |
| } |