/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * vi:set noexpandtab tabstop=8 shiftwidth=8: * * Copyright (C) 2017 Richard Hughes * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include "gs-fwupd-app.h" const gchar * gs_fwupd_app_get_device_id (GsApp *app) { return gs_app_get_metadata_item (app, "fwupd::DeviceID"); } const gchar * gs_fwupd_app_get_update_uri (GsApp *app) { return gs_app_get_metadata_item (app, "fwupd::UpdateID"); } gboolean gs_fwupd_app_get_is_locked (GsApp *app) { GVariant *tmp = gs_app_get_metadata_variant (app, "fwupd::IsLocked"); if (tmp == NULL) return FALSE; return g_variant_get_boolean (tmp); } void gs_fwupd_app_set_device_id (GsApp *app, const gchar *device_id) { gs_app_set_metadata (app, "fwupd::DeviceID", device_id); } void gs_fwupd_app_set_update_uri (GsApp *app, const gchar *update_uri) { /* cannot overwrite the value, thus remove it first; an overwrite can happen for example when a historical update was found and there is also a new update for the same device */ gs_app_set_metadata (app, "fwupd::UpdateID", NULL); gs_app_set_metadata (app, "fwupd::UpdateID", update_uri); } void gs_fwupd_app_set_is_locked (GsApp *app, gboolean is_locked) { g_autoptr(GVariant) tmp = g_variant_new_boolean (is_locked); gs_app_set_metadata_variant (app, "fwupd::IsLocked", tmp); } #if FWUPD_CHECK_VERSION(1, 8, 1) static gchar * /* (transfer full) */ gs_fwupd_problem_to_string (FwupdClient *client, FwupdDevice *dev, FwupdDeviceProblem problem) { if (problem == FWUPD_DEVICE_PROBLEM_SYSTEM_POWER_TOO_LOW) { if (fwupd_client_get_battery_level (client) == FWUPD_BATTERY_LEVEL_INVALID || fwupd_client_get_battery_threshold (client) == FWUPD_BATTERY_LEVEL_INVALID) { /* TRANSLATORS: as in laptop battery power */ return g_strdup (_("System power is too low to perform the update")); } return g_strdup_printf ( /* TRANSLATORS: as in laptop battery power */ _("System power is too low to perform the update (%u%%, requires %u%%)"), fwupd_client_get_battery_level (client), fwupd_client_get_battery_threshold (client)); } if (problem == FWUPD_DEVICE_PROBLEM_UNREACHABLE) { /* TRANSLATORS: for example, a Bluetooth mouse that is in powersave mode */ return g_strdup (_("Device is unreachable, or out of wireless range")); } if (problem == FWUPD_DEVICE_PROBLEM_POWER_TOO_LOW) { if (fwupd_device_get_battery_level (dev) == FWUPD_BATTERY_LEVEL_INVALID || fwupd_device_get_battery_threshold (dev) == FWUPD_BATTERY_LEVEL_INVALID) { /* TRANSLATORS: for example the batteries *inside* the Bluetooth mouse */ return g_strdup_printf (_("Device battery power is too low")); } /* TRANSLATORS: for example the batteries *inside* the Bluetooth mouse */ return g_strdup_printf (_("Device battery power is too low (%u%%, requires %u%%)"), fwupd_device_get_battery_level (dev), fwupd_device_get_battery_threshold (dev)); } if (problem == FWUPD_DEVICE_PROBLEM_UPDATE_PENDING) { /* TRANSLATORS: usually this is when we're waiting for a reboot */ return g_strdup (_("Device is waiting for the update to be applied")); } if (problem == FWUPD_DEVICE_PROBLEM_REQUIRE_AC_POWER) { /* TRANSLATORS: as in, wired mains power for a laptop */ return g_strdup (_("Device requires AC power to be connected")); } if (problem == FWUPD_DEVICE_PROBLEM_LID_IS_CLOSED) { /* TRANSLATORS: lid means "laptop top cover" */ return g_strdup (_("Device cannot be used while the lid is closed")); } return NULL; } #endif void gs_fwupd_app_set_from_device (GsApp *app, FwupdClient *client, FwupdDevice *dev) { GPtrArray *guids; /* something can be done */ if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE) #if FWUPD_CHECK_VERSION(1, 8, 1) || fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN) #endif ) gs_app_set_state (app, GS_APP_STATE_UPDATABLE_LIVE); /* reboot required to apply update */ if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_REBOOT)) gs_app_add_quirk (app, GS_APP_QUIRK_NEEDS_REBOOT); /* is removable or cannot be used during update */ if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_INTERNAL) || !fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_USABLE_DURING_UPDATE)) gs_app_add_quirk (app, GS_APP_QUIRK_UNUSABLE_DURING_UPDATE); guids = fwupd_device_get_guids (dev); if (guids->len > 0) { g_autofree gchar *guid_str = NULL; g_auto(GStrv) tmp = g_new0 (gchar *, guids->len + 1); for (guint i = 0; i < guids->len; i++) tmp[i] = g_strdup (g_ptr_array_index (guids, i)); guid_str = g_strjoinv (",", tmp); gs_app_set_metadata (app, "fwupd::Guid", guid_str); } if (fwupd_device_get_name (dev) != NULL) { g_autofree gchar *vendor_name = NULL; if (fwupd_device_get_vendor (dev) == NULL || g_str_has_prefix (fwupd_device_get_name (dev), fwupd_device_get_vendor (dev))) { vendor_name = g_strdup (fwupd_device_get_name (dev)); } else { vendor_name = g_strdup_printf ("%s %s", fwupd_device_get_vendor (dev), fwupd_device_get_name (dev)); } gs_app_set_name (app, GS_APP_QUALITY_NORMAL, vendor_name); } if (fwupd_device_get_summary (dev) != NULL) { gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, fwupd_device_get_summary (dev)); } if (fwupd_device_get_version (dev) != NULL) { gs_app_set_version (app, fwupd_device_get_version (dev)); } if (fwupd_device_get_created (dev) != 0) gs_app_set_install_date (app, fwupd_device_get_created (dev)); #if FWUPD_CHECK_VERSION(1, 8, 1) if (fwupd_device_get_problems (dev) != FWUPD_DEVICE_PROBLEM_NONE) { g_autoptr(GString) problems = g_string_new (NULL); for (guint i = 0; i < sizeof (FwupdDeviceProblem) * 8; i++) { FwupdDeviceProblem problem = 1ull << i; g_autofree gchar *tmp = NULL; if (!fwupd_device_has_problem (dev, problem)) continue; tmp = gs_fwupd_problem_to_string (client, dev, problem); if (tmp == NULL) continue; if (problems->len) g_string_append_c (problems, '\n'); g_string_append (problems, tmp); } if (problems->len) gs_app_set_metadata (app, "GnomeSoftware::problems", problems->str); else gs_app_set_metadata (app, "GnomeSoftware::problems", NULL); } else { gs_app_set_metadata (app, "GnomeSoftware::problems", NULL); } #endif /* needs action */ if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_NEEDS_BOOTLOADER) #if FWUPD_CHECK_VERSION(1, 8, 1) || fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN) || fwupd_device_get_problems (dev) != FWUPD_DEVICE_PROBLEM_NONE #endif ) gs_app_add_quirk (app, GS_APP_QUIRK_NEEDS_USER_ACTION); else gs_app_remove_quirk (app, GS_APP_QUIRK_NEEDS_USER_ACTION); } static gchar * gs_fwupd_release_get_name (FwupdRelease *release) { const gchar *name = fwupd_release_get_name (release); GPtrArray *cats = fwupd_release_get_categories (release); for (guint i = 0; i < cats->len; i++) { const gchar *cat = g_ptr_array_index (cats, i); if (g_strcmp0 (cat, "X-Device") == 0) { /* TRANSLATORS: a specific part of hardware, * the first %s is the device name, e.g. 'Unifying Receiver` */ return g_strdup_printf (_("%s Device Update"), name); } if (g_strcmp0 (cat, "X-System") == 0) { /* TRANSLATORS: the entire system, e.g. all internal devices, * the first %s is the device name, e.g. 'ThinkPad P50` */ return g_strdup_printf (_("%s System Update"), name); } if (g_strcmp0 (cat, "X-EmbeddedController") == 0) { /* TRANSLATORS: the EC is typically the keyboard controller chip, * the first %s is the device name, e.g. 'ThinkPad P50` */ return g_strdup_printf (_("%s Embedded Controller Update"), name); } if (g_strcmp0 (cat, "X-ManagementEngine") == 0) { /* TRANSLATORS: ME stands for Management Engine, the Intel AMT thing, * the first %s is the device name, e.g. 'ThinkPad P50` */ return g_strdup_printf (_("%s ME Update"), name); } if (g_strcmp0 (cat, "X-CorporateManagementEngine") == 0) { /* TRANSLATORS: ME stands for Management Engine (with Intel AMT), * where the first %s is the device name, e.g. 'ThinkPad P50` */ return g_strdup_printf (_("%s Corporate ME Update"), name); } if (g_strcmp0 (cat, "X-ConsumerManagementEngine") == 0) { /* TRANSLATORS: ME stands for Management Engine, where * the first %s is the device name, e.g. 'ThinkPad P50` */ return g_strdup_printf (_("%s Consumer ME Update"), name); } if (g_strcmp0 (cat, "X-Controller") == 0) { /* TRANSLATORS: the controller is a device that has other devices * plugged into it, for example ThunderBolt, FireWire or USB, * the first %s is the device name, e.g. 'Intel ThunderBolt` */ return g_strdup_printf (_("%s Controller Update"), name); } if (g_strcmp0 (cat, "X-ThunderboltController") == 0) { /* TRANSLATORS: the Thunderbolt controller is a device that * has other high speed Thunderbolt devices plugged into it; * the first %s is the system name, e.g. 'ThinkPad P50` */ return g_strdup_printf (_("%s Thunderbolt Controller Update"), name); } if (g_strcmp0 (cat, "X-CpuMicrocode") == 0) { /* TRANSLATORS: the CPU microcode is firmware loaded onto the CPU * at system bootup */ return g_strdup_printf (_("%s CPU Microcode Update"), name); } if (g_strcmp0 (cat, "X-Configuration") == 0) { /* TRANSLATORS: configuration refers to hardware state, * e.g. a security database or a default power value */ return g_strdup_printf (_("%s Configuration Update"), name); } if (g_strcmp0 (cat, "X-Battery") == 0) { /* TRANSLATORS: battery refers to the system power source */ return g_strdup_printf (_("%s Battery Update"), name); } if (g_strcmp0 (cat, "X-Camera") == 0) { /* TRANSLATORS: camera can refer to the laptop internal * camera in the bezel or external USB webcam */ return g_strdup_printf (_("%s Camera Update"), name); } if (g_strcmp0 (cat, "X-TPM") == 0) { /* TRANSLATORS: TPM refers to a Trusted Platform Module */ return g_strdup_printf (_("%s TPM Update"), name); } if (g_strcmp0 (cat, "X-Touchpad") == 0) { /* TRANSLATORS: TouchPad refers to a flat input device */ return g_strdup_printf (_("%s Touchpad Update"), name); } if (g_strcmp0 (cat, "X-Mouse") == 0) { /* TRANSLATORS: Mouse refers to a handheld input device */ return g_strdup_printf (_("%s Mouse Update"), name); } if (g_strcmp0 (cat, "X-Keyboard") == 0) { /* TRANSLATORS: Keyboard refers to an input device for typing */ return g_strdup_printf (_("%s Keyboard Update"), name); } if (g_strcmp0 (cat, "X-StorageController") == 0) { /* TRANSLATORS: Storage Controller is typically a RAID or SAS adapter */ return g_strdup_printf (_("%s Storage Controller Update"), name); } if (g_strcmp0 (cat, "X-NetworkInterface") == 0) { /* TRANSLATORS: Network Interface refers to the physical * PCI card, not the logical wired connection */ return g_strdup_printf (_("%s Network Interface Update"), name); } if (g_strcmp0 (cat, "X-VideoDisplay") == 0) { /* TRANSLATORS: Video Display refers to the laptop internal display or * external monitor */ return g_strdup_printf (_("%s Display Update"), name); } if (g_strcmp0 (cat, "X-BaseboardManagementController") == 0) { /* TRANSLATORS: BMC refers to baseboard management controller which * is the device that updates all the other firmware on the system */ return g_strdup_printf (_("%s BMC Update"), name); } if (g_strcmp0 (cat, "X-UsbReceiver") == 0) { /* TRANSLATORS: Receiver refers to a radio device, e.g. a tiny Bluetooth * device that stays in the USB port so the wireless peripheral works */ return g_strdup_printf (_("%s USB Receiver Update"), name); } if (g_strcmp0 (cat, "X-Drive") == 0) { /* TRANSLATORS: drive refers to a storage device, e.g. SATA disk */ return g_strdup_printf (_("%s Drive Update"), name); } if (g_strcmp0 (cat, "X-FlashDrive") == 0) { /* TRANSLATORS: flash refers to solid state storage, e.g. UFS or eMMC */ return g_strdup_printf (_("%s Flash Drive Update"), name); } if (g_strcmp0 (cat, "X-SolidStateDrive") == 0) { /* TRANSLATORS: SSD refers to a Solid State Drive, e.g. non-rotating * SATA or NVMe disk */ return g_strdup_printf (_("%s SSD Update"), name); } if (g_strcmp0 (cat, "X-Gpu") == 0) { /* TRANSLATORS: GPU refers to a Graphics Processing Unit, e.g. * the "video card" */ return g_strdup_printf (_("%s GPU Update"), name); } if (g_strcmp0 (cat, "X-Dock") == 0) { /* TRANSLATORS: Dock refers to the port replicator hardware laptops are * cradled in, or lowered onto */ return g_strdup_printf (_("%s Dock Update"), name); } if (g_strcmp0 (cat, "X-UsbDock") == 0) { /* TRANSLATORS: Dock refers to the port replicator device connected * by plugging in a USB cable -- which may or may not also provide power */ return g_strdup_printf (_("%s USB Dock Update"), name); } } /* default fallback */ return g_strdup (name); } static AsUrgencyKind gs_fwupd_release_urgency_to_as_urgency_kind (FwupdReleaseUrgency urgency) { switch (urgency) { case FWUPD_RELEASE_URGENCY_LOW: return AS_URGENCY_KIND_LOW; case FWUPD_RELEASE_URGENCY_MEDIUM: return AS_URGENCY_KIND_MEDIUM; case FWUPD_RELEASE_URGENCY_HIGH: return AS_URGENCY_KIND_HIGH; case FWUPD_RELEASE_URGENCY_CRITICAL: return AS_URGENCY_KIND_CRITICAL; case FWUPD_RELEASE_URGENCY_UNKNOWN: default: return AS_URGENCY_KIND_UNKNOWN; } } void gs_fwupd_app_set_from_release (GsApp *app, FwupdRelease *rel) { GPtrArray *locations = fwupd_release_get_locations (rel); if (fwupd_release_get_name (rel) != NULL) { g_autofree gchar *tmp = gs_fwupd_release_get_name (rel); gs_app_set_name (app, GS_APP_QUALITY_NORMAL, tmp); } if (fwupd_release_get_summary (rel) != NULL) { gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, fwupd_release_get_summary (rel)); } if (fwupd_release_get_homepage (rel) != NULL) { gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, fwupd_release_get_homepage (rel)); } if (fwupd_release_get_size (rel) != 0) { gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, 0); gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, fwupd_release_get_size (rel)); } if (fwupd_release_get_version (rel) != NULL) gs_app_set_update_version (app, fwupd_release_get_version (rel)); if (fwupd_release_get_license (rel) != NULL) { gs_app_set_license (app, GS_APP_QUALITY_NORMAL, fwupd_release_get_license (rel)); } if (locations->len > 0) { const gchar *uri = g_ptr_array_index (locations, 0); /* typically the first URI will be the main HTTP mirror, and we * don't have the capability to use an IPFS/IPNS URL anyway */ gs_app_set_origin_hostname (app, uri); gs_fwupd_app_set_update_uri (app, uri); } if (fwupd_release_get_description (rel) != NULL) { g_autofree gchar *tmp = NULL; #if AS_CHECK_VERSION(1, 0, 0) tmp = as_markup_convert (fwupd_release_get_description (rel), AS_MARKUP_KIND_TEXT, NULL); #else tmp = as_markup_convert_simple (fwupd_release_get_description (rel), NULL); #endif if (tmp != NULL) gs_app_set_update_details_text (app, tmp); } if (fwupd_release_get_detach_image (rel) != NULL) { g_autoptr(AsScreenshot) ss = as_screenshot_new (); g_autoptr(AsImage) im = as_image_new (); as_image_set_kind (im, AS_IMAGE_KIND_SOURCE); as_image_set_url (im, fwupd_release_get_detach_image (rel)); as_screenshot_set_kind (ss, AS_SCREENSHOT_KIND_DEFAULT); as_screenshot_add_image (ss, im); if (fwupd_release_get_detach_caption (rel) != NULL) as_screenshot_set_caption (ss, fwupd_release_get_detach_caption (rel), NULL); gs_app_set_action_screenshot (app, ss); } gs_app_set_update_urgency (app, gs_fwupd_release_urgency_to_as_urgency_kind (fwupd_release_get_urgency (rel))); }