Пример #1
0
static void
snapd_error_convert (GError **perror)
{
	GError *error = perror != NULL ? *perror : NULL;

	/* not set */
	if (error == NULL)
		return;

	/* this are allowed for low-level errors */
	if (gs_utils_error_convert_gio (perror))
		return;

	/* custom to this plugin */
	if (error->domain == SNAPD_ERROR) {
		switch (error->code) {
		case SNAPD_ERROR_AUTH_DATA_REQUIRED:
			error->code = GS_PLUGIN_ERROR_AUTH_REQUIRED;
			g_free (error->message);
			error->message = g_strdup ("Requires authentication with @snapd");
			break;
		case SNAPD_ERROR_AUTH_DATA_INVALID:
		case SNAPD_ERROR_TWO_FACTOR_INVALID:
			error->code = GS_PLUGIN_ERROR_AUTH_INVALID;
			break;
		case SNAPD_ERROR_AUTH_CANCELLED:
			error->code = GS_PLUGIN_ERROR_CANCELLED;
			break; 
		case SNAPD_ERROR_CONNECTION_FAILED:
		case SNAPD_ERROR_WRITE_FAILED:
		case SNAPD_ERROR_READ_FAILED:
		case SNAPD_ERROR_BAD_REQUEST:
		case SNAPD_ERROR_BAD_RESPONSE:
		case SNAPD_ERROR_PERMISSION_DENIED:
		case SNAPD_ERROR_FAILED:
		case SNAPD_ERROR_TERMS_NOT_ACCEPTED:
		case SNAPD_ERROR_PAYMENT_NOT_SETUP:
		case SNAPD_ERROR_PAYMENT_DECLINED:
		case SNAPD_ERROR_ALREADY_INSTALLED:
		case SNAPD_ERROR_NOT_INSTALLED:
		case SNAPD_ERROR_NO_UPDATE_AVAILABLE:
		case SNAPD_ERROR_PASSWORD_POLICY_ERROR:
		case SNAPD_ERROR_NEEDS_DEVMODE:
		case SNAPD_ERROR_NEEDS_CLASSIC:
		case SNAPD_ERROR_NEEDS_CLASSIC_SYSTEM:
		default:
			error->code = GS_PLUGIN_ERROR_FAILED;
			break;
		}
	} else {
		g_warning ("can't reliably fixup error from domain %s",
			   g_quark_to_string (error->domain));
		error->code = GS_PLUGIN_ERROR_FAILED;
	}
	error->domain = GS_PLUGIN_ERROR;
}
Пример #2
0
static gchar *
gs_plugin_fwupd_get_file_checksum (const gchar *filename,
				   GChecksumType checksum_type,
				   GError **error)
{
	gsize len;
	g_autofree gchar *data = NULL;

	if (!g_file_get_contents (filename, &data, &len, error)) {
		gs_utils_error_convert_gio (error);
		return NULL;
	}
	return g_compute_checksum_for_data (checksum_type, (const guchar *)data, len);
}
Пример #3
0
static void
gs_plugin_fwupd_error_convert (GError **perror)
{
	GError *error = perror != NULL ? *perror : NULL;

	/* not set */
	if (error == NULL)
		return;

	/* already correct */
	if (error->domain == GS_PLUGIN_ERROR)
		return;

	/* this are allowed for low-level errors */
	if (gs_utils_error_convert_gio (perror))
		return;

	/* this are allowed for low-level errors */
	if (gs_utils_error_convert_gdbus (perror))
		return;

	/* custom to this plugin */
	if (error->domain == FWUPD_ERROR) {
		switch (error->code) {
		case FWUPD_ERROR_ALREADY_PENDING:
		case FWUPD_ERROR_INVALID_FILE:
		case FWUPD_ERROR_NOT_SUPPORTED:
			error->code = GS_PLUGIN_ERROR_NOT_SUPPORTED;
			break;
		case FWUPD_ERROR_AUTH_FAILED:
			error->code = GS_PLUGIN_ERROR_AUTH_INVALID;
			break;
		case FWUPD_ERROR_SIGNATURE_INVALID:
			error->code = GS_PLUGIN_ERROR_NO_SECURITY;
			break;
		case FWUPD_ERROR_AC_POWER_REQUIRED:
			error->code = GS_PLUGIN_ERROR_AC_POWER_REQUIRED;
			break;
		default:
			error->code = GS_PLUGIN_ERROR_FAILED;
			break;
		}
	} else {
		g_warning ("can't reliably fixup error from domain %s",
			   g_quark_to_string (error->domain));
		error->code = GS_PLUGIN_ERROR_FAILED;
	}
	error->domain = GS_PLUGIN_ERROR;
}
Пример #4
0
static GHashTable *
gs_plugin_steam_load_app_manifest (const gchar *fn, GError **error)
{
	GHashTable *manifest = NULL;
	guint i;
	guint j;
	g_autofree gchar *data = NULL;
	g_auto(GStrv) lines = NULL;

	/* get file */
	if (!g_file_get_contents (fn, &data, NULL, error)) {
		gs_utils_error_convert_gio (error);
		return NULL;
	}

	/* parse each line */
	manifest = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
	lines = g_strsplit (data, "\n", -1);
	for (i = 0; lines[i] != NULL; i++) {
		gboolean is_key = TRUE;
		const gchar *tmp = lines[i];
		g_autoptr(GString) key = g_string_new ("");
		g_autoptr(GString) value = g_string_new ("");
		for (j = 0; tmp[j] != '\0'; j++) {

			/* alphanum, so either key or value */
			if (g_ascii_isalnum (tmp[j])) {
				g_string_append_c (is_key ? key : value, tmp[j]);
				continue;
			}

			/* first whitespace after the key */
			if (g_ascii_isspace (tmp[j]) && key->len > 0)
				is_key = FALSE;
		}
		if (g_getenv ("GS_PLUGIN_STEAM_DEBUG") != NULL)
			g_debug ("manifest %s=%s", key->str, value->str);
		if (key->len == 0 || value->len == 0)
			continue;
		g_hash_table_insert (manifest,
				     g_strdup (key->str),
				     g_strdup (value->str));
	}
	return manifest;
}
Пример #5
0
gboolean
gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	g_autoptr(GFile) file = g_file_new_for_path (priv->reposdir);

	/* watch for changes */
	priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, cancellable, error);
	if (priv->monitor == NULL) {
		gs_utils_error_convert_gio (error);
		return FALSE;
	}
	g_signal_connect (priv->monitor, "changed",
			  G_CALLBACK (gs_plugin_repos_changed_cb), plugin);

	/* unconditionally at startup */
	return gs_plugin_repos_setup (plugin, cancellable, error);
}
Пример #6
0
gboolean
gs_plugin_launch (GsPlugin *plugin, GsApp *app,
		  GCancellable *cancellable, GError **error)
{
	const gchar *gameid;
	g_autofree gchar *cmdline = NULL;

	/* only process this app if was created by this plugin */
	if (g_strcmp0 (gs_app_get_management_plugin (app),
		       gs_plugin_get_name (plugin)) != 0)
		return TRUE;

	/* this is async as steam is a different process: FIXME: use D-Bus */
	gameid = gs_app_get_metadata_item (app, "X-Steam-GameID");
	cmdline = g_strdup_printf ("steam steam://run/%s", gameid);
	if (!g_spawn_command_line_sync (cmdline, NULL, NULL, NULL, error)) {
		gs_utils_error_convert_gio (error);
		return FALSE;
	}
	return TRUE;
}
gboolean
gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	priv->monitor = pk_offline_get_prepared_monitor (cancellable, error);
	if (priv->monitor == NULL) {
		gs_utils_error_convert_gio (error);
		return FALSE;
	}
	g_signal_connect (priv->monitor, "changed",
			  G_CALLBACK (gs_plugin_systemd_updates_changed_cb),
			  plugin);

	/* check if we have permission to trigger the update */
	priv->permission = gs_utils_get_permission (
		"org.freedesktop.packagekit.trigger-offline-update");
	if (priv->permission != NULL) {
		g_signal_connect (priv->permission, "notify",
				  G_CALLBACK (gs_plugin_systemd_updates_permission_cb),
				  plugin);
	}
	return TRUE;
}
Пример #8
0
static gboolean
gs_plugin_repos_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	g_autoptr(GDir) dir = NULL;
	const gchar *fn;

	/* already valid */
	if (priv->valid)
		return TRUE;

	/* clear existing */
	g_hash_table_remove_all (priv->urls);

	/* search all files */
	dir = g_dir_open (priv->reposdir, 0, error);
	if (dir == NULL) {
		gs_utils_error_convert_gio (error);
		return FALSE;
	}
	while ((fn = g_dir_read_name (dir)) != NULL) {
		g_autofree gchar *filename = NULL;
		g_auto(GStrv) groups = NULL;
		g_autoptr(GKeyFile) kf = g_key_file_new ();
		guint i;

		/* not a repo */
		if (!g_str_has_suffix (fn, ".repo"))
			continue;

		/* load file */
		filename = g_build_filename (priv->reposdir, fn, NULL);
		if (!g_key_file_load_from_file (kf, filename,
						G_KEY_FILE_NONE,
						error)) {
			gs_utils_error_convert_gio (error);
			return FALSE;
		}

		/* we can have multiple repos in one file */
		groups = g_key_file_get_groups (kf, NULL);
		for (i = 0; groups[i] != NULL; i++) {
			g_autofree gchar *tmp = NULL;
			tmp = g_key_file_get_string (kf, groups[i], "baseurl", NULL);
			if (tmp != NULL) {
				g_hash_table_insert (priv->urls,
						     g_strdup (groups[i]),
						     g_strdup (tmp));
				continue;
			}
			tmp = g_key_file_get_string (kf, groups[i], "metalink", NULL);
			if (tmp != NULL) {
				g_hash_table_insert (priv->urls,
						     g_strdup (groups[i]),
						     g_strdup (tmp));
				continue;
			}
		}
	}

	/* success */
	priv->valid = TRUE;
	return TRUE;
}
Пример #9
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;
}
Пример #10
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;
}
Пример #11
0
static GPtrArray *
gs_plugin_steam_parse_appinfo_file (const gchar *filename, GError **error)
{
	GPtrArray *apps;
	GHashTable *app = NULL;
	const gchar *tmp;
	guint8 *data = NULL;
	gsize data_len = 0;
	guint i = 0;
	gboolean debug =  g_getenv ("GS_PLUGIN_STEAM_DEBUG") != NULL;

	/* load file */
	if (!g_file_get_contents (filename, (gchar **) &data, &data_len, error)) {
		gs_utils_error_convert_gio (error);
		return NULL;
	}

	/* a GPtrArray of GHashTable */
	apps = g_ptr_array_new_with_free_func ((GDestroyNotify) g_hash_table_unref);

	/* find the first application and avoid header */
	gs_plugin_steam_find_next_sync_point (data, data_len, &i);
	for (i = i + 1; i < data_len; i++) {
		if (debug)
			g_debug ("%04x {0x%02x} %s", i, data[i], gs_plugin_steam_token_kind_to_str (data[i]));
		if (data[i] == GS_PLUGIN_STEAM_TOKEN_START) {

			/* this is a new application/game */
			if (data[i+1] == 0x02) {
				/* reset */
				app = gs_plugin_steam_add_app (apps);
				i++;
				continue;
			}

			/* new group */
			if (g_ascii_isprint (data[i+1])) {
				tmp = gs_plugin_steam_consume_string (data, data_len, &i);
				if (debug)
					g_debug ("[%s] {", tmp);
				continue;
			}

			/* something went wrong */
			if (debug)
				g_debug ("CORRUPTION DETECTED");
			gs_plugin_steam_find_next_sync_point (data, data_len, &i);
			continue;
		}
		if (data[i] == GS_PLUGIN_STEAM_TOKEN_END) {
			if (debug)
				g_debug ("}");
			continue;
		}
		if (data[i] == GS_PLUGIN_STEAM_TOKEN_STRING) {
			const gchar *value;
			tmp = gs_plugin_steam_consume_string (data, data_len, &i);
			value = gs_plugin_steam_consume_string (data, data_len, &i);
			if (debug)
				g_debug ("\t%s=%s", tmp, value);
			if (tmp != NULL && value != NULL) {
				if (g_hash_table_lookup (app, tmp) != NULL)
					continue;
				g_hash_table_insert (app,
						     g_strdup (tmp),
						     g_variant_new_string (value));
			}
			continue;
		}
		if (data[i] == GS_PLUGIN_STEAM_TOKEN_INTEGER) {
			guint32 value;
			tmp = gs_plugin_steam_consume_string (data, data_len, &i);
			value = gs_plugin_steam_consume_uint32 (data, data_len, &i);
			if (debug)
				g_debug ("\t%s=%u", tmp, value);
			if (tmp != NULL) {
				if (g_hash_table_lookup (app, tmp) != NULL)
					continue;
				g_hash_table_insert (app,
						     g_strdup (tmp),
						     g_variant_new_uint32 (value));
			}
			continue;
		}
	}

	return apps;
}
Пример #12
0
gboolean
gs_plugin_file_to_app (GsPlugin *plugin,
		       GsAppList *list,
		       GFile *file,
		       GCancellable *cancellable,
		       GError **error)
{
	GsApp *app;
	guint i;
	g_autofree gchar *content_type = NULL;
	g_autofree gchar *output = NULL;
	g_auto(GStrv) argv = NULL;
	g_auto(GStrv) tokens = NULL;
	g_autoptr(GString) str = NULL;
	const gchar *mimetypes[] = {
		"application/vnd.debian.binary-package",
		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;

	/* exec sync */
	argv = g_new0 (gchar *, 5);
	argv[0] = g_strdup (DPKG_DEB_BINARY);
	argv[1] = g_strdup ("--showformat=${Package}\\n"
			    "${Version}\\n"
			    "${Installed-Size}\\n"
			    "${Homepage}\\n"
			    "${Description}");
	argv[2] = g_strdup ("-W");
	argv[3] = g_file_get_path (file);
	if (!g_spawn_sync (NULL, argv, NULL,
			   G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
			   NULL, NULL, &output, NULL, NULL, error)) {
		gs_utils_error_convert_gio (error);
		return FALSE;
	}

	/* parse output */
	tokens = g_strsplit (output, "\n", 0);
	if (g_strv_length (tokens) < 5) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "dpkg-deb output format incorrect:\n\"%s\"\n", output);
		return FALSE;
	}

	/* create app */
	app = gs_app_new (NULL);
	gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL);
	gs_app_add_source (app, tokens[0]);
	gs_app_set_name (app, GS_APP_QUALITY_LOWEST, tokens[0]);
	gs_app_set_version (app, tokens[1]);
	gs_app_set_size_installed (app, 1024 * g_ascii_strtoull (tokens[2], NULL, 10));
	gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, tokens[3]);
	gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, tokens[4]);
	gs_app_set_kind (app, AS_APP_KIND_GENERIC);
	gs_app_set_metadata (app, "GnomeSoftware::Creator",
			     gs_plugin_get_name (plugin));

	/* multiline text */
	str = g_string_new ("");
	for (i = 5; tokens[i] != NULL; i++) {
		if (g_strcmp0 (tokens[i], " .") == 0) {
			if (str->len > 0)
				g_string_truncate (str, str->len - 1);
			g_string_append (str, "\n");
			continue;
		}
		g_strstrip (tokens[i]);
		g_string_append_printf (str, "%s ", tokens[i]);
	}
	if (str->len > 0)
		g_string_truncate (str, str->len - 1);
	gs_app_set_description (app, GS_APP_QUALITY_LOWEST, str->str);

	/* success */
	gs_app_list_add (list, app);
	return TRUE;
}
Пример #13
0
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;
}