static GsApp * snap_to_app (GsPlugin *plugin, SnapdSnap *snap) { GsPluginData *priv = gs_plugin_get_data (plugin); GStrv common_ids; g_autofree gchar *appstream_id = NULL; g_autofree gchar *unique_id = NULL; g_autoptr(GsApp) app = NULL; SnapdConfinement confinement; /* Get the AppStream ID from the snap, or generate a fallback one */ common_ids = snapd_snap_get_common_ids (snap); if (g_strv_length (common_ids) == 1) appstream_id = g_strdup (common_ids[0]); else appstream_id = g_strdup_printf ("io.snapcraft.%s-%s", snapd_snap_get_name (snap), snapd_snap_get_id (snap)); switch (snapd_snap_get_snap_type (snap)) { case SNAPD_SNAP_TYPE_APP: unique_id = g_strdup_printf ("system/snap/*/desktop/%s/*", appstream_id); break; case SNAPD_SNAP_TYPE_KERNEL: case SNAPD_SNAP_TYPE_GADGET: case SNAPD_SNAP_TYPE_OS: unique_id = g_strdup_printf ("system/snap/*/runtime/%s/*", appstream_id); break; default: case SNAPD_SNAP_TYPE_UNKNOWN: unique_id = g_strdup_printf ("system/snap/*/*/%s/*", appstream_id); break; } app = gs_plugin_cache_lookup (plugin, unique_id); if (app == NULL) { app = gs_app_new (NULL); gs_app_set_from_unique_id (app, unique_id); gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_SNAP); gs_app_set_metadata (app, "snap::name", snapd_snap_get_name (snap)); gs_plugin_cache_add (plugin, unique_id, app); } gs_app_set_management_plugin (app, "snap"); if (gs_app_get_kind (app) != AS_APP_KIND_DESKTOP) gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); if (gs_plugin_check_distro_id (plugin, "ubuntu")) gs_app_add_quirk (app, GS_APP_QUIRK_PROVENANCE); confinement = snapd_snap_get_confinement (snap); if (confinement != SNAPD_CONFINEMENT_UNKNOWN) { GEnumClass *enum_class = g_type_class_ref (SNAPD_TYPE_CONFINEMENT); gs_app_set_metadata (app, "snap::confinement", g_enum_get_value (enum_class, confinement)->value_nick); g_type_class_unref (enum_class); } if (priv->system_confinement == SNAPD_SYSTEM_CONFINEMENT_STRICT && confinement == SNAPD_CONFINEMENT_STRICT) gs_app_add_kudo (app, GS_APP_KUDO_SANDBOXED); return g_steal_pointer (&app); }
gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { GPtrArray *provides; guint i; /* not required */ if (gs_app_get_icons(app)->len > 0) return TRUE; if (gs_app_get_kind (app) != AS_APP_KIND_DRIVER) return TRUE; /* do any of the modaliases match any installed hardware */ provides = gs_app_get_provides (app); for (i = 0 ; i < provides->len; i++) { AsProvide *prov = g_ptr_array_index (provides, i); if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_MODALIAS) continue; if (gs_plugin_modalias_matches (plugin, as_provide_get_value (prov))) { g_autoptr(AsIcon) ic = NULL; ic = as_icon_new (); as_icon_set_kind (ic, AS_ICON_KIND_STOCK); as_icon_set_name (ic, "emblem-system-symbolic"); gs_app_add_icon (app, ic); gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); break; } } return TRUE; }
static GsApp * gs_plugin_generic_updates_get_os_update (GsPlugin *plugin) { GsApp *app; const gchar *id = "org.gnome.Software.OsUpdate"; g_autoptr(AsIcon) ic = NULL; /* create new */ app = gs_app_new (id); gs_app_add_quirk (app, GS_APP_QUIRK_IS_PROXY); gs_app_set_management_plugin (app, ""); gs_app_set_kind (app, AS_APP_KIND_OS_UPDATE); gs_app_set_state (app, AS_APP_STATE_UPDATABLE_LIVE); gs_app_set_name (app, GS_APP_QUALITY_NORMAL, /* TRANSLATORS: this is a group of updates that are not * packages and are not shown in the main list */ _("OS Updates")); gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, /* TRANSLATORS: this is a longer description of the * "OS Updates" string */ _("Includes performance, stability and security improvements.")); gs_app_set_description (app, GS_APP_QUALITY_NORMAL, gs_app_get_summary (app)); ic = as_icon_new (); as_icon_set_kind (ic, AS_ICON_KIND_STOCK); as_icon_set_name (ic, "software-update-available-symbolic"); gs_app_add_icon (app, ic); return app; }
gboolean gs_plugin_add_updates (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { guint i; g_autoptr(GError) error_local = NULL; g_auto(GStrv) package_ids = NULL; /* get the id's if the file exists */ package_ids = pk_offline_get_prepared_ids (&error_local); if (package_ids == NULL) { if (g_error_matches (error_local, PK_OFFLINE_ERROR, PK_OFFLINE_ERROR_NO_DATA)) { return TRUE; } g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "Failed to get prepared IDs: %s", error_local->message); return FALSE; } /* add them to the new array */ for (i = 0; package_ids[i] != NULL; i++) { g_autoptr(GsApp) app = NULL; g_auto(GStrv) split = NULL; /* search in the cache */ app = gs_plugin_cache_lookup (plugin, package_ids[i]); if (app != NULL) { gs_app_list_add (list, app); continue; } /* create new app */ app = gs_app_new (NULL); gs_app_add_quirk (app, AS_APP_QUIRK_NEEDS_REBOOT); gs_app_set_management_plugin (app, "packagekit"); gs_app_add_source_id (app, package_ids[i]); split = pk_package_id_split (package_ids[i]); gs_app_add_source (app, split[PK_PACKAGE_ID_NAME]); gs_app_set_update_version (app, split[PK_PACKAGE_ID_VERSION]); gs_app_set_state (app, AS_APP_STATE_UPDATABLE); gs_app_set_kind (app, AS_APP_KIND_GENERIC); gs_app_set_size_download (app, 0); gs_app_list_add (list, app); /* save in the cache */ gs_plugin_cache_add (plugin, package_ids[i], app); } return TRUE; }
static GsApp * gs_plugin_fwupd_new_app_from_device (GsPlugin *plugin, FwupdDevice *dev) { FwupdRelease *rel = fwupd_device_get_release_default (dev); GsApp *app; g_autofree gchar *id = NULL; g_autoptr(AsIcon) icon = NULL; /* older versions of fwups didn't record this for historical devices */ if (fwupd_release_get_appstream_id (rel) == NULL) return NULL; /* get from cache */ id = as_utils_unique_id_build (AS_APP_SCOPE_SYSTEM, AS_BUNDLE_KIND_UNKNOWN, NULL, /* origin */ AS_APP_KIND_FIRMWARE, fwupd_release_get_appstream_id (rel), NULL); app = gs_plugin_cache_lookup (plugin, id); if (app == NULL) { app = gs_app_new (id); gs_plugin_cache_add (plugin, id, app); } /* default stuff */ gs_app_set_kind (app, AS_APP_KIND_FIRMWARE); gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_CABINET); gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); gs_app_set_management_plugin (app, "fwupd"); gs_app_add_category (app, "System"); gs_fwupd_app_set_device_id (app, fwupd_device_get_id (dev)); /* create icon */ icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "application-x-firmware"); gs_app_add_icon (app, icon); gs_fwupd_app_set_from_release (app, rel); gs_fwupd_app_set_from_device (app, dev); if (fwupd_release_get_appstream_id (rel) != NULL) gs_app_set_id (app, fwupd_release_get_appstream_id (rel)); /* the same as we have already */ if (g_strcmp0 (fwupd_device_get_version (dev), fwupd_release_get_version (rel)) == 0) { g_warning ("same firmware version as installed"); } return app; }
gboolean gs_plugin_add_popular (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { guint i; const gchar *apps[] = { "org.gnome.Builder.desktop", "org.gnome.Calculator.desktop", "org.gnome.clocks.desktop", "org.gnome.Dictionary.desktop", "org.gnome.Documents.desktop", "org.gnome.Evince.desktop", "org.gnome.gedit.desktop", "org.gnome.Maps.desktop", "org.gnome.Weather.desktop", NULL }; /* we've already got enough popular apps */ if (gs_app_list_length (list) >= 5) return TRUE; /* just add all */ g_debug ("using hardcoded as only %u apps", gs_app_list_length (list)); for (i = 0; apps[i] != NULL; i++) { g_autoptr(GsApp) app = NULL; /* look in the cache */ app = gs_plugin_cache_lookup (plugin, apps[i]); if (app != NULL) { gs_app_list_add (list, app); continue; } /* create new */ app = gs_app_new (apps[i]); gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX); gs_app_set_metadata (app, "GnomeSoftware::Creator", gs_plugin_get_name (plugin)); gs_app_list_add (list, app); /* save in the cache */ gs_plugin_cache_add (plugin, apps[i], app); } return TRUE; }
gboolean gs_plugin_add_search (GsPlugin *plugin, gchar **values, GsAppList *list, GCancellable *cancellable, GError **error) { guint i; for (i = 0; values[i] != NULL; i++) { if (g_strcmp0 (values[i], "fotoshop") == 0) { g_autoptr(GsApp) app = gs_app_new ("gimp.desktop"); gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX); gs_app_list_add (list, app); } } return TRUE; }
gboolean gs_plugin_add_sources (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); g_autoptr(GPtrArray) remotes = NULL; /* find all remotes */ remotes = fwupd_client_get_remotes (priv->client, cancellable, error); if (remotes == NULL) return FALSE; for (guint i = 0; i < remotes->len; i++) { FwupdRemote *remote = g_ptr_array_index (remotes, i); g_autofree gchar *id = NULL; g_autoptr(GsApp) app = NULL; /* ignore these, they're built in */ if (fwupd_remote_get_kind (remote) != FWUPD_REMOTE_KIND_DOWNLOAD) continue; /* create something that we can use to enable/disable */ id = g_strdup_printf ("org.fwupd.%s.remote", fwupd_remote_get_id (remote)); app = gs_app_new (id); gs_app_set_kind (app, AS_APP_KIND_SOURCE); gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM); gs_app_set_state (app, fwupd_remote_get_enabled (remote) ? AS_APP_STATE_INSTALLED : AS_APP_STATE_AVAILABLE); gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); gs_app_set_name (app, GS_APP_QUALITY_LOWEST, fwupd_remote_get_title (remote)); #if FWUPD_CHECK_VERSION(1,0,7) gs_app_set_agreement (app, fwupd_remote_get_agreement (remote)); #endif gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, fwupd_remote_get_metadata_uri (remote)); gs_app_set_metadata (app, "fwupd::remote-id", fwupd_remote_get_id (remote)); gs_app_set_management_plugin (app, "fwupd"); gs_app_list_add (list, app); } return TRUE; }
gboolean gs_plugin_add_installed (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { g_autofree gchar *macaroon = NULL; g_auto(GStrv) discharges = NULL; g_autoptr(JsonArray) result = NULL; guint i; get_macaroon (plugin, &macaroon, &discharges); result = gs_snapd_list (macaroon, discharges, cancellable, error); if (result == NULL) return FALSE; for (i = 0; i < json_array_get_length (result); i++) { JsonObject *package = json_array_get_object_element (result, i); g_autoptr(GsApp) app = NULL; const gchar *status, *name; status = json_object_get_string_member (package, "status"); if (g_strcmp0 (status, "active") != 0) continue; /* create a unique ID for deduplication, TODO: branch? */ name = json_object_get_string_member (package, "name"); app = gs_app_new (name); gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM); gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_SNAP); gs_app_set_management_plugin (app, "snap"); gs_app_set_kind (app, AS_APP_KIND_DESKTOP); gs_app_add_quirk (app, AS_APP_QUIRK_NOT_REVIEWABLE); refine_app (plugin, app, package, TRUE, cancellable); gs_app_list_add (list, app); } return TRUE; }
static GsApp * gs_plugin_fwupd_new_app_from_device_raw (GsPlugin *plugin, FwupdDevice *device) { GPtrArray *icons; g_autofree gchar *id = NULL; g_autoptr(GsApp) app = NULL; /* create a GsApp based on the device, not the release */ id = gs_plugin_fwupd_build_device_id (device); app = gs_app_new (id); gs_app_set_kind (app, AS_APP_KIND_FIRMWARE); gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM); gs_app_set_state (app, AS_APP_STATE_INSTALLED); gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); gs_app_set_version (app, fwupd_device_get_version (device)); gs_app_set_name (app, GS_APP_QUALITY_LOWEST, fwupd_device_get_name (device)); gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, fwupd_device_get_summary (device)); gs_app_set_description (app, GS_APP_QUALITY_LOWEST, fwupd_device_get_description (device)); gs_app_set_origin (app, fwupd_device_get_vendor (device)); gs_fwupd_app_set_device_id (app, fwupd_device_get_id (device)); gs_app_set_management_plugin (app, "fwupd"); /* create icon */ icons = fwupd_device_get_icons (device); for (guint j = 0; j < icons->len; j++) { const gchar *icon = g_ptr_array_index (icons, j); g_autoptr(AsIcon) icon_tmp = as_icon_new (); if (g_str_has_prefix (icon, "/")) { as_icon_set_kind (icon_tmp, AS_ICON_KIND_LOCAL); as_icon_set_filename (icon_tmp, icon); } else { as_icon_set_kind (icon_tmp, AS_ICON_KIND_STOCK); as_icon_set_name (icon_tmp, icon); } gs_app_add_icon (app, icon_tmp); } return g_steal_pointer (&app); }
gboolean gs_plugin_add_featured (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { guint i; /* we've already got enough featured apps */ if (gs_app_list_length (list) >= 5) return TRUE; /* just add all */ g_debug ("using hardcoded as only %u apps", gs_app_list_length (list)); for (i = 0; myapps[i].id != NULL; i++) { g_autoptr(GsApp) app = NULL; /* look in the cache */ app = gs_plugin_cache_lookup (plugin, myapps[i].id); if (app != NULL) { gs_app_list_add (list, app); continue; } /* create new */ app = gs_app_new (myapps[i].id); gs_app_add_quirk (app, AS_APP_QUIRK_MATCH_ANY_PREFIX); gs_app_set_metadata (app, "GnomeSoftware::Creator", gs_plugin_get_name (plugin)); gs_app_set_metadata (app, "GnomeSoftware::FeatureTile-css", myapps[i].css); gs_app_list_add (list, app); /* save in the cache */ gs_plugin_cache_add (plugin, myapps[i].id, app); } return TRUE; }
gboolean gs_plugin_add_distro_upgrades (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); gsize len; guint i; g_autofree gchar *data = NULL; g_autoptr(GPtrArray) distros = NULL; g_autoptr(GSettings) settings = NULL; /* just ensure there is any data, no matter how old */ if (!gs_plugin_fedora_distro_upgrades_refresh (plugin, G_MAXUINT, cancellable, error)) return FALSE; /* get cached file */ if (!g_file_get_contents (priv->cachefn, &data, &len, error)) { gs_utils_error_convert_gio (error); return FALSE; } /* parse data */ settings = g_settings_new ("org.gnome.software"); distros = parse_pkgdb_collections_data (data, (gssize) len, error); if (distros == NULL) return FALSE; g_ptr_array_sort (distros, sort_distros_cb); for (i = 0; i < distros->len; i++) { DistroInfo *distro_info = g_ptr_array_index (distros, i); g_autofree gchar *app_id = NULL; g_autofree gchar *app_version = NULL; g_autofree gchar *background = NULL; g_autofree gchar *cache_key = NULL; g_autofree gchar *url = NULL; g_autofree gchar *css = NULL; g_autoptr(GsApp) app = NULL; g_autoptr(AsIcon) ic = NULL; /* only interested in upgrades to the same distro */ if (g_strcmp0 (distro_info->name, priv->os_name) != 0) continue; /* only interested in newer versions, but not more than N+2 */ if (distro_info->version <= priv->os_version || distro_info->version > priv->os_version + 2) continue; /* only interested in non-devel distros */ if (!g_settings_get_boolean (settings, "show-upgrade-prerelease")) { if (distro_info->status == DISTRO_STATUS_DEVEL) continue; } /* search in the cache */ cache_key = g_strdup_printf ("release-%u", distro_info->version); app = gs_plugin_cache_lookup (plugin, cache_key); if (app != NULL) { gs_app_list_add (list, app); continue; } app_id = g_strdup_printf ("org.fedoraproject.release-%u.upgrade", distro_info->version); app_version = g_strdup_printf ("%u", distro_info->version); /* icon from disk */ ic = as_icon_new (); as_icon_set_kind (ic, AS_ICON_KIND_LOCAL); as_icon_set_filename (ic, "/usr/share/pixmaps/fedora-logo-sprite.png"); /* create */ app = gs_app_new (app_id); gs_app_set_kind (app, AS_APP_KIND_OS_UPGRADE); gs_app_set_state (app, AS_APP_STATE_AVAILABLE); gs_app_set_name (app, GS_APP_QUALITY_LOWEST, distro_info->name); gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, /* TRANSLATORS: this is a title for Fedora distro upgrades */ _("A major upgrade, with new features and added polish.")); gs_app_set_description (app, GS_APP_QUALITY_LOWEST, "Fedora Workstation is a polished, " "easy to use operating system for " "laptop and desktop computers, with a " "complete set of tools for developers " "and makers of all kinds."); gs_app_set_version (app, app_version); gs_app_set_size_installed (app, 1024 * 1024 * 1024); /* estimate */ gs_app_set_size_download (app, 256 * 1024 * 1024); /* estimate */ gs_app_set_license (app, GS_APP_QUALITY_LOWEST, "LicenseRef-free"); gs_app_add_quirk (app, AS_APP_QUIRK_NEEDS_REBOOT); gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE); gs_app_add_quirk (app, AS_APP_QUIRK_NOT_REVIEWABLE); gs_app_set_origin_ui (app, distro_info->name); gs_app_add_icon (app, ic); gs_app_set_management_plugin (app, "packagekit"); /* show a Fedora magazine article for the release */ url = g_strdup_printf ("https://fedoramagazine.org/whats-new-fedora-%u-workstation", distro_info->version); gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, url); /* use a fancy background */ background = get_upgrade_css_background (distro_info->version); css = g_strdup_printf ("background: %s;" "background-position: center;" "background-size: cover;", background); gs_app_set_metadata (app, "GnomeSoftware::UpgradeBanner-css", css); gs_app_list_add (list, app); /* save in the cache */ gs_plugin_cache_add (plugin, cache_key, app); } return TRUE; }
/** * gs_plugin_refine_app: */ gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { Header h; const gchar *fn; gint rc; g_auto(rpmdbMatchIterator) mi = NULL; g_auto(rpmts) ts = NULL; /* not required */ if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION) == 0) return TRUE; /* no need to run the plugin */ if (gs_app_get_source_default (app) != NULL && gs_app_get_source_id_default (app) != NULL) return TRUE; /* open db readonly */ ts = rpmtsCreate(); rpmtsSetRootDir (ts, NULL); rc = rpmtsOpenDB (ts, O_RDONLY); if (rc != 0) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to open rpmdb: %i", rc); return FALSE; } /* look for a specific file */ fn = gs_app_get_metadata_item (app, "appstream::source-file"); if (fn == NULL) return TRUE; if (!g_str_has_prefix (fn, "/usr")) return TRUE; mi = rpmtsInitIterator (ts, RPMDBI_INSTFILENAMES, fn, 0); if (mi == NULL) { g_debug ("rpm: no search results for %s", fn); return TRUE; } /* on rpm-ostree this package cannot be removed 'live' */ gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY); /* process any results */ g_debug ("rpm: querying for %s with %s", gs_app_get_id (app), fn); while ((h = rpmdbNextIterator (mi)) != NULL) { guint64 epoch; const gchar *name; const gchar *version; const gchar *arch; const gchar *release; const gchar *license; /* add default source */ name = headerGetString (h, RPMTAG_NAME); if (gs_app_get_source_default (app) == NULL) { g_debug ("rpm: setting source to %s", name); gs_app_add_source (app, name); } /* set size */ if (gs_app_get_size_download (app) == 0) gs_app_set_size_download (app, 0); if (gs_app_get_size_installed (app) == 0) { guint64 tmp; tmp = headerGetNumber (h, RPMTAG_SIZE); gs_app_set_size_installed (app, tmp); } /* set license */ license = headerGetString (h, RPMTAG_LICENSE); if (gs_app_get_license (app) == NULL && license != NULL) { g_autofree gchar *tmp = NULL; tmp = as_utils_license_to_spdx (license); gs_app_set_license (app, GS_APP_QUALITY_NORMAL, tmp); } /* add version */ version = headerGetString (h, RPMTAG_VERSION); if (gs_app_get_version (app) == NULL) { g_debug ("rpm: setting version to %s", version); gs_app_set_version (app, version); } /* add source-id */ if (gs_app_get_source_id_default (app) == NULL) { g_autofree gchar *tmp = NULL; release = headerGetString (h, RPMTAG_RELEASE); arch = headerGetString (h, RPMTAG_ARCH); epoch = headerGetNumber (h, RPMTAG_EPOCH); if (epoch > 0) { tmp = g_strdup_printf ("%s;%" G_GUINT64_FORMAT ":%s-%s;%s;installed", name, epoch, version, release, arch); } else { tmp = g_strdup_printf ("%s;%s-%s;%s;installed", name, version, release, arch); } g_debug ("rpm: setting source-id to %s", tmp); gs_app_add_source_id (app, tmp); } } return TRUE; }
static void refine_app (GsPlugin *plugin, GsApp *app, JsonObject *package, gboolean from_search, GCancellable *cancellable) { g_autofree gchar *macaroon = NULL; g_auto(GStrv) discharges = NULL; const gchar *status, *icon_url, *launch_name = NULL; g_autoptr(GdkPixbuf) icon_pixbuf = NULL; gint64 size = -1; get_macaroon (plugin, &macaroon, &discharges); status = json_object_get_string_member (package, "status"); if (g_strcmp0 (status, "installed") == 0 || g_strcmp0 (status, "active") == 0) { const gchar *update_available; update_available = json_object_has_member (package, "update_available") ? json_object_get_string_member (package, "update_available") : NULL; if (update_available) gs_app_set_state (app, AS_APP_STATE_UPDATABLE); else { if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE) gs_app_set_state (app, AS_APP_STATE_UNKNOWN); gs_app_set_state (app, AS_APP_STATE_INSTALLED); } } else if (g_strcmp0 (status, "not installed") == 0 || g_strcmp0 (status, "available") == 0) { gs_app_set_state (app, AS_APP_STATE_AVAILABLE); } gs_app_set_name (app, GS_APP_QUALITY_HIGHEST, json_object_get_string_member (package, "summary")); gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST, json_object_get_string_member (package, "summary")); gs_app_set_description (app, GS_APP_QUALITY_HIGHEST, json_object_get_string_member (package, "description")); gs_app_set_version (app, json_object_get_string_member (package, "version")); if (json_object_has_member (package, "installed-size")) { size = json_object_get_int_member (package, "installed-size"); if (size > 0) gs_app_set_size_installed (app, (guint64) size); } if (json_object_has_member (package, "download-size")) { size = json_object_get_int_member (package, "download-size"); if (size > 0) gs_app_set_size_download (app, (guint64) size); } gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE); icon_url = json_object_get_string_member (package, "icon"); if (g_str_has_prefix (icon_url, "/")) { g_autofree gchar *icon_data = NULL; gsize icon_data_length; g_autoptr(GError) error = NULL; icon_data = gs_snapd_get_resource (macaroon, discharges, icon_url, &icon_data_length, cancellable, &error); if (icon_data != NULL) { g_autoptr(GdkPixbufLoader) loader = NULL; loader = gdk_pixbuf_loader_new (); gdk_pixbuf_loader_write (loader, (guchar *) icon_data, icon_data_length, NULL); gdk_pixbuf_loader_close (loader, NULL); icon_pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader)); } else g_printerr ("Failed to get icon: %s\n", error->message); } else { g_autoptr(SoupMessage) message = NULL; g_autoptr(GdkPixbufLoader) loader = NULL; message = soup_message_new (SOUP_METHOD_GET, icon_url); if (message != NULL) { soup_session_send_message (gs_plugin_get_soup_session (plugin), message); loader = gdk_pixbuf_loader_new (); gdk_pixbuf_loader_write (loader, (guint8 *) message->response_body->data, (gsize) message->response_body->length, NULL); gdk_pixbuf_loader_close (loader, NULL); icon_pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader)); } } if (icon_pixbuf) { gs_app_set_pixbuf (app, icon_pixbuf); } else { g_autoptr(AsIcon) icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "package-x-generic"); gs_app_add_icon (app, icon); } if (json_object_has_member (package, "screenshots") && gs_app_get_screenshots (app)->len <= 0) { JsonArray *screenshots; guint i; screenshots = json_object_get_array_member (package, "screenshots"); for (i = 0; i < json_array_get_length (screenshots); i++) { JsonObject *screenshot = json_array_get_object_element (screenshots, i); g_autoptr(AsScreenshot) ss = NULL; g_autoptr(AsImage) image = NULL; ss = as_screenshot_new (); as_screenshot_set_kind (ss, AS_SCREENSHOT_KIND_NORMAL); image = as_image_new (); as_image_set_url (image, json_object_get_string_member (screenshot, "url")); as_image_set_kind (image, AS_IMAGE_KIND_SOURCE); as_screenshot_add_image (ss, image); gs_app_add_screenshot (app, ss); } } if (!from_search) { JsonArray *apps; apps = json_object_get_array_member (package, "apps"); if (apps && json_array_get_length (apps) > 0) launch_name = json_object_get_string_member (json_array_get_object_element (apps, 0), "name"); if (launch_name) gs_app_set_metadata (app, "snap::launch-name", launch_name); else gs_app_add_quirk (app, AS_APP_QUIRK_NOT_LAUNCHABLE); } }
/** * gs_appstream_refine_app: */ gboolean gs_appstream_refine_app (GsPlugin *plugin, GsApp *app, AsApp *item, GError **error) { AsRelease *rel; GHashTable *urls; GPtrArray *pkgnames; GPtrArray *kudos; const gchar *tmp; guint i; /* set the kind to be more precise */ if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN || gs_app_get_kind (app) == AS_APP_KIND_GENERIC) { gs_app_set_kind (app, as_app_get_kind (item)); } /* is installed already */ if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN) { switch (as_app_get_source_kind (item)) { case AS_APP_SOURCE_KIND_APPDATA: case AS_APP_SOURCE_KIND_DESKTOP: gs_app_set_kind (app, AS_APP_KIND_DESKTOP); gs_app_set_state (app, AS_APP_STATE_INSTALLED); break; case AS_APP_SOURCE_KIND_METAINFO: gs_app_set_state (app, AS_APP_STATE_INSTALLED); break; case AS_APP_SOURCE_KIND_APPSTREAM: gs_app_set_state (app, as_app_get_state (item)); break; default: break; } } /* set management plugin automatically */ gs_refine_item_management_plugin (app, item); /* set id */ if (as_app_get_id (item) != NULL && gs_app_get_id (app) == NULL) gs_app_set_id (app, as_app_get_id (item)); /* set name */ tmp = as_app_get_name (item, NULL); if (tmp != NULL) { if (g_str_has_prefix (tmp, "(Nightly) ")) { tmp += 10; if (gs_app_get_metadata_item (app, "X-XdgApp-Tags") == NULL) gs_app_set_metadata (app, "X-XdgApp-Tags", "nightly"); } gs_app_set_name (app, GS_APP_QUALITY_HIGHEST, tmp); } /* set summary */ tmp = as_app_get_comment (item, NULL); if (tmp != NULL) { gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST, tmp); } /* add urls */ urls = as_app_get_urls (item); if (g_hash_table_size (urls) > 0 && gs_app_get_url (app, AS_URL_KIND_HOMEPAGE) == NULL) { GList *l; g_autoptr(GList) keys = NULL; keys = g_hash_table_get_keys (urls); for (l = keys; l != NULL; l = l->next) { gs_app_set_url (app, as_url_kind_from_string (l->data), g_hash_table_lookup (urls, l->data)); } } /* set licence */ if (as_app_get_project_license (item) != NULL && gs_app_get_license (app) == NULL) gs_app_set_license (app, GS_APP_QUALITY_HIGHEST, as_app_get_project_license (item)); /* set keywords */ if (as_app_get_keywords (item, NULL) != NULL && gs_app_get_keywords (app) == NULL) { gs_app_set_keywords (app, as_app_get_keywords (item, NULL)); gs_app_add_kudo (app, GS_APP_KUDO_HAS_KEYWORDS); } /* set origin */ if (as_app_get_origin (item) != NULL && gs_app_get_origin (app) == NULL) { gs_app_set_origin (app, as_app_get_origin (item)); } /* set description */ tmp = as_app_get_description (item, NULL); if (tmp != NULL) { g_autofree gchar *from_xml = NULL; from_xml = as_markup_convert_simple (tmp, error); if (from_xml == NULL) { g_prefix_error (error, "trying to parse '%s': ", tmp); return FALSE; } gs_app_set_description (app, GS_APP_QUALITY_HIGHEST, from_xml); } /* set icon */ if (as_app_get_icon_default (item) != NULL && gs_app_get_pixbuf (app) == NULL) gs_refine_item_pixbuf (plugin, app, item); /* set categories */ if (as_app_get_categories (item) != NULL && gs_app_get_categories (app)->len == 0) gs_app_set_categories (app, as_app_get_categories (item)); /* set project group */ if (as_app_get_project_group (item) != NULL && gs_app_get_project_group (app) == NULL) gs_app_set_project_group (app, as_app_get_project_group (item)); /* this is a core application for the desktop and cannot be removed */ if (_as_app_has_compulsory_for_desktop (item, "GNOME") && gs_app_get_kind (app) == AS_APP_KIND_DESKTOP) gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY); /* set id kind */ if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN) gs_app_set_kind (app, as_app_get_kind (item)); /* copy all the metadata */ gs_appstream_copy_metadata (app, item); /* set package names */ pkgnames = as_app_get_pkgnames (item); if (pkgnames->len > 0 && gs_app_get_sources(app)->len == 0) gs_app_set_sources (app, pkgnames); /* set addons */ gs_appstream_refine_add_addons (plugin, app, item); /* set screenshots */ gs_appstream_refine_add_screenshots (app, item); /* are the screenshots perfect */ if (gs_appstream_are_screenshots_perfect (item)) gs_app_add_kudo (app, GS_APP_KUDO_PERFECT_SCREENSHOTS); /* was this application released recently */ if (gs_appstream_is_recent_release (item)) gs_app_add_kudo (app, GS_APP_KUDO_RECENT_RELEASE); /* add kudos */ if (as_app_get_language (item, plugin->locale) > 50) gs_app_add_kudo (app, GS_APP_KUDO_MY_LANGUAGE); /* add new-style kudos */ kudos = as_app_get_kudos (item); for (i = 0; i < kudos->len; i++) { tmp = g_ptr_array_index (kudos, i); switch (as_kudo_kind_from_string (tmp)) { case AS_KUDO_KIND_SEARCH_PROVIDER: gs_app_add_kudo (app, GS_APP_KUDO_SEARCH_PROVIDER); break; case AS_KUDO_KIND_USER_DOCS: gs_app_add_kudo (app, GS_APP_KUDO_INSTALLS_USER_DOCS); break; case AS_KUDO_KIND_APP_MENU: gs_app_add_kudo (app, GS_APP_KUDO_USES_APP_MENU); break; case AS_KUDO_KIND_MODERN_TOOLKIT: gs_app_add_kudo (app, GS_APP_KUDO_MODERN_TOOLKIT); break; case AS_KUDO_KIND_NOTIFICATIONS: gs_app_add_kudo (app, GS_APP_KUDO_USES_NOTIFICATIONS); break; case AS_KUDO_KIND_HIGH_CONTRAST: gs_app_add_kudo (app, GS_APP_KUDO_HIGH_CONTRAST); break; case AS_KUDO_KIND_HI_DPI_ICON: gs_app_add_kudo (app, GS_APP_KUDO_HI_DPI_ICON); break; default: g_debug ("no idea how to handle kudo '%s'", tmp); break; } } /* is there any update information */ rel = as_app_get_release_default (item); if (rel != NULL) { tmp = as_release_get_description (rel, NULL); if (tmp != NULL) { g_autofree gchar *desc = NULL; desc = as_markup_convert (tmp, AS_MARKUP_CONVERT_FORMAT_MARKDOWN, error); if (desc == NULL) return FALSE; gs_app_set_update_details (app, desc); } gs_app_set_update_urgency (app, as_release_get_urgency (rel)); gs_app_set_update_version (app, as_release_get_version (rel)); } return TRUE; }
gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); g_autoptr(SnapdClient) client = NULL; const gchar *name; g_autoptr(SnapdSnap) local_snap = NULL; g_autoptr(SnapdSnap) store_snap = NULL; SnapdSnap *snap; const gchar *developer_name; g_autofree gchar *description = NULL; /* not us */ if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0) return TRUE; client = get_client (plugin, error); if (client == NULL) return FALSE; /* get information from local snaps and store */ local_snap = snapd_client_get_snap_sync (client, gs_app_get_metadata_item (app, "snap::name"), cancellable, NULL); if (local_snap == NULL || (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS) != 0) store_snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"), cancellable, NULL); if (local_snap == NULL && store_snap == NULL) return TRUE; if (local_snap != NULL) gs_app_set_state (app, AS_APP_STATE_INSTALLED); else gs_app_set_state (app, AS_APP_STATE_AVAILABLE); /* use store information for basic metadata over local information */ snap = store_snap != NULL ? store_snap : local_snap; name = snapd_snap_get_title (snap); if (name == NULL || g_strcmp0 (name, "") == 0) name = snapd_snap_get_name (snap); gs_app_set_name (app, GS_APP_QUALITY_NORMAL, name); gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, snapd_snap_get_summary (snap)); description = gs_plugin_snap_get_description_safe (snap); if (description != NULL) gs_app_set_description (app, GS_APP_QUALITY_NORMAL, description); gs_app_set_license (app, GS_APP_QUALITY_NORMAL, snapd_snap_get_license (snap)); developer_name = snapd_snap_get_publisher_display_name (snap); if (developer_name == NULL) developer_name = snapd_snap_get_publisher_username (snap); gs_app_set_developer_name (app, developer_name); if (snapd_snap_get_publisher_validation (snap) == SNAPD_PUBLISHER_VALIDATION_VERIFIED) gs_app_add_quirk (app, GS_APP_QUIRK_DEVELOPER_VERIFIED); snap = local_snap != NULL ? local_snap : store_snap; gs_app_set_version (app, snapd_snap_get_version (snap)); switch (snapd_snap_get_snap_type (snap)) { case SNAPD_SNAP_TYPE_APP: gs_app_set_kind (app, AS_APP_KIND_DESKTOP); break; case SNAPD_SNAP_TYPE_KERNEL: case SNAPD_SNAP_TYPE_GADGET: case SNAPD_SNAP_TYPE_OS: gs_app_set_kind (app, AS_APP_KIND_RUNTIME); break; default: case SNAPD_SNAP_TYPE_UNKNOWN: gs_app_set_kind (app, AS_APP_KIND_UNKNOWN); break; } /* add information specific to installed snaps */ if (local_snap != NULL) { SnapdApp *snap_app; GDateTime *install_date; install_date = snapd_snap_get_install_date (local_snap); gs_app_set_size_installed (app, snapd_snap_get_installed_size (local_snap)); gs_app_set_install_date (app, install_date != NULL ? g_date_time_to_unix (install_date) : GS_APP_INSTALL_DATE_UNKNOWN); snap_app = get_primary_app (local_snap); if (snap_app != NULL) { gs_app_set_metadata (app, "snap::launch-name", snapd_app_get_name (snap_app)); gs_app_set_metadata (app, "snap::launch-desktop", snapd_app_get_desktop_file (snap_app)); } else { gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); } } /* add information specific to store snaps */ if (store_snap != NULL) { gs_app_set_origin (app, priv->store_name); gs_app_set_size_download (app, snapd_snap_get_download_size (store_snap)); if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS && gs_app_get_screenshots (app)->len == 0) refine_screenshots (app, store_snap); } /* load icon if requested */ if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON && gs_app_get_pixbuf (app) == NULL) load_icon (plugin, client, app, gs_app_get_metadata_item (app, "snap::name"), local_snap, store_snap, cancellable); return TRUE; }
/** * gs_plugin_file_to_app: */ gboolean gs_plugin_file_to_app (GsPlugin *plugin, GList **list, GFile *file, GCancellable *cancellable, GError **error) { g_autofree gchar *content_type = NULL; g_autofree gchar *id_prefixed = NULL; g_autoptr(GBytes) appstream_gz = NULL; g_autoptr(GBytes) icon_data = NULL; g_autoptr(GBytes) metadata = NULL; g_autoptr(GsApp) app = NULL; g_autoptr(XdgAppBundleRef) xref_bundle = NULL; const gchar *mimetypes[] = { "application/vnd.xdgapp", NULL }; /* does this match any of the mimetypes we support */ content_type = gs_utils_get_content_type (file, cancellable, error); if (content_type == NULL) return FALSE; if (!g_strv_contains (mimetypes, content_type)) return TRUE; /* load bundle */ xref_bundle = xdg_app_bundle_ref_new (file, error); if (xref_bundle == NULL) { g_prefix_error (error, "error loading bundle: "); return FALSE; } /* create a virtual ID */ id_prefixed = gs_plugin_xdg_app_build_id (XDG_APP_REF (xref_bundle)); /* load metadata */ app = gs_app_new (id_prefixed); gs_app_set_kind (app, AS_APP_KIND_DESKTOP); gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL); gs_app_set_size_installed (app, xdg_app_bundle_ref_get_installed_size (xref_bundle)); gs_plugin_xdg_app_set_metadata (app, XDG_APP_REF (xref_bundle)); metadata = xdg_app_bundle_ref_get_metadata (xref_bundle); if (!gs_plugin_xdg_app_set_app_metadata (app, g_bytes_get_data (metadata, NULL), g_bytes_get_size (metadata), error)) return FALSE; /* load AppStream */ appstream_gz = xdg_app_bundle_ref_get_appstream (xref_bundle); if (appstream_gz != NULL) { g_autoptr(GZlibDecompressor) decompressor = NULL; g_autoptr(GInputStream) stream_gz = NULL; g_autoptr(GInputStream) stream_data = NULL; g_autoptr(GBytes) appstream = NULL; g_autoptr(AsStore) store = NULL; g_autofree gchar *id = NULL; AsApp *item; /* decompress data */ decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); stream_gz = g_memory_input_stream_new_from_bytes (appstream_gz); if (stream_gz == NULL) return FALSE; stream_data = g_converter_input_stream_new (stream_gz, G_CONVERTER (decompressor)); appstream = g_input_stream_read_bytes (stream_data, 0x100000, /* 1Mb */ cancellable, error); if (appstream == NULL) return FALSE; store = as_store_new (); if (!as_store_from_bytes (store, appstream, cancellable, error)) return FALSE; /* find app */ id = g_strdup_printf ("%s.desktop", gs_app_get_xdgapp_name (app)); item = as_store_get_app_by_id (store, id); if (item == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "application %s not found", id); return FALSE; } /* copy details from AppStream to app */ if (!gs_appstream_refine_app (plugin, app, item, error)) return FALSE; } /* load icon */ icon_data = xdg_app_bundle_ref_get_icon (xref_bundle, 64 * gs_plugin_get_scale (plugin)); if (icon_data == NULL) icon_data = xdg_app_bundle_ref_get_icon (xref_bundle, 64); if (icon_data != NULL) { g_autoptr(GInputStream) stream_icon = NULL; g_autoptr(GdkPixbuf) pixbuf = NULL; stream_icon = g_memory_input_stream_new_from_bytes (icon_data); pixbuf = gdk_pixbuf_new_from_stream (stream_icon, cancellable, error); if (pixbuf == NULL) return FALSE; gs_app_set_pixbuf (app, pixbuf); } else { g_autoptr(AsIcon) icon = NULL; icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "application-x-executable"); gs_app_set_icon (app, icon); } /* not quite true: this just means we can update this specific app */ if (xdg_app_bundle_ref_get_origin (xref_bundle)) gs_app_add_quirk (app, AS_APP_QUIRK_HAS_SOURCE); g_debug ("created local app: %s", gs_app_to_string (app)); gs_app_list_add (list, app); return TRUE; }