static AsApp * load_desktop (const gchar *prefix, const gchar *icons_dir, guint min_icon_size, const gchar *app_name, const gchar *appdata_id, GError **error) { AsIcon *icon; g_autofree gchar *desktop_basename = NULL; g_autofree gchar *desktop_path = NULL; g_autoptr(AsApp) app = NULL; if (appdata_id != NULL) desktop_basename = g_strdup (appdata_id); else desktop_basename = g_strconcat (app_name, ".desktop", NULL); desktop_path = g_build_filename (prefix, "share/applications", desktop_basename, NULL); app = as_app_new (); if (!as_app_parse_file (app, desktop_path, AS_APP_PARSE_FLAG_USE_HEURISTICS | AS_APP_PARSE_FLAG_ALLOW_VETO, error)) return NULL; if (as_app_get_kind (app) == AS_APP_KIND_UNKNOWN) { g_set_error (error, AS_APP_ERROR, AS_APP_ERROR_FAILED, "%s has no recognised type", as_app_get_id (AS_APP (app))); return NULL; } icon = as_app_get_icon_default (AS_APP (app)); if (icon != NULL) { g_autofree gchar *key = NULL; key = g_strdup (as_icon_get_name (icon)); if (as_icon_get_kind (icon) == AS_ICON_KIND_STOCK) { as_compose_app_log (app, "using stock icon %s", key); } else { g_autoptr(GError) error_local = NULL; gboolean ret; g_ptr_array_set_size (as_app_get_icons (AS_APP (app)), 0); ret = add_icons (app, icons_dir, min_icon_size, prefix, key, error); if (!ret) return NULL; } } return g_steal_pointer (&app); }
static gboolean asb_plugin_desktop_refine (AsbPlugin *plugin, AsbPackage *pkg, const gchar *filename, AsbApp *app, const gchar *tmpdir, GError **error) { AsIcon *icon; AsAppParseFlags parse_flags = AS_APP_PARSE_FLAG_USE_HEURISTICS | AS_APP_PARSE_FLAG_ALLOW_VETO; gboolean ret; g_autoptr(AsApp) desktop_app = NULL; g_autoptr(GdkPixbuf) pixbuf = NULL; /* use GenericName fallback */ if (asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_USE_FALLBACKS)) parse_flags |= AS_APP_PARSE_FLAG_USE_FALLBACKS; /* create app */ desktop_app = as_app_new (); if (!as_app_parse_file (desktop_app, filename, parse_flags, error)) return FALSE; /* copy all metadata */ as_app_subsume_full (AS_APP (app), desktop_app, AS_APP_SUBSUME_FLAG_NO_OVERWRITE); /* is the icon a stock-icon-name? */ icon = as_app_get_icon_default (AS_APP (app)); if (icon != NULL) { g_autofree gchar *key = NULL; key = g_strdup (as_icon_get_name (icon)); if (as_icon_get_kind (icon) == AS_ICON_KIND_STOCK) { asb_package_log (pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "using stock icon %s", key); } else { g_autoptr(GError) error_local = NULL; g_ptr_array_set_size (as_app_get_icons (AS_APP (app)), 0); ret = asb_plugin_desktop_add_icons (plugin, app, tmpdir, key, &error_local); if (!ret) { as_app_add_veto (AS_APP (app), "%s", error_local->message); } } } return TRUE; }
/** * as_app_parse_desktop_file: **/ gboolean as_app_parse_desktop_file (AsApp *app, const gchar *desktop_file, AsAppParseFlags flags, GError **error) { GKeyFileFlags kf_flags = G_KEY_FILE_KEEP_TRANSLATIONS; gchar *tmp; guint i; g_autoptr(GError) error_local = NULL; g_autofree gchar *app_id = NULL; g_autoptr(GKeyFile) kf = NULL; g_auto(GStrv) keys = NULL; /* load file */ kf = g_key_file_new (); if (flags & AS_APP_PARSE_FLAG_KEEP_COMMENTS) kf_flags |= G_KEY_FILE_KEEP_COMMENTS; if (!g_key_file_load_from_file (kf, desktop_file, kf_flags, &error_local)) { g_set_error (error, AS_APP_ERROR, AS_APP_ERROR_INVALID_TYPE, "Failed to parse %s: %s", desktop_file, error_local->message); return FALSE; } /* create app */ app_id = g_path_get_basename (desktop_file); as_app_set_id_kind (app, AS_ID_KIND_DESKTOP); /* is blacklisted */ if (as_utils_is_blacklisted_id (app_id)) as_app_add_veto (app, "%s is not an application", app_id); /* Ubuntu helpfully put the package name in the desktop file name */ tmp = g_strstr_len (app_id, -1, ":"); if (tmp != NULL) as_app_set_id (app, tmp + 1); else as_app_set_id (app, app_id); /* look at all the keys */ keys = g_key_file_get_keys (kf, G_KEY_FILE_DESKTOP_GROUP, NULL, error); if (keys == NULL) return FALSE; for (i = 0; keys[i] != NULL; i++) { if (!as_app_parse_file_key (app, kf, keys[i], flags, error)) return FALSE; if ((flags & AS_APP_PARSE_FLAG_USE_HEURISTICS) > 0) { if (!as_app_infer_file_key (app, kf, keys[i], error)) return FALSE; } } /* perform any fallbacks */ if ((flags & AS_APP_PARSE_FLAG_USE_FALLBACKS) > 0 && as_app_get_comment_size (app) == 0) { for (i = 0; keys[i] != NULL; i++) { if (!as_app_parse_file_key_fallback_comment (app, kf, keys[i], error)) return FALSE; } } /* all applications require icons */ if (as_app_get_icons(app)->len == 0) as_app_add_veto (app, "%s has no icon", app_id); return TRUE; }
static GsApp * gs_editor_convert_app (GsEditor *self, AsApp *item) { AsApp *item_global; AsAppState item_state; GsApp *app; const gchar *keys[] = { "GnomeSoftware::AppTile-css", "GnomeSoftware::FeatureTile-css", "GnomeSoftware::UpgradeBanner-css", NULL }; /* copy name, summary and description */ app = gs_app_new (as_app_get_id (item)); item_global = as_store_get_app_by_id (self->store_global, as_app_get_id (item)); if (item_global == NULL) { const gchar *tmp; g_autoptr(AsIcon) ic = NULL; g_debug ("no app found for %s, using fallback", as_app_get_id (item)); /* copy from AsApp, falling back to something sane */ tmp = as_app_get_name (item, NULL); if (tmp == NULL) tmp = "Application"; gs_app_set_name (app, GS_APP_QUALITY_NORMAL, tmp); tmp = as_app_get_comment (item, NULL); if (tmp == NULL) tmp = "Description"; gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, tmp); tmp = as_app_get_description (item, NULL); if (tmp == NULL) tmp = "A multiline description"; gs_app_set_description (app, GS_APP_QUALITY_NORMAL, tmp); ic = as_icon_new (); as_icon_set_kind (ic, AS_ICON_KIND_STOCK); as_icon_set_name (ic, "application-x-executable"); gs_app_add_icon (app, ic); item_state = as_app_get_state (item); } else { GPtrArray *icons; g_debug ("found global app for %s", as_app_get_id (item)); gs_app_set_name (app, GS_APP_QUALITY_NORMAL, as_app_get_name (item_global, NULL)); gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, as_app_get_comment (item_global, NULL)); gs_app_set_description (app, GS_APP_QUALITY_NORMAL, as_app_get_description (item_global, NULL)); icons = as_app_get_icons (item_global); for (guint i = 0; i < icons->len; i++) { AsIcon *icon = g_ptr_array_index (icons, i); gs_app_add_icon (app, icon); } item_state = as_app_get_state (item_global); } /* copy state */ if (item_state == AS_APP_STATE_UNKNOWN) item_state = AS_APP_STATE_AVAILABLE; gs_app_set_state (app, item_state); /* copy version */ gs_app_set_version (app, "3.28"); /* load pixbuf */ gs_editor_refine_app_pixbuf (app); /* copy metadata */ for (guint i = 0; keys[i] != NULL; i++) { g_autoptr(GError) error = NULL; const gchar *markup = as_app_get_metadata_item (item, keys[i]); if (markup != NULL) { g_autofree gchar *css_new = NULL; css_new = gs_editor_css_download_resources (self, markup, &error); if (css_new == NULL) { g_warning ("%s", error->message); gs_app_set_metadata (app, keys[i], markup); } else { gs_app_set_metadata (app, keys[i], css_new); } } else { gs_app_set_metadata (app, keys[i], NULL); } } return app; }
/** * asb_plugin_process_filename: */ static gboolean asb_plugin_process_filename (AsbPlugin *plugin, AsbPackage *pkg, const gchar *filename, GList **apps, const gchar *tmpdir, GError **error) { AsIcon *icon; AsAppParseFlags parse_flags = AS_APP_PARSE_FLAG_USE_HEURISTICS; gboolean ret; _cleanup_free_ gchar *app_id = NULL; _cleanup_free_ gchar *full_filename = NULL; _cleanup_object_unref_ AsbApp *app = NULL; _cleanup_object_unref_ GdkPixbuf *pixbuf = NULL; /* use GenericName fallback */ if (asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_USE_FALLBACKS)) parse_flags |= AS_APP_PARSE_FLAG_USE_FALLBACKS; /* create app */ app_id = g_path_get_basename (filename); app = asb_app_new (pkg, app_id); asb_app_set_hidpi_enabled (app, asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_HIDPI_ICONS)); full_filename = g_build_filename (tmpdir, filename, NULL); if (!as_app_parse_file (AS_APP (app), full_filename, parse_flags, error)) return FALSE; /* NoDisplay apps are never included */ if (as_app_get_metadata_item (AS_APP (app), "NoDisplay") != NULL) asb_app_add_requires_appdata (app, "NoDisplay=true"); /* Settings or DesktopSettings requires AppData */ if (!asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_IGNORE_SETTINGS)) { if (as_app_has_category (AS_APP (app), "Settings")) asb_app_add_requires_appdata (app, "Category=Settings"); if (as_app_has_category (AS_APP (app), "DesktopSettings")) asb_app_add_requires_appdata (app, "Category=DesktopSettings"); } /* is the icon a stock-icon-name? */ icon = as_app_get_icon_default (AS_APP (app)); if (icon != NULL) { _cleanup_free_ gchar *key = NULL; key = g_strdup (as_icon_get_name (icon)); if (as_icon_get_kind (icon) == AS_ICON_KIND_STOCK) { asb_package_log (pkg, ASB_PACKAGE_LOG_LEVEL_DEBUG, "using stock icon %s", key); } else { _cleanup_error_free_ GError *error_local = NULL; g_ptr_array_set_size (as_app_get_icons (AS_APP (app)), 0); ret = asb_plugin_desktop_add_icons (plugin, app, tmpdir, key, &error_local); if (!ret) { as_app_add_veto (AS_APP (app), "%s", error_local->message); } } } /* add */ asb_plugin_add_app (apps, AS_APP (app)); return TRUE; }
static gboolean asb_plugin_process_filename (AsbPlugin *plugin, AsbPackage *pkg, const gchar *filename, GList **apps, GError **error) { AsProblemKind problem_kind; AsProblem *problem; GPtrArray *icons; const gchar *tmp; guint i; g_autoptr(AsbApp) app = NULL; g_autoptr(GPtrArray) problems = NULL; app = asb_app_new (NULL, NULL); if (!as_app_parse_file (AS_APP (app), filename, AS_APP_PARSE_FLAG_USE_HEURISTICS, error)) return FALSE; if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_UNKNOWN) { g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "%s has no recognised type", as_app_get_id (AS_APP (app))); return FALSE; } /* validate */ problems = as_app_validate (AS_APP (app), AS_APP_VALIDATE_FLAG_NO_NETWORK | AS_APP_VALIDATE_FLAG_RELAX, error); if (problems == NULL) return FALSE; asb_app_set_package (app, pkg); for (i = 0; i < problems->len; i++) { problem = g_ptr_array_index (problems, i); problem_kind = as_problem_get_kind (problem); asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_WARNING, "AppData problem: %s : %s", as_problem_kind_to_string (problem_kind), as_problem_get_message (problem)); } /* nuke things that do not belong */ icons = as_app_get_icons (AS_APP (app)); if (icons->len > 0) g_ptr_array_set_size (icons, 0); /* fix up the project license */ tmp = as_app_get_project_license (AS_APP (app)); if (tmp != NULL && !as_utils_is_spdx_license (tmp)) { g_autofree gchar *license_spdx = NULL; license_spdx = as_utils_license_to_spdx (tmp); if (as_utils_is_spdx_license (license_spdx)) { asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_WARNING, "project license fixup: %s -> %s", tmp, license_spdx); as_app_set_project_license (AS_APP (app), license_spdx); } else { asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_WARNING, "project license is invalid: %s", tmp); as_app_set_project_license (AS_APP (app), NULL); } } /* check license */ tmp = as_app_get_metadata_license (AS_APP (app)); if (tmp == NULL) { g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "AppData %s has no licence", filename); return FALSE; } if (!as_utils_is_spdx_license (tmp)) { g_set_error (error, ASB_PLUGIN_ERROR, ASB_PLUGIN_ERROR_FAILED, "AppData %s license '%s' invalid", filename, tmp); return FALSE; } /* log updateinfo */ tmp = as_app_get_update_contact (AS_APP (app)); if (tmp != NULL) { asb_package_log (asb_app_get_package (app), ASB_PACKAGE_LOG_LEVEL_INFO, "Upstream contact <%s>", tmp); } /* add icon for firmware */ if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_FIRMWARE) { 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"); as_app_add_icon (AS_APP (app), icon); } /* fix up input methods */ if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_INPUT_METHOD) { g_autoptr(AsIcon) icon = NULL; icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "system-run-symbolic"); as_app_add_icon (AS_APP (app), icon); as_app_add_category (AS_APP (app), "Addons"); as_app_add_category (AS_APP (app), "InputSources"); } /* fix up codecs */ if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_CODEC) { 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"); as_app_add_icon (AS_APP (app), icon); as_app_add_category (AS_APP (app), "Addons"); as_app_add_category (AS_APP (app), "Codecs"); } /* success */ asb_app_set_hidpi_enabled (app, asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_HIDPI_ICONS)); asb_plugin_add_app (apps, AS_APP (app)); return TRUE; }
static gboolean gs_plugin_steam_update_store_app (GsPlugin *plugin, AsStore *store, GHashTable *app, GError **error) { const gchar *name; GVariant *tmp; guint32 gameid; gchar *app_id; g_autofree gchar *cache_basename = NULL; g_autofree gchar *cache_fn = NULL; g_autofree gchar *gameid_str = NULL; g_autofree gchar *html = NULL; g_autofree gchar *uri = NULL; g_autoptr(AsApp) item = NULL; /* this is the key */ tmp = g_hash_table_lookup (app, "gameid"); if (tmp == NULL) return TRUE; gameid = g_variant_get_uint32 (tmp); /* valve use the name as the application ID, not the gameid */ tmp = g_hash_table_lookup (app, "name"); if (tmp == NULL) return TRUE; name = g_variant_get_string (tmp, NULL); app_id = g_strdup_printf ("%s.desktop", name); /* already exists */ if (as_store_get_app_by_id (store, app_id) != NULL) { g_debug ("already exists %" G_GUINT32_FORMAT ", skipping", gameid); return TRUE; } /* create application with the gameid as the key */ g_debug ("parsing steam %" G_GUINT32_FORMAT, gameid); item = as_app_new (); as_app_set_kind (item, AS_APP_KIND_DESKTOP); as_app_set_project_license (item, "Steam"); as_app_set_id (item, app_id); as_app_set_name (item, NULL, name); as_app_add_category (item, "Game"); as_app_add_kudo_kind (item, AS_KUDO_KIND_MODERN_TOOLKIT); as_app_set_comment (item, NULL, "Available on Steam"); /* this is for the GNOME Software plugin */ gameid_str = g_strdup_printf ("%" G_GUINT32_FORMAT, gameid); as_app_add_metadata (item, "X-Steam-GameID", gameid_str); as_app_add_metadata (item, "GnomeSoftware::Plugin", "steam"); /* ban certains apps based on the name */ if (g_strstr_len (name, -1, "Dedicated Server") != NULL) as_app_add_veto (item, "Dedicated Server"); /* oslist */ tmp = g_hash_table_lookup (app, "oslist"); if (tmp == NULL) { as_app_add_veto (item, "No operating systems listed"); } else if (g_strstr_len (g_variant_get_string (tmp, NULL), -1, "linux") == NULL) { as_app_add_veto (item, "No Linux support"); } /* url: homepage */ tmp = g_hash_table_lookup (app, "homepage"); if (tmp != NULL) as_app_add_url (item, AS_URL_KIND_HOMEPAGE, g_variant_get_string (tmp, NULL)); /* developer name */ tmp = g_hash_table_lookup (app, "developer"); if (tmp != NULL) as_app_set_developer_name (item, NULL, g_variant_get_string (tmp, NULL)); /* type */ tmp = g_hash_table_lookup (app, "type"); if (tmp != NULL) { const gchar *kind = g_variant_get_string (tmp, NULL); if (g_strcmp0 (kind, "DLC") == 0 || g_strcmp0 (kind, "Config") == 0 || g_strcmp0 (kind, "Tool") == 0) as_app_add_veto (item, "type is %s", kind); } /* don't bother saving apps with failures */ if (as_app_get_vetos(item)->len > 0) return TRUE; /* icons */ tmp = g_hash_table_lookup (app, "clienticns"); if (tmp != NULL) { g_autoptr(GError) error_local = NULL; g_autofree gchar *ic_uri = NULL; ic_uri = g_strdup_printf ("https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/%" G_GUINT32_FORMAT "/%s.icns", gameid, g_variant_get_string (tmp, NULL)); if (!gs_plugin_steam_download_icon (plugin, item, ic_uri, &error_local)) { g_warning ("Failed to parse clienticns: %s", error_local->message); } } /* try clienticon */ if (as_app_get_icons(item)->len == 0) { tmp = g_hash_table_lookup (app, "clienticon"); if (tmp != NULL) { g_autoptr(GError) error_local = NULL; g_autofree gchar *ic_uri = NULL; ic_uri = g_strdup_printf ("http://cdn.akamai.steamstatic.com/steamcommunity/public/images/apps/%" G_GUINT32_FORMAT "/%s.ico", gameid, g_variant_get_string (tmp, NULL)); if (!gs_plugin_steam_download_icon (plugin, item, ic_uri, &error_local)) { g_warning ("Failed to parse clienticon: %s", error_local->message); } } } /* fall back to a resized logo */ if (as_app_get_icons(item)->len == 0) { tmp = g_hash_table_lookup (app, "logo"); if (tmp != NULL) { AsIcon *icon = NULL; g_autofree gchar *ic_uri = NULL; ic_uri = g_strdup_printf ("http://cdn.akamai.steamstatic.com/steamcommunity/public/images/apps/%" G_GUINT32_FORMAT "/%s.jpg", gameid, g_variant_get_string (tmp, NULL)); icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_REMOTE); as_icon_set_url (icon, ic_uri); as_app_add_icon (item, icon); } } /* size */ tmp = g_hash_table_lookup (app, "maxsize"); if (tmp != NULL) { /* string when over 16Gb... :/ */ if (g_strcmp0 (g_variant_get_type_string (tmp), "u") == 0) { g_autofree gchar *val = NULL; val = g_strdup_printf ("%" G_GUINT32_FORMAT, g_variant_get_uint32 (tmp)); as_app_add_metadata (item, "X-Steam-Size", val); } else { as_app_add_metadata (item, "X-Steam-Size", g_variant_get_string (tmp, NULL)); } } /* download page from the store */ cache_basename = g_strdup_printf ("%s.html", gameid_str); cache_fn = gs_utils_get_cache_filename ("steam", cache_basename, GS_UTILS_CACHE_FLAG_WRITEABLE, error); if (cache_fn == NULL) return FALSE; if (!g_file_test (cache_fn, G_FILE_TEST_EXISTS)) { g_autoptr(GsApp) app_dl = gs_app_new (gs_plugin_get_name (plugin)); uri = g_strdup_printf ("http://store.steampowered.com/app/%s/", gameid_str); if (!gs_plugin_download_file (plugin, app_dl, uri, cache_fn, NULL, /* GCancellable */ error)) return FALSE; } /* get screenshots and descriptions */ if (!g_file_get_contents (cache_fn, &html, NULL, error)) { gs_utils_error_convert_gio (error); return FALSE; } if (!gs_plugin_steam_update_screenshots (item, html, error)) return FALSE; if (!gs_plugin_steam_update_description (item, html, error)) return FALSE; /* add */ as_store_add_app (store, item); return TRUE; }