diff options
author | Richard Hughes <richard@hughsie.com> | 2018-03-14 13:29:25 +0000 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2018-04-11 20:50:12 +0100 |
commit | 0bb8ae6f2dec2b3ff6bf6f908955969e1b460d8a (patch) | |
tree | d7870f815386c4b3e7a5664e0bbbec19fea61950 /libappstream-glib | |
parent | 786a2c85c06ba82d41db9eb5490c964d3bd7754d (diff) | |
download | appstream-glib-0bb8ae6f2dec2b3ff6bf6f908955969e1b460d8a.tar.gz |
Add support for component agreements
This enables a lot of software to comply with the GDPR and also allows us to
show translated warning and EULA text to unsuspecting users.
Diffstat (limited to 'libappstream-glib')
-rw-r--r-- | libappstream-glib/as-agreement-private.h | 46 | ||||
-rw-r--r-- | libappstream-glib/as-agreement-section-private.h | 46 | ||||
-rw-r--r-- | libappstream-glib/as-agreement-section.c | 276 | ||||
-rw-r--r-- | libappstream-glib/as-agreement-section.h | 68 | ||||
-rw-r--r-- | libappstream-glib/as-agreement.c | 330 | ||||
-rw-r--r-- | libappstream-glib/as-agreement.h | 88 | ||||
-rw-r--r-- | libappstream-glib/as-app-private.h | 2 | ||||
-rw-r--r-- | libappstream-glib/as-app.c | 128 | ||||
-rw-r--r-- | libappstream-glib/as-app.h | 11 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 53 | ||||
-rw-r--r-- | libappstream-glib/as-tag.c | 2 | ||||
-rw-r--r-- | libappstream-glib/as-tag.gperf | 2 | ||||
-rw-r--r-- | libappstream-glib/as-tag.h | 4 | ||||
-rw-r--r-- | libappstream-glib/meson.build | 8 |
14 files changed, 1062 insertions, 2 deletions
diff --git a/libappstream-glib/as-agreement-private.h b/libappstream-glib/as-agreement-private.h new file mode 100644 index 0000000..fb6132b --- /dev/null +++ b/libappstream-glib/as-agreement-private.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes <richard@hughsie.com> + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (__APPSTREAM_GLIB_PRIVATE_H) && !defined (AS_COMPILATION) +#error "Only <appstream-glib.h> can be included directly." +#endif + +#ifndef __AS_AGREEMENT_PRIVATE_H +#define __AS_AGREEMENT_PRIVATE_H + +#include <glib-object.h> + +#include "as-agreement.h" +#include "as-node-private.h" + +G_BEGIN_DECLS + +GNode *as_agreement_node_insert (AsAgreement *agreement, + GNode *parent, + AsNodeContext *ctx); +gboolean as_agreement_node_parse (AsAgreement *agreement, + GNode *node, + AsNodeContext *ctx, + GError **error); + +G_END_DECLS + +#endif /* __AS_AGREEMENT_PRIVATE_H */ diff --git a/libappstream-glib/as-agreement-section-private.h b/libappstream-glib/as-agreement-section-private.h new file mode 100644 index 0000000..315972d --- /dev/null +++ b/libappstream-glib/as-agreement-section-private.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes <richard@hughsie.com> + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (__APPSTREAM_GLIB_PRIVATE_H) && !defined (AS_COMPILATION) +#error "Only <appstream-glib.h> can be included directly." +#endif + +#ifndef __AS_AGREEMENT_SECTION_PRIVATE_H +#define __AS_AGREEMENT_SECTION_PRIVATE_H + +#include <glib-object.h> + +#include "as-agreement-section.h" +#include "as-node-private.h" + +G_BEGIN_DECLS + +GNode *as_agreement_section_node_insert (AsAgreementSection *agreement_section, + GNode *parent, + AsNodeContext *ctx); +gboolean as_agreement_section_node_parse (AsAgreementSection *agreement_section, + GNode *node, + AsNodeContext *ctx, + GError **error); + +G_END_DECLS + +#endif /* __AS_AGREEMENT_SECTION_PRIVATE_H */ diff --git a/libappstream-glib/as-agreement-section.c b/libappstream-glib/as-agreement-section.c new file mode 100644 index 0000000..aa29098 --- /dev/null +++ b/libappstream-glib/as-agreement-section.c @@ -0,0 +1,276 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes <richard@hughsie.com> + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:as-agreement-section + * @short_description: Object representing a agreement section + * @include: appstream-glib.h + * @stability: Unstable + * + * Agreements are typically split up into sections. + * + * See also: #AsAgreement, #AsAgreementDetail + */ + +#include "config.h" + +#include "as-node-private.h" +#include "as-agreement-section-private.h" +#include "as-ref-string.h" +#include "as-tag.h" + +typedef struct { + AsRefString *kind; + AsRefString *name; + AsRefString *desc; +} AsAgreementSectionPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AsAgreementSection, as_agreement_section, G_TYPE_OBJECT) + +#define GET_PRIVATE(o) (as_agreement_section_get_instance_private (o)) + +static void +as_agreement_section_finalize (GObject *object) +{ + AsAgreementSection *agreement_section = AS_AGREEMENT_SECTION (object); + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + + if (priv->kind != NULL) + as_ref_string_unref (priv->kind); + if (priv->name != NULL) + as_ref_string_unref (priv->name); + if (priv->desc != NULL) + as_ref_string_unref (priv->desc); + + G_OBJECT_CLASS (as_agreement_section_parent_class)->finalize (object); +} + +static void +as_agreement_section_init (AsAgreementSection *agreement_section) +{ +// AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); +} + +static void +as_agreement_section_class_init (AsAgreementSectionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = as_agreement_section_finalize; +} + +/** + * as_agreement_section_get_kind: + * @agreement_section: a #AsAgreementSection instance. + * + * Gets the agreement section kind. + * + * Returns: a string, e.g. "GDPR", or NULL + * + * Since: 0.7.8 + **/ +const gchar * +as_agreement_section_get_kind (AsAgreementSection *agreement_section) +{ + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + return priv->kind; +} + +/** + * as_agreement_section_set_kind: + * @agreement_section: a #AsAgreementSection instance. + * @kind: the rating kind, e.g. "GDPR" + * + * Sets the agreement section kind. + * + * Since: 0.7.8 + **/ +void +as_agreement_section_set_kind (AsAgreementSection *agreement_section, const gchar *kind) +{ + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + as_ref_string_assign_safe (&priv->kind, kind); +} + +/** + * as_agreement_section_get_name: + * @agreement_section: a #AsAgreementSection instance. + * @locale: (nullable): the locale. e.g. "en_GB" + * + * Gets the agreement section name. + * + * Returns: a string, e.g. "GDPR", or NULL + * + * Since: 0.7.8 + **/ +const gchar * +as_agreement_section_get_name (AsAgreementSection *agreement_section, const gchar *locale) +{ + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + return priv->name; +} + +/** + * as_agreement_section_set_name: + * @agreement_section: a #AsAgreementSection instance. + * @locale: (nullable): the locale. e.g. "en_GB" + * @name: the rating name, e.g. "GDPR" + * + * Sets the agreement section name. + * + * Since: 0.7.8 + **/ +void +as_agreement_section_set_name (AsAgreementSection *agreement_section, + const gchar *locale, const gchar *name) +{ + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + as_ref_string_assign_safe (&priv->name, name); +} + +/** + * as_agreement_section_get_description: + * @agreement_section: a #AsAgreementSection instance. + * @locale: (nullable): the locale. e.g. "en_GB" + * + * Gets the agreement section desc. + * + * Returns: a string, e.g. "GDPR", or NULL + * + * Since: 0.7.8 + **/ +const gchar * +as_agreement_section_get_description (AsAgreementSection *agreement_section, + const gchar *locale) +{ + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + return priv->desc; +} + +/** + * as_agreement_section_set_description: + * @agreement_section: a #AsAgreementSection instance. + * @locale: (nullable): the locale. e.g. "en_GB" + * @desc: the rating desc, e.g. "GDPR" + * + * Sets the agreement section desc. + * + * Since: 0.7.8 + **/ +void +as_agreement_section_set_description (AsAgreementSection *agreement_section, + const gchar *locale, const gchar *desc) +{ + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + as_ref_string_assign_safe (&priv->desc, desc); +} + +/** + * as_agreement_section_node_insert: (skip) + * @agreement_section: a #AsAgreementSection instance. + * @parent: the parent #GNode to use.. + * @ctx: the #AsNodeContext + * + * Inserts the agreement_section into the DOM tree. + * + * Returns: (transfer none): A populated #GNode, or %NULL + * + * Since: 0.7.8 + **/ +GNode * +as_agreement_section_node_insert (AsAgreementSection *agreement_section, + GNode *parent, + AsNodeContext *ctx) +{ + AsAgreementSectionPrivate *priv = GET_PRIVATE (agreement_section); + GNode *n = as_node_insert (parent, "agreement_section", NULL, + AS_NODE_INSERT_FLAG_NONE, + NULL); + if (priv->kind != NULL) + as_node_add_attribute (n, "type", priv->kind); + if (priv->desc != NULL) { + as_node_insert (n, "description", priv->desc, + AS_NODE_INSERT_FLAG_PRE_ESCAPED, NULL); + } + + return n; +} + +/** + * as_agreement_section_node_parse: + * @agreement_section: a #AsAgreementSection instance. + * @node: a #GNode. + * @ctx: a #AsNodeContext. + * @error: A #GError or %NULL. + * + * Populates the object from a DOM node. + * + * Returns: %TRUE for success + * + * Since: 0.7.8 + **/ +gboolean +as_agreement_section_node_parse (AsAgreementSection *agreement_section, GNode *node, + AsNodeContext *ctx, GError **error) +{ + const gchar *tmp; + + /* get ID */ + tmp = as_node_get_attribute (node, "type"); + if (tmp != NULL) + as_agreement_section_set_kind (agreement_section, tmp); + + /* get sections and details */ + for (GNode *c = node->children; c != NULL; c = c->next) { + if (as_node_get_tag (c) == AS_TAG_NAME) { + as_agreement_section_set_name (agreement_section, + as_node_get_attribute (c, "xml:lang"), + as_node_get_data (c)); + continue; + } + if (as_node_get_tag (c) == AS_TAG_DESCRIPTION) { + g_autoptr(GString) xml = NULL; + xml = as_node_to_xml (c->children, + AS_NODE_TO_XML_FLAG_INCLUDE_SIBLINGS); + as_agreement_section_set_description (agreement_section, + as_node_get_attribute (c, "xml:lang"), + xml->str); + continue; + } + } + return TRUE; +} + +/** + * as_agreement_section_new: + * + * Creates a new #AsAgreementSection. + * + * Returns: (transfer full): a #AsAgreementSection + * + * Since: 0.7.8 + **/ +AsAgreementSection * +as_agreement_section_new (void) +{ + AsAgreementSection *agreement_section; + agreement_section = g_object_new (AS_TYPE_AGREEMENT_SECTION, NULL); + return AS_AGREEMENT_SECTION (agreement_section); +} diff --git a/libappstream-glib/as-agreement-section.h b/libappstream-glib/as-agreement-section.h new file mode 100644 index 0000000..5f56a57 --- /dev/null +++ b/libappstream-glib/as-agreement-section.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes <richard@hughsie.com> + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (__APPSTREAM_GLIB_H) && !defined (AS_COMPILATION) +#error "Only <appstream-glib.h> can be included directly." +#endif + +#ifndef __AS_AGREEMENT_SECTION_H +#define __AS_AGREEMENT_SECTION_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define AS_TYPE_AGREEMENT_SECTION (as_agreement_section_get_type ()) +G_DECLARE_DERIVABLE_TYPE (AsAgreementSection, as_agreement_section, AS, AGREEMENT_SECTION, GObject) + +struct _AsAgreementSectionClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_as_reserved1) (void); + void (*_as_reserved2) (void); + void (*_as_reserved3) (void); + void (*_as_reserved4) (void); + void (*_as_reserved5) (void); + void (*_as_reserved6) (void); + void (*_as_reserved7) (void); + void (*_as_reserved8) (void); +}; + +AsAgreementSection *as_agreement_section_new (void); + +const gchar *as_agreement_section_get_kind (AsAgreementSection *agreement_section); +void as_agreement_section_set_kind (AsAgreementSection *agreement_section, + const gchar *kind); +const gchar *as_agreement_section_get_name (AsAgreementSection *agreement_section, + const gchar *locale); +void as_agreement_section_set_name (AsAgreementSection *agreement_section, + const gchar *locale, + const gchar *name); +const gchar *as_agreement_section_get_description (AsAgreementSection *agreement_section, + const gchar *locale); +void as_agreement_section_set_description (AsAgreementSection *agreement_section, + const gchar *locale, + const gchar *desc); + +G_END_DECLS + +#endif /* __AS_AGREEMENT_SECTION_H */ diff --git a/libappstream-glib/as-agreement.c b/libappstream-glib/as-agreement.c new file mode 100644 index 0000000..8c78204 --- /dev/null +++ b/libappstream-glib/as-agreement.c @@ -0,0 +1,330 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes <richard@hughsie.com> + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:as-agreement + * @short_description: Object representing a privacy policy + * @include: appstream-glib.h + * @stability: Unstable + * + * Agreements can be used by components to specify GDPR, EULA or other warnings. + * + * See also: #AsAgreementDetail, #AsAgreementSection + */ + +#include "config.h" + +#include "as-node-private.h" +#include "as-agreement-private.h" +#include "as-agreement-section-private.h" +#include "as-ref-string.h" +#include "as-tag.h" + +typedef struct { + AsAgreementKind kind; + AsRefString *version_id; + GPtrArray *sections; +} AsAgreementPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (AsAgreement, as_agreement, G_TYPE_OBJECT) + +#define GET_PRIVATE(o) (as_agreement_get_instance_private (o)) + +static void +as_agreement_finalize (GObject *object) +{ + AsAgreement *agreement = AS_AGREEMENT (object); + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + + if (priv->version_id != NULL) + as_ref_string_unref (priv->version_id); + g_ptr_array_unref (priv->sections); + + G_OBJECT_CLASS (as_agreement_parent_class)->finalize (object); +} + +static void +as_agreement_init (AsAgreement *agreement) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + priv->sections = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); +} + +static void +as_agreement_class_init (AsAgreementClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = as_agreement_finalize; +} + +/** + * as_agreement_kind_to_string: + * @value: the #AsAgreementKind. + * + * Converts the enumerated value to an text representation. + * + * Returns: string version of @value + * + * Since: 0.7.8 + **/ +const gchar * +as_agreement_kind_to_string (AsAgreementKind value) +{ + if (value == AS_AGREEMENT_KIND_GENERIC) + return "generic"; + if (value == AS_AGREEMENT_KIND_EULA) + return "eula"; + if (value == AS_AGREEMENT_KIND_PRIVACY) + return "privacy"; + return "unknown"; +} + +/** + * as_agreement_kind_from_string: + * @value: the string. + * + * Converts the text representation to an enumerated value. + * + * Returns: a #AsAgreementKind or %AS_AGREEMENT_KIND_UNKNOWN for unknown + * + * Since: 0.7.8 + **/ +AsAgreementKind +as_agreement_kind_from_string (const gchar *value) +{ + if (g_strcmp0 (value, "generic") == 0) + return AS_AGREEMENT_KIND_GENERIC; + if (g_strcmp0 (value, "eula") == 0) + return AS_AGREEMENT_KIND_EULA; + if (g_strcmp0 (value, "privacy") == 0) + return AS_AGREEMENT_KIND_PRIVACY; + return AS_AGREEMENT_KIND_UNKNOWN; +} + +/** + * as_agreement_get_kind: + * @agreement: a #AsAgreement instance. + * + * Gets the agreement kind. + * + * Returns: a string, e.g. %AS_AGREEMENT_KIND_EULA + * + * Since: 0.7.8 + **/ +AsAgreementKind +as_agreement_get_kind (AsAgreement *agreement) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + return priv->kind; +} + +/** + * as_agreement_set_kind: + * @agreement: a #AsAgreement instance. + * @kind: the agreement kind, e.g. %AS_AGREEMENT_KIND_EULA + * + * Sets the agreement kind. + * + * Since: 0.7.8 + **/ +void +as_agreement_set_kind (AsAgreement *agreement, AsAgreementKind kind) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + priv->kind = kind; +} + +/** + * as_agreement_get_version_id: + * @agreement: a #AsAgreement instance. + * + * Gets the agreement version_id. + * + * Returns: a string, e.g. "1.4a", or NULL + * + * Since: 0.7.8 + **/ +const gchar * +as_agreement_get_version_id (AsAgreement *agreement) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + return priv->version_id; +} + +/** + * as_agreement_set_version_id: + * @agreement: a #AsAgreement instance. + * @version_id: the agreement version ID, e.g. "1.4a" + * + * Sets the agreement version identifier. + * + * Since: 0.7.8 + **/ +void +as_agreement_set_version_id (AsAgreement *agreement, const gchar *version_id) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + as_ref_string_assign_safe (&priv->version_id, version_id); +} + +/** + * as_agreement_get_sections: + * @agreement: a #AsAgreement instance. + * + * Gets all the sections in the agreement. + * + * Returns: (transfer container) (element-type AsAgreementSection): array + * + * Since: 0.7.8 + **/ +GPtrArray * +as_agreement_get_sections (AsAgreement *agreement) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + return priv->sections; +} + +/** + * as_agreement_get_section_default: + * @agreement: a #AsAgreement instance. + * + * Gets the first section in the agreement. + * + * Returns: (transfer none): agreement section, or %NULL + * + * Since: 0.7.8 + **/ +AsAgreementSection * +as_agreement_get_section_default (AsAgreement *agreement) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + if (priv->sections->len == 0) + return NULL; + return AS_AGREEMENT_SECTION (g_ptr_array_index (priv->sections, 0)); +} + +/** + * as_agreement_add_detail: + * @agreement: a #AsAgreement instance. + * @agreement_section: a #AsAgreementSection instance. + * + * Adds a section to the agreement. + * + * Since: 0.7.8 + **/ +void +as_agreement_add_section (AsAgreement *agreement, AsAgreementSection *agreement_section) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + g_ptr_array_add (priv->sections, g_object_ref (agreement_section)); +} + +/** + * as_agreement_node_insert: (skip) + * @agreement: a #AsAgreement instance. + * @parent: the parent #GNode to use.. + * @ctx: the #AsNodeContext + * + * Inserts the agreement into the DOM tree. + * + * Returns: (transfer none): A populated #GNode, or %NULL + * + * Since: 0.7.8 + **/ +GNode * +as_agreement_node_insert (AsAgreement *agreement, + GNode *parent, + AsNodeContext *ctx) +{ + AsAgreementPrivate *priv = GET_PRIVATE (agreement); + GNode *n = as_node_insert (parent, "agreement", NULL, + AS_NODE_INSERT_FLAG_NONE, + NULL); + if (priv->kind != AS_AGREEMENT_KIND_UNKNOWN) { + as_node_add_attribute (n, "type", + as_agreement_kind_to_string (priv->kind)); + } + if (priv->version_id != NULL) + as_node_add_attribute (n, "version_id", priv->version_id); + for (guint i = 0; i < priv->sections->len; i++) { + AsAgreementSection *ps = g_ptr_array_index (priv->sections, i); + as_agreement_section_node_insert (ps, n, ctx); + } + + return n; +} + +/** + * as_agreement_node_parse: + * @agreement: a #AsAgreement instance. + * @node: a #GNode. + * @ctx: a #AsNodeContext. + * @error: A #GError or %NULL. + * + * Populates the object from a DOM node. + * + * Returns: %TRUE for success + * + * Since: 0.7.8 + **/ +gboolean +as_agreement_node_parse (AsAgreement *agreement, GNode *node, + AsNodeContext *ctx, GError **error) +{ + const gchar *tmp; + + /* get ID */ + tmp = as_node_get_attribute (node, "type"); + if (tmp != NULL) + as_agreement_set_kind (agreement, as_agreement_kind_from_string (tmp)); + tmp = as_node_get_attribute (node, "version_id"); + if (tmp != NULL) + as_agreement_set_version_id (agreement, tmp); + + /* get sections and details */ + for (GNode *c = node->children; c != NULL; c = c->next) { + if (as_node_get_tag (c) == AS_TAG_AGREEMENT_SECTION) { + g_autoptr(AsAgreementSection) ps = as_agreement_section_new (); + if (!as_agreement_section_node_parse (ps, c, ctx, error)) + return FALSE; + as_agreement_add_section (agreement, ps); + continue; + } + } + return TRUE; +} + +/** + * as_agreement_new: + * + * Creates a new #AsAgreement. + * + * Returns: (transfer full): a #AsAgreement + * + * Since: 0.7.8 + **/ +AsAgreement * +as_agreement_new (void) +{ + AsAgreement *agreement; + agreement = g_object_new (AS_TYPE_AGREEMENT, NULL); + return AS_AGREEMENT (agreement); +} diff --git a/libappstream-glib/as-agreement.h b/libappstream-glib/as-agreement.h new file mode 100644 index 0000000..a832a7a --- /dev/null +++ b/libappstream-glib/as-agreement.h @@ -0,0 +1,88 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2018 Richard Hughes <richard@hughsie.com> + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (__APPSTREAM_GLIB_H) && !defined (AS_COMPILATION) +#error "Only <appstream-glib.h> can be included directly." +#endif + +#ifndef __AS_AGREEMENT_H +#define __AS_AGREEMENT_H + +#include <glib-object.h> + +#include "as-agreement-section.h" + +G_BEGIN_DECLS + +#define AS_TYPE_AGREEMENT (as_agreement_get_type ()) +G_DECLARE_DERIVABLE_TYPE (AsAgreement, as_agreement, AS, AGREEMENT, GObject) + +struct _AsAgreementClass +{ + GObjectClass parent_class; + /*< private >*/ + void (*_as_reserved1) (void); + void (*_as_reserved2) (void); + void (*_as_reserved3) (void); + void (*_as_reserved4) (void); + void (*_as_reserved5) (void); + void (*_as_reserved6) (void); + void (*_as_reserved7) (void); + void (*_as_reserved8) (void); +}; + +/** + * AsAgreementKind: + * @AS_AGREEMENT_KIND_UNKNOWN: Unknown value + * @AS_AGREEMENT_KIND_GENERIC: A generic agreement without a specific type + * @AS_AGREEMENT_KIND_EULA: An End User License Agreement + * @AS_AGREEMENT_KIND_PRIVACY: A privacy agreement, typically a GDPR statement + * + * The kind of the agreement. + **/ +typedef enum { + AS_AGREEMENT_KIND_UNKNOWN, + AS_AGREEMENT_KIND_GENERIC, + AS_AGREEMENT_KIND_EULA, + AS_AGREEMENT_KIND_PRIVACY, + /*< private >*/ + AS_AGREEMENT_KIND_LAST +} AsAgreementKind; + +AsAgreement *as_agreement_new (void); + +const gchar *as_agreement_kind_to_string (AsAgreementKind value); +AsAgreementKind as_agreement_kind_from_string (const gchar *value); + +AsAgreementKind as_agreement_get_kind (AsAgreement *agreement); +void as_agreement_set_kind (AsAgreement *agreement, + AsAgreementKind kind); +const gchar *as_agreement_get_version_id (AsAgreement *agreement); +void as_agreement_set_version_id (AsAgreement *agreement, + const gchar *version_id); +AsAgreementSection *as_agreement_get_section_default (AsAgreement *agreement); +GPtrArray *as_agreement_get_sections (AsAgreement *agreement); +void as_agreement_add_section (AsAgreement *agreement, + AsAgreementSection *agreement_section); + +G_END_DECLS + +#endif /* __AS_AGREEMENT_H */ diff --git a/libappstream-glib/as-app-private.h b/libappstream-glib/as-app-private.h index b9e0dd2..0d81cd5 100644 --- a/libappstream-glib/as-app-private.h +++ b/libappstream-glib/as-app-private.h @@ -57,6 +57,7 @@ G_BEGIN_DECLS * @AS_APP_PROBLEM_DUPLICATE_RELEASE: More than one release with the same version * @AS_APP_PROBLEM_DUPLICATE_SCREENSHOT: More than one screenshot with the same URL * @AS_APP_PROBLEM_DUPLICATE_CONTENT_RATING: More than one content rating with the same kind + * @AS_APP_PROBLEM_DUPLICATE_AGREEMENT: More than one agreement with the same kind * * The application problems detected when loading. **/ @@ -82,6 +83,7 @@ typedef enum { AS_APP_PROBLEM_DUPLICATE_RELEASE = 1 << 17, AS_APP_PROBLEM_DUPLICATE_SCREENSHOT = 1 << 18, AS_APP_PROBLEM_DUPLICATE_CONTENT_RATING = 1 << 19, + AS_APP_PROBLEM_DUPLICATE_AGREEMENT = 1 << 20, /*< private >*/ AS_APP_PROBLEM_LAST } AsAppProblems; diff --git a/libappstream-glib/as-app.c b/libappstream-glib/as-app.c index ddfc60a..11556e6 100644 --- a/libappstream-glib/as-app.c +++ b/libappstream-glib/as-app.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2014-2017 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2014-2018 Richard Hughes <richard@hughsie.com> * * Licensed under the GNU Lesser General Public License Version 2.1 * @@ -40,6 +40,7 @@ #include "as-app-private.h" #include "as-bundle-private.h" #include "as-content-rating-private.h" +#include "as-agreement-private.h" #include "as-enums.h" #include "as-icon-private.h" #include "as-node-private.h" @@ -87,6 +88,7 @@ typedef struct GPtrArray *screenshots; /* of AsScreenshot */ GPtrArray *reviews; /* of AsReview */ GPtrArray *content_ratings; /* of AsContentRating */ + GPtrArray *agreements; /* of AsAgreement */ GPtrArray *icons; /* of AsIcon */ GPtrArray *bundles; /* of AsBundle */ GPtrArray *translations; /* of AsTranslation */ @@ -454,6 +456,7 @@ as_app_finalize (GObject *object) g_ptr_array_unref (priv->categories); g_ptr_array_unref (priv->compulsory_for_desktops); g_ptr_array_unref (priv->content_ratings); + g_ptr_array_unref (priv->agreements); g_ptr_array_unref (priv->extends); g_ptr_array_unref (priv->kudos); g_ptr_array_unref (priv->permissions); @@ -483,6 +486,7 @@ as_app_init (AsApp *app) priv->categories = g_ptr_array_new_with_free_func ((GDestroyNotify) as_ref_string_unref); priv->compulsory_for_desktops = g_ptr_array_new_with_free_func ((GDestroyNotify) as_ref_string_unref); priv->content_ratings = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->agreements = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); priv->extends = g_ptr_array_new_with_free_func ((GDestroyNotify) as_ref_string_unref); priv->keywords = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) as_ref_string_unref, @@ -1317,6 +1321,68 @@ as_app_get_content_rating (AsApp *app, const gchar *kind) } /** + * as_app_get_agreements: + * @app: a #AsApp instance. + * + * Gets any agreements the application has defined. + * + * Returns: (element-type AsAgreement) (transfer none): an array + * + * Since: 0.7.8 + **/ +GPtrArray * +as_app_get_agreements (AsApp *app) +{ + AsAppPrivate *priv = GET_PRIVATE (app); + return priv->agreements; +} + +/** + * as_app_get_agreement_by_kind: + * @app: a #AsApp instance. + * @kind: an agreement kind, e.g. %AS_AGREEMENT_KIND_EULA + * + * Gets a agreement the application has defined of a specific type. + * + * Returns: (transfer none): a #AsAgreement or NULL for not found + * + * Since: 0.7.8 + **/ +AsAgreement * +as_app_get_agreement_by_kind (AsApp *app, AsAgreementKind kind) +{ + AsAppPrivate *priv = GET_PRIVATE (app); + guint i; + + for (i = 0; i < priv->agreements->len; i++) { + AsAgreement *agreement; + agreement = g_ptr_array_index (priv->agreements, i); + if (as_agreement_get_kind (agreement) == kind) + return agreement; + } + return NULL; +} + +/** + * as_app_get_agreement_default: + * @app: a #AsApp instance. + * + * Gets a privacy policys the application has defined of a specific type. + * + * Returns: (transfer none): a #AsAgreement or NULL for not found + * + * Since: 0.7.8 + **/ +AsAgreement * +as_app_get_agreement_default (AsApp *app) +{ + AsAppPrivate *priv = GET_PRIVATE (app); + if (priv->agreements->len < 1) + return NULL; + return g_ptr_array_index (priv->agreements, 0); +} + +/** * as_app_get_icons: * @app: a #AsApp instance. * @@ -3389,6 +3455,33 @@ as_app_add_content_rating (AsApp *app, AsContentRating *content_rating) g_ptr_array_add (priv->content_ratings, g_object_ref (content_rating)); } +/** + * as_app_add_agreement: + * @app: a #AsApp instance. + * @agreement: a #AsAgreement instance. + * + * Adds a agreement to an application. + * + * Since: 0.7.8 + **/ +void +as_app_add_agreement (AsApp *app, AsAgreement *agreement) +{ + AsAppPrivate *priv = GET_PRIVATE (app); + + /* handle untrusted */ + if ((priv->trust_flags & AS_APP_TRUST_FLAG_CHECK_DUPLICATES) > 0) { + for (guint i = 0; i < priv->agreements->len; i++) { + AsAgreement *cr_tmp = g_ptr_array_index (priv->agreements, i); + if (as_agreement_get_kind (cr_tmp) == as_agreement_get_kind (agreement)) { + priv->problems |= AS_APP_PROBLEM_DUPLICATE_AGREEMENT; + return; + } + } + } + g_ptr_array_add (priv->agreements, g_object_ref (agreement)); +} + static gboolean as_app_check_icon_duplicate (AsIcon *icon1, AsIcon *icon2) { @@ -4087,6 +4180,18 @@ as_app_subsume_private (AsApp *app, AsApp *donor, guint64 flags) } } + /* agreements */ + if (flags & AS_APP_SUBSUME_FLAG_AGREEMENTS) { + if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && + priv->agreements->len > 0) + g_ptr_array_set_size (papp->agreements, 0); + for (i = 0; i < priv->agreements->len; i++) { + AsAgreement *agreement; + agreement = g_ptr_array_index (priv->agreements, i); + as_app_add_agreement (app, agreement); + } + } + /* provides */ if (flags & AS_APP_SUBSUME_FLAG_PROVIDES) { if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 && @@ -4657,6 +4762,15 @@ as_app_node_insert (AsApp *app, GNode *parent, AsNodeContext *ctx) } } + /* <agreements> */ + if (priv->agreements->len > 0) { + for (i = 0; i < priv->agreements->len; i++) { + AsAgreement *agreement; + agreement = g_ptr_array_index (priv->agreements, i); + as_agreement_node_insert (agreement, node_app, ctx); + } + } + /* <releases> */ if (priv->releases->len > 0) { g_ptr_array_sort (priv->releases, as_app_releases_sort_cb); @@ -5127,6 +5241,17 @@ as_app_node_parse_child (AsApp *app, GNode *n, guint32 flags, break; } + /* <agreements> */ + case AS_TAG_AGREEMENT: + { + g_autoptr(AsAgreement) agreement = NULL; + agreement = as_agreement_new (); + if (!as_agreement_node_parse (agreement, n, ctx, error)) + return FALSE; + as_app_add_agreement (app, agreement); + break; + } + /* <releases> */ case AS_TAG_RELEASES: if (!(flags & AS_APP_PARSE_FLAG_APPEND_DATA)) @@ -5280,6 +5405,7 @@ as_app_node_parse_full (AsApp *app, GNode *node, guint32 flags, g_ptr_array_set_size (priv->suggests, 0); g_ptr_array_set_size (priv->requires, 0); g_ptr_array_set_size (priv->content_ratings, 0); + g_ptr_array_set_size (priv->agreements, 0); g_ptr_array_set_size (priv->launchables, 0); g_hash_table_remove_all (priv->keywords); } diff --git a/libappstream-glib/as-app.h b/libappstream-glib/as-app.h index 3b4f1e0..a878479 100644 --- a/libappstream-glib/as-app.h +++ b/libappstream-glib/as-app.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2014-2017 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2014-2018 Richard Hughes <richard@hughsie.com> * * Licensed under the GNU Lesser General Public License Version 2.1 * @@ -40,6 +40,7 @@ #include "as-review.h" #include "as-suggest.h" #include "as-content-rating.h" +#include "as-agreement.h" #include "as-translation.h" G_BEGIN_DECLS @@ -108,6 +109,7 @@ typedef enum { * @AS_APP_SUBSUME_FLAG_SCREENSHOTS: Copy the screenshots * @AS_APP_SUBSUME_FLAG_REVIEWS: Copy the reviews * @AS_APP_SUBSUME_FLAG_CONTENT_RATINGS: Copy the content ratings + * @AS_APP_SUBSUME_FLAG_AGREEMENTS: Copy the agreements * @AS_APP_SUBSUME_FLAG_PROVIDES: Copy the provides * @AS_APP_SUBSUME_FLAG_ICONS: Copy the icons * @AS_APP_SUBSUME_FLAG_MIMETYPES: Copy the mimetypes @@ -170,6 +172,7 @@ typedef enum { AS_APP_SUBSUME_FLAG_SOURCE_KIND = 1ull << 34, /* Since: 0.6.1 */ AS_APP_SUBSUME_FLAG_SUGGESTS = 1ull << 35, /* Since: 0.6.3 */ AS_APP_SUBSUME_FLAG_LAUNCHABLES = 1ull << 36, /* Since: 0.6.13 */ + AS_APP_SUBSUME_FLAG_AGREEMENTS = 1ull << 37, /* Since: 0.7.8 */ /*< private >*/ AS_APP_SUBSUME_FLAG_LAST, } AsAppSubsumeFlags; @@ -182,6 +185,7 @@ typedef enum { AS_APP_SUBSUME_FLAG_COMMENT | \ AS_APP_SUBSUME_FLAG_COMPULSORY | \ AS_APP_SUBSUME_FLAG_CONTENT_RATINGS | \ + AS_APP_SUBSUME_FLAG_AGREEMENTS | \ AS_APP_SUBSUME_FLAG_DESCRIPTION | \ AS_APP_SUBSUME_FLAG_DEVELOPER_NAME | \ AS_APP_SUBSUME_FLAG_EXTENDS | \ @@ -646,6 +650,8 @@ void as_app_add_review (AsApp *app, AsReview *review); void as_app_add_content_rating (AsApp *app, AsContentRating *content_rating); +void as_app_add_agreement (AsApp *app, + AsAgreement *agreement); void as_app_add_icon (AsApp *app, AsIcon *icon); void as_app_add_bundle (AsApp *app, @@ -709,6 +715,9 @@ gboolean as_app_to_file (AsApp *app, GError **error); AsContentRating *as_app_get_content_rating (AsApp *app, const gchar *kind); +AsAgreement *as_app_get_agreement_by_kind (AsApp *app, + AsAgreementKind kind); +AsAgreement *as_app_get_agreement_default (AsApp *app); AsScreenshot *as_app_get_screenshot_default (AsApp *app); AsIcon *as_app_get_icon_default (AsApp *app); AsIcon *as_app_get_icon_for_size (AsApp *app, diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c index ead8c81..3c85a12 100644 --- a/libappstream-glib/as-self-test.c +++ b/libappstream-glib/as-self-test.c @@ -27,6 +27,7 @@ #include <string.h> #include <fnmatch.h> +#include "as-agreement-private.h" #include "as-app-private.h" #include "as-app-builder.h" #include "as-bundle-private.h" @@ -1273,6 +1274,57 @@ as_test_image_func (void) g_assert (ret); } +static void +as_test_agreement_func (void) +{ + GError *error = NULL; + AsAgreementSection *sect; + AsNode *n; + AsNode *root; + GString *xml; + const gchar *src = + "<agreement type=\"eula\" version_id=\"1.2.3a\">\n" + "<agreement_section type=\"intro\">\n" + "<description><p>Mighty Fine</p></description>\n" + "</agreement_section>\n" + "</agreement>\n"; + gboolean ret; + g_autoptr(AsAgreement) agreement = NULL; + g_autoptr(AsNodeContext) ctx = NULL; + + agreement = as_agreement_new (); + + /* to object */ + root = as_node_from_xml (src, 0, &error); + g_assert_no_error (error); + g_assert (root != NULL); + n = as_node_find (root, "agreement"); + g_assert (n != NULL); + ctx = as_node_context_new (); + ret = as_agreement_node_parse (agreement, n, ctx, &error); + g_assert_no_error (error); + g_assert (ret); + as_node_unref (root); + + /* verify */ + g_assert_cmpint (as_agreement_get_kind (agreement), ==, AS_AGREEMENT_KIND_EULA); + g_assert_cmpstr (as_agreement_get_version_id (agreement), ==, "1.2.3a"); + sect = as_agreement_get_section_default (agreement); + g_assert_nonnull (sect); + g_assert_cmpstr (as_agreement_section_get_kind (sect), ==, "intro"); + g_assert_cmpstr (as_agreement_section_get_description (sect, NULL), ==, "<p>Mighty Fine</p>"); + + /* back to node */ + root = as_node_new (); + as_node_context_set_version (ctx, 0.4); + n = as_agreement_node_insert (agreement, root, ctx); + xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE); + ret = as_test_compare_lines (xml->str, src, &error); + g_assert_no_error (error); + g_assert (ret); + g_string_free (xml, TRUE); + as_node_unref (root); +} static void as_test_review_func (void) @@ -5576,6 +5628,7 @@ main (int argc, char **argv) g_test_add_func ("/AppStream/icon{embedded}", as_test_icon_embedded_func); g_test_add_func ("/AppStream/bundle", as_test_bundle_func); g_test_add_func ("/AppStream/review", as_test_review_func); + g_test_add_func ("/AppStream/agreement", as_test_agreement_func); g_test_add_func ("/AppStream/translation", as_test_translation_func); g_test_add_func ("/AppStream/suggest", as_test_suggest_func); g_test_add_func ("/AppStream/image", as_test_image_func); diff --git a/libappstream-glib/as-tag.c b/libappstream-glib/as-tag.c index 56aad4d..adf3a54 100644 --- a/libappstream-glib/as-tag.c +++ b/libappstream-glib/as-tag.c @@ -190,6 +190,8 @@ as_tag_to_string (AsTag tag) "requires", "custom", "launchable", + "agreement", + "agreement_section", NULL }; if (tag > AS_TAG_LAST) tag = AS_TAG_LAST; diff --git a/libappstream-glib/as-tag.gperf b/libappstream-glib/as-tag.gperf index b090d49..8f70954 100644 --- a/libappstream-glib/as-tag.gperf +++ b/libappstream-glib/as-tag.gperf @@ -67,3 +67,5 @@ suggests, AS_TAG_SUGGESTS requires, AS_TAG_REQUIRES custom, AS_TAG_CUSTOM launchable, AS_TAG_LAUNCHABLE +agreement, AS_TAG_AGREEMENT +agreement_section, AS_TAG_AGREEMENT_SECTION diff --git a/libappstream-glib/as-tag.h b/libappstream-glib/as-tag.h index adb7c79..61af6b8 100644 --- a/libappstream-glib/as-tag.h +++ b/libappstream-glib/as-tag.h @@ -92,6 +92,8 @@ G_BEGIN_DECLS * @AS_TAG_REQUIRES: `requires` * @AS_TAG_CUSTOM: `custom` * @AS_TAG_LAUNCHABLE: `launchable` + * @AS_TAG_AGREEMENT: `agreement` + * @AS_TAG_AGREEMENT_SECTION: `agreement_section` * * The tag type. **/ @@ -156,6 +158,8 @@ typedef enum { AS_TAG_REQUIRES, /* Since: 0.6.7 */ AS_TAG_CUSTOM, /* Since: 0.6.8 */ AS_TAG_LAUNCHABLE, /* Since: 0.6.13 */ + AS_TAG_AGREEMENT, /* Since: 0.7.8 */ + AS_TAG_AGREEMENT_SECTION, /* Since: 0.7.8 */ /*< private >*/ AS_TAG_LAST } AsTag; diff --git a/libappstream-glib/meson.build b/libappstream-glib/meson.build index 19576fa..33e1f61 100644 --- a/libappstream-glib/meson.build +++ b/libappstream-glib/meson.build @@ -50,6 +50,8 @@ headers = [ 'as-markup.h', 'as-monitor.h', 'as-node.h', + 'as-agreement.h', + 'as-agreement-section.h', 'as-problem.h', 'as-profile.h', 'as-provide.h', @@ -84,6 +86,8 @@ sources = [ 'as-monitor.c', 'as-monitor.c', 'as-node.c', + 'as-agreement.c', + 'as-agreement-section.c', 'as-problem.c', 'as-profile.c', 'as-provide.c', @@ -189,6 +193,10 @@ introspection_sources = [ 'as-markup.h', 'as-node.c', 'as-node.h', + 'as-agreement.c', + 'as-agreement.h', + 'as-agreement-section.c', + 'as-agreement-section.h', 'as-problem.c', 'as-problem.h', 'as-provide.c', |