static gboolean
asb_plugin_process_filename (AsbPlugin *plugin,
			     AsbPackage *pkg,
			     const gchar *filename,
			     GList **apps,
			     GError **error)
{
	AsProblemKind problem_kind;
	AsProblem *problem;
	GPtrArray *icons;
	const gchar *tmp;
	guint i;
	g_autoptr(AsbApp) app = NULL;
	g_autoptr(GPtrArray) problems = NULL;

	app = asb_app_new (NULL, NULL);
	if (!as_app_parse_file (AS_APP (app), filename,
				AS_APP_PARSE_FLAG_USE_HEURISTICS,
				error))
		return FALSE;
	if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_UNKNOWN) {
		g_set_error (error,
			     ASB_PLUGIN_ERROR,
			     ASB_PLUGIN_ERROR_FAILED,
			     "%s has no recognised type",
			     as_app_get_id (AS_APP (app)));
		return FALSE;
	}

	/* validate */
	problems = as_app_validate (AS_APP (app),
				    AS_APP_VALIDATE_FLAG_NO_NETWORK |
				    AS_APP_VALIDATE_FLAG_RELAX,
				    error);
	if (problems == NULL)
		return FALSE;
	asb_app_set_package (app, pkg);
	for (i = 0; i < problems->len; i++) {
		problem = g_ptr_array_index (problems, i);
		problem_kind = as_problem_get_kind (problem);
		asb_package_log (asb_app_get_package (app),
				 ASB_PACKAGE_LOG_LEVEL_WARNING,
				 "AppData problem: %s : %s",
				 as_problem_kind_to_string (problem_kind),
				 as_problem_get_message (problem));
	}

	/* nuke things that do not belong */
	icons = as_app_get_icons (AS_APP (app));
	if (icons->len > 0)
		g_ptr_array_set_size (icons, 0);

	/* fix up the project license */
	tmp = as_app_get_project_license (AS_APP (app));
	if (tmp != NULL && !as_utils_is_spdx_license (tmp)) {
		g_autofree gchar *license_spdx = NULL;
		license_spdx = as_utils_license_to_spdx (tmp);
		if (as_utils_is_spdx_license (license_spdx)) {
			asb_package_log (asb_app_get_package (app),
					 ASB_PACKAGE_LOG_LEVEL_WARNING,
					 "project license fixup: %s -> %s",
					 tmp, license_spdx);
			as_app_set_project_license (AS_APP (app), license_spdx);
		} else {
			asb_package_log (asb_app_get_package (app),
					 ASB_PACKAGE_LOG_LEVEL_WARNING,
					 "project license is invalid: %s", tmp);
			as_app_set_project_license (AS_APP (app), NULL);
		}
	}

	/* check license */
	tmp = as_app_get_metadata_license (AS_APP (app));
	if (tmp == NULL) {
		g_set_error (error,
			     ASB_PLUGIN_ERROR,
			     ASB_PLUGIN_ERROR_FAILED,
			     "AppData %s has no licence",
			     filename);
		return FALSE;
	}
	if (!as_utils_is_spdx_license (tmp)) {
		g_set_error (error,
			     ASB_PLUGIN_ERROR,
			     ASB_PLUGIN_ERROR_FAILED,
			     "AppData %s license '%s' invalid",
			     filename, tmp);
		return FALSE;
	}

	/* log updateinfo */
	tmp = as_app_get_update_contact (AS_APP (app));
	if (tmp != NULL) {
		asb_package_log (asb_app_get_package (app),
				 ASB_PACKAGE_LOG_LEVEL_INFO,
				 "Upstream contact <%s>", tmp);
	}

	/* add icon for firmware */
	if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_FIRMWARE) {
		g_autoptr(AsIcon) icon = NULL;
		icon = as_icon_new ();
		as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
		as_icon_set_name (icon, "application-x-executable");
		as_app_add_icon (AS_APP (app), icon);
	}

	/* fix up input methods */
	if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_INPUT_METHOD) {
		g_autoptr(AsIcon) icon = NULL;
		icon = as_icon_new ();
		as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
		as_icon_set_name (icon, "system-run-symbolic");
		as_app_add_icon (AS_APP (app), icon);
		as_app_add_category (AS_APP (app), "Addons");
		as_app_add_category (AS_APP (app), "InputSources");
	}

	/* fix up codecs */
	if (as_app_get_kind (AS_APP (app)) == AS_APP_KIND_CODEC) {
		g_autoptr(AsIcon) icon = NULL;
		icon = as_icon_new ();
		as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
		as_icon_set_name (icon, "application-x-executable");
		as_app_add_icon (AS_APP (app), icon);
		as_app_add_category (AS_APP (app), "Addons");
		as_app_add_category (AS_APP (app), "Codecs");
	}

	/* success */
	asb_app_set_hidpi_enabled (app, asb_context_get_flag (plugin->ctx,
							      ASB_CONTEXT_FLAG_HIDPI_ICONS));
	asb_plugin_add_app (apps, AS_APP (app));
	return TRUE;
}
/**
 * gs_plugin_filename_to_app:
 */
gboolean
gs_plugin_filename_to_app (GsPlugin *plugin,
			   GList **list,
			   const gchar *filename,
			   GCancellable *cancellable,
			   GError **error)
{
	const gchar *package_id;
	gboolean supported;
	PkDetails *item;
	ProgressData data;
	g_autoptr (PkResults) results = NULL;
	g_autofree gchar *basename = NULL;
	g_autofree gchar *license_spdx = NULL;
	g_auto(GStrv) files = NULL;
	g_auto(GStrv) split = NULL;
	g_autoptr(GPtrArray) array = NULL;
	g_autoptr(GsApp) app = NULL;

	/* does this match any of the mimetypes we support */
	if (!gs_plugin_packagekit_refresh_content_type_matches (filename,
								&supported,
								cancellable,
								error))
		return FALSE;
	if (!supported)
		return TRUE;

	data.plugin = plugin;
	data.ptask = NULL;

	/* get details */
	files = g_strsplit (filename, "\t", -1);
	pk_client_set_cache_age (PK_CLIENT (plugin->priv->task), G_MAXUINT);
	results = pk_client_get_details_local (PK_CLIENT (plugin->priv->task),
					       files,
					       cancellable,
					       gs_plugin_packagekit_progress_cb, &data,
					       error);
	if (results == NULL)
		return FALSE;

	/* get results */
	array = pk_results_get_details_array (results);
	if (array->len == 0) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_FAILED,
			     "no details for %s", filename);
		return FALSE;
	}
	if (array->len > 1) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_FAILED,
			     "too many details [%i] for %s",
			     array->len, filename);
		return FALSE;
	}

	/* create application */
	item = g_ptr_array_index (array, 0);
	app = gs_app_new (NULL);
	package_id = pk_details_get_package_id (item);
	split = pk_package_id_split (package_id);
	basename = g_path_get_basename (filename);
	gs_app_set_management_plugin (app, "PackageKit");
	gs_app_set_kind (app, GS_APP_KIND_PACKAGE);
	gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL);
	if (pk_details_get_summary (item))
		gs_app_set_name (app, GS_APP_QUALITY_LOWEST,
				 pk_details_get_summary (item));
	else
		gs_app_set_name (app, GS_APP_QUALITY_LOWEST, split[PK_PACKAGE_ID_NAME]);
	gs_app_set_version (app, split[PK_PACKAGE_ID_VERSION]);
	gs_app_set_metadata (app, "PackageKit::local-filename", filename);
	gs_app_set_origin (app, basename);
	gs_app_add_source (app, split[PK_PACKAGE_ID_NAME]);
	gs_app_add_source_id (app, package_id);
	gs_plugin_packagekit_refresh_set_text (app,
					       pk_details_get_description (item));
	gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, pk_details_get_url (item));
	gs_app_set_size (app, pk_details_get_size (item));
	license_spdx = as_utils_license_to_spdx (pk_details_get_license (item));
	gs_app_set_licence (app, license_spdx, GS_APP_QUALITY_LOWEST);

	/* look for a desktop file so we can use a valid application id */
	if (!gs_plugin_packagekit_refresh_guess_app_id (plugin,
							app,
							filename,
							cancellable,
							error))
		return FALSE;

	gs_plugin_add_app (list, app);
	return TRUE;
}
/**
 * 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;
}