static void
process_directory (ProcessApplicationData  *data,
                   GFileInfo               *file_info,
                   GError                 **error)
{
	TrackerSparqlBuilder *sparql;
	gchar *urn, *path, *uri;

	sparql = data->sparql;

	path = g_file_get_path (data->file);
	uri = g_file_get_uri (data->file);
	urn = tracker_sparql_escape_uri_printf ("urn:applications-dir:%s", path);

	tracker_sparql_builder_insert_silent_open (sparql, TRACKER_OWN_GRAPH_URN);

	tracker_sparql_builder_subject_iri (sparql, urn);

	tracker_sparql_builder_predicate (sparql, "a");
	tracker_sparql_builder_object (sparql, "nfo:FileDataObject");
	tracker_sparql_builder_object (sparql, "nie:DataObject");
	tracker_sparql_builder_object (sparql, "nie:Folder");

	tracker_sparql_builder_predicate (sparql, "tracker:available");
	tracker_sparql_builder_object_boolean (sparql, TRUE);

	tracker_sparql_builder_predicate (sparql, "nie:isStoredAs");
	tracker_sparql_builder_object_iri (sparql, urn);

	tracker_sparql_builder_predicate (sparql, "nie:url");
	tracker_sparql_builder_object_string (sparql, uri);

	if (file_info) {
		guint64 time;

		time = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
		tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
		tracker_sparql_builder_object_date (sparql, (time_t *) &time);
	}

	tracker_sparql_builder_insert_close (data->sparql);

	g_free (path);
	g_free (urn);
	g_free (uri);
}
static void
process_desktop_file (ProcessApplicationData  *data,
                      GFileInfo               *file_info,
                      GError                 **error)
{
	TrackerSparqlBuilder *sparql;
	GKeyFile *key_file;
	gchar *name = NULL;
	gchar *path;
	gchar *type;
	gchar *filename;
	gchar *uri = NULL;
	GStrv cats;
	gsize cats_len;
	gboolean is_software = TRUE;
	const gchar *parent_urn;
	gchar *lang;
#ifdef HAVE_MEEGOTOUCH
	gchar *logical_id = NULL;
	gchar *translation_catalog = NULL;
#endif /* HAVE_MEEGOTOUCH */

	sparql = data->sparql;
	key_file = data->key_file;
	type = data->type;

	path = g_file_get_path (data->file);

	/* Retrieve LANG locale setup */
	lang = tracker_locale_get (TRACKER_LOCALE_LANGUAGE);

	/* Try to get the categories with our desired LANG locale... */
	cats = g_key_file_get_locale_string_list (key_file, GROUP_DESKTOP_ENTRY, "Categories", lang, &cats_len, NULL);
	if (!cats) {
		/* If our desired locale failed, use the list of LANG locales prepared by GLib
		 * (will return untranslated string if none of the locales available) */
		cats = g_key_file_get_locale_string_list (key_file, GROUP_DESKTOP_ENTRY, "Categories", NULL, &cats_len, NULL);
	}

	/* NOTE: We sanitize categories later on when iterating them */

#ifdef HAVE_MEEGOTOUCH
	/* If defined, start with the logical strings */
	logical_id = g_key_file_get_string (key_file, GROUP_DESKTOP_ENTRY, "X-MeeGo-Logical-Id", NULL);
	translation_catalog = g_key_file_get_string (key_file, GROUP_DESKTOP_ENTRY, "X-MeeGo-Translation-Catalog", NULL);

	if (logical_id && translation_catalog) {
		name = tracker_meego_translate (translation_catalog, logical_id);
	}

	g_free (logical_id);
	g_free (translation_catalog);
#endif /* HAVE_MEEGOTOUCH */

	if (!name) {
		/* Try to get the name with our desired LANG locale... */
		name = g_key_file_get_locale_string (key_file, GROUP_DESKTOP_ENTRY, "Name", lang, NULL);
		if (!name) {
			/* If our desired locale failed, use the list of LANG locales prepared by GLib
			 * (will return untranslated string if none of the locales available) */
			name = g_key_file_get_locale_string (key_file, GROUP_DESKTOP_ENTRY, "Name", NULL, NULL);
		}
	}

	/* Sanitize name */
	if (name) {
		g_strstrip (name);
	}

	if (name && g_ascii_strcasecmp (type, "Directory") == 0) {
		gchar *canonical_uri = tracker_sparql_escape_uri_printf (SOFTWARE_CATEGORY_URN_PREFIX "%s", path);
		gchar *icon = g_key_file_get_string (key_file, GROUP_DESKTOP_ENTRY, "Icon", NULL);

		uri = canonical_uri;
		tracker_sparql_builder_insert_silent_open (sparql, TRACKER_OWN_GRAPH_URN);
		tracker_sparql_builder_subject_iri (sparql, uri);

		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nfo:SoftwareCategory");

		if (icon) {
			gchar *escaped_icon;
			gchar *icon_uri;

			/* Sanitize icon */
			g_strstrip (icon);

			escaped_icon = g_uri_escape_string (icon, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);

			icon_uri = g_strdup_printf (THEME_ICON_URN_PREFIX "%s", escaped_icon);

			tracker_sparql_builder_subject_iri (sparql, icon_uri);
			tracker_sparql_builder_predicate (sparql, "a");
			tracker_sparql_builder_object (sparql, "nfo:Image");

			tracker_sparql_builder_subject_iri (sparql, uri);
			tracker_sparql_builder_predicate (sparql, "nfo:softwareCategoryIcon");
			tracker_sparql_builder_object_iri (sparql, icon_uri);

			g_free (icon_uri);
			g_free (escaped_icon);
			g_free (icon);
		}

		is_software = FALSE;
	} else if (name && g_ascii_strcasecmp (type, "Application") == 0) {
		uri = g_file_get_uri (data->file);
		tracker_sparql_builder_insert_silent_open (sparql, TRACKER_OWN_GRAPH_URN);

		tracker_sparql_builder_subject_iri (sparql, APPLICATION_DATASOURCE_URN);
		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nie:DataSource");

		tracker_sparql_builder_subject_iri (sparql, uri);

		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nfo:SoftwareApplication");
		tracker_sparql_builder_object (sparql, "nie:DataObject");

		tracker_sparql_builder_predicate (sparql, "nie:dataSource");
		tracker_sparql_builder_object_iri (sparql, APPLICATION_DATASOURCE_URN);
	} else if (name && g_ascii_strcasecmp (type, "Link") == 0) {
		gchar *url = g_key_file_get_string (key_file, GROUP_DESKTOP_ENTRY, "URL", NULL);

		if (url) {
			uri = g_file_get_uri (data->file);
			tracker_sparql_builder_insert_silent_open (sparql, TRACKER_OWN_GRAPH_URN);

			tracker_sparql_builder_subject_iri (sparql, uri);
			tracker_sparql_builder_predicate (sparql, "a");
			tracker_sparql_builder_object (sparql, "nfo:Bookmark");

			tracker_sparql_builder_predicate (sparql, "nfo:bookmarks");
			tracker_sparql_builder_object_iri (sparql, url);

			tracker_sparql_builder_predicate (sparql, "nie:dataSource");
			tracker_sparql_builder_object_iri (sparql, APPLICATION_DATASOURCE_URN);

			is_software = FALSE;

			g_free (url);
		} else {
			g_warning ("Invalid desktop file: '%s'", uri);
			g_warning ("  Type 'Link' requires a URL");
		}
#ifdef HAVE_MEEGOTOUCH
	} else if (name && g_ascii_strcasecmp (type, "ControlPanelApplet") == 0) {
		/* Special case control panel applets */
		/* The URI of the InformationElement should be a UUID URN */
		uri = g_file_get_uri (data->file);
		tracker_sparql_builder_insert_silent_open (sparql, TRACKER_MINER_FS_GRAPH_URN);

		tracker_sparql_builder_subject_iri (sparql, APPLET_DATASOURCE_URN);
		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nie:DataSource");

		/* TODO This is atm specific for Maemo */
		tracker_sparql_builder_subject_iri (sparql, uri);

		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "maemo:ControlPanelApplet");

		tracker_sparql_builder_predicate (sparql, "nie:dataSource");
		tracker_sparql_builder_object_iri (sparql, APPLET_DATASOURCE_URN);

		/* This matches SomeApplet as Type= */
	} else if (name && g_str_has_suffix (type, "Applet")) {
		/* The URI of the InformationElement should be a UUID URN */
		uri = g_file_get_uri (data->file);
		tracker_sparql_builder_insert_silent_open (sparql, TRACKER_MINER_FS_GRAPH_URN);

		tracker_sparql_builder_subject_iri (sparql, APPLET_DATASOURCE_URN);
		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nie:DataSource");

		/* TODO This is atm specific for Maemo */
		tracker_sparql_builder_subject_iri (sparql, uri);

		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "maemo:SoftwareApplet");

		tracker_sparql_builder_predicate (sparql, "nie:dataSource");
		tracker_sparql_builder_object_iri (sparql, APPLET_DATASOURCE_URN);

	} else if (name && g_ascii_strcasecmp (type, "DUIApplication") == 0) {

		uri = g_file_get_uri (data->file);
		tracker_sparql_builder_insert_silent_open (sparql, TRACKER_MINER_FS_GRAPH_URN);

		tracker_sparql_builder_subject_iri (sparql, APPLICATION_DATASOURCE_URN);
		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nie:DataSource");

		tracker_sparql_builder_subject_iri (sparql, uri);

		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nfo:SoftwareApplication");
		tracker_sparql_builder_object (sparql, "nie:DataObject");

		tracker_sparql_builder_predicate (sparql, "nie:dataSource");
		tracker_sparql_builder_object_iri (sparql, APPLICATION_DATASOURCE_URN);
#endif /* HAVE_MEEGOTOUCH */
	} else {
		/* Invalid type, all valid types are already listed above */
		uri = g_file_get_uri (data->file);
		tracker_sparql_builder_insert_silent_open (sparql, TRACKER_OWN_GRAPH_URN);

		tracker_sparql_builder_subject_iri (sparql, APPLICATION_DATASOURCE_URN);
		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nie:DataSource");

		tracker_sparql_builder_subject_iri (sparql, uri);

		tracker_sparql_builder_predicate (sparql, "a");
		tracker_sparql_builder_object (sparql, "nfo:SoftwareApplication");
		tracker_sparql_builder_object (sparql, "nie:DataObject");

		tracker_sparql_builder_predicate (sparql, "nie:dataSource");
		tracker_sparql_builder_object_iri (sparql, APPLICATION_DATASOURCE_URN);

		if (name) {
			/* If we got a name, then the issue comes from the type.
			 * As we're defaulting to Application here, we just g_debug() the problem. */
			g_debug ("Invalid desktop file: '%s'", uri);
			g_debug ("  Type '%s' is not part of the desktop file specification (expected 'Application', 'Link' or 'Directory')", type);
			g_debug ("  Defaulting to 'Application'");
		} else {
			/* If we didn't get a name, the problem is more severe as we don't default it
			 * to anything, so we g_warning() it.  */
			g_warning ("Invalid desktop file: '%s'", uri);
#ifdef HAVE_MEEGOTOUCH
			g_warning ("  Couldn't get name, missing or wrong key (X-MeeGo-Logical-Id, X-MeeGo-Translation-Catalog or Name)");
#else
			g_warning ("  Couldn't get name, missing key (Name)");
#endif
		}
	}

	if (sparql && uri) {
		gchar *desktop_file_uri;

		tracker_sparql_builder_predicate (sparql, "a");

		if (is_software) {
			tracker_sparql_builder_object (sparql, "nfo:Executable");
		}

		tracker_sparql_builder_object (sparql, "nfo:FileDataObject");
		tracker_sparql_builder_object (sparql, "nie:DataObject");

		/* Apparently this gets added by the file-module ATM
		   tracker_sparql_builder_predicate (sparql, "tracker:available");
		   tracker_sparql_builder_object_boolean (sparql, TRUE); */

		/* We should always always have a proper name if the desktop file is correct
		 * w.r.t to the Meego or Freedesktop specs, but sometimes this is not true,
		 * so instead of passing wrong stuff to the SPARQL builder, we avoid it.
		 * If we don't have a proper name, we already warned it before. */
		if (name) {
			tracker_sparql_builder_predicate (sparql, "nie:title");
			tracker_sparql_builder_object_string (sparql, name);
		}

		if (is_software) {
			gchar *icon;

			insert_data_from_desktop_file (sparql,
			                               uri,
			                               TRACKER_PREFIX_NIE "comment",
			                               key_file,
			                               "Comment",
			                               lang);
			insert_data_from_desktop_file (sparql,
			                               uri,
			                               TRACKER_PREFIX_NFO "softwareCmdLine",
			                               key_file,
			                               "Exec",
			                               lang);

			icon = g_key_file_get_string (key_file, GROUP_DESKTOP_ENTRY, "Icon", NULL);

			if (icon) {
				gchar *escaped_icon;
				gchar *icon_uri;

				/* Sanitize icon */
				g_strstrip (icon);

				escaped_icon = g_uri_escape_string (icon, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);

				icon_uri = g_strdup_printf (THEME_ICON_URN_PREFIX "%s", escaped_icon);

				tracker_sparql_builder_subject_iri (sparql, icon_uri);
				tracker_sparql_builder_predicate (sparql, "a");
				tracker_sparql_builder_object (sparql, "nfo:Image");

				tracker_sparql_builder_subject_iri (sparql, uri);
				tracker_sparql_builder_predicate (sparql, "nfo:softwareIcon");
				tracker_sparql_builder_object_iri (sparql, icon_uri);

				g_free (icon_uri);
				g_free (escaped_icon);
				g_free (icon);
			}
		}

		if (cats) {
			gsize i;

			for (i = 0 ; cats[i] && i < cats_len ; i++) {
				gchar *cat_uri;
				gchar *cat;

				cat = cats[i];

				if (!cat) {
					continue;
				}

				/* Sanitize category */
				g_strstrip (cat);

				cat_uri = tracker_sparql_escape_uri_printf (SOFTWARE_CATEGORY_URN_PREFIX "%s", cat);

				/* There are also .desktop
				 * files that describe these categories, but we can handle
				 * preemptively creating them if we visit a app .desktop
				 * file that mentions one that we don't yet know about */

				tracker_sparql_builder_subject_iri (sparql, cat_uri);
				tracker_sparql_builder_predicate (sparql, "a");
				tracker_sparql_builder_object (sparql, "nfo:SoftwareCategory");

				tracker_sparql_builder_predicate (sparql, "nie:title");
				tracker_sparql_builder_object_string (sparql, cat);

				tracker_sparql_builder_subject_iri (sparql, uri);
				tracker_sparql_builder_predicate (sparql, "nie:isLogicalPartOf");
				tracker_sparql_builder_object_iri (sparql, cat_uri);

				g_free (cat_uri);
			}
		}

		filename = g_filename_display_basename (path);
		tracker_sparql_builder_predicate (sparql, "nfo:fileName");
		tracker_sparql_builder_object_string (sparql, filename);
		g_free (filename);

		/* The URL of the DataObject */
		desktop_file_uri = g_file_get_uri (data->file);
		tracker_sparql_builder_predicate (sparql, "nie:url");
		tracker_sparql_builder_object_string (sparql, desktop_file_uri);

		/* Laying the link between the IE and the DO */
		tracker_sparql_builder_subject_iri (sparql, uri);
		tracker_sparql_builder_predicate (sparql, "nie:isStoredAs");
		tracker_sparql_builder_object_iri (sparql, desktop_file_uri);


		g_free (desktop_file_uri);
	}

	if (file_info) {
		guint64 time;

		time = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
		tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
		tracker_sparql_builder_object_date (sparql, (time_t *) &time);
	}

	parent_urn = tracker_miner_fs_get_parent_urn (TRACKER_MINER_FS (data->miner), data->file);

	if (parent_urn) {
		tracker_sparql_builder_predicate (sparql, "nfo:belongsToContainer");
		tracker_sparql_builder_object_iri (sparql, parent_urn);
	}

	tracker_sparql_builder_insert_close (sparql);

	g_strfreev (cats);

	g_free (uri);
	g_free (path);
	g_free (name);
	g_free (lang);
}
static inline void
process_item (ProcessUserguideData  *data,
              GFileInfo             *file_info,
              gboolean               is_dir,
              GError               **error)
{
	TrackerSparqlBuilder *sparql;
	gchar *uri;
	const gchar *mime_type;
	const gchar *urn;
	const gchar *parent_urn;
	gboolean is_iri;
	guint64 time_;

	sparql = data->sparql;

	uri = g_file_get_uri (data->file);
	mime_type = g_file_info_get_content_type (file_info);

	urn = get_file_urn (data->miner, data->file, &is_iri);

	tracker_sparql_builder_insert_silent_open (sparql, NULL);
	tracker_sparql_builder_graph_open (sparql, TRACKER_MINER_FS_GRAPH_URN);

	if (is_iri) {
		tracker_sparql_builder_subject_iri (sparql, urn);
	} else {
		tracker_sparql_builder_subject (sparql, urn);
	}

	tracker_sparql_builder_predicate (sparql, "a");
	tracker_sparql_builder_object (sparql, "nfo:FileDataObject");
	tracker_sparql_builder_object (sparql, "nie:InformationElement");

	if (is_dir) {
		tracker_sparql_builder_object (sparql, "nfo:Folder");
	} else {
		tracker_sparql_builder_object (sparql, "nfo:HelpDocument");
	}

	parent_urn = tracker_miner_fs_get_parent_urn (TRACKER_MINER_FS (data->miner), data->file);

	if (parent_urn) {
		tracker_sparql_builder_predicate (sparql, "nfo:belongsToContainer");
		tracker_sparql_builder_object_iri (sparql, parent_urn);
	}

	tracker_sparql_builder_predicate (sparql, "nfo:fileName");
	tracker_sparql_builder_object_string (sparql, g_file_info_get_display_name (file_info));

	tracker_sparql_builder_predicate (sparql, "nfo:fileSize");
	tracker_sparql_builder_object_int64 (sparql, g_file_info_get_size (file_info));

	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);

	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS);
	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);

	/* Laying the link between the IE and the DO. We use IE = DO */
	tracker_sparql_builder_predicate (sparql, "nie:isStoredAs");
	if (is_iri) {
		tracker_sparql_builder_object_iri (sparql, urn);
	} else {
		tracker_sparql_builder_object (sparql, urn);
	}

	/* The URL of the DataObject (because IE = DO, this is correct) */
	tracker_sparql_builder_predicate (sparql, "nie:url");
	tracker_sparql_builder_object_string (sparql, uri);

	tracker_sparql_builder_predicate (sparql, "nie:mimeType");
	tracker_sparql_builder_object_string (sparql, mime_type);

	/* FIXME: Add nie:dataSource for switching different userguides? */
	tracker_sparql_builder_predicate (sparql, "tracker:available");
	tracker_sparql_builder_object_boolean (sparql, TRUE);

	if (!is_dir) {
		gchar *content = NULL;
		gchar *title = NULL;

		/* Get content */
		parser_get_file_content (uri, MAX_EXTRACT_SIZE, &content, &title);

		g_message ("Adding userguide:'%s', uri:'%s'",
		           title,
		           uri);

		if (title && title[0]) {
			tracker_sparql_builder_predicate (sparql, "nie:title");
			tracker_sparql_builder_object_unvalidated (sparql, title);
		}

		if (content && content[0]) {
			tracker_sparql_builder_predicate (sparql, "nie:plainTextContent");
			tracker_sparql_builder_object_unvalidated (sparql, content);
		}

		g_free (content);
		g_free (title);
	} else {
		g_message ("Adding userguide directory:'%s'", uri);
	}

	tracker_sparql_builder_graph_close (sparql);
	tracker_sparql_builder_insert_close (sparql);

	g_free (uri);
}