Beispiel #1
0
static gboolean
pk_backend_spawn_parse_stdout (PkBackendSpawn *backend_spawn,
			       PkBackendJob *job,
			       const gchar *line,
			       GError **error)
{
	guint size;
	gchar *command;
	gchar *text;
	guint64 speed;
	guint64 download_size_remaining;
	PkInfoEnum info;
	PkRestartEnum restart;
	PkGroupEnum group;
	gulong package_size;
	gint percentage;
	PkErrorEnum error_enum;
	PkStatusEnum status_enum;
	PkRestartEnum restart_enum;
	PkSigTypeEnum sig_type;
	PkUpdateStateEnum update_state_enum;
	PkMediaTypeEnum media_type_enum;
	PkDistroUpgradeEnum distro_upgrade_enum;
	PkBackendSpawnPrivate *priv = backend_spawn->priv;
	g_auto(GStrv) sections = NULL;

	g_return_val_if_fail (PK_IS_BACKEND_SPAWN (backend_spawn), FALSE);

	/* check if output line */
	if (line == NULL)
		return FALSE;

	/* split by tab */
	sections = g_strsplit (line, "\t", 0);
	command = sections[0];

	/* get size */
	size = g_strv_length (sections);

	if (g_strcmp0 (command, "package") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		if (pk_package_id_check (sections[2]) == FALSE) {
			g_set_error_literal (error, 1, 0, "invalid package_id");
			return FALSE;
		}
		info = pk_info_enum_from_string (sections[1]);
		if (info == PK_INFO_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Info enum not recognised, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}
		g_strdelimit (sections[3], PK_UNSAFE_DELIMITERS, ' ');
		if (!g_utf8_validate (sections[3], -1, NULL)) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[3]);
			return FALSE;
		}
		pk_backend_job_package (job, info, sections[2], sections[3]);
	} else if (g_strcmp0 (command, "details") == 0) {
		if (size != 8) {
			g_set_error (error, 1, 0,
				     "invalid command'%s', size %i",
				     command, size);
			return FALSE;
		}
		group = pk_group_enum_from_string (sections[4]);

		/* ITS4: ignore, checked for overflow */
		package_size = atol (sections[7]);
		if (package_size > 1073741824) {
			g_set_error_literal (error, 1, 0,
					     "package size cannot be that large");
			return FALSE;
		}
		g_strdelimit (sections[5], PK_UNSAFE_DELIMITERS, ' ');
		if (!g_utf8_validate (sections[4], -1, NULL)) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[5]);
			return FALSE;
		}
		text = g_strdup (sections[5]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');
		pk_backend_job_details (job, sections[1], sections[2], sections[3],
					group, text, sections[6], package_size);
		g_free (text);
	} else if (g_strcmp0 (command, "finished") == 0) {
		if (size != 1) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		pk_backend_job_finished (job);
		priv->is_busy = FALSE;

		/* from this point on, we can start the kill timer */
		pk_backend_spawn_start_kill_timer (backend_spawn);

	} else if (g_strcmp0 (command, "files") == 0) {
		g_auto(GStrv) tmp = NULL;
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		tmp = g_strsplit (sections[2], ";", -1);
		pk_backend_job_files (job, sections[1], tmp);
	} else if (g_strcmp0 (command, "repo-detail") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		g_strdelimit (sections[2], PK_UNSAFE_DELIMITERS, ' ');
		if (!g_utf8_validate (sections[2], -1, NULL)) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[2]);
			return FALSE;
		}
		if (g_strcmp0 (sections[3], "true") == 0) {
			pk_backend_job_repo_detail (job, sections[1], sections[2], TRUE);
		} else if (g_strcmp0 (sections[3], "false") == 0) {
			pk_backend_job_repo_detail (job, sections[1], sections[2], FALSE);
		} else {
			g_set_error (error, 1, 0, "invalid qualifier '%s'", sections[3]);
			return FALSE;
		}
	} else if (g_strcmp0 (command, "updatedetail") == 0) {
		g_auto(GStrv) updates = NULL;
		g_auto(GStrv) obsoletes = NULL;
		g_auto(GStrv) vendor_urls = NULL;
		g_auto(GStrv) bugzilla_urls = NULL;
		g_auto(GStrv) cve_urls = NULL;
		if (size != 13) {
			g_set_error (error, 1, 0, "invalid command '%s', size %i", command, size);
			return FALSE;
		}
		restart = pk_restart_enum_from_string (sections[7]);
		if (restart == PK_RESTART_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Restart enum not recognised, and hence ignored: '%s'", sections[7]);
			return FALSE;
		}
		g_strdelimit (sections[12], PK_UNSAFE_DELIMITERS, ' ');
		if (!g_utf8_validate (sections[12], -1, NULL)) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[12]);
			return FALSE;
		}
		update_state_enum = pk_update_state_enum_from_string (sections[10]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (sections[8], ";", '\n');
		g_strdelimit (sections[9], ";", '\n');
		updates = g_strsplit (sections[2], "&", -1);
		obsoletes = g_strsplit (sections[3], "&", -1);
		vendor_urls = g_strsplit (sections[4], ";", -1);
		bugzilla_urls = g_strsplit (sections[5], ";", -1);
		cve_urls = g_strsplit (sections[6], ";", -1);
		pk_backend_job_update_detail (job,
					  sections[1],
					  updates,
					  obsoletes,
					  vendor_urls,
					  bugzilla_urls,
					  cve_urls,
					  restart,
					  sections[8],
					  sections[9],
					  update_state_enum,
					  sections[11],
					  sections[12]);
	} else if (g_strcmp0 (command, "percentage") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		if (!pk_strtoint (sections[1], &percentage)) {
			g_set_error (error, 1, 0, "invalid percentage value %s", sections[1]);
			return FALSE;
		} else if (percentage < 0 || percentage > 100) {
			g_set_error (error, 1, 0, "invalid percentage value %i", percentage);
			return FALSE;
		} else {
			pk_backend_job_set_percentage (job, percentage);
		}
	} else if (g_strcmp0 (command, "item-progress") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		if (!pk_package_id_check (sections[1])) {
			g_set_error (error, 1, 0, "invalid package_id");
			return FALSE;
		}
		status_enum = pk_status_enum_from_string (sections[2]);
		if (status_enum == PK_STATUS_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Status enum not recognised, and hence ignored: '%s'", sections[2]);
			return FALSE;
		}
		if (!pk_strtoint (sections[3], &percentage)) {
			g_set_error (error, 1, 0, "invalid item-progress value %s", sections[3]);
			return FALSE;
		}
		if (percentage < 0 || percentage > 100) {
			g_set_error (error, 1, 0, "invalid item-progress value %i", percentage);
			return FALSE;
		}
		pk_backend_job_set_item_progress (job,
						  sections[1],
						  status_enum,
						  percentage);
	} else if (g_strcmp0 (command, "error") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		error_enum = pk_error_enum_from_string (sections[1]);
		if (error_enum == PK_ERROR_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Error enum not recognised, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}
		/* convert back all the ;'s to newlines */
		text = g_strdup (sections[2]);

		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');

		/* convert % else we try to format them */
		g_strdelimit (text, "%", '$');

		pk_backend_job_error_code (job, error_enum, "%s", text);
		g_free (text);
	} else if (g_strcmp0 (command, "requirerestart") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		restart_enum = pk_restart_enum_from_string (sections[1]);
		if (restart_enum == PK_RESTART_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Restart enum not recognised, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}
		if (!pk_package_id_check (sections[2])) {
			g_set_error (error, 1, 0, "invalid package_id");
			return FALSE;
		}
		pk_backend_job_require_restart (job, restart_enum, sections[2]);
	} else if (g_strcmp0 (command, "status") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		status_enum = pk_status_enum_from_string (sections[1]);
		if (status_enum == PK_STATUS_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Status enum not recognised, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}
		pk_backend_job_set_status (job, status_enum);
	} else if (g_strcmp0 (command, "speed") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		if (!pk_strtouint64 (sections[1], &speed)) {
			g_set_error (error, 1, 0,
				     "failed to parse speed: '%s'",
				     sections[1]);
			return FALSE;
		}
		pk_backend_job_set_speed (job, speed);
	} else if (g_strcmp0 (command, "download-size-remaining") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		if (!pk_strtouint64 (sections[1], &download_size_remaining)) {
			g_set_error (error, 1, 0,
				     "failed to parse download_size_remaining: '%s'",
				     sections[1]);
			return FALSE;
		}
		pk_backend_job_set_download_size_remaining (job, download_size_remaining);
	} else if (g_strcmp0 (command, "allow-cancel") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		if (g_strcmp0 (sections[1], "true") == 0) {
			pk_backend_job_set_allow_cancel (job, TRUE);
		} else if (g_strcmp0 (sections[1], "false") == 0) {
			pk_backend_job_set_allow_cancel (job, FALSE);
		} else {
			g_set_error (error, 1, 0, "invalid section '%s'", sections[1]);
			return FALSE;
		}
	} else if (g_strcmp0 (command, "no-percentage-updates") == 0) {
		if (size != 1) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		pk_backend_job_set_percentage (job, PK_BACKEND_PERCENTAGE_INVALID);
	} else if (g_strcmp0 (command, "repo-signature-required") == 0) {

		if (size != 9) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}

		sig_type = pk_sig_type_enum_from_string (sections[8]);
		if (sig_type == PK_SIGTYPE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Sig enum not recognised, and hence ignored: '%s'", sections[8]);
			return FALSE;
		}
		if (pk_strzero (sections[1])) {
			g_set_error (error, 1, 0, "package_id blank, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}
		if (pk_strzero (sections[2])) {
			g_set_error (error, 1, 0, "repository name blank, and hence ignored: '%s'", sections[2]);
			return FALSE;
		}

		/* pass _all_ of the data */
		pk_backend_job_repo_signature_required (job, sections[1],
							  sections[2], sections[3], sections[4],
							  sections[5], sections[6], sections[7], sig_type);
	} else if (g_strcmp0 (command, "eula-required") == 0) {

		if (size != 5) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}

		if (pk_strzero (sections[1])) {
			g_set_error (error, 1, 0, "eula_id blank, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}

		if (pk_strzero (sections[2])) {
			g_set_error (error, 1, 0, "package_id blank, and hence ignored: '%s'", sections[2]);
			return FALSE;
		}

		if (pk_strzero (sections[4])) {
			g_set_error (error, 1, 0, "agreement name blank, and hence ignored: '%s'", sections[4]);
			return FALSE;
		}

		pk_backend_job_eula_required (job, sections[1], sections[2], sections[3], sections[4]);
	} else if (g_strcmp0 (command, "media-change-required") == 0) {

		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}

		media_type_enum = pk_media_type_enum_from_string (sections[1]);
		if (media_type_enum == PK_MEDIA_TYPE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "media type enum not recognised, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}

		pk_backend_job_media_change_required (job, media_type_enum, sections[2], sections[3]);
	} else if (g_strcmp0 (command, "distro-upgrade") == 0) {

		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}

		distro_upgrade_enum = pk_distro_upgrade_enum_from_string (sections[1]);
		if (distro_upgrade_enum == PK_DISTRO_UPGRADE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "distro upgrade enum not recognised, and hence ignored: '%s'", sections[1]);
			return FALSE;
		}
		g_strdelimit (sections[3], PK_UNSAFE_DELIMITERS, ' ');
		if (!g_utf8_validate (sections[3], -1, NULL)) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[3]);
			return FALSE;
		}

		pk_backend_job_distro_upgrade (job, distro_upgrade_enum, sections[2], sections[3]);
	} else if (g_strcmp0 (command, "category") == 0) {

		if (size != 6) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			return FALSE;
		}
		if (g_strcmp0 (sections[1], sections[2]) == 0) {
			g_set_error_literal (error, 1, 0, "cat_id cannot be the same as parent_id");
			return FALSE;
		}
		if (pk_strzero (sections[2])) {
			g_set_error_literal (error, 1, 0, "cat_id cannot not blank");
			return FALSE;
		}
		if (pk_strzero (sections[3])) {
			g_set_error_literal (error, 1, 0, "name cannot not blank");
			return FALSE;
		}
		g_strdelimit (sections[4], PK_UNSAFE_DELIMITERS, ' ');
		if (!g_utf8_validate (sections[4], -1, NULL)) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[4]);
			return FALSE;
		}
		if (pk_strzero (sections[5])) {
			g_set_error_literal (error, 1, 0, "icon cannot not blank");
			return FALSE;
		}
		if (g_str_has_prefix (sections[5], "/")) {
			g_set_error (error, 1, 0, "icon '%s' should be a named icon, not a path", sections[5]);
			return FALSE;
		}
		pk_backend_job_category (job, sections[1], sections[2], sections[3], sections[4], sections[5]);
	} else {
		g_set_error (error, 1, 0, "invalid command '%s'", command);
		return FALSE;
	}
	return TRUE;
}
/**
 * pk_backend_spawn_parse_stdout:
 **/
static gboolean
pk_backend_spawn_parse_stdout (PkBackendSpawn *backend_spawn,
			       PkBackendJob *job,
			       const gchar *line,
			       GError **error)
{
	gchar **sections;
	guint size;
	gchar *command;
	gchar *text;
	gboolean ret = TRUE;
	guint64 speed;
	guint64 download_size_remaining;
	PkInfoEnum info;
	PkRestartEnum restart;
	PkGroupEnum group;
	gulong package_size;
	gint percentage;
	PkErrorEnum error_enum;
	PkStatusEnum status_enum;
	PkMessageEnum message_enum;
	PkRestartEnum restart_enum;
	PkSigTypeEnum sig_type;
	PkUpdateStateEnum update_state_enum;
	PkMediaTypeEnum media_type_enum;
	PkDistroUpgradeEnum distro_upgrade_enum;
	PkBackendSpawnPrivate *priv = backend_spawn->priv;

	g_return_val_if_fail (PK_IS_BACKEND_SPAWN (backend_spawn), FALSE);

	/* check if output line */
	if (line == NULL)
		return FALSE;

	/* split by tab */
	sections = g_strsplit (line, "\t", 0);
	command = sections[0];

	/* get size */
	size = g_strv_length (sections);

	if (g_strcmp0 (command, "package") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		if (pk_package_id_check (sections[2]) == FALSE) {
			g_set_error_literal (error, 1, 0, "invalid package_id");
			ret = FALSE;
			goto out;
		}
		info = pk_info_enum_from_string (sections[1]);
		if (info == PK_INFO_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Info enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		g_strdelimit (sections[3], PK_UNSAFE_DELIMITERS, ' ');
		ret = g_utf8_validate (sections[3], -1, NULL);
		if (!ret) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[3]);
			ret = FALSE;
			goto out;
		}
		pk_backend_job_package (job, info, sections[2], sections[3]);
	} else if (g_strcmp0 (command, "details") == 0) {
		if (size != 7) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		group = pk_group_enum_from_string (sections[3]);

		/* ITS4: ignore, checked for overflow */
		package_size = atol (sections[6]);
		if (package_size > 1073741824) {
			g_set_error_literal (error, 1, 0, "package size cannot be larger than one Gb");
			ret = FALSE;
			goto out;
		}
		g_strdelimit (sections[4], PK_UNSAFE_DELIMITERS, ' ');
		ret = g_utf8_validate (sections[4], -1, NULL);
		if (!ret) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[4]);
			ret = FALSE;
			goto out;
		}
		text = g_strdup (sections[4]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');
		pk_backend_job_details (job, sections[1], sections[2],
					group, text, sections[5], package_size);
		g_free (text);
	} else if (g_strcmp0 (command, "finished") == 0) {
		if (size != 1) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		pk_backend_job_finished (job);
		priv->is_busy = FALSE;

		/* from this point on, we can start the kill timer */
		pk_backend_spawn_start_kill_timer (backend_spawn);

	} else if (g_strcmp0 (command, "files") == 0) {
		gchar **tmp;
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		tmp = g_strsplit (sections[2], ";", -1);
		pk_backend_job_files (job, sections[1], tmp);
		g_strfreev (tmp);
	} else if (g_strcmp0 (command, "repo-detail") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		g_strdelimit (sections[2], PK_UNSAFE_DELIMITERS, ' ');
		ret = g_utf8_validate (sections[2], -1, NULL);
		if (!ret) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[2]);
			ret = FALSE;
			goto out;
		}
		if (g_strcmp0 (sections[3], "true") == 0) {
			pk_backend_job_repo_detail (job, sections[1], sections[2], TRUE);
		} else if (g_strcmp0 (sections[3], "false") == 0) {
			pk_backend_job_repo_detail (job, sections[1], sections[2], FALSE);
		} else {
			g_set_error (error, 1, 0, "invalid qualifier '%s'", sections[3]);
			ret = FALSE;
			goto out;
		}
	} else if (g_strcmp0 (command, "updatedetail") == 0) {
		gchar **updates;
		gchar **obsoletes;
		gchar **vendor_urls;
		gchar **bugzilla_urls;
		gchar **cve_urls;
		if (size != 13) {
			g_set_error (error, 1, 0, "invalid command '%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		restart = pk_restart_enum_from_string (sections[7]);
		if (restart == PK_RESTART_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Restart enum not recognised, and hence ignored: '%s'", sections[7]);
			ret = FALSE;
			goto out;
		}
		g_strdelimit (sections[12], PK_UNSAFE_DELIMITERS, ' ');
		ret = g_utf8_validate (sections[12], -1, NULL);
		if (!ret) {
			g_set_error (error, 1, 0,
				     "text '%s' was not valid UTF8!",
				     sections[12]);
			ret = FALSE;
			goto out;
		}
		update_state_enum = pk_update_state_enum_from_string (sections[10]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (sections[8], ";", '\n');
		g_strdelimit (sections[9], ";", '\n');
		updates = g_strsplit (sections[2], "&", -1);
		obsoletes = g_strsplit (sections[3], "&", -1);
		vendor_urls = g_strsplit (sections[4], ";", -1);
		bugzilla_urls = g_strsplit (sections[5], ";", -1);
		cve_urls = g_strsplit (sections[6], ";", -1);
		pk_backend_job_update_detail (job,
					  sections[1],
					  updates,
					  obsoletes,
					  vendor_urls,
					  bugzilla_urls,
					  cve_urls,
					  restart,
					  sections[8],
					  sections[9],
					  update_state_enum,
					  sections[11],
					  sections[12]);
		g_strfreev (updates);
		g_strfreev (obsoletes);
		g_strfreev (vendor_urls);
		g_strfreev (bugzilla_urls);
		g_strfreev (cve_urls);
	} else if (g_strcmp0 (command, "percentage") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		ret = pk_strtoint (sections[1], &percentage);
		if (!ret) {
			g_set_error (error, 1, 0, "invalid percentage value %s", sections[1]);
			ret = FALSE;
		} else if (percentage < 0 || percentage > 100) {
			g_set_error (error, 1, 0, "invalid percentage value %i", percentage);
			ret = FALSE;
		} else {
			pk_backend_job_set_percentage (job, percentage);
		}
	} else if (g_strcmp0 (command, "item-progress") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		if (!pk_package_id_check (sections[1])) {
			g_set_error (error, 1, 0, "invalid package_id");
			ret = FALSE;
			goto out;
		}
		status_enum = pk_status_enum_from_string (sections[2]);
		if (status_enum == PK_STATUS_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Status enum not recognised, and hence ignored: '%s'", sections[2]);
			ret = FALSE;
			goto out;
		}
		ret = pk_strtoint (sections[3], &percentage);
		if (!ret) {
			g_set_error (error, 1, 0, "invalid item-progress value %s", sections[3]);
			ret = FALSE;
			goto out;
		}
		if (percentage < 0 || percentage > 100) {
			g_set_error (error, 1, 0, "invalid item-progress value %i", percentage);
			ret = FALSE;
			goto out;
		}
		pk_backend_job_set_item_progress (job,
						  sections[1],
						  status_enum,
						  percentage);
	} else if (g_strcmp0 (command, "error") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		error_enum = pk_error_enum_from_string (sections[1]);
		if (error_enum == PK_ERROR_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Error enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		/* convert back all the ;'s to newlines */
		text = g_strdup (sections[2]);

		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');

		/* convert % else we try to format them */
		g_strdelimit (text, "%", '$');

		pk_backend_job_error_code (job, error_enum, "%s", text);
		g_free (text);
	} else if (g_strcmp0 (command, "requirerestart") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		restart_enum = pk_restart_enum_from_string (sections[1]);
		if (restart_enum == PK_RESTART_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Restart enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		if (!pk_package_id_check (sections[2])) {
			g_set_error (error, 1, 0, "invalid package_id");
			ret = FALSE;
			goto out;
		}
		pk_backend_job_require_restart (job, restart_enum, sections[2]);
	} else if (g_strcmp0 (command, "message") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
		message_enum = pk_message_enum_from_string (sections[1]);
G_GNUC_END_IGNORE_DEPRECATIONS
		if (message_enum == PK_MESSAGE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Message enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		text = g_strdup (sections[2]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
		pk_backend_job_message (job, message_enum, "%s", text);
G_GNUC_END_IGNORE_DEPRECATIONS
		g_free (text);
	} else if (g_strcmp0 (command, "status") == 0) {
Beispiel #3
0
/**
 * pk_backend_spawn_parse_stdout:
 **/
static gboolean
pk_backend_spawn_parse_stdout (PkBackendSpawn *backend_spawn, const gchar *line, GError **error)
{
	gchar **sections;
	guint size;
	gchar *command;
	gchar *text;
	gboolean ret = TRUE;
	guint64 speed;
	PkInfoEnum info;
	PkRestartEnum restart;
	PkGroupEnum group;
	gulong package_size;
	gint percentage;
	PkErrorEnum error_enum;
	PkStatusEnum status_enum;
	PkMessageEnum message_enum;
	PkRestartEnum restart_enum;
	PkSigTypeEnum sig_type;
	PkUpdateStateEnum update_state_enum;
	PkMediaTypeEnum media_type_enum;
	PkDistroUpgradeEnum distro_upgrade_enum;
	PkBackendSpawnPrivate *priv = backend_spawn->priv;

	g_return_val_if_fail (PK_IS_BACKEND_SPAWN (backend_spawn), FALSE);

	/* check if output line */
	if (line == NULL)
		return FALSE;

	/* split by tab */
	sections = g_strsplit (line, "\t", 0);
	command = sections[0];

	/* get size */
	size = g_strv_length (sections);

	if (g_strcmp0 (command, "package") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		if (pk_package_id_check (sections[2]) == FALSE) {
			g_set_error_literal (error, 1, 0, "invalid package_id");
			ret = FALSE;
			goto out;
		}
		info = pk_info_enum_from_string (sections[1]);
		if (info == PK_INFO_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Info enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		pk_backend_package (priv->backend, info, sections[2], sections[3]);
	} else if (g_strcmp0 (command, "details") == 0) {
		if (size != 7) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		group = pk_group_enum_from_string (sections[3]);

		/* ITS4: ignore, checked for overflow */
		package_size = atol (sections[6]);
		if (package_size > 1073741824) {
			g_set_error_literal (error, 1, 0, "package size cannot be larger than one Gb");
			ret = FALSE;
			goto out;
		}
		text = g_strdup (sections[4]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');
		pk_backend_details (priv->backend, sections[1], sections[2],
					group, text, sections[5], package_size);
		g_free (text);
	} else if (g_strcmp0 (command, "finished") == 0) {
		if (size != 1) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		pk_backend_finished (priv->backend);

		/* from this point on, we can start the kill timer */
		pk_backend_spawn_start_kill_timer (backend_spawn);

	} else if (g_strcmp0 (command, "files") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		pk_backend_files (priv->backend, sections[1], sections[2]);
	} else if (g_strcmp0 (command, "repo-detail") == 0) {
		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		if (g_strcmp0 (sections[3], "true") == 0) {
			pk_backend_repo_detail (priv->backend, sections[1], sections[2], TRUE);
		} else if (g_strcmp0 (sections[3], "false") == 0) {
			pk_backend_repo_detail (priv->backend, sections[1], sections[2], FALSE);
		} else {
			g_set_error (error, 1, 0, "invalid qualifier '%s'", sections[3]);
			ret = FALSE;
			goto out;
		}
	} else if (g_strcmp0 (command, "updatedetail") == 0) {
		if (size != 13) {
			g_set_error (error, 1, 0, "invalid command '%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		restart = pk_restart_enum_from_string (sections[7]);
		if (restart == PK_RESTART_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Restart enum not recognised, and hence ignored: '%s'", sections[7]);
			ret = FALSE;
			goto out;
		}
		update_state_enum = pk_update_state_enum_from_string (sections[10]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (sections[8], ";", '\n');
		g_strdelimit (sections[9], ";", '\n');
		pk_backend_update_detail (priv->backend, sections[1],
					  sections[2], sections[3], sections[4],
					  sections[5], sections[6], restart, sections[8],
					  sections[9], update_state_enum,
					  sections[11], sections[12]);
	} else if (g_strcmp0 (command, "percentage") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		ret = pk_strtoint (sections[1], &percentage);
		if (!ret) {
			g_set_error (error, 1, 0, "invalid percentage value %s", sections[1]);
			ret = FALSE;
		} else if (percentage < 0 || percentage > 100) {
			g_set_error (error, 1, 0, "invalid percentage value %i", percentage);
			ret = FALSE;
		} else {
			pk_backend_set_percentage (priv->backend, percentage);
		}
	} else if (g_strcmp0 (command, "subpercentage") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		ret = pk_strtoint (sections[1], &percentage);
		if (!ret) {
			g_set_error (error, 1, 0, "invalid subpercentage value %s", sections[1]);
			ret = FALSE;
		} else if (percentage < 0 || percentage > 100) {
			g_set_error (error, 1, 0, "invalid subpercentage value %i", percentage);
			ret = FALSE;
		} else {
			pk_backend_set_sub_percentage (priv->backend, percentage);
		}
	} else if (g_strcmp0 (command, "item-percentage") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		if (!pk_package_id_check (sections[1])) {
			g_set_error (error, 1, 0, "invalid package_id");
			ret = FALSE;
			goto out;
		}
		ret = pk_strtoint (sections[2], &percentage);
		if (!ret) {
			g_set_error (error, 1, 0, "invalid item-percentage value %s", sections[1]);
			ret = FALSE;
		} else if (percentage < 0 || percentage > 100) {
			g_set_error (error, 1, 0, "invalid item-percentage value %i", percentage);
			ret = FALSE;
		} else {
			pk_backend_set_item_progress (priv->backend,
							sections[1],
							percentage);
		}
	} else if (g_strcmp0 (command, "error") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		error_enum = pk_error_enum_from_string (sections[1]);
		if (error_enum == PK_ERROR_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Error enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		/* convert back all the ;'s to newlines */
		text = g_strdup (sections[2]);

		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');

		/* convert % else we try to format them */
		g_strdelimit (text, "%", '$');

		pk_backend_error_code (priv->backend, error_enum, text);
		g_free (text);
	} else if (g_strcmp0 (command, "requirerestart") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		restart_enum = pk_restart_enum_from_string (sections[1]);
		if (restart_enum == PK_RESTART_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Restart enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		if (!pk_package_id_check (sections[2])) {
			g_set_error (error, 1, 0, "invalid package_id");
			ret = FALSE;
			goto out;
		}
		pk_backend_require_restart (priv->backend, restart_enum, sections[2]);
	} else if (g_strcmp0 (command, "message") == 0) {
		if (size != 3) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		message_enum = pk_message_enum_from_string (sections[1]);
		if (message_enum == PK_MESSAGE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Message enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		text = g_strdup (sections[2]);
		/* convert ; to \n as we can't emit them on stdout */
		g_strdelimit (text, ";", '\n');
		pk_backend_message (priv->backend, message_enum, text);
		g_free (text);
	} else if (g_strcmp0 (command, "change-transaction-data") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		pk_backend_set_transaction_data (priv->backend, sections[1]);
	} else if (g_strcmp0 (command, "status") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		status_enum = pk_status_enum_from_string (sections[1]);
		if (status_enum == PK_STATUS_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Status enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		pk_backend_set_status (priv->backend, status_enum);
	} else if (g_strcmp0 (command, "speed") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		ret = pk_strtouint64 (sections[1], &speed);
		if (!ret) {
			g_set_error (error, 1, 0,
				     "failed to parse speed: '%s'",
				     sections[1]);
			ret = FALSE;
			goto out;
		}
		pk_backend_set_speed (priv->backend, speed);
	} else if (g_strcmp0 (command, "allow-cancel") == 0) {
		if (size != 2) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		if (g_strcmp0 (sections[1], "true") == 0) {
			pk_backend_set_allow_cancel (priv->backend, TRUE);
		} else if (g_strcmp0 (sections[1], "false") == 0) {
			pk_backend_set_allow_cancel (priv->backend, FALSE);
		} else {
			g_set_error (error, 1, 0, "invalid section '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
	} else if (g_strcmp0 (command, "no-percentage-updates") == 0) {
		if (size != 1) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		pk_backend_set_percentage (priv->backend, PK_BACKEND_PERCENTAGE_INVALID);
	} else if (g_strcmp0 (command, "repo-signature-required") == 0) {

		if (size != 9) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}

		sig_type = pk_sig_type_enum_from_string (sections[8]);
		if (sig_type == PK_SIGTYPE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "Sig enum not recognised, and hence ignored: '%s'", sections[8]);
			ret = FALSE;
			goto out;
		}
		if (pk_strzero (sections[1])) {
			g_set_error (error, 1, 0, "package_id blank, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}
		if (pk_strzero (sections[2])) {
			g_set_error (error, 1, 0, "repository name blank, and hence ignored: '%s'", sections[2]);
			ret = FALSE;
			goto out;
		}

		/* pass _all_ of the data */
		ret = pk_backend_repo_signature_required (priv->backend, sections[1],
							  sections[2], sections[3], sections[4],
							  sections[5], sections[6], sections[7], sig_type);
		goto out;

	} else if (g_strcmp0 (command, "eula-required") == 0) {

		if (size != 5) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}

		if (pk_strzero (sections[1])) {
			g_set_error (error, 1, 0, "eula_id blank, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}

		if (pk_strzero (sections[2])) {
			g_set_error (error, 1, 0, "package_id blank, and hence ignored: '%s'", sections[2]);
			ret = FALSE;
			goto out;
		}

		if (pk_strzero (sections[4])) {
			g_set_error (error, 1, 0, "agreement name blank, and hence ignored: '%s'", sections[4]);
			ret = FALSE;
			goto out;
		}

		ret = pk_backend_eula_required (priv->backend, sections[1], sections[2], sections[3], sections[4]);
		goto out;

	} else if (g_strcmp0 (command, "media-change-required") == 0) {

		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}

		media_type_enum = pk_media_type_enum_from_string (sections[1]);
		if (media_type_enum == PK_MEDIA_TYPE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "media type enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}

		ret = pk_backend_media_change_required (priv->backend, media_type_enum, sections[2], sections[3]);
		goto out;
	} else if (g_strcmp0 (command, "distro-upgrade") == 0) {

		if (size != 4) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}

		distro_upgrade_enum = pk_distro_upgrade_enum_from_string (sections[1]);
		if (distro_upgrade_enum == PK_DISTRO_UPGRADE_ENUM_UNKNOWN) {
			g_set_error (error, 1, 0, "distro upgrade enum not recognised, and hence ignored: '%s'", sections[1]);
			ret = FALSE;
			goto out;
		}

		ret = pk_backend_distro_upgrade (priv->backend, distro_upgrade_enum, sections[2], sections[3]);
		goto out;
	} else if (g_strcmp0 (command, "category") == 0) {

		if (size != 6) {
			g_set_error (error, 1, 0, "invalid command'%s', size %i", command, size);
			ret = FALSE;
			goto out;
		}
		if (g_strcmp0 (sections[1], sections[2]) == 0) {
			g_set_error_literal (error, 1, 0, "cat_id cannot be the same as parent_id");
			ret = FALSE;
			goto out;
		}
		if (pk_strzero (sections[2])) {
			g_set_error_literal (error, 1, 0, "cat_id cannot not blank");
			ret = FALSE;
			goto out;
		}
		if (pk_strzero (sections[3])) {
			g_set_error_literal (error, 1, 0, "name cannot not blank");
			ret = FALSE;
			goto out;
		}
		if (pk_strzero (sections[5])) {
			g_set_error_literal (error, 1, 0, "icon cannot not blank");
			ret = FALSE;
			goto out;
		}
		if (g_str_has_prefix (sections[5], "/")) {
			g_set_error (error, 1, 0, "icon '%s' should be a named icon, not a path", sections[5]);
			ret = FALSE;
			goto out;
		}
		ret = pk_backend_category (priv->backend, sections[1], sections[2], sections[3], sections[4], sections[5]);
		goto out;
	} else {
		ret = FALSE;
		g_set_error (error, 1, 0, "invalid command '%s'", command);
	}
out:
	g_strfreev (sections);
	return ret;
}
Beispiel #4
0
/**
 * pk_offline_get_results:
 * @error: A #GError or %NULL
 *
 * Gets the last result of the offline transaction.
 *
 * Return value: (transfer full): A #PkResults, or %NULL
 *
 * Since: 0.9.6
 **/
PkResults *
pk_offline_get_results (GError **error)
{
	gboolean ret;
	gboolean success;
	guint i;
	g_autoptr(GError) error_local = NULL;
	g_autofree gchar *data = NULL;
	g_autoptr(GKeyFile) file = NULL;
	g_autoptr(PkError) pk_error = NULL;
	g_autoptr(PkResults) results = NULL;
	g_auto(GStrv) package_ids = NULL;

	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* does not exist */
	if (!g_file_test (PK_OFFLINE_RESULTS_FILENAME, G_FILE_TEST_EXISTS)) {
		g_set_error_literal (error,
				     PK_OFFLINE_ERROR,
				     PK_OFFLINE_ERROR_NO_DATA,
				     "no update results available");
		return NULL;
	}

	/* load data */
	file = g_key_file_new ();
	ret = g_key_file_load_from_file (file,
					 PK_OFFLINE_RESULTS_FILENAME,
					 G_KEY_FILE_NONE,
					 &error_local);
	if (!ret) {
		g_set_error (error,
			     PK_OFFLINE_ERROR,
			     PK_OFFLINE_ERROR_FAILED,
			     "results file invalid: %s",
			     error_local->message);
		return NULL;
	}

	/* add error */
	results = pk_results_new ();
	success = g_key_file_get_boolean (file, PK_OFFLINE_RESULTS_GROUP,
					  "Success", NULL);
	if (!success) {
		g_autofree gchar *details = NULL;
		g_autofree gchar *enum_str = NULL;
		pk_error = pk_error_new ();
		enum_str = g_key_file_get_string (file,
						  PK_OFFLINE_RESULTS_GROUP,
						  "ErrorCode",
						  NULL);
		details = g_key_file_get_string (file,
						 PK_OFFLINE_RESULTS_GROUP,
						 "ErrorDetails",
						 NULL);
		g_object_set (pk_error,
			      "code", pk_error_enum_from_string (enum_str),
			      "details", details,
			      NULL);
		pk_results_set_error_code (results, pk_error);
		pk_results_set_exit_code (results, PK_EXIT_ENUM_FAILED);
	} else {
		pk_results_set_exit_code (results, PK_EXIT_ENUM_SUCCESS);
	}

	/* add packages */
	data = g_key_file_get_string (file, PK_OFFLINE_RESULTS_GROUP,
				      "Packages", NULL);
	if (data != NULL) {
		package_ids = g_strsplit (data, ",", -1);
		for (i = 0; package_ids[i] != NULL; i++) {
			g_autoptr(PkPackage) pkg = NULL;
			pkg = pk_package_new ();
			pk_package_set_info (pkg, PK_INFO_ENUM_UPDATING);
			if (!pk_package_set_id (pkg, package_ids[i], error))
				return NULL;
			pk_results_add_package (results, pkg);
		}
	}
	return g_object_ref (results);
}
gboolean
gs_plugin_add_updates_historical (GsPlugin *plugin,
				  GsAppList *list,
				  GCancellable *cancellable,
				  GError **error)
{
	gboolean ret;
	guint64 mtime;
	guint i;
	g_auto(GStrv) package_ids = NULL;
	g_autofree gchar *packages = NULL;
	g_autoptr(GFile) file = NULL;
	g_autoptr(GFileInfo) info = NULL;
	g_autoptr(GKeyFile) key_file = NULL;

	/* was any offline update attempted */
	if (!g_file_test (PK_OFFLINE_UPDATE_RESULTS_FILENAME, G_FILE_TEST_EXISTS))
		return TRUE;

	/* get the mtime of the results */
	file = g_file_new_for_path (PK_OFFLINE_UPDATE_RESULTS_FILENAME);
	info = g_file_query_info (file,
				  G_FILE_ATTRIBUTE_TIME_MODIFIED,
				  G_FILE_QUERY_INFO_NONE,
				  cancellable,
				  error);
	if (info == NULL)
		return FALSE;
	mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);

	/* open the file */
	key_file = g_key_file_new ();
	ret = g_key_file_load_from_file (key_file,
					 PK_OFFLINE_UPDATE_RESULTS_FILENAME,
					 G_KEY_FILE_NONE,
					 error);
	if (!ret)
		return FALSE;

	/* only return results if successful */
	ret = g_key_file_get_boolean (key_file,
				      PK_OFFLINE_UPDATE_RESULTS_GROUP,
				      "Success",
				      NULL);
	if (!ret) {
		g_autofree gchar *code = NULL;
		g_autofree gchar *details = NULL;
		code = g_key_file_get_string (key_file,
					      PK_OFFLINE_UPDATE_RESULTS_GROUP,
					      "ErrorCode",
					      error);
		if (code == NULL)
			return FALSE;
		details = g_key_file_get_string (key_file,
						 PK_OFFLINE_UPDATE_RESULTS_GROUP,
						 "ErrorDetails",
						 error);
		if (details == NULL)
			return FALSE;
		return gs_plugin_packagekit_convert_error (error,
							   pk_error_enum_from_string (code),
							   details);
	}

	/* get list of package-ids */
	packages = g_key_file_get_string (key_file,
					  PK_OFFLINE_UPDATE_RESULTS_GROUP,
					  "Packages",
					  NULL);
	if (packages == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "No 'Packages' in %s",
			     PK_OFFLINE_UPDATE_RESULTS_FILENAME);
		return FALSE;
	}
	package_ids = g_strsplit (packages, ",", -1);
	for (i = 0; package_ids[i] != NULL; i++) {
		g_autoptr(GsApp) app = NULL;
		g_auto(GStrv) split = NULL;
		app = gs_app_new (NULL);
		split = g_strsplit (package_ids[i], ";", 4);
		gs_app_add_source (app, split[0]);
		gs_app_set_update_version (app, split[1]);
		gs_app_set_management_plugin (app, "packagekit");
		gs_app_add_source_id (app, package_ids[i]);
		gs_app_set_state (app, AS_APP_STATE_UPDATABLE);
		gs_app_set_kind (app, AS_APP_KIND_GENERIC);
		gs_app_set_install_date (app, mtime);
		gs_app_set_metadata (app, "GnomeSoftware::Creator",
				     gs_plugin_get_name (plugin));
		gs_app_list_add (list, app);
	}
	return TRUE;
}