/**
 * tracker_miner_manager_get_running:
 * @manager: a #trackerMinerManager
 *
 * Returns a list of references for all active miners. Active miners
 * are miners which are running within a process.
 *
 * Returns: (transfer full) (element-type utf8) (nullable): a #GSList which
 * must be freed with g_slist_free() and all contained data with g_free().
 * Otherwise %NULL is returned if there are no miners.
 *
 * Since: 0.8
 **/
GSList *
tracker_miner_manager_get_running (TrackerMinerManager *manager)
{
	TrackerMinerManagerPrivate *priv;
	GSList *list = NULL;
	GError *error = NULL;
	GVariant *v;
	GVariantIter *iter;
	const gchar *str = NULL;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), NULL);

	priv = TRACKER_MINER_MANAGER_GET_PRIVATE (manager);

	if (!priv->connection) {
		return NULL;
	}

	v = g_dbus_connection_call_sync (priv->connection,
	                                 "org.freedesktop.DBus",
	                                 "/org/freedesktop/DBus",
	                                 "org.freedesktop.DBus",
	                                 "ListNames",
	                                 NULL,
	                                 G_VARIANT_TYPE ("(as)"),
	                                 G_DBUS_CALL_FLAGS_NONE,
	                                 -1,
	                                 NULL,
	                                 &error);

	if (error) {
		g_critical ("Could not get a list of names registered on the session bus, %s",
		            error ? error->message : "no error given");
		g_clear_error (&error);
		return NULL;
	}

	g_variant_get (v, "(as)", &iter);
	while (g_variant_iter_loop (iter, "&s", &str)) {
		if (!g_str_has_prefix (str, TRACKER_MINER_DBUS_NAME_PREFIX)) {
			continue;
		}

		/* Special case miner-fs which has
		 * additional D-Bus interface.
		 */
		if (strcmp (str, "org.freedesktop.Tracker1.Miner.Files.Index") == 0) {
			continue;
		}

		list = g_slist_prepend (list, g_strdup (str));
	}

	g_variant_iter_free (iter);
	g_variant_unref (v);

	list = g_slist_reverse (list);

	return list;
}
/**
 * tracker_miner_manager_index_file:
 * @manager: a #TrackerMinerManager
 * @file: a URL valid in GIO of a file to give to the miner for processing
 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
 *
 * Tells the filesystem miner to index the @file.
 *
 * On failure @error will be set.
 *
 * Returns: %TRUE on success, otherwise %FALSE.
 *
 * Since: 0.10
 **/
gboolean
tracker_miner_manager_index_file (TrackerMinerManager  *manager,
                                  GFile                *file,
                                  GError              **error)
{
	TrackerMinerManagerPrivate *priv;
	gchar *uri;
	GVariant *v;
	GError *new_error = NULL;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (G_IS_FILE (file), FALSE);

	if (!g_file_query_exists (file, NULL)) {
		g_set_error_literal (error,
		                     TRACKER_MINER_MANAGER_ERROR,
		                     TRACKER_MINER_MANAGER_ERROR_NOENT,
		                     "File or directory does not exist");
		return FALSE;
	}

	if (!tracker_miner_manager_is_active (manager,
	                                      "org.freedesktop.Tracker1.Miner.Files")) {
		g_set_error_literal (error,
		                     TRACKER_MINER_MANAGER_ERROR,
		                     TRACKER_MINER_MANAGER_ERROR_NOT_AVAILABLE,
		                     "Filesystem miner is not active");
		return FALSE;
	}

	priv = TRACKER_MINER_MANAGER_GET_PRIVATE (manager);

	uri = g_file_get_uri (file);

	v = g_dbus_connection_call_sync (priv->connection,
	                                 "org.freedesktop.Tracker1.Miner.Files.Index",
	                                 "/org/freedesktop/Tracker1/Miner/Files/Index",
	                                 "org.freedesktop.Tracker1.Miner.Files.Index",
	                                 "IndexFile",
	                                 g_variant_new ("(s)", uri),
	                                 NULL,
	                                 G_DBUS_CALL_FLAGS_NONE,
	                                 -1,
	                                 NULL,
	                                 &new_error);

	g_free (uri);

	if (new_error) {
		g_propagate_error (error, new_error);
		return FALSE;
	}

	g_variant_unref (v);

	return FALSE;
}
/**
 * tracker_miner_manager_index_file:
 * @manager: a #TrackerMinerManager
 * @file: a URL valid in GIO of a file to give to the miner for processing
 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
 *
 * Tells the filesystem miner to start indexing the @file.
 *
 * On failure @error will be set.
 *
 * Returns: %TRUE on success, otherwise %FALSE.
 *
 * Since: 0.10
 **/
gboolean
tracker_miner_manager_index_file (TrackerMinerManager  *manager,
                                  GFile                *file,
                                  GError              **error)
{
	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (G_IS_FILE (file), FALSE);

	return miner_manager_index_file_sync (manager, file, NULL, error);
}
/**
 * tracker_miner_manager_pause_for_process:
 * @manager: a #TrackerMinerManager.
 * @miner: miner reference
 * @reason: reason to pause
 * @cookie: (out) (allow-none): return location for the pause cookie ID
 *
 * This function operates exactly the same way as
 * tracker_miner_manager_pause() with the exception that if the calling
 * process dies, the pause is resumed. This API is useful for cases
 * where the calling process has a risk of crashing without resuming
 * the pause.
 *
 * NOTE: If you call g_object_unref() on the @manager before you
 * intend to resume the pause and it finalizes, it will automatically
 * resume.
 *
 * Returns: %TRUE if the miner was paused successfully, otherwise
 * %FALSE.
 *
 * Since: 0.10.15
 **/
gboolean
tracker_miner_manager_pause_for_process (TrackerMinerManager *manager,
                                         const gchar         *miner,
                                         const gchar         *reason,
                                         guint32             *cookie)
{
	GDBusProxy *proxy;
	const gchar *app_name;
	GError *error = NULL;
	GVariant *v;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (miner != NULL, FALSE);
	g_return_val_if_fail (reason != NULL, FALSE);

	proxy = find_miner_proxy (manager, miner, TRUE);

	if (!proxy) {
		g_critical ("No D-Bus proxy found for miner '%s'", miner);
		return FALSE;
	}

	/* Find a reasonable app name */
	app_name = g_get_application_name ();

	if (!app_name) {
		app_name = g_get_prgname ();
	}

	if (!app_name) {
		app_name = "TrackerMinerManager client";
	}

	v = g_dbus_proxy_call_sync (proxy,
	                            "PauseForProcess",
	                            g_variant_new ("(ss)", app_name, reason),
	                            G_DBUS_CALL_FLAGS_NONE,
	                            -1,
	                            NULL,
	                            &error);

	if (error) {
		g_critical ("Could not pause miner '%s': %s", miner, error->message);
		g_error_free (error);
		return FALSE;
	}

	if (cookie) {
		g_variant_get (v, "(i)", cookie);
	}

	g_variant_unref (v);

	return TRUE;
}
/**
 * tracker_miner_manager_reindex_by_mimetype:
 * @manager: a #TrackerMinerManager
 * @mimetypes: (in): an array of mimetypes (E.G. "text/plain"). All items
 * with a mimetype in that list will be reindexed.
 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
 *
 * Tells the filesystem miner to reindex any file with a mimetype in
 * the @mimetypes list.
 *
 * On failure @error will be set.
 *
 * Returns: %TRUE on success, otherwise %FALSE.
 *
 * Since: 0.10
 **/
gboolean
tracker_miner_manager_reindex_by_mimetype (TrackerMinerManager  *manager,
                                           const GStrv           mimetypes,
                                           GError              **error)
{
	TrackerMinerManagerPrivate *priv;
	GVariant *v;
	GError *new_error = NULL;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (mimetypes != NULL, FALSE);

	if (!tracker_miner_manager_is_active (manager,
	                                      "org.freedesktop.Tracker1.Miner.Files")) {
		g_set_error_literal (error,
		                     TRACKER_MINER_MANAGER_ERROR,
		                     TRACKER_MINER_MANAGER_ERROR_NOT_AVAILABLE,
		                     "Filesystem miner is not active");
		return FALSE;
	}

	priv = TRACKER_MINER_MANAGER_GET_PRIVATE (manager);

	v = g_dbus_connection_call_sync (priv->connection,
	                                 "org.freedesktop.Tracker1.Miner.Files.Index",
	                                 "/org/freedesktop/Tracker1/Miner/Files/Index",
	                                 "org.freedesktop.Tracker1.Miner.Files.Index",
	                                 "ReindexMimeTypes",
	                                 g_variant_new ("(^as)", mimetypes),
	                                 NULL,
	                                 G_DBUS_CALL_FLAGS_NONE,
	                                 -1,
	                                 NULL,
	                                 &new_error);

	if (new_error) {
		g_propagate_error (error, new_error);
		return FALSE;
	}

	g_variant_unref (v);

	return FALSE;
}
/**
 * tracker_miner_manager_get_description:
 * @manager: a #TrackerMinerManager
 * @miner: miner reference
 *
 * Returns the description for the given @miner.
 *
 * Returns: (transfer none): A string which should not be freed or %NULL if none is specified.
 *
 * Since: 0.8
 **/
const gchar *
tracker_miner_manager_get_description (TrackerMinerManager *manager,
                                       const gchar         *miner)
{
	TrackerMinerManagerPrivate *priv;
	GList *m;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), NULL);
	g_return_val_if_fail (miner != NULL, NULL);

	priv = TRACKER_MINER_MANAGER_GET_PRIVATE (manager);

	for (m = priv->miners; m; m = m->next) {
		MinerData *data = m->data;

		if (strcmp (miner, data->dbus_name) == 0) {
			return data->description;
		}
	}

	return NULL;
}
/**
 * tracker_miner_manager_is_active:
 * @manager: a #TrackerMinerManager
 * @miner: miner reference
 *
 * Returns the miner's current activity.
 *
 * Returns: %TRUE if the @miner is active, otherwise %FALSE.
 *
 * Since: 0.8
 **/
gboolean
tracker_miner_manager_is_active (TrackerMinerManager *manager,
                                 const gchar         *miner)
{
	TrackerMinerManagerPrivate *priv;
	GError *error = NULL;
	gboolean active = FALSE;
	GVariant *v;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (miner != NULL, FALSE);

	priv = TRACKER_MINER_MANAGER_GET_PRIVATE (manager);

	v = g_dbus_connection_call_sync (priv->connection,
	                                 "org.freedesktop.DBus",
	                                 "/org/freedesktop/DBus",
	                                 "org.freedesktop.DBus",
	                                 "NameHasOwner",
	                                 g_variant_new ("(s)", miner),
	                                 (GVariantType *) "(b)",
	                                 G_DBUS_CALL_FLAGS_NONE,
	                                 -1,
	                                 NULL,
	                                 &error);

	if (error) {
		g_critical ("Could not check whether miner '%s' is currently active: %s",
		            miner, error ? error->message : "no error given");
		g_error_free (error);
		return FALSE;
	}

	g_variant_get (v, "(b)", &active);
	g_variant_unref (v);

	return active;
}
/**
 * tracker_miner_manager_ignore_next_update:
 * @manager: a #TrackerMinerManager
 * @miner: miner reference
 * @urls: (in): the subjects to ignore the next updates of
 *
 * Tells the @miner to ignore any events for the next @urls. This is
 * used for cases where a file is updated by Tracker by the
 * tracker-writeback service. This API is used to avoid signalling up
 * the stack the changes to @urls.
 *
 * Returns: %TRUE on success, otherwise %FALSE.
 *
 * Since: 0.8
 *
 * Deprecated: 0.12
 **/
gboolean
tracker_miner_manager_ignore_next_update (TrackerMinerManager *manager,
                                          const gchar         *miner,
                                          const gchar        **urls)
{
	GDBusProxy *proxy;
	GError *error = NULL;
	GVariant *v;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (miner != NULL, FALSE);

	proxy = find_miner_proxy (manager, miner, TRUE);

	if (!proxy) {
		g_warning ("No D-Bus proxy found for miner '%s'", miner);
		return FALSE;
	}

	v = g_dbus_proxy_call_sync (proxy,
	                            "IgnoreNextUpdate",
	                            g_variant_new ("(^as)", urls),
	                            G_DBUS_CALL_FLAGS_NONE,
	                            -1,
	                            NULL,
	                            &error);

	if (error) {
		g_warning ("Could not ignore next update for miner '%s': %s", miner, error->message);
		g_error_free (error);
		return FALSE;
	}

	g_variant_unref (v);

	return TRUE;
}
/**
 * tracker_miner_manager_resume:
 * @manager: a #TrackerMinerManager
 * @miner: miner reference
 * @cookie: pause cookie
 *
 * Tells @miner to resume activity. The miner won't actually resume
 * operations until all pause requests have been resumed.
 *
 * Returns: %TRUE if the miner was successfully resumed, otherwise
 * %FALSE.
 *
 * Since: 0.8
 **/
gboolean
tracker_miner_manager_resume (TrackerMinerManager *manager,
                              const gchar         *miner,
                              guint32              cookie)
{
	GDBusProxy *proxy;
	GError *error = NULL;
	GVariant *v;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (miner != NULL, FALSE);
	proxy = find_miner_proxy (manager, miner, TRUE);

	if (!proxy) {
		g_critical ("No D-Bus proxy found for miner '%s'", miner);
		return FALSE;
	}

	v = g_dbus_proxy_call_sync (proxy,
	                            "Resume",
	                            g_variant_new ("(i)", (gint) cookie),
	                            G_DBUS_CALL_FLAGS_NONE,
	                            -1,
	                            NULL,
	                            &error);

	if (error) {
		g_critical ("Could not resume miner '%s': %s", miner, error->message);
		g_error_free (error);
		return FALSE;
	}

	g_variant_unref (v);

	return TRUE;
}
/**
 * tracker_miner_manager_is_paused:
 * @manager: a #TrackerMinerManager
 * @miner: miner reference
 * @applications: (out callee-allocates) (allow-none) (transfer full):
 * return location for application names.
 * @reasons: (out callee-allocates) (allow-none) (transfer full):
 * return location for pause reasons.
 *
 * This function either returns %FALSE if the miner is not paused,
 * or returns %TRUE and fills in @applications and @reasons with
 * the pause reasons and the applications that asked for it. Both
 * arrays will have the same lengh, and will be sorted so the
 * application/pause reason pairs have the same index.
 *
 * Returns: %TRUE if @miner is paused, otherwise %FALSE.
 *
 * Since: 0.8
 **/
gboolean
tracker_miner_manager_is_paused (TrackerMinerManager *manager,
                                 const gchar         *miner,
                                 GStrv               *applications,
                                 GStrv               *reasons)
{
	GDBusProxy *proxy;
	GStrv apps, r;
	GError *error = NULL;
	gboolean paused;
	GVariant *v;

	if (applications) {
		*applications = NULL;
	}

	if (reasons) {
		*reasons = NULL;
	}

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), TRUE);
	g_return_val_if_fail (miner != NULL, TRUE);

	proxy = find_miner_proxy (manager, miner, TRUE);

	if (!proxy) {
		g_critical ("No D-Bus proxy found for miner '%s'", miner);
		return FALSE;
	}

	v = g_dbus_proxy_call_sync (proxy,
	                            "GetPauseDetails",
	                            NULL,
	                            G_DBUS_CALL_FLAGS_NONE,
	                            -1,
	                            NULL,
	                            &error);

	if (error) {
		g_critical ("Could not get pause details for miner '%s': %s", miner,
		            error->message);
		g_error_free (error);
		return FALSE;
	}

	g_variant_get (v, "(^as^as)", &apps, &r);
	g_variant_unref (v);

	paused = (g_strv_length (apps) > 0);

	if (applications) {
		*applications = apps;
	} else {
		g_strfreev (apps);
	}

	if (reasons) {
		*reasons = r;
	} else  {
		g_strfreev (r);
	}

	return paused;
}
/**
 * tracker_miner_manager_get_status:
 * @manager: a #TrackerMinerManager
 * @miner: miner reference
 * @status: (out) (allow-none): return location for status
 * @progress: (out) (allow-none): return location for progress
 * @remaining_time: (out) (allow-none): return location for remaining time
 *
 * Returns the current status, progress and remaining time for @miner.
 * @remaining_time will be 0 if not possible to compute it yet,
 * and less than zero if it is not applicable.
 *
 * Returns: %TRUE if the status could be retrieved successfully,
 * otherwise %FALSE
 *
 * Since: 0.12
 **/
gboolean
tracker_miner_manager_get_status (TrackerMinerManager  *manager,
                                  const gchar          *miner,
                                  gchar               **status,
                                  gdouble              *progress,
                                  gint                 *remaining_time)
{
	GDBusProxy *proxy;

	g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
	g_return_val_if_fail (miner != NULL, FALSE);
	/* At least one of them should be asked */
	g_return_val_if_fail (status != NULL ||
	                      progress != NULL ||
	                      remaining_time != NULL, FALSE);

	proxy = find_miner_proxy (manager, miner, TRUE);

	if (!proxy) {
		g_critical ("No D-Bus proxy found for miner '%s'", miner);
		return FALSE;
	}

	if (progress) {
		GError *error = NULL;
		GVariant *v;

		v = g_dbus_proxy_call_sync (proxy,
		                            "GetProgress",
		                            NULL,
		                            G_DBUS_CALL_FLAGS_NONE,
		                            -1,
		                            NULL,
		                            &error);
		if (error) {
			/* We handle this error as a special case, some
			 * plugins don't have .service files.
			 */
			if (error->code != G_DBUS_ERROR_SERVICE_UNKNOWN) {
				g_critical ("Could not get miner progress for '%s': %s", miner,
				            error->message);
			}

			g_error_free (error);

			return FALSE;
		}

		g_variant_get (v, "(d)", progress);
		g_variant_unref (v);
	}

	if (status) {
		GError *error = NULL;
		GVariant *v;

		v = g_dbus_proxy_call_sync (proxy,
		                            "GetStatus",
		                            NULL,
		                            G_DBUS_CALL_FLAGS_NONE,
		                            -1,
		                            NULL,
		                            &error);
		if (error) {
			g_critical ("Could not get miner status for '%s': %s", miner,
			            error->message);
			g_error_free (error);
			return FALSE;
		}

		g_variant_get (v, "(s)", status);
		g_variant_unref (v);
	}

	if (remaining_time) {
		GError *error = NULL;
		GVariant *v;

		v = g_dbus_proxy_call_sync (proxy,
		                            "GetRemainingTime",
		                            NULL,
		                            G_DBUS_CALL_FLAGS_NONE,
		                            -1,
		                            NULL,
		                            &error);
		if (error) {
			g_critical ("Could not get miner remaining processing "
			            "time for '%s': %s", miner,
			            error->message);
			g_error_free (error);
			return FALSE;
		}

		g_variant_get (v, "(i)", remaining_time);
		g_variant_unref (v);
	}

	return TRUE;
}