コード例 #1
0
ファイル: gs-editor.c プロジェクト: GNOME/gnome-software
static void
gs_editor_refine_app_pixbuf (GsApp *app)
{
	GPtrArray *icons;
	if (gs_app_get_pixbuf (app) != NULL)
		return;
	icons = gs_app_get_icons (app);
	for (guint i = 0; i < icons->len; i++) {
		AsIcon *ic = g_ptr_array_index (icons, i);
		g_autoptr(GError) error = NULL;
		if (as_icon_get_kind (ic) == AS_ICON_KIND_STOCK) {

			g_autoptr(GdkPixbuf) pb = NULL;
			pb = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
						       as_icon_get_name (ic),
						       64,
						       GTK_ICON_LOOKUP_FORCE_SIZE,
						       &error);
			if (pb == NULL) {
				g_warning ("failed to load icon: %s", error->message);
				continue;
			}
			gs_app_set_pixbuf (app, pb);
		} else {
			if (!as_icon_load (ic, AS_ICON_LOAD_FLAG_SEARCH_SIZE, &error)) {
				g_warning ("failed to load icon: %s", error->message);
				continue;
			}
			gs_app_set_pixbuf (app, as_icon_get_pixbuf (ic));
		}
		break;
	}
}
コード例 #2
0
ファイル: as-compose.c プロジェクト: AOSC-Dev/appstream-glib
static AsApp *
load_desktop (const gchar *prefix,
	      const gchar *icons_dir,
	      guint        min_icon_size,
	      const gchar *app_name,
	      const gchar *appdata_id,
	      GError **error)
{
	AsIcon *icon;
	g_autofree gchar *desktop_basename = NULL;
	g_autofree gchar *desktop_path = NULL;
	g_autoptr(AsApp) app = NULL;

	if (appdata_id != NULL)
		desktop_basename = g_strdup (appdata_id);
	else
		desktop_basename = g_strconcat (app_name, ".desktop", NULL);
	desktop_path = g_build_filename (prefix, "share/applications", desktop_basename, NULL);

	app = as_app_new ();
	if (!as_app_parse_file (app, desktop_path,
				AS_APP_PARSE_FLAG_USE_HEURISTICS |
				AS_APP_PARSE_FLAG_ALLOW_VETO,
				error))
		return NULL;
	if (as_app_get_kind (app) == AS_APP_KIND_UNKNOWN) {
		g_set_error (error,
			     AS_APP_ERROR,
			     AS_APP_ERROR_FAILED,
			     "%s has no recognised type",
			     as_app_get_id (AS_APP (app)));
		return NULL;
	}

	icon = as_app_get_icon_default (AS_APP (app));
	if (icon != NULL) {
		g_autofree gchar *key = NULL;
		key = g_strdup (as_icon_get_name (icon));
		if (as_icon_get_kind (icon) == AS_ICON_KIND_STOCK) {
			as_compose_app_log (app,
					    "using stock icon %s", key);
		} else {
			g_autoptr(GError) error_local = NULL;
			gboolean ret;

			g_ptr_array_set_size (as_app_get_icons (AS_APP (app)), 0);
			ret = add_icons (app,
					 icons_dir,
					 min_icon_size,
					 prefix,
					 key,
					 error);
			if (!ret)
				return NULL;
		}
	}

	return g_steal_pointer (&app);
}
コード例 #3
0
static gboolean
asb_plugin_desktop_refine (AsbPlugin *plugin,
			   AsbPackage *pkg,
			   const gchar *filename,
			   AsbApp *app,
			   const gchar *tmpdir,
			   GError **error)
{
	AsIcon *icon;
	AsAppParseFlags parse_flags = AS_APP_PARSE_FLAG_USE_HEURISTICS |
				      AS_APP_PARSE_FLAG_ALLOW_VETO;
	gboolean ret;
	g_autoptr(AsApp) desktop_app = NULL;
	g_autoptr(GdkPixbuf) pixbuf = NULL;

	/* use GenericName fallback */
	if (asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_USE_FALLBACKS))
		parse_flags |= AS_APP_PARSE_FLAG_USE_FALLBACKS;

	/* create app */
	desktop_app = as_app_new ();
	if (!as_app_parse_file (desktop_app, filename, parse_flags, error))
		return FALSE;

	/* copy all metadata */
	as_app_subsume_full (AS_APP (app), desktop_app, AS_APP_SUBSUME_FLAG_NO_OVERWRITE);

	/* is the icon a stock-icon-name? */
	icon = as_app_get_icon_default (AS_APP (app));
	if (icon != NULL) {
		g_autofree gchar *key = NULL;
		key = g_strdup (as_icon_get_name (icon));
		if (as_icon_get_kind (icon) == AS_ICON_KIND_STOCK) {
			asb_package_log (pkg,
					 ASB_PACKAGE_LOG_LEVEL_DEBUG,
					 "using stock icon %s", key);
		} else {
			g_autoptr(GError) error_local = NULL;
			g_ptr_array_set_size (as_app_get_icons (AS_APP (app)), 0);
			ret = asb_plugin_desktop_add_icons (plugin,
							    app,
							    tmpdir,
							    key,
							    &error_local);
			if (!ret) {
				as_app_add_veto (AS_APP (app), "%s",
						 error_local->message);
			}
		}
	}

	return TRUE;
}
コード例 #4
0
/**
 * gs_refine_item_pixbuf:
 */
static void
gs_refine_item_pixbuf (GsPlugin *plugin, GsApp *app, AsApp *item)
{
	AsIcon *icon;
	gboolean ret;
	g_autoptr(GError) error = NULL;
	g_autofree gchar *fn = NULL;
	g_autofree gchar *cachedir = NULL;

	icon = as_app_get_icon_default (item);
	switch (as_icon_get_kind (icon)) {
	case AS_ICON_KIND_REMOTE:
		gs_app_set_icon (app, icon);
		if (as_icon_get_filename (icon) == NULL) {
			cachedir = gs_utils_get_cachedir ("icons", NULL);
			fn = g_build_filename (cachedir, as_icon_get_name (icon), NULL);
			as_icon_set_filename (icon, fn);
			as_icon_set_prefix (icon, cachedir);
		}
		if (g_file_test (fn, G_FILE_TEST_EXISTS)) {
			as_icon_set_kind (icon, AS_ICON_KIND_LOCAL);
			ret = gs_app_load_icon (app, plugin->scale, &error);
			if (!ret) {
				g_warning ("failed to load icon %s: %s",
					   as_icon_get_name (icon),
					   error->message);
				return;
			}
		}
		break;
	case AS_ICON_KIND_STOCK:
	case AS_ICON_KIND_LOCAL:
		gs_app_set_icon (app, icon);

		/* does not exist, so try to find using the icon theme */
		if (as_icon_get_kind (icon) == AS_ICON_KIND_LOCAL &&
		    as_icon_get_filename (icon) == NULL)
			as_icon_set_kind (icon, AS_ICON_KIND_STOCK);

		/* load */
		ret = gs_app_load_icon (app, plugin->scale, &error);
		if (!ret) {
			g_warning ("failed to load %s icon %s: %s",
				   as_icon_kind_to_string (as_icon_get_kind (icon)),
				   as_icon_get_name (icon),
				   error->message);
				return;
		}
		break;
	case AS_ICON_KIND_CACHED:
		if (plugin->scale == 2)
			icon = as_app_get_icon_for_size (item, 128, 128);
		if (icon == NULL)
			icon = as_app_get_icon_for_size (item, 64, 64);
		if (icon == NULL) {
			g_warning ("failed to find cached icon %s",
				   as_icon_get_name (icon));
			return;
		}
		if (!as_icon_load (icon, AS_ICON_LOAD_FLAG_SEARCH_SIZE, &error)) {
			g_warning ("failed to load cached icon %s: %s",
				   as_icon_get_name (icon), error->message);
				return;
		}
		gs_app_set_pixbuf (app, as_icon_get_pixbuf (icon));
		break;
	default:
		g_warning ("icon kind unknown for %s", as_app_get_id (item));
		break;
	}
}
コード例 #5
0
static void
as_app_validate_icons (AsApp *app, AsAppValidateHelper *helper)
{
	AsIcon *icon;
	AsIconKind icon_kind;
	const gchar *icon_name;

	/* just check the default icon */
	icon = as_app_get_icon_default (app);
	if (icon == NULL) {
		AsFormat *fmt = as_app_get_format_default (app);
		if (fmt != NULL &&
		    as_format_get_kind (fmt) == AS_FORMAT_KIND_APPSTREAM &&
		    as_app_get_kind (app) == AS_APP_KIND_DESKTOP) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "desktop application has no icon");
		}
		return;
	}

	/* check the content is correct */
	icon_kind = as_icon_get_kind (icon);
	switch (icon_kind) {
	case AS_ICON_KIND_STOCK:
		icon_name = as_icon_get_name (icon);
		if (!as_utils_is_stock_icon_name (icon_name)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "stock icon is not valid [%s]",
					     icon_name);
		}
		break;
	case AS_ICON_KIND_LOCAL:
		icon_name = as_icon_get_filename (icon);
		if (icon_name == NULL ||
		    !g_str_has_prefix (icon_name, "/")) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "local icon is not a filename [%s]",
					     icon_name);
		}
		break;
	case AS_ICON_KIND_CACHED:
		icon_name = as_icon_get_name (icon);
		if (icon_name == NULL ||
		    g_str_has_prefix (icon_name, "/")) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "cached icon is a filename [%s]",
					     icon_name);
		}
		break;
	case AS_ICON_KIND_REMOTE:
		icon_name = as_icon_get_url (icon);
		if (!g_str_has_prefix (icon_name, "http://") &&
		    !g_str_has_prefix (icon_name, "https://")) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "remote icon is not a url [%s]",
					     icon_name);
		}
		break;
	default:
		break;
	}
}
コード例 #6
0
/**
 * as_app_validate:
 * @app: a #AsApp instance.
 * @flags: the #AsAppValidateFlags to use, e.g. %AS_APP_VALIDATE_FLAG_NONE
 * @error: A #GError or %NULL.
 *
 * Validates data in the instance for style and consistency.
 *
 * Returns: (transfer container) (element-type AsProblem): A list of problems, or %NULL
 *
 * Since: 0.1.4
 **/
GPtrArray *
as_app_validate (AsApp *app, guint32 flags, GError **error)
{
	AsAppProblems problems;
	AsFormat *format;
	GError *error_local = NULL;
	GHashTable *urls;
	GList *l;
	const gchar *description;
	const gchar *key;
	const gchar *license;
	const gchar *name;
	const gchar *summary;
	const gchar *tmp;
	const gchar *update_contact;
	gboolean deprecated_failure = FALSE;
	gboolean require_appstream_spec_only = FALSE;
	gboolean require_contactdetails = FALSE;
	gboolean require_copyright = FALSE;
	gboolean require_description = FALSE;
	gboolean require_project_license = FALSE;
	gboolean require_sentence_case = FALSE;
	gboolean require_translations = FALSE;
	gboolean require_url = TRUE;
	gboolean require_content_license = TRUE;
	gboolean require_name = TRUE;
	gboolean require_translation = FALSE;
	gboolean require_content_rating = FALSE;
	gboolean require_name_shorter_than_summary = FALSE;
	gboolean validate_license = TRUE;
	gboolean ret;
	guint length_name_max = 60;
	guint length_name_min = 3;
	guint length_summary_max = 200;
	guint length_summary_min = 8;
	guint number_para_max = 10;
	guint number_para_min = 1;
	guint str_len;
	g_autoptr(GList) keys = NULL;
	g_autoptr(AsAppValidateHelper) helper = g_new0 (AsAppValidateHelper, 1);

	/* has to be set */
	format = as_app_get_format_default (app);
	if (format == NULL) {
		g_set_error_literal (error,
				     AS_APP_ERROR,
				     AS_APP_ERROR_FAILED,
				     "cannot validate without at least one format");
		return NULL;
	}

	/* only for desktop and console apps */
	if (as_app_get_kind (app) == AS_APP_KIND_DESKTOP ||
	    as_app_get_kind (app) == AS_APP_KIND_CONSOLE) {
		require_content_rating = TRUE;
		require_description = TRUE;
	}

	/* relax the requirements a bit */
	if ((flags & AS_APP_VALIDATE_FLAG_RELAX) > 0) {
		length_name_max = 100;
		length_summary_max = 200;
		require_content_license = FALSE;
		validate_license = FALSE;
		require_url = FALSE;
		number_para_max = 20;
		number_para_min = 1;
		require_sentence_case = FALSE;
		require_content_rating = FALSE;
		switch (as_format_get_kind (format)) {
		case AS_FORMAT_KIND_METAINFO:
		case AS_FORMAT_KIND_APPDATA:
			require_name = FALSE;
			break;
		default:
			break;
		}
	}

	/* make the requirements more strict */
	if ((flags & AS_APP_VALIDATE_FLAG_STRICT) > 0) {
		deprecated_failure = TRUE;
		require_copyright = TRUE;
		require_translations = TRUE;
		require_project_license = TRUE;
		require_content_license = TRUE;
		require_appstream_spec_only = TRUE;
		require_sentence_case = TRUE;
		require_name_shorter_than_summary = TRUE;
		require_contactdetails = TRUE;
		require_translation = TRUE;
		number_para_min = 2;
		number_para_max = 4;
	}

	/* addons don't need such a long description */
	switch (as_format_get_kind (format)) {
	case AS_FORMAT_KIND_METAINFO:
	case AS_FORMAT_KIND_APPDATA:
		number_para_min = 1;
		break;
	default:
		break;
	}

	/* set up networking */
	helper->app = app;
	helper->probs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
	helper->screenshot_urls = g_ptr_array_new_with_free_func (g_free);
	helper->flags = flags;
	if (!as_app_validate_setup_networking (helper, error))
		return NULL;

	/* invalid component type */
	if (as_app_get_kind (app) == AS_APP_KIND_UNKNOWN) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_ATTRIBUTE_INVALID,
				     "<component> has invalid type attribute");

	}
	as_app_validate_check_id (helper, as_app_get_id (app));

	/* metadata_license */
	license = as_app_get_metadata_license (app);
	if (license != NULL) {
		if (require_content_license &&
		    !as_app_validate_is_content_license (license)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "<metadata_license> is not valid [%s]",
					     license);
		} else if (validate_license) {
			if (!as_app_validate_license (license, &error_local)) {
				g_prefix_error (&error_local,
						"<metadata_license> is not valid [%s]",
						license);
				ai_app_validate_add (helper,
						     AS_PROBLEM_KIND_TAG_INVALID,
						     "%s", error_local->message);
				g_clear_error (&error_local);
			}
		}
	}
	if (license == NULL) {
		switch (as_format_get_kind (format)) {
		case AS_FORMAT_KIND_APPDATA:
		case AS_FORMAT_KIND_METAINFO:
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "<metadata_license> is not present");
			break;
		default:
			break;
		}
	}

	/* project_license */
	license = as_app_get_project_license (app);
	if (license != NULL && validate_license) {
		if (!as_app_validate_license (license, &error_local)) {
			g_prefix_error (&error_local,
					"<project_license> is not valid [%s]",
					license);
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "%s", error_local->message);
			g_clear_error (&error_local);
		}
	}
	if (require_project_license && license == NULL) {
		switch (as_format_get_kind (format)) {
		case AS_FORMAT_KIND_APPDATA:
		case AS_FORMAT_KIND_METAINFO:
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "<project_license> is not present");
			break;
		default:
			break;
		}
	}

	/* categories */
	if (as_format_get_kind (format) == AS_FORMAT_KIND_APPSTREAM &&
	    as_app_get_kind (app) == AS_APP_KIND_DESKTOP) {
		GPtrArray *categories = as_app_get_categories (app);
		guint nr_toplevel_cats = 0;
		const gchar *cats[] = { "AudioVideo",
					"Development",
					"Education",
					"Game",
					"Graphics",
					"Network",
					"Office",
					"Science",
					"Settings",
					"System",
					"Utility",
					NULL };
		for (guint i = 0; i < categories->len; i++) {
			const gchar *cat = g_ptr_array_index (categories, i);
			for (guint j = 0; cats[j] != NULL; j++) {
				if (g_strcmp0 (cats[j], cat) == 0)
					nr_toplevel_cats++;
			}
		}
		if (nr_toplevel_cats == 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "<category> must include main categories "
					     "from the desktop entry spec");
		} else if (nr_toplevel_cats > 3) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "too many main <category> types: %u",
					     nr_toplevel_cats);
		}
	}

	/* translation */
	if (require_translation &&
	    as_format_get_kind (format) == AS_FORMAT_KIND_APPDATA &&
	    as_app_get_translations (app)->len == 0) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_MISSING,
				     "<translation> not specified");
	}

	/* pkgname */
	if (as_app_get_pkgname_default (app) != NULL &&
	    as_format_get_kind (format) == AS_FORMAT_KIND_METAINFO) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "<pkgname> not allowed in metainfo");
	}

	/* appdata */
	if (as_format_get_kind (format) == AS_FORMAT_KIND_APPDATA &&
	    as_app_get_kind (app) == AS_APP_KIND_DESKTOP) {
		AsIcon *icon = as_app_get_icon_default (app);
		if (icon != NULL &&
		    as_icon_get_kind (icon) != AS_ICON_KIND_REMOTE) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "<icon> not allowed in desktop appdata");
		}
	}

	/* extends */
	if (as_app_get_extends(app)->len == 0 &&
	    as_app_get_kind (app) == AS_APP_KIND_ADDON &&
	    as_format_get_kind (format) == AS_FORMAT_KIND_METAINFO) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_MISSING,
				     "<extends> is not present");
	}

	/* update_contact */
	update_contact = as_app_get_update_contact (app);
	if (g_strcmp0 (update_contact,
		       "someone_who_cares@upstream_project.org") == 0) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "<update_contact> is still set to a dummy value");
	}
	if (update_contact != NULL && strlen (update_contact) < 6) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_STYLE_INCORRECT,
				     "<update_contact> is too short [%s]",
				     update_contact);
	}
	if (require_contactdetails && update_contact == NULL) {
		switch (as_format_get_kind (format)) {
		case AS_FORMAT_KIND_APPDATA:
		case AS_FORMAT_KIND_METAINFO:
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "<update_contact> is not present");
			break;
		default:
			break;
		}
	}

	/* only found for files */
	problems = as_app_get_problems (app);
	if (as_format_get_kind (format) == AS_FORMAT_KIND_APPDATA ||
	    as_format_get_kind (format) == AS_FORMAT_KIND_METAINFO) {
		if ((problems & AS_APP_PROBLEM_NO_XML_HEADER) > 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_MARKUP_INVALID,
					     "<?xml> header not found");
		}
		if (require_copyright &&
		    (problems & AS_APP_PROBLEM_NO_COPYRIGHT_INFO) > 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_VALUE_MISSING,
					     "<!-- Copyright [year] [name] --> is not present");
		}
		if (deprecated_failure &&
		    (problems & AS_APP_PROBLEM_UPDATECONTACT_FALLBACK) > 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "<updatecontact> should be <update_contact>");
		}
	}

	/* check invalid values */
	if ((problems & AS_APP_PROBLEM_INVALID_PROJECT_GROUP) > 0) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "<project_group> is not valid");
	}

	/* only allow XML in the specification */
	if (require_appstream_spec_only &&
	    (problems & AS_APP_PROBLEM_INVALID_XML_TAG) > 0) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "XML data contains unknown tag");
	}

	/* only allow XML in the specification */
	if (problems & AS_APP_PROBLEM_EXPECTED_CHILDREN) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "Expected children for tag");
	}

	/* only allow XML in the specification */
	if (problems & AS_APP_PROBLEM_INVALID_KEYWORDS) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "<keyword> invalid contents");
	}

	/* releases all have to have unique versions */
	if (problems & AS_APP_PROBLEM_DUPLICATE_RELEASE) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "<release> version was duplicated");
	}
	if (problems & AS_APP_PROBLEM_DUPLICATE_SCREENSHOT) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "<screenshot> content was duplicated");
	}
	if (problems & AS_APP_PROBLEM_DUPLICATE_CONTENT_RATING) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_INVALID,
				     "<content_rating> was duplicated");
	}

	/* check for things that have to exist */
	if (as_app_get_id (app) == NULL) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_MISSING,
				     "<id> is not present");
	}

	/* games require a content rating */
	if (require_content_rating) {
		GPtrArray *ratings = as_app_get_content_ratings (app);
		if (ratings->len == 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "<content_rating> required "
					     "[use https://odrs.gnome.org/oars]");
		}
	}

	/* url */
	urls = as_app_get_urls (app);
	keys = g_hash_table_get_keys (urls);
	for (l = keys; l != NULL; l = l->next) {
		key = l->data;
		if (g_strcmp0 (key, "unknown") == 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "<url> type invalid [%s]", key);
		}
		tmp = g_hash_table_lookup (urls, key);
		if (tmp == NULL || tmp[0] == '\0')
			continue;
		if (!g_str_has_prefix (tmp, "http://") &&
		    !g_str_has_prefix (tmp, "https://")) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_INVALID,
					     "<url> does not start with 'http://' [%s]",
					     tmp);
		}
	}

	/* screenshots */
	as_app_validate_screenshots (app, helper);

	/* icons */
	as_app_validate_icons (app, helper);

	/* releases */
	if (!as_app_validate_releases (app, helper, error))
		return NULL;

	/* kudos */
	if (!as_app_validate_kudos (app, helper, error))
		return NULL;

	/* name */
	name = as_app_get_name (app, "C");
	if (name != NULL) {
		str_len = (guint) strlen (name);
		if (str_len < length_name_min) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<name> is too short [%s] minimum is %u chars",
					     name, length_name_min);
		}
		if (str_len > length_name_max) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<name> is too long [%s] maximum is %u chars",
					     name, length_name_max);
		}
		if (ai_app_validate_fullstop_ending (name)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<name> cannot end in '.' [%s]",
					     name);
		}
		if (as_app_validate_has_hyperlink (name)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<name> cannot contain a hyperlink [%s]",
					     name);
		}
		if (require_sentence_case &&
		    !as_app_validate_has_first_word_capital (helper, name)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<name> requires sentence case [%s]",
					     name);
		}
	} else if (require_name) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_MISSING,
				     "<name> is not present");
	}

	/* comment */
	summary = as_app_get_comment (app, "C");
	if (summary != NULL) {
		str_len = (guint) strlen (summary);
		if (str_len < length_summary_min) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<summary> is too short [%s] minimum is %u chars",
					     summary, length_summary_min);
		}
		if (str_len > length_summary_max) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<summary> is too long [%s] maximum is %u chars",
					     summary, length_summary_max);
		}
		if (require_sentence_case &&
		    ai_app_validate_fullstop_ending (summary)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<summary> cannot end in '.' [%s]",
					     summary);
		}
		if (as_app_validate_has_hyperlink (summary)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<summary> cannot contain a hyperlink [%s]",
					     summary);
		}
		if (require_sentence_case &&
		    !as_app_validate_has_first_word_capital (helper, summary)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<summary> requires sentence case [%s]",
					     summary);
		}
	} else if (require_name) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_TAG_MISSING,
				     "<summary> is not present");
	}
	if (require_name_shorter_than_summary &&
	    summary != NULL && name != NULL &&
	    strlen (summary) < strlen (name)) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_STYLE_INCORRECT,
				     "<summary> is shorter than <name>");
	}
	description = as_app_get_description (app, "C");
	if (description == NULL) {
		if (require_description) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "<description> required");
		}
	} else {
		ret = as_app_validate_description (description,
						   helper,
						   number_para_min,
						   number_para_max,
						   FALSE,
						   &error_local);
		if (!ret) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_MARKUP_INVALID,
					     "%s", error_local->message);
			g_error_free (error_local);
		}
	}
	if (require_translations) {
		if (name != NULL &&
		    as_app_get_name_size (app) == 1 &&
		    (problems & AS_APP_PROBLEM_INTLTOOL_NAME) == 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TRANSLATIONS_REQUIRED,
					     "<name> has no translations");
		}
		if (summary != NULL &&
		    as_app_get_comment_size (app) == 1 &&
		    (problems & AS_APP_PROBLEM_INTLTOOL_SUMMARY) == 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TRANSLATIONS_REQUIRED,
					     "<summary> has no translations");
		}
		if (description != NULL &&
		    as_app_get_description_size (app) == 1 &&
		    (problems & AS_APP_PROBLEM_INTLTOOL_DESCRIPTION) == 0) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TRANSLATIONS_REQUIRED,
					     "<description> has no translations");
		}
	}

	/* developer_name */
	name = as_app_get_developer_name (app, NULL);
	if (name != NULL) {
		str_len = (guint) strlen (name);
		if (str_len < length_name_min) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<developer_name> is too short [%s] minimum is %u chars",
					     name, length_name_min);
		}
		if (str_len > length_name_max) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<developer_name> is too long [%s] maximum is %u chars",
					     name, length_name_max);
		}
		if (as_app_validate_has_hyperlink (name)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<developer_name> cannot contain a hyperlink [%s]",
					     name);
		}
		if (as_app_validate_has_email (name)) {
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_STYLE_INCORRECT,
					     "<developer_name> cannot contain an email address [%s]",
					     name);
		}
	}

	/* using deprecated names */
	if (deprecated_failure && (problems & AS_APP_PROBLEM_DEPRECATED_LICENCE) > 0) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_ATTRIBUTE_INVALID,
				     "<licence> is deprecated, use "
				     "<metadata_license> instead");
	}
	if ((problems & AS_APP_PROBLEM_MULTIPLE_ENTRIES) > 0) {
		ai_app_validate_add (helper,
				     AS_PROBLEM_KIND_MARKUP_INVALID,
				     "<application> used more than once");
	}

	/* require homepage */
	if (require_url && as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE) == NULL) {
		switch (as_format_get_kind (format)) {
		case AS_FORMAT_KIND_APPDATA:
		case AS_FORMAT_KIND_METAINFO:
			ai_app_validate_add (helper,
					     AS_PROBLEM_KIND_TAG_MISSING,
					     "<url> is not present");
			break;
		default:
			break;
		}
	}
	return helper->probs;
}
コード例 #7
0
/**
 * asb_plugin_process_filename:
 */
static gboolean
asb_plugin_process_filename (AsbPlugin *plugin,
			     AsbPackage *pkg,
			     const gchar *filename,
			     GList **apps,
			     const gchar *tmpdir,
			     GError **error)
{
	AsIcon *icon;
	AsAppParseFlags parse_flags = AS_APP_PARSE_FLAG_USE_HEURISTICS;
	gboolean ret;
	_cleanup_free_ gchar *app_id = NULL;
	_cleanup_free_ gchar *full_filename = NULL;
	_cleanup_object_unref_ AsbApp *app = NULL;
	_cleanup_object_unref_ GdkPixbuf *pixbuf = NULL;

	/* use GenericName fallback */
	if (asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_USE_FALLBACKS))
		parse_flags |= AS_APP_PARSE_FLAG_USE_FALLBACKS;

	/* create app */
	app_id = g_path_get_basename (filename);
	app = asb_app_new (pkg, app_id);
	asb_app_set_hidpi_enabled (app, asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_HIDPI_ICONS));
	full_filename = g_build_filename (tmpdir, filename, NULL);
	if (!as_app_parse_file (AS_APP (app), full_filename, parse_flags, error))
		return FALSE;

	/* NoDisplay apps are never included */
	if (as_app_get_metadata_item (AS_APP (app), "NoDisplay") != NULL)
		asb_app_add_requires_appdata (app, "NoDisplay=true");

	/* Settings or DesktopSettings requires AppData */
	if (!asb_context_get_flag (plugin->ctx, ASB_CONTEXT_FLAG_IGNORE_SETTINGS)) {
		if (as_app_has_category (AS_APP (app), "Settings"))
			asb_app_add_requires_appdata (app, "Category=Settings");
		if (as_app_has_category (AS_APP (app), "DesktopSettings"))
			asb_app_add_requires_appdata (app, "Category=DesktopSettings");
	}

	/* is the icon a stock-icon-name? */
	icon = as_app_get_icon_default (AS_APP (app));
	if (icon != NULL) {
		_cleanup_free_ gchar *key = NULL;
		key = g_strdup (as_icon_get_name (icon));
		if (as_icon_get_kind (icon) == AS_ICON_KIND_STOCK) {
			asb_package_log (pkg,
					 ASB_PACKAGE_LOG_LEVEL_DEBUG,
					 "using stock icon %s", key);
		} else {
			_cleanup_error_free_ GError *error_local = NULL;
			g_ptr_array_set_size (as_app_get_icons (AS_APP (app)), 0);
			ret = asb_plugin_desktop_add_icons (plugin,
							    app,
							    tmpdir,
							    key,
							    &error_local);
			if (!ret) {
				as_app_add_veto (AS_APP (app), "%s",
						 error_local->message);
			}
		}
	}

	/* add */
	asb_plugin_add_app (apps, AS_APP (app));
	return TRUE;
}