Пример #1
0
static gboolean
gs_plugin_odrs_invalidate_cache (AsReview *review, GError **error)
{
	g_autofree gchar *cachefn_basename = NULL;
	g_autofree gchar *cachefn = NULL;
	g_autoptr(GFile) cachefn_file = NULL;

	/* look in the cache */
	cachefn_basename = g_strdup_printf ("%s.json",
					    as_review_get_metadata_item (review, "app_id"));
	cachefn = gs_utils_get_cache_filename ("reviews",
					       cachefn_basename,
					       GS_UTILS_CACHE_FLAG_WRITEABLE,
					       error);
	if (cachefn == NULL)
		return FALSE;
	cachefn_file = g_file_new_for_path (cachefn);
	if (!g_file_query_exists (cachefn_file, NULL))
		return TRUE;
	return g_file_delete (cachefn_file, NULL, error);
}
Пример #2
0
static gboolean
gs_plugin_odrs_refresh_ratings (GsPlugin *plugin,
				guint cache_age,
				GCancellable *cancellable,
				GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	g_autofree gchar *fn = NULL;
	g_autofree gchar *uri = NULL;
	g_autoptr(GsApp) app_dl = gs_app_new (gs_plugin_get_name (plugin));

	/* check cache age */
	fn = gs_utils_get_cache_filename ("ratings",
					  "odrs.json",
					  GS_UTILS_CACHE_FLAG_WRITEABLE,
					  error);
	if (fn == NULL)
		return FALSE;
	if (cache_age > 0) {
		guint tmp;
		g_autoptr(GFile) file = NULL;
		file = g_file_new_for_path (fn);
		tmp = gs_utils_get_file_age (file);
		if (tmp < cache_age) {
			g_debug ("%s is only %u seconds old, so ignoring refresh",
				 fn, tmp);
			return gs_plugin_odrs_load_ratings (plugin, fn, error);
		}
	}

	/* download the complete file */
	uri = g_strdup_printf ("%s/ratings", priv->review_server);
	if (!gs_plugin_download_file (plugin, app_dl, uri, fn, cancellable, error)) {
		gs_utils_error_add_unique_id (error, priv->cached_origin);
		return FALSE;
	}
	return gs_plugin_odrs_load_ratings (plugin, fn, error);
}
Пример #3
0
static GPtrArray *
gs_plugin_odrs_fetch_for_app (GsPlugin *plugin, GsApp *app, GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	const gchar *version;
	guint status_code;
	g_autofree gchar *cachefn_basename = NULL;
	g_autofree gchar *cachefn = NULL;
	g_autofree gchar *data = NULL;
	g_autofree gchar *uri = NULL;
	g_autoptr(GFile) cachefn_file = NULL;
	g_autoptr(GPtrArray) reviews = NULL;
	g_autoptr(JsonBuilder) builder = NULL;
	g_autoptr(JsonGenerator) json_generator = NULL;
	g_autoptr(JsonNode) json_root = NULL;
	g_autoptr(SoupMessage) msg = NULL;

	/* look in the cache */
	cachefn_basename = g_strdup_printf ("%s.json", gs_app_get_id (app));
	cachefn = gs_utils_get_cache_filename ("reviews",
					       cachefn_basename,
					       GS_UTILS_CACHE_FLAG_WRITEABLE,
					       error);
	if (cachefn == NULL)
		return NULL;
	cachefn_file = g_file_new_for_path (cachefn);
	if (gs_utils_get_file_age (cachefn_file) < ODRS_REVIEW_CACHE_AGE_MAX) {
		g_autofree gchar *json_data = NULL;
		if (!g_file_get_contents (cachefn, &json_data, NULL, error))
			return NULL;
		g_debug ("got review data for %s from %s",
			 gs_app_get_id (app), cachefn);
		return gs_plugin_odrs_parse_reviews (plugin,
						     json_data, -1,
						     error);
	}

	/* not always available */
	version = gs_app_get_version (app);
	if (version == NULL)
		version = "unknown";

	/* create object with review data */
	builder = json_builder_new ();
	json_builder_begin_object (builder);
	json_builder_set_member_name (builder, "user_hash");
	json_builder_add_string_value (builder, priv->user_hash);
	json_builder_set_member_name (builder, "app_id");
	json_builder_add_string_value (builder, gs_app_get_id (app));
	json_builder_set_member_name (builder, "locale");
	json_builder_add_string_value (builder, gs_plugin_get_locale (plugin));
	json_builder_set_member_name (builder, "distro");
	json_builder_add_string_value (builder, priv->distro);
	json_builder_set_member_name (builder, "version");
	json_builder_add_string_value (builder, version);
	json_builder_set_member_name (builder, "limit");
	json_builder_add_int_value (builder, ODRS_REVIEW_NUMBER_RESULTS_MAX);
	json_builder_end_object (builder);

	/* export as a string */
	json_root = json_builder_get_root (builder);
	json_generator = json_generator_new ();
	json_generator_set_pretty (json_generator, TRUE);
	json_generator_set_root (json_generator, json_root);
	data = json_generator_to_data (json_generator, NULL);
	if (data == NULL)
		return NULL;
	uri = g_strdup_printf ("%s/fetch", priv->review_server);
	msg = soup_message_new (SOUP_METHOD_POST, uri);
	soup_message_set_request (msg, "application/json; charset=utf-8",
				  SOUP_MEMORY_COPY, data, strlen (data));
	status_code = soup_session_send_message (gs_plugin_get_soup_session (plugin), msg);
	if (status_code != SOUP_STATUS_OK) {
		if (!gs_plugin_odrs_parse_success (msg->response_body->data,
						   msg->response_body->length,
						   error))
			return NULL;
		/* not sure what to do here */
		g_set_error_literal (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_DOWNLOAD_FAILED,
				     "status code invalid");
		gs_utils_error_add_unique_id (error, priv->cached_origin);
		return NULL;
	}
	reviews = gs_plugin_odrs_parse_reviews (plugin,
						msg->response_body->data,
						msg->response_body->length,
						error);
	if (reviews == NULL)
		return NULL;
	g_debug ("odrs returned: %s", msg->response_body->data);

	/* save to the cache */
	if (!g_file_set_contents (cachefn,
				  msg->response_body->data,
				  msg->response_body->length,
				  error))
		return NULL;

	/* success */
	return g_steal_pointer (&reviews);
}
Пример #4
0
static GsApp *
gs_plugin_fwupd_new_app (GsPlugin *plugin, FwupdDevice *dev, GError **error)
{
	FwupdRelease *rel = fwupd_device_get_release_default (dev);
	GPtrArray *checksums;
	const gchar *update_uri;
	g_autofree gchar *basename = NULL;
	g_autofree gchar *filename_cache = NULL;
	g_autoptr(GFile) file = NULL;
	g_autoptr(GsApp) app = NULL;

	/* update unsupported */
	app = gs_plugin_fwupd_new_app_from_device (plugin, dev);
	if (gs_app_get_state (app) != AS_APP_STATE_UPDATABLE_LIVE) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "%s [%s] cannot be updated",
			     gs_app_get_name (app), gs_app_get_id (app));
		return NULL;
	}

	/* some missing */
	if (gs_app_get_id (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No id for firmware");
		return NULL;
	}
	if (gs_app_get_version (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No version! for %s!", gs_app_get_id (app));
		return NULL;
	}
	if (gs_app_get_update_version (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No update-version! for %s!", gs_app_get_id (app));
		return NULL;
	}
	checksums = fwupd_release_get_checksums (rel);
	if (checksums->len == 0) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NO_SECURITY,
			     "%s [%s] (%s) has no checksums, ignoring as unsafe",
			     gs_app_get_name (app),
			     gs_app_get_id (app),
			     gs_app_get_update_version (app));
		return NULL;
	}
	update_uri = fwupd_release_get_uri (rel);
	if (update_uri == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_INVALID_FORMAT,
			     "no location available for %s [%s]",
			     gs_app_get_name (app), gs_app_get_id (app));
		return NULL;
	}

	/* does the firmware already exist in the cache? */
	basename = g_path_get_basename (update_uri);
	filename_cache = gs_utils_get_cache_filename ("fwupd",
						      basename,
						      GS_UTILS_CACHE_FLAG_NONE,
						      error);
	if (filename_cache == NULL)
		return NULL;

	/* delete the file if the checksum does not match */
	if (g_file_test (filename_cache, G_FILE_TEST_EXISTS)) {
		const gchar *checksum_tmp = NULL;
		g_autofree gchar *checksum = NULL;

		/* we can migrate to something better than SHA1 when the LVFS
		 * starts producing metadata with multiple hash types */
		checksum_tmp = fwupd_checksum_get_by_kind (checksums,
							   G_CHECKSUM_SHA1);
		if (checksum_tmp == NULL) {
			g_set_error (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_INVALID_FORMAT,
				     "No valid checksum for %s",
				     filename_cache);
		}
		checksum = gs_plugin_fwupd_get_file_checksum (filename_cache,
							      G_CHECKSUM_SHA1,
							      error);
		if (checksum == NULL)
			return NULL;
		if (g_strcmp0 (checksum_tmp, checksum) != 0) {
			g_set_error (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_INVALID_FORMAT,
				     "%s does not match checksum, expected %s got %s",
				     filename_cache, checksum_tmp, checksum);
			g_unlink (filename_cache);
			return NULL;
		}
	}

	/* already downloaded, so overwrite */
	if (g_file_test (filename_cache, G_FILE_TEST_EXISTS))
		gs_app_set_size_download (app, 0);

	/* actually add the application */
	file = g_file_new_for_path (filename_cache);
	gs_app_set_local_file (app, file);
	return g_steal_pointer (&app);
}
Пример #5
0
static gboolean
gs_plugin_fwupd_refresh_remote (GsPlugin *plugin,
				FwupdRemote *remote,
				guint cache_age,
				GCancellable *cancellable,
				GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	GChecksumType checksum_kind;
	const gchar *url_sig = NULL;
	const gchar *url = NULL;
	g_autoptr(GError) error_local = NULL;
	g_autofree gchar *basename = NULL;
	g_autofree gchar *basename_sig = NULL;
	g_autofree gchar *cache_id = NULL;
	g_autofree gchar *checksum = NULL;
	g_autofree gchar *filename = NULL;
	g_autofree gchar *filename_sig = NULL;
	g_autoptr(GBytes) data = NULL;
	g_autoptr(GsApp) app_dl = gs_app_new (gs_plugin_get_name (plugin));

	/* sanity check */
	if (fwupd_remote_get_filename_cache_sig (remote) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_FAILED,
			     "remote %s has no cache signature",
			     fwupd_remote_get_id (remote));
		return FALSE;
	}

	/* check cache age */
	if (cache_age > 0) {
		guint64 age = fwupd_remote_get_age (remote);
		guint tmp = age < G_MAXUINT ? (guint) age : G_MAXUINT;
		if (tmp < cache_age) {
			g_debug ("%s is only %u seconds old, so ignoring refresh",
				 filename_sig, tmp);
			return TRUE;
		}
	}

	/* download the signature first, it's smaller */
	cache_id = g_strdup_printf ("fwupd/remotes.d/%s", fwupd_remote_get_id (remote));
	basename_sig = g_path_get_basename (fwupd_remote_get_filename_cache_sig (remote));
	filename_sig = gs_utils_get_cache_filename (cache_id, basename_sig,
						    GS_UTILS_CACHE_FLAG_WRITEABLE,
						    error);

	/* download the signature first, it's smaller */
	url_sig = fwupd_remote_get_metadata_uri_sig (remote);
	gs_app_set_summary_missing (app_dl,
				    /* TRANSLATORS: status text when downloading */
				    _("Downloading firmware update signature…"));
	data = gs_plugin_download_data (plugin, app_dl, url_sig, cancellable, error);
	if (data == NULL) {
		gs_utils_error_add_origin_id (error, priv->cached_origin);
		return FALSE;
	}

	/* is the signature hash the same as we had before? */
	checksum_kind = fwupd_checksum_guess_kind (fwupd_remote_get_checksum (remote));
	checksum = g_compute_checksum_for_data (checksum_kind,
						(const guchar *) g_bytes_get_data (data, NULL),
						g_bytes_get_size (data));
	if (g_strcmp0 (checksum, fwupd_remote_get_checksum (remote)) == 0) {
		g_debug ("signature of %s is unchanged", url_sig);
		return TRUE;
	}

	/* save to a file */
	g_debug ("saving new remote signature to %s:", filename_sig);
	if (!g_file_set_contents (filename_sig,
				  g_bytes_get_data (data, NULL),
				  (guint) g_bytes_get_size (data),
				  &error_local)) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_WRITE_FAILED,
			     "Failed to save firmware signature: %s",
			     error_local->message);
		return FALSE;
	}

	/* download the payload and save to file */
	basename = g_path_get_basename (fwupd_remote_get_filename_cache (remote));
	filename = gs_utils_get_cache_filename (cache_id, basename,
						GS_UTILS_CACHE_FLAG_WRITEABLE,
						error);
	if (filename == NULL)
		return FALSE;
	g_debug ("saving new firmware metadata to %s:", filename);
	gs_app_set_summary_missing (app_dl,
				    /* TRANSLATORS: status text when downloading */
				    _("Downloading firmware update metadata…"));
	url = fwupd_remote_get_metadata_uri (remote);
	if (!gs_plugin_download_file (plugin, app_dl, url, filename,
				      cancellable, error)) {
		gs_utils_error_add_origin_id (error, priv->cached_origin);
		return FALSE;
	}

	/* phew, lets send all this to fwupd */
	if (!fwupd_client_update_metadata (priv->client,
					   fwupd_remote_get_id (remote),
					   filename,
					   filename_sig,
					   cancellable,
					   error)) {
		gs_plugin_fwupd_error_convert (error);
		return FALSE;
	}
	return TRUE;
}
Пример #6
0
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;
}
Пример #7
0
static gboolean
gs_plugin_steam_download_icon (GsPlugin *plugin,
			       AsApp *app,
			       const gchar *uri,
			       GError **error)
{
	gsize data_len;
	g_autofree gchar *cache_basename = NULL;
	g_autofree gchar *cache_fn = NULL;
	g_autofree gchar *cache_png = NULL;
	g_autofree gchar *data = NULL;
	g_autoptr(AsIcon) icon = NULL;
	g_autoptr(GdkPixbuf) pb = NULL;

	/* download icons from the cdn */
	cache_basename = g_path_get_basename (uri);
	cache_fn = gs_utils_get_cache_filename ("steam",
						cache_basename,
						GS_UTILS_CACHE_FLAG_NONE,
						error);
	if (cache_fn == NULL)
		return FALSE;
	if (g_file_test (cache_fn, G_FILE_TEST_EXISTS)) {
		if (!g_file_get_contents (cache_fn, &data, &data_len, error)) {
			gs_utils_error_convert_gio (error);
			return FALSE;
		}
	} else {
		if (!gs_mkdir_parent (cache_fn, error))
			return FALSE;
		if (!gs_plugin_download_file (plugin,
					      NULL, /* GsApp */
					      uri,
					      cache_fn,
					      NULL, /* GCancellable */
					      error))
			return FALSE;
	}

	/* load the icon as large as possible */
	pb = gdk_pixbuf_new_from_file (cache_fn, error);
	if (pb == NULL) {
		gs_utils_error_convert_gdk_pixbuf (error);
		return FALSE;
	}

	/* too small? */
	if (gdk_pixbuf_get_width (pb) < 48 ||
	    gdk_pixbuf_get_height (pb) < 48) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_INVALID_FORMAT,
			     "icon is too small %ix%i",
			     gdk_pixbuf_get_width (pb),
			     gdk_pixbuf_get_height (pb));
		return FALSE;
	}

	/* save to cache */
	memcpy (cache_basename + 40, ".png\0", 5);
	cache_png = gs_utils_get_cache_filename ("steam",
						 cache_basename,
						 GS_UTILS_CACHE_FLAG_WRITEABLE,
						 error);
	if (cache_png == NULL)
		return FALSE;
	if (!gdk_pixbuf_save (pb, cache_png, "png", error, NULL)) {
		gs_utils_error_convert_gdk_pixbuf (error);
		return FALSE;
	}

	/* add an icon */
	icon = as_icon_new ();
	as_icon_set_kind (icon, AS_ICON_KIND_LOCAL);
	as_icon_set_filename (icon, cache_png);
	as_app_add_icon (app, icon);
	return TRUE;
}
Пример #8
0
void
gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
				GCancellable *cancellable)
{
	AsImage *im = NULL;
	const gchar *url;
	g_autofree gchar *basename = NULL;
	g_autofree gchar *cache_kind = NULL;
	g_autofree gchar *cachefn_thumb = NULL;
	g_autofree gchar *sizedir = NULL;
	g_autoptr(SoupURI) base_uri = NULL;

	g_return_if_fail (GS_IS_SCREENSHOT_IMAGE (ssimg));

	g_return_if_fail (AS_IS_SCREENSHOT (ssimg->screenshot));
	g_return_if_fail (ssimg->width != 0);
	g_return_if_fail (ssimg->height != 0);

	/* load an image according to the scale factor */
	ssimg->scale = (guint) gtk_widget_get_scale_factor (GTK_WIDGET (ssimg));
	im = as_screenshot_get_image (ssimg->screenshot,
				      ssimg->width * ssimg->scale,
				      ssimg->height * ssimg->scale);

	/* if we've failed to load a HiDPI image, fallback to LoDPI */
	if (im == NULL && ssimg->scale > 1) {
		ssimg->scale = 1;
		im = as_screenshot_get_image (ssimg->screenshot,
					      ssimg->width,
					      ssimg->height);
	}
	if (im == NULL) {
		/* TRANSLATORS: this is when we request a screenshot size that
		 * the generator did not create or the parser did not add */
		gs_screenshot_image_set_error (ssimg, _("Screenshot size not found"));
		return;
	}

	/* check if the URL points to a local file */
	url = as_image_get_url (im);
	if (g_str_has_prefix (url, "file://")) {
		g_free (ssimg->filename);
		ssimg->filename = g_strdup (url + 7);
		if (g_file_test (ssimg->filename, G_FILE_TEST_EXISTS)) {
			as_screenshot_show_image (ssimg);
			return;
		}
	}

	basename = gs_screenshot_get_cachefn_for_url (url);
	if (ssimg->width == G_MAXUINT || ssimg->height == G_MAXUINT) {
		sizedir = g_strdup ("unknown");
	} else {
		sizedir = g_strdup_printf ("%ux%u", ssimg->width * ssimg->scale, ssimg->height * ssimg->scale);
	}
	cache_kind = g_build_filename ("screenshots", sizedir, NULL);
	g_free (ssimg->filename);
	ssimg->filename = gs_utils_get_cache_filename (cache_kind,
						       basename,
						       GS_UTILS_CACHE_FLAG_NONE,
						       NULL);
	if (ssimg->filename == NULL) {
		/* TRANSLATORS: this is when we try create the cache directory
		 * but we were out of space or permission was denied */
		gs_screenshot_image_set_error (ssimg, _("Could not create cache"));
		return;
	}

	/* does local file already exist and has recently been downloaded */
	if (g_file_test (ssimg->filename, G_FILE_TEST_EXISTS)) {
		guint64 age_max;
		g_autoptr(GFile) file = NULL;

		/* show the image we have in cache while we're checking for the
		 * new screenshot (which probably won't have changed) */
		as_screenshot_show_image (ssimg);

		/* verify the cache age against the maximum allowed */
		age_max = g_settings_get_uint (ssimg->settings,
					       "screenshot-cache-age-maximum");
		file = g_file_new_for_path (ssimg->filename);
		/* image new enough, not re-requesting from server */
		if (age_max > 0 && gs_utils_get_file_age (file) < age_max)
			return;
	}

	/* if we're not showing a full-size image, we try loading a blurred
	 * smaller version of it straight away */
	if (!ssimg->showing_image &&
	    ssimg->width > AS_IMAGE_THUMBNAIL_WIDTH &&
	    ssimg->height > AS_IMAGE_THUMBNAIL_HEIGHT) {
		const gchar *url_thumb;
		g_autofree gchar *basename_thumb = NULL;
		g_autofree gchar *cache_kind_thumb = NULL;
		im = as_screenshot_get_image (ssimg->screenshot,
					      AS_IMAGE_THUMBNAIL_WIDTH * ssimg->scale,
					      AS_IMAGE_THUMBNAIL_HEIGHT * ssimg->scale);
		url_thumb = as_image_get_url (im);
		basename_thumb = gs_screenshot_get_cachefn_for_url (url_thumb);
		cache_kind_thumb = g_build_filename ("screenshots", "112x63", NULL);
		cachefn_thumb = gs_utils_get_cache_filename (cache_kind_thumb,
							     basename_thumb,
							     GS_UTILS_CACHE_FLAG_NONE,
							     NULL);
		if (cachefn_thumb == NULL)
			return;
		if (g_file_test (cachefn_thumb, G_FILE_TEST_EXISTS))
			gs_screenshot_image_show_blurred (ssimg, cachefn_thumb);
	}

	/* re-request the cache filename, which might be different as it needs
	 * to be writable this time */
	g_free (ssimg->filename);
	ssimg->filename = gs_utils_get_cache_filename (cache_kind,
						       basename,
						       GS_UTILS_CACHE_FLAG_WRITEABLE,
						       NULL);

	/* download file */
	g_debug ("downloading %s to %s", url, ssimg->filename);
	base_uri = soup_uri_new (url);
	if (base_uri == NULL || !SOUP_URI_VALID_FOR_HTTP (base_uri)) {
		/* TRANSLATORS: this is when we try to download a screenshot
		 * that was not a valid URL */
		gs_screenshot_image_set_error (ssimg, _("Screenshot not valid"));
		return;
	}

	/* cancel any previous messages */
	if (ssimg->message != NULL) {
		soup_session_cancel_message (ssimg->session,
		                             ssimg->message,
		                             SOUP_STATUS_CANCELLED);
		g_clear_object (&ssimg->message);
	}

	ssimg->message = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
	if (ssimg->message == NULL) {
		/* TRANSLATORS: this is when networking is not available */
		gs_screenshot_image_set_error (ssimg, _("Screenshot not available"));
		return;
	}

	/* not all servers support If-Modified-Since, but worst case we just
	 * re-download the entire file again every 30 days */
	if (g_file_test (ssimg->filename, G_FILE_TEST_EXISTS)) {
		g_autoptr(GFile) file = g_file_new_for_path (ssimg->filename);
		gs_screenshot_soup_msg_set_modified_request (ssimg->message, file);
	}

	/* send async */
	soup_session_queue_message (ssimg->session,
				    g_object_ref (ssimg->message) /* transfer full */,
				    gs_screenshot_image_complete_cb,
				    g_object_ref (ssimg));
}
Пример #9
0
static gboolean
gs_screenshot_image_save_downloaded_img (GsScreenshotImage *ssimg,
					 GdkPixbuf *pixbuf,
					 GError **error)
{
	g_autoptr(AsImage) im = NULL;
	gboolean ret;
	const GPtrArray *images;
	g_autoptr(GError) error_local = NULL;
	g_autofree char *filename = NULL;
	g_autofree char *size_dir = NULL;
	g_autofree char *cache_kind = NULL;
	g_autofree char *basename = NULL;
	guint width = ssimg->width;
	guint height = ssimg->height;

	/* save to file, using the same code as the AppStream builder
	 * so the preview looks the same */
	im = as_image_new ();
	as_image_set_pixbuf (im, pixbuf);
	ret = as_image_save_filename (im, ssimg->filename,
				      ssimg->width * ssimg->scale,
				      ssimg->height * ssimg->scale,
				      AS_IMAGE_SAVE_FLAG_PAD_16_9,
				      error);

	if (!ret)
		return FALSE;

	if (ssimg->screenshot == NULL)
		return TRUE;

	images = as_screenshot_get_images (ssimg->screenshot);
	if (images->len > 1)
		return TRUE;

	if (width == AS_IMAGE_THUMBNAIL_WIDTH &&
	    height == AS_IMAGE_THUMBNAIL_HEIGHT) {
		width = AS_IMAGE_NORMAL_WIDTH;
		height = AS_IMAGE_NORMAL_HEIGHT;
	} else {
		width = AS_IMAGE_THUMBNAIL_WIDTH;
		height = AS_IMAGE_THUMBNAIL_HEIGHT;
	}

	width *= ssimg->scale;
	height *= ssimg->scale;
	basename = g_path_get_basename (ssimg->filename);
	size_dir = g_strdup_printf ("%ux%u", width, height);
	cache_kind = g_build_filename ("screenshots", size_dir, NULL);
	filename = gs_utils_get_cache_filename (cache_kind, basename,
						GS_UTILS_CACHE_FLAG_WRITEABLE,
						&error_local);

        if (filename == NULL) {
		/* if we cannot get a cache filename, warn about that but do not
		 * set a user's visible error because this is a complementary
		 * operation */
                g_warning ("Failed to get cache filename for counterpart "
                           "screenshot '%s' in folder '%s': %s", basename,
                           cache_kind, error_local->message);
                return TRUE;
        }

	ret = as_image_save_filename (im, filename, width, height,
				      AS_IMAGE_SAVE_FLAG_PAD_16_9,
				      &error_local);

	if (!ret) {
		/* if we cannot save this screenshot, warn about that but do not
		 * set a user's visible error because this is a complementary
		 * operation */
                g_warning ("Failed to save screenshot '%s': %s", filename,
                           error_local->message);
        }

	return TRUE;
}
Пример #10
0
gboolean
gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	const gchar *verstr = NULL;
	gchar *endptr = NULL;
	g_autoptr(GFile) file = NULL;
	g_autoptr(GsOsRelease) os_release = NULL;

	/* get the file to cache */
	priv->cachefn = gs_utils_get_cache_filename ("upgrades",
						     "fedora.json",
						     GS_UTILS_CACHE_FLAG_WRITEABLE,
						     error);
	if (priv->cachefn == NULL)
		return FALSE;

	/* watch this in case it is changed by the user */
	file = g_file_new_for_path (priv->cachefn);
	priv->cachefn_monitor = g_file_monitor (file,
							G_FILE_MONITOR_NONE,
							cancellable,
							error);
	if (priv->cachefn_monitor == NULL)
		return FALSE;
	g_signal_connect (priv->cachefn_monitor, "changed",
			  G_CALLBACK (gs_plugin_fedora_distro_upgrades_changed_cb), plugin);

	/* read os-release for the current versions */
	os_release = gs_os_release_new (error);
	if (os_release == NULL)
		return FALSE;
	priv->os_name = g_strdup (gs_os_release_get_name (os_release));
	if (priv->os_name == NULL)
		return FALSE;
	verstr = gs_os_release_get_version_id (os_release);
	if (verstr == NULL)
		return FALSE;

	/* parse the version */
	priv->os_version = g_ascii_strtoull (verstr, &endptr, 10);
	if (endptr == verstr || priv->os_version > G_MAXUINT) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_INVALID_FORMAT,
			     "Failed parse VERSION_ID: %s", verstr);
		return FALSE;
	}

	/* add source */
	priv->cached_origin = gs_app_new (gs_plugin_get_name (plugin));
	gs_app_set_kind (priv->cached_origin, AS_APP_KIND_SOURCE);
	gs_app_set_origin_ui (priv->cached_origin, "Fedora Project PkgDb");
	gs_app_set_origin_hostname (priv->cached_origin,
				    FEDORA_PKGDB_COLLECTIONS_API_URI);

	/* add the source to the plugin cache which allows us to match the
	 * unique ID to a GsApp when creating an event */
	gs_plugin_cache_add (plugin,
			     gs_app_get_unique_id (priv->cached_origin),
			     priv->cached_origin);

	/* success */
	return TRUE;
}