/**
 * gs_plugin_xdg_app_set_metadata_installed:
 */
static void
gs_plugin_xdg_app_set_metadata_installed (GsApp *app, XdgAppInstalledRef *xref)
{
	guint64 mtime;
	guint64 size_installed;
	g_autofree gchar *metadata_fn = NULL;
	g_autoptr(GFile) file = NULL;
	g_autoptr(GFileInfo) info = NULL;

	/* for all types */
	gs_plugin_xdg_app_set_metadata (app, XDG_APP_REF (xref));

	/* get the last time the app was updated */
	metadata_fn = g_build_filename (xdg_app_installed_ref_get_deploy_dir (xref),
					"..",
					"active",
					NULL);
	file = g_file_new_for_path (metadata_fn);
	info = g_file_query_info (file,
				  G_FILE_ATTRIBUTE_TIME_MODIFIED,
				  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
				  NULL, NULL);
	if (info != NULL) {
		mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
		gs_app_set_install_date (app, mtime);
	}

	/* this is faster than resolving */
	gs_app_set_origin (app, xdg_app_installed_ref_get_origin (xref));

	/* this is faster than xdg_app_installation_fetch_remote_size_sync() */
	size_installed = xdg_app_installed_ref_get_installed_size (xref);
	if (size_installed != 0)
		gs_app_set_size_installed (app, size_installed);
}
Example #2
0
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_refine_item_size:
 */
static gboolean
gs_plugin_refine_item_size (GsPlugin *plugin,
			    GsApp *app,
			    GCancellable *cancellable,
			    GError **error)
{
	GsPluginData *priv = gs_plugin_get_data (plugin);
	gboolean ret;
	guint64 download_size;
	guint64 installed_size;
	g_autoptr(AsProfileTask) ptask = NULL;
	g_autoptr(GError) error_local = NULL;

	/* already set */
	if (gs_app_get_size_installed (app) > 0 &&
	    gs_app_get_size_download (app) > 0)
		return TRUE;

	/* need commit */
	if (!gs_plugin_refine_item_commit (plugin, app, cancellable, error))
		return FALSE;

	/* need runtime */
	if (!gs_plugin_refine_item_runtime (plugin, app, cancellable, error))
		return FALSE;

	/* calculate the platform size too if the app is not installed */
	if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE &&
	    gs_app_get_xdgapp_kind (app) == XDG_APP_REF_KIND_APP) {
		GsApp *app_runtime;

		/* find out what runtime the application depends on */
		if (!gs_plugin_refine_item_runtime (plugin,
						    app,
						    cancellable,
						    error))
			return FALSE;

		/* is the app_runtime already installed? */
		app_runtime = gs_app_get_runtime (app);
		if (!gs_plugin_refine_item_state (plugin,
						  app_runtime,
						  cancellable,
						  error))
			return FALSE;
		if (gs_app_get_state (app_runtime) == AS_APP_STATE_INSTALLED) {
			g_debug ("runtime %s is already installed, so not adding size",
				 gs_app_get_id (app_runtime));
		} else {
			if (!gs_plugin_refine_item_size (plugin,
							 app_runtime,
							 cancellable,
							 error))
				return FALSE;
		}
	}

	/* just get the size of the runtime */
	ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
					  "xdg-app::refine-size");
	ret = xdg_app_installation_fetch_remote_size_sync (priv->installation,
							   gs_app_get_origin (app),
							   gs_app_get_xdgapp_commit (app),
							   &download_size,
							   &installed_size,
							   cancellable, &error_local);
	if (!ret) {
		g_warning ("libxdgapp failed to return application size: %s",
			   error_local->message);
		gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE);
		gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
	} else {
		gs_app_set_size_installed (app, installed_size);
		gs_app_set_size_download (app, download_size);
	}
	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;
}
Example #5
0
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_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;
}
Example #7
0
gboolean
gs_plugin_refine_app (GsPlugin *plugin,
		      GsApp *app,
		      GsPluginRefineFlags flags,
		      GCancellable *cancellable,
		      GError **error)
{
	const gchar *gameid;
	const gchar *tmp;
	g_autofree gchar *manifest_basename = NULL;
	g_autofree gchar *fn = NULL;
	g_autoptr(GHashTable) manifest = NULL;

	/* check is us */
	gameid = gs_app_get_metadata_item (app, "X-Steam-GameID");
	if (gameid == NULL)
		return TRUE;

	/* is this true? */
	gs_app_set_kind (app, AS_ID_KIND_DESKTOP);

	/* no way of knowing */
	if (gs_app_get_size_download (app) == 0)
		gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);

	/* hardcoded */
	if (gs_app_get_origin_hostname (app) == NULL)
		gs_app_set_origin_hostname (app, "steampowered.com");

	/* size */
	tmp = gs_app_get_metadata_item (app, "X-Steam-Size");
	if (tmp != NULL) {
		guint64 sz;
		sz = g_ascii_strtoull (tmp, NULL, 10);
		if (sz > 0)
			gs_app_set_size_installed (app, sz);
	}

	/* check manifest */
	manifest_basename = g_strdup_printf ("appmanifest_%s.acf", gameid);
	fn = g_build_filename (g_get_user_data_dir (),
			       "Steam",
			       "steamapps",
			       manifest_basename,
			       NULL);
	if (!g_file_test (fn, G_FILE_TEST_EXISTS)) {
		/* can never have been installed */
		gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
		return TRUE;
	}
	manifest = gs_plugin_steam_load_app_manifest (fn, error);
	if (manifest == NULL)
		return FALSE;

	/* this is better than the download size */
	tmp = g_hash_table_lookup (manifest, "SizeOnDisk");
	if (tmp != NULL) {
		guint64 sz;
		sz = g_ascii_strtoull (tmp, NULL, 10);
		if (sz > 0)
			gs_app_set_size_installed (app, sz);
	}

	/* set state */
	tmp = g_hash_table_lookup (manifest, "StateFlags");
	if (tmp != NULL) {
		guint64 state_flags;

		/* set state */
		state_flags = g_ascii_strtoull (tmp, NULL, 10);
		if (state_flags & GS_STEAM_STATE_FLAG_DOWNLOADING ||
		    state_flags & GS_STEAM_STATE_FLAG_PREALLOCATING ||
		    state_flags & GS_STEAM_STATE_FLAG_ADDING_FILES ||
		    state_flags & GS_STEAM_STATE_FLAG_COMMITTING ||
		    state_flags & GS_STEAM_STATE_FLAG_STAGING)
			gs_app_set_state (app, AS_APP_STATE_INSTALLING);
		else if (state_flags & GS_STEAM_STATE_FLAG_UNINSTALLING)
			gs_app_set_state (app, AS_APP_STATE_REMOVING);
		else if (state_flags & GS_STEAM_STATE_FLAG_FULLY_INSTALLED)
			gs_app_set_state (app, AS_APP_STATE_INSTALLED);
		else if (state_flags & GS_STEAM_STATE_FLAG_UNINSTALLED)
			gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
	}

	/* set install date */
	tmp = g_hash_table_lookup (manifest, "LastUpdated");
	if (tmp != NULL) {
		guint64 ts;
		ts = g_ascii_strtoull (tmp, NULL, 10);
		if (ts > 0)
			gs_app_set_install_date (app, ts);
	}

	return TRUE;
}
Example #8
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;
}
Example #9
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;
}