/* * Copyright (C) 2021 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include "config.h" #include "fwupd-enums-private.h" #include "fwupd-request-private.h" /** * FwupdRequest: * * A user request from the device. * * See also: [class@FwupdDevice] */ typedef struct { gchar *id; FwupdRequestKind kind; guint64 created; gchar *device_id; gchar *message; gchar *image; } FwupdRequestPrivate; enum { PROP_0, PROP_ID, PROP_KIND, PROP_MESSAGE, PROP_IMAGE, PROP_LAST }; G_DEFINE_TYPE_WITH_PRIVATE (FwupdRequest, fwupd_request, G_TYPE_OBJECT) #define GET_PRIVATE(o) (fwupd_request_get_instance_private (o)) /** * fwupd_request_kind_to_string: * @kind: a update message kind, e.g. %FWUPD_REQUEST_KIND_IMMEDIATE * * Converts a enumerated update message kind to a string. * * Returns: identifier string * * Since: 1.6.2 **/ const gchar * fwupd_request_kind_to_string (FwupdRequestKind kind) { if (kind == FWUPD_REQUEST_KIND_UNKNOWN) return "unknown"; if (kind == FWUPD_REQUEST_KIND_POST) return "post"; if (kind == FWUPD_REQUEST_KIND_IMMEDIATE) return "immediate"; return NULL; } /** * fwupd_request_kind_from_string: * @kind: a string, e.g. `immediate` * * Converts a string to an enumerated update message kind. * * Returns: enumerated value * * Since: 1.6.2 **/ FwupdRequestKind fwupd_request_kind_from_string (const gchar *kind) { if (g_strcmp0 (kind, "unknown") == 0) return FWUPD_REQUEST_KIND_UNKNOWN; if (g_strcmp0 (kind, "post") == 0) return FWUPD_REQUEST_KIND_POST; if (g_strcmp0 (kind, "immediate") == 0) return FWUPD_REQUEST_KIND_IMMEDIATE; return FWUPD_REQUEST_KIND_LAST; } /** * fwupd_request_get_id: * @self: a #FwupdRequest * * Gets the ID. * * Returns: the ID, or %NULL if unset * * Since: 1.6.2 **/ const gchar * fwupd_request_get_id (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FWUPD_IS_REQUEST (self), NULL); return priv->id; } /** * fwupd_request_set_id: * @self: a #FwupdRequest * @id: (nullable): the request ID, e.g. `USB:foo` * * Sets the ID. * * Since: 1.6.2 **/ void fwupd_request_set_id (FwupdRequest *self, const gchar *id) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_REQUEST (self)); /* not changed */ if (g_strcmp0 (priv->id, id) == 0) return; g_free (priv->id); priv->id = g_strdup (id); } /** * fwupd_request_get_device_id: * @self: a #FwupdRequest * * Gets the device_id that created the request. * * Returns: the device_id, or %NULL if unset * * Since: 1.6.2 **/ const gchar * fwupd_request_get_device_id (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FWUPD_IS_REQUEST (self), NULL); return priv->device_id; } /** * fwupd_request_set_device_id: * @self: a #FwupdRequest * @device_id: (nullable): the device_id, e.g. `colorhug` * * Sets the device_id that created the request. * * Since: 1.6.2 **/ void fwupd_request_set_device_id (FwupdRequest *self, const gchar *device_id) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_REQUEST (self)); /* not changed */ if (g_strcmp0 (priv->device_id, device_id) == 0) return; g_free (priv->device_id); priv->device_id = g_strdup (device_id); } /** * fwupd_request_get_created: * @self: a #FwupdRequest * * Gets when the request was created. * * Returns: the UNIX time, or 0 if unset * * Since: 1.6.2 **/ guint64 fwupd_request_get_created (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FWUPD_IS_REQUEST (self), 0); return priv->created; } /** * fwupd_request_set_created: * @self: a #FwupdRequest * @created: the UNIX time * * Sets when the request was created. * * Since: 1.6.2 **/ void fwupd_request_set_created (FwupdRequest *self, guint64 created) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_REQUEST (self)); priv->created = created; } /** * fwupd_request_to_variant: * @self: a #FwupdRequest * * Serialize the request data. * * Returns: the serialized data, or %NULL for error * * Since: 1.6.2 **/ GVariant * fwupd_request_to_variant (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); GVariantBuilder builder; g_return_val_if_fail (FWUPD_IS_REQUEST (self), NULL); /* create an array with all the metadata in */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); if (priv->id != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_APPSTREAM_ID, g_variant_new_string (priv->id)); } if (priv->created > 0) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_CREATED, g_variant_new_uint64 (priv->created)); } if (priv->device_id != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_PLUGIN, g_variant_new_string (priv->device_id)); } if (priv->message != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_MESSAGE, g_variant_new_string (priv->message)); } if (priv->image != NULL) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_UPDATE_IMAGE, g_variant_new_string (priv->image)); } if (priv->kind != FWUPD_REQUEST_KIND_UNKNOWN) { g_variant_builder_add (&builder, "{sv}", FWUPD_RESULT_KEY_REQUEST_KIND, g_variant_new_uint32 (priv->kind)); } return g_variant_new ("a{sv}", &builder); } static void fwupd_request_from_key_value (FwupdRequest *self, const gchar *key, GVariant *value) { if (g_strcmp0 (key, FWUPD_RESULT_KEY_APPSTREAM_ID) == 0) { fwupd_request_set_id (self, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_CREATED) == 0) { fwupd_request_set_created (self, g_variant_get_uint64 (value)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_DEVICE_ID) == 0) { fwupd_request_set_device_id (self, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_MESSAGE) == 0) { fwupd_request_set_message (self, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_UPDATE_IMAGE) == 0) { fwupd_request_set_image (self, g_variant_get_string (value, NULL)); return; } if (g_strcmp0 (key, FWUPD_RESULT_KEY_REQUEST_KIND) == 0) { fwupd_request_set_kind (self, g_variant_get_uint32 (value)); return; } } static void fwupd_pad_kv_str (GString *str, const gchar *key, const gchar *value) { /* ignore */ if (key == NULL || value == NULL) return; g_string_append_printf (str, " %s: ", key); for (gsize i = strlen (key); i < 20; i++) g_string_append (str, " "); g_string_append_printf (str, "%s\n", value); } static void fwupd_pad_kv_unx (GString *str, const gchar *key, guint64 value) { g_autoptr(GDateTime) date = NULL; g_autofree gchar *tmp = NULL; /* ignore */ if (value == 0) return; date = g_date_time_new_from_unix_utc ((gint64) value); tmp = g_date_time_format (date, "%F"); fwupd_pad_kv_str (str, key, tmp); } /** * fwupd_request_get_message: * @self: a #FwupdRequest * * Gets the update message. * * Returns: the update message, or %NULL if unset * * Since: 1.6.2 **/ const gchar * fwupd_request_get_message (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FWUPD_IS_REQUEST (self), NULL); return priv->message; } /** * fwupd_request_set_message: * @self: a #FwupdRequest * @message: (nullable): the update message string * * Sets the update message. * * Since: 1.6.2 **/ void fwupd_request_set_message (FwupdRequest *self, const gchar *message) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_REQUEST (self)); /* not changed */ if (g_strcmp0 (priv->message, message) == 0) return; g_free (priv->message); priv->message = g_strdup (message); g_object_notify (G_OBJECT (self), "message"); } /** * fwupd_request_get_image: * @self: a #FwupdRequest * * Gets the update image. * * Returns: the update image URL, or %NULL if unset * * Since: 1.6.2 **/ const gchar * fwupd_request_get_image (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FWUPD_IS_REQUEST (self), NULL); return priv->image; } /** * fwupd_request_set_image: * @self: a #FwupdRequest * @image: (nullable): the update image URL * * Sets the update image. * * Since: 1.6.2 **/ void fwupd_request_set_image (FwupdRequest *self, const gchar *image) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_REQUEST (self)); /* not changed */ if (g_strcmp0 (priv->image, image) == 0) return; g_free (priv->image); priv->image = g_strdup (image); g_object_notify (G_OBJECT (self), "image"); } /** * fwupd_request_get_kind: * @self: a #FwupdRequest * * Returns what the request is currently doing. * * Returns: the kind value, e.g. %FWUPD_STATUS_REQUEST_WRITE * * Since: 1.6.2 **/ FwupdRequestKind fwupd_request_get_kind (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_val_if_fail (FWUPD_IS_REQUEST (self), 0); return priv->kind; } /** * fwupd_request_set_kind: * @self: a #FwupdRequest * @kind: the kind value, e.g. %FWUPD_STATUS_REQUEST_WRITE * * Sets what the request is currently doing. * * Since: 1.6.2 **/ void fwupd_request_set_kind (FwupdRequest *self, FwupdRequestKind kind) { FwupdRequestPrivate *priv = GET_PRIVATE (self); g_return_if_fail (FWUPD_IS_REQUEST (self)); if (priv->kind == kind) return; priv->kind = kind; g_object_notify (G_OBJECT (self), "kind"); } /** * fwupd_request_to_string: * @self: a #FwupdRequest * * Builds a text representation of the object. * * Returns: text, or %NULL for invalid * * Since: 1.6.2 **/ gchar * fwupd_request_to_string (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); GString *str = g_string_new (NULL); g_return_val_if_fail (FWUPD_IS_REQUEST (self), NULL); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_APPSTREAM_ID, priv->id); if (priv->kind != FWUPD_REQUEST_KIND_UNKNOWN) { fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_REQUEST_KIND, fwupd_request_kind_to_string (priv->kind)); } fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DEVICE_ID, priv->device_id); fwupd_pad_kv_unx (str, FWUPD_RESULT_KEY_CREATED, priv->created); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_MESSAGE, priv->message); fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_UPDATE_IMAGE, priv->image); return g_string_free (str, FALSE); } static void fwupd_request_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { FwupdRequest *self = FWUPD_REQUEST (object); FwupdRequestPrivate *priv = GET_PRIVATE (self); switch (prop_id) { case PROP_ID: g_value_set_string (value, priv->id); break; case PROP_MESSAGE: g_value_set_string (value, priv->message); break; case PROP_IMAGE: g_value_set_string (value, priv->image); break; case PROP_KIND: g_value_set_uint (value, priv->kind); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void fwupd_request_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { FwupdRequest *self = FWUPD_REQUEST (object); switch (prop_id) { case PROP_ID: fwupd_request_set_id (self, g_value_get_string (value)); break; case PROP_MESSAGE: fwupd_request_set_message (self, g_value_get_string (value)); break; case PROP_IMAGE: fwupd_request_set_image (self, g_value_get_string (value)); break; case PROP_KIND: fwupd_request_set_kind (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void fwupd_request_finalize (GObject *object) { FwupdRequest *self = FWUPD_REQUEST (object); FwupdRequestPrivate *priv = GET_PRIVATE (self); g_free (priv->id); g_free (priv->device_id); g_free (priv->message); g_free (priv->image); G_OBJECT_CLASS (fwupd_request_parent_class)->finalize (object); } static void fwupd_request_init (FwupdRequest *self) { FwupdRequestPrivate *priv = GET_PRIVATE (self); priv->created = g_get_real_time () / G_USEC_PER_SEC; } static void fwupd_request_class_init (FwupdRequestClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; object_class->finalize = fwupd_request_finalize; object_class->get_property = fwupd_request_get_property; object_class->set_property = fwupd_request_set_property; pspec = g_param_spec_string ("id", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_ID, pspec); pspec = g_param_spec_uint ("kind", NULL, NULL, FWUPD_REQUEST_KIND_UNKNOWN, FWUPD_REQUEST_KIND_LAST, FWUPD_REQUEST_KIND_UNKNOWN, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_KIND, pspec); pspec = g_param_spec_string ("message", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_MESSAGE, pspec); pspec = g_param_spec_string ("image", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME); g_object_class_install_property (object_class, PROP_IMAGE, pspec); } static void fwupd_request_set_from_variant_iter (FwupdRequest *self, GVariantIter *iter) { GVariant *value; const gchar *key; while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { fwupd_request_from_key_value (self, key, value); g_variant_unref (value); } } /** * fwupd_request_from_variant: * @value: the serialized data * * Creates a new request using serialized data. * * Returns: (transfer full): a new #FwupdRequest, or %NULL if @value was invalid * * Since: 1.6.2 **/ FwupdRequest * fwupd_request_from_variant (GVariant *value) { FwupdRequest *self = NULL; const gchar *type_string; g_autoptr(GVariantIter) iter = NULL; /* format from GetDetails */ type_string = g_variant_get_type_string (value); if (g_strcmp0 (type_string, "(a{sv})") == 0) { self = fwupd_request_new (); g_variant_get (value, "(a{sv})", &iter); fwupd_request_set_from_variant_iter (self, iter); } else if (g_strcmp0 (type_string, "a{sv}") == 0) { self = fwupd_request_new (); g_variant_get (value, "a{sv}", &iter); fwupd_request_set_from_variant_iter (self, iter); } else { g_warning ("type %s not known", type_string); } return self; } /** * fwupd_request_new: * * Creates a new request. * * Returns: a new #FwupdRequest * * Since: 1.6.2 **/ FwupdRequest * fwupd_request_new (void) { FwupdRequest *self; self = g_object_new (FWUPD_TYPE_REQUEST, NULL); return FWUPD_REQUEST (self); }