1 /*
2 * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
3 * Copyright (C) 2015 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #include <gio/gio.h>
24 #include <string.h>
25
26 #include <libtracker-common/tracker-dbus.h>
27 #include <libtracker-common/tracker-type-utils.h>
28 #include <libtracker-common/tracker-domain-ontology.h>
29 #include <libtracker-miner/tracker-miner.h>
30
31 #include "tracker-miner-manager.h"
32
33 /**
34 * SECTION:tracker-miner-manager
35 * @short_description: External control and monitoring of miners
36 * @include: libtracker-control/tracker-control.h
37 *
38 * #TrackerMinerManager keeps track of available miners, their current
39 * progress/status, and also allows basic external control on them, such
40 * as pausing or resuming data processing.
41 **/
42
43 #define DESKTOP_ENTRY_GROUP "D-BUS Service"
44 #define DBUS_NAME_SUFFIX_KEY "NameSuffix"
45 #define DBUS_PATH_KEY "Path"
46 #define DISPLAY_NAME_KEY "DisplayName"
47 #define DESCRIPTION_KEY "Comment"
48
49 #define METHOD_INDEX_FILE "IndexFile"
50 #define METHOD_INDEX_FILE_FOR_PROCESS "IndexFileForProcess"
51
52 typedef struct TrackerMinerManagerPrivate TrackerMinerManagerPrivate;
53 typedef struct MinerData MinerData;
54
55 struct MinerData {
56 gchar *dbus_name;
57 gchar *dbus_path;
58 gchar *display_name;
59 gchar *description;
60 gchar *name_suffix;
61
62 GDBusConnection *connection;
63 guint progress_signal;
64 guint paused_signal;
65 guint resumed_signal;
66 guint watch_name_id;
67 GObject *manager; /* weak */
68 };
69
70 struct TrackerMinerManagerPrivate {
71 GDBusConnection *connection;
72 GList *miners;
73 GHashTable *miner_proxies;
74
75 /* Property values */
76 gboolean auto_start;
77 gchar *domain_ontology_name;
78 TrackerDomainOntology *domain_ontology;
79 };
80
81 static void miner_manager_initable_iface_init (GInitableIface *iface);
82 static void miner_manager_set_property (GObject *object,
83 guint param_id,
84 const GValue *value,
85 GParamSpec *pspec);
86 static void miner_manager_get_property (GObject *object,
87 guint param_id,
88 GValue *value,
89 GParamSpec *pspec);
90 static void miner_manager_finalize (GObject *object);
91 static void initialize_miners_data (TrackerMinerManager *manager);
92
93 G_DEFINE_TYPE_WITH_CODE (TrackerMinerManager, tracker_miner_manager, G_TYPE_OBJECT,
94 G_ADD_PRIVATE (TrackerMinerManager)
95 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
96 miner_manager_initable_iface_init));
97
98 enum {
99 PROP_0,
100 PROP_AUTO_START,
101 PROP_DOMAIN_ONTOLOGY
102 };
103
104 enum {
105 MINER_PROGRESS,
106 MINER_PAUSED,
107 MINER_RESUMED,
108 MINER_ACTIVATED,
109 MINER_DEACTIVATED,
110 LAST_SIGNAL
111 };
112
113 static guint signals [LAST_SIGNAL] = { 0 };
114
115 static void
tracker_miner_manager_class_init(TrackerMinerManagerClass * klass)116 tracker_miner_manager_class_init (TrackerMinerManagerClass *klass)
117 {
118 GObjectClass *object_class = G_OBJECT_CLASS (klass);
119
120 object_class->set_property = miner_manager_set_property;
121 object_class->get_property = miner_manager_get_property;
122 object_class->finalize = miner_manager_finalize;
123
124 g_object_class_install_property (object_class,
125 PROP_AUTO_START,
126 g_param_spec_boolean ("auto-start",
127 "Auto Start",
128 "If set, auto starts miners when querying their status",
129 TRUE,
130 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
131 g_object_class_install_property (object_class,
132 PROP_DOMAIN_ONTOLOGY,
133 g_param_spec_string ("domain-ontology",
134 "Domain ontology",
135 "The domain ontology this object controls",
136 NULL,
137 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
138
139 /**
140 * TrackerMinerManager::miner-progress:
141 * @manager: the #TrackerMinerManager
142 * @miner: miner reference
143 * @status: miner status
144 * @progress: miner progress, from 0 to 1
145 * @remaining_time: remaining processing time
146 *
147 * The ::miner-progress signal is meant to report status/progress changes
148 * in any tracked miner.
149 *
150 * Since: 0.12
151 **/
152 signals [MINER_PROGRESS] =
153 g_signal_new ("miner-progress",
154 G_OBJECT_CLASS_TYPE (object_class),
155 G_SIGNAL_RUN_LAST,
156 G_STRUCT_OFFSET (TrackerMinerManagerClass, miner_progress),
157 NULL, NULL,
158 NULL,
159 G_TYPE_NONE, 4,
160 G_TYPE_STRING,
161 G_TYPE_STRING,
162 G_TYPE_DOUBLE,
163 G_TYPE_INT);
164 /**
165 * TrackerMinerManager::miner-paused:
166 * @manager: the #TrackerMinerManager
167 * @miner: miner reference
168 *
169 * The ::miner-paused signal will be emitted whenever a miner
170 * (referenced by @miner) is paused.
171 *
172 * Since: 0.8
173 **/
174 signals [MINER_PAUSED] =
175 g_signal_new ("miner-paused",
176 G_OBJECT_CLASS_TYPE (object_class),
177 G_SIGNAL_RUN_LAST,
178 G_STRUCT_OFFSET (TrackerMinerManagerClass, miner_paused),
179 NULL, NULL,
180 NULL,
181 G_TYPE_NONE, 1,
182 G_TYPE_STRING);
183 /**
184 * TrackerMinerManager::miner-resumed:
185 * @manager: the #TrackerMinerManager
186 * @miner: miner reference
187 *
188 * The ::miner-resumed signal will be emitted whenever a miner
189 * (referenced by @miner) is resumed.
190 *
191 * Since: 0.8
192 **/
193 signals [MINER_RESUMED] =
194 g_signal_new ("miner-resumed",
195 G_OBJECT_CLASS_TYPE (object_class),
196 G_SIGNAL_RUN_LAST,
197 G_STRUCT_OFFSET (TrackerMinerManagerClass, miner_resumed),
198 NULL, NULL,
199 NULL,
200 G_TYPE_NONE, 1,
201 G_TYPE_STRING);
202 /**
203 * TrackerMinerManager::miner-activated:
204 * @manager: the #TrackerMinerManager
205 * @miner: miner reference
206 *
207 * The ::miner-activated signal will be emitted whenever a miner
208 * (referenced by @miner) is activated (technically, this means
209 * the miner has appeared in the session bus).
210 *
211 * Since: 0.8
212 **/
213 signals [MINER_ACTIVATED] =
214 g_signal_new ("miner-activated",
215 G_OBJECT_CLASS_TYPE (object_class),
216 G_SIGNAL_RUN_LAST,
217 G_STRUCT_OFFSET (TrackerMinerManagerClass, miner_activated),
218 NULL, NULL,
219 NULL,
220 G_TYPE_NONE, 1,
221 G_TYPE_STRING);
222 /**
223 * TrackerMinerManager::miner-deactivated:
224 * @manager: the #TrackerMinerManager
225 * @miner: miner reference
226 *
227 * The ::miner-deactivated signal will be emitted whenever a miner
228 * (referenced by @miner) is deactivated (technically, this means
229 * the miner has disappeared from the session bus).
230 *
231 * Since: 0.8
232 **/
233 signals [MINER_DEACTIVATED] =
234 g_signal_new ("miner-deactivated",
235 G_OBJECT_CLASS_TYPE (object_class),
236 G_SIGNAL_RUN_LAST,
237 G_STRUCT_OFFSET (TrackerMinerManagerClass, miner_deactivated),
238 NULL, NULL,
239 NULL,
240 G_TYPE_NONE, 1,
241 G_TYPE_STRING);
242 }
243
244 static void
miner_manager_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)245 miner_manager_set_property (GObject *object,
246 guint prop_id,
247 const GValue *value,
248 GParamSpec *pspec)
249 {
250 TrackerMinerManager *manager;
251 TrackerMinerManagerPrivate *priv;
252
253 manager = TRACKER_MINER_MANAGER (object);
254 priv = tracker_miner_manager_get_instance_private (manager);
255
256 switch (prop_id) {
257 case PROP_AUTO_START:
258 priv->auto_start = g_value_get_boolean (value);
259 break;
260 case PROP_DOMAIN_ONTOLOGY:
261 priv->domain_ontology_name = g_value_dup_string (value);
262 break;
263 default:
264 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
265 break;
266 }
267 }
268
269 static void
miner_manager_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)270 miner_manager_get_property (GObject *object,
271 guint prop_id,
272 GValue *value,
273 GParamSpec *pspec)
274 {
275 TrackerMinerManager *manager;
276 TrackerMinerManagerPrivate *priv;
277
278 manager = TRACKER_MINER_MANAGER (object);
279 priv = tracker_miner_manager_get_instance_private (manager);
280
281 switch (prop_id) {
282 case PROP_AUTO_START:
283 g_value_set_boolean (value, priv->auto_start);
284 break;
285 case PROP_DOMAIN_ONTOLOGY:
286 g_value_set_string (value, priv->domain_ontology_name);
287 break;
288 default:
289 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
290 break;
291 }
292 }
293
294 static GDBusProxy *
find_miner_proxy(TrackerMinerManager * manager,const gchar * name,gboolean try_suffix)295 find_miner_proxy (TrackerMinerManager *manager,
296 const gchar *name,
297 gboolean try_suffix)
298 {
299 TrackerMinerManagerPrivate *priv;
300 GHashTableIter iter;
301 gpointer key, value;
302
303 priv = tracker_miner_manager_get_instance_private (manager);
304 g_hash_table_iter_init (&iter, priv->miner_proxies);
305
306 while (g_hash_table_iter_next (&iter, &key, &value)) {
307 if (g_strcmp0 (name, (gchar *) value) == 0) {
308 return key;
309 }
310
311 if (try_suffix) {
312 if (g_str_has_suffix (value, name)) {
313 return key;
314 }
315 }
316 }
317
318 return NULL;
319 }
320
321 static void
miner_appears(GDBusConnection * connection,const gchar * name,const gchar * name_owner,gpointer user_data)322 miner_appears (GDBusConnection *connection,
323 const gchar *name,
324 const gchar *name_owner,
325 gpointer user_data)
326 {
327 MinerData *data = user_data;
328 if (data->manager) {
329 g_signal_emit (data->manager, signals[MINER_ACTIVATED], 0, data->dbus_name);
330 }
331 }
332
333 static void
miner_disappears(GDBusConnection * connection,const gchar * name,gpointer user_data)334 miner_disappears (GDBusConnection *connection,
335 const gchar *name,
336 gpointer user_data)
337 {
338 MinerData *data = user_data;
339 if (data->manager) {
340 g_signal_emit (data->manager, signals[MINER_DEACTIVATED], 0, data->dbus_name);
341 }
342 }
343
344 static void
miner_progress_changed(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)345 miner_progress_changed (GDBusConnection *connection,
346 const gchar *sender_name,
347 const gchar *object_path,
348 const gchar *interface_name,
349 const gchar *signal_name,
350 GVariant *parameters,
351 gpointer user_data)
352 {
353 MinerData *data = user_data;
354 const gchar *status = NULL;
355 gdouble progress = 0;
356 gint remaining_time = -1;
357
358 g_variant_get (parameters, "(&sdi)", &status, &progress, &remaining_time);
359 if (data->manager) {
360 g_signal_emit (data->manager, signals[MINER_PROGRESS], 0, data->dbus_name, status, progress, remaining_time);
361 }
362 }
363
364 static void
miner_paused(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)365 miner_paused (GDBusConnection *connection,
366 const gchar *sender_name,
367 const gchar *object_path,
368 const gchar *interface_name,
369 const gchar *signal_name,
370 GVariant *parameters,
371 gpointer user_data)
372 {
373 MinerData *data = user_data;
374 if (data->manager) {
375 g_signal_emit (data->manager, signals[MINER_PAUSED], 0, data->dbus_name);
376 }
377 }
378
379 static void
miner_resumed(GDBusConnection * connection,const gchar * sender_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,gpointer user_data)380 miner_resumed (GDBusConnection *connection,
381 const gchar *sender_name,
382 const gchar *object_path,
383 const gchar *interface_name,
384 const gchar *signal_name,
385 GVariant *parameters,
386 gpointer user_data)
387 {
388 MinerData *data = user_data;
389 if (data->manager) {
390 g_signal_emit (data->manager, signals[MINER_RESUMED], 0, data->dbus_name);
391 }
392 }
393
394 static void
data_manager_weak_notify(gpointer user_data,GObject * old_object)395 data_manager_weak_notify (gpointer user_data, GObject *old_object)
396 {
397 MinerData *data = user_data;
398 data->manager = NULL;
399 }
400
401 static void
tracker_miner_manager_init(TrackerMinerManager * manager)402 tracker_miner_manager_init (TrackerMinerManager *manager)
403 {
404 TrackerMinerManagerPrivate *priv;
405
406 priv = tracker_miner_manager_get_instance_private (manager);
407
408 priv->miner_proxies = g_hash_table_new_full (NULL, NULL,
409 (GDestroyNotify) g_object_unref,
410 (GDestroyNotify) g_free);
411 }
412
413 static gboolean
miner_manager_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)414 miner_manager_initable_init (GInitable *initable,
415 GCancellable *cancellable,
416 GError **error)
417 {
418 TrackerMinerManager *manager;
419 GError *inner_error = NULL;
420 TrackerMinerManagerPrivate *priv;
421 GList *m;
422
423 manager = TRACKER_MINER_MANAGER (initable);
424 priv = tracker_miner_manager_get_instance_private (manager);
425
426 priv->connection = g_bus_get_sync (TRACKER_IPC_BUS, NULL, &inner_error);
427 if (!priv->connection) {
428 g_propagate_error (error, inner_error);
429 return FALSE;
430 }
431
432 priv->domain_ontology = tracker_domain_ontology_new (priv->domain_ontology_name,
433 cancellable, &inner_error);
434 if (!priv->domain_ontology) {
435 g_propagate_error (error, inner_error);
436 return FALSE;
437 }
438
439 initialize_miners_data (manager);
440
441 for (m = priv->miners; m; m = m->next) {
442 GDBusProxy *proxy;
443 MinerData *data;
444
445 data = m->data;
446 data->connection = g_object_ref (priv->connection);
447 data->manager = G_OBJECT (manager);
448 g_object_weak_ref (data->manager, data_manager_weak_notify, data);
449
450 proxy = g_dbus_proxy_new_sync (priv->connection,
451 (priv->auto_start ?
452 G_DBUS_PROXY_FLAGS_NONE :
453 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START),
454 NULL,
455 data->dbus_name,
456 data->dbus_path,
457 TRACKER_MINER_DBUS_INTERFACE,
458 NULL,
459 &inner_error);
460 /* This error shouldn't be considered fatal */
461 if (inner_error) {
462 g_critical ("Could not create proxy on the D-Bus session bus, %s",
463 inner_error ? inner_error->message : "no error given.");
464 g_clear_error (&inner_error);
465 continue;
466 }
467
468 data->progress_signal = g_dbus_connection_signal_subscribe (priv->connection,
469 data->dbus_name,
470 TRACKER_MINER_DBUS_INTERFACE,
471 "Progress",
472 data->dbus_path,
473 NULL,
474 G_DBUS_SIGNAL_FLAGS_NONE,
475 miner_progress_changed,
476 data,
477 NULL);
478
479 data->paused_signal = g_dbus_connection_signal_subscribe (priv->connection,
480 data->dbus_name,
481 TRACKER_MINER_DBUS_INTERFACE,
482 "Paused",
483 data->dbus_path,
484 NULL,
485 G_DBUS_SIGNAL_FLAGS_NONE,
486 miner_paused,
487 data,
488 NULL);
489
490
491 data->resumed_signal = g_dbus_connection_signal_subscribe (priv->connection,
492 data->dbus_name,
493 TRACKER_MINER_DBUS_INTERFACE,
494 "Resumed",
495 data->dbus_path,
496 NULL,
497 G_DBUS_SIGNAL_FLAGS_NONE,
498 miner_resumed,
499 data,
500 NULL);
501
502 g_hash_table_insert (priv->miner_proxies, proxy, g_strdup (data->dbus_name));
503
504 data->watch_name_id = g_bus_watch_name (TRACKER_IPC_BUS,
505 data->dbus_name,
506 G_BUS_NAME_WATCHER_FLAGS_NONE,
507 miner_appears,
508 miner_disappears,
509 data,
510 NULL);
511
512 }
513
514 return TRUE;
515 }
516
517 static void
miner_manager_initable_iface_init(GInitableIface * iface)518 miner_manager_initable_iface_init (GInitableIface *iface)
519 {
520 iface->init = miner_manager_initable_init;
521 }
522
523
524 static void
miner_data_free(MinerData * data)525 miner_data_free (MinerData *data)
526 {
527 if (data->watch_name_id != 0) {
528 g_bus_unwatch_name (data->watch_name_id);
529 }
530
531 if (data->progress_signal) {
532 g_dbus_connection_signal_unsubscribe (data->connection,
533 data->progress_signal);
534 }
535
536 if (data->paused_signal) {
537 g_dbus_connection_signal_unsubscribe (data->connection,
538 data->paused_signal);
539 }
540
541 if (data->resumed_signal) {
542 g_dbus_connection_signal_unsubscribe (data->connection,
543 data->resumed_signal);
544 }
545
546 if (data->connection) {
547 g_object_unref (data->connection);
548 }
549
550 if (data->manager) {
551 g_object_weak_unref (data->manager, data_manager_weak_notify, data);
552 }
553
554 g_free (data->dbus_path);
555 g_free (data->dbus_name);
556 g_free (data->display_name);
557 g_free (data->description);
558 g_free (data->name_suffix);
559 g_slice_free (MinerData, data);
560 }
561
562 static void
miner_manager_finalize(GObject * object)563 miner_manager_finalize (GObject *object)
564 {
565 TrackerMinerManagerPrivate *priv;
566
567 priv = tracker_miner_manager_get_instance_private (TRACKER_MINER_MANAGER (object));
568
569 if (priv->connection) {
570 g_object_unref (priv->connection);
571 }
572
573 g_list_foreach (priv->miners, (GFunc) miner_data_free, NULL);
574 g_list_free (priv->miners);
575 g_hash_table_unref (priv->miner_proxies);
576 g_free (priv->domain_ontology_name);
577 g_clear_pointer (&priv->domain_ontology, tracker_domain_ontology_unref);
578
579 G_OBJECT_CLASS (tracker_miner_manager_parent_class)->finalize (object);
580 }
581
582 /**
583 * tracker_miner_manager_new:
584 *
585 * Creates a new #TrackerMinerManager instance.
586 *
587 * Note: Auto-starting miners when querying status will be enabled.
588 *
589 * Returns: a #TrackerMinerManager or #NULL if an error happened.
590 *
591 * Since: 0.8
592 **/
593 TrackerMinerManager *
tracker_miner_manager_new(void)594 tracker_miner_manager_new (void)
595 {
596 GError *inner_error = NULL;
597 TrackerMinerManager *manager;
598
599 manager = g_initable_new (TRACKER_TYPE_MINER_MANAGER,
600 NULL,
601 &inner_error,
602 NULL);
603 if (!manager) {
604 g_critical ("Couldn't create new TrackerMinerManager: '%s'",
605 inner_error ? inner_error->message : "unknown error");
606 g_clear_error (&inner_error);
607 }
608
609 return manager;
610 }
611
612 /**
613 * tracker_miner_manager_new_full:
614 * @auto_start: Flag to disable auto-starting the miners when querying status
615 * @error: a #GError to report errors.
616 *
617 * Creates a new #TrackerMinerManager.
618 *
619 * Returns: a #TrackerMinerManager. On error, #NULL is returned and @error is set
620 * accordingly.
621 *
622 * Since: 0.10.5
623 **/
624 TrackerMinerManager *
tracker_miner_manager_new_full(gboolean auto_start,GError ** error)625 tracker_miner_manager_new_full (gboolean auto_start,
626 GError **error)
627 {
628 GError *inner_error = NULL;
629 TrackerMinerManager *manager;
630 const gchar *domain_ontology;
631
632 domain_ontology = tracker_sparql_connection_get_domain ();
633 manager = g_initable_new (TRACKER_TYPE_MINER_MANAGER,
634 NULL,
635 &inner_error,
636 "domain-ontology", domain_ontology,
637 "auto-start", auto_start,
638 NULL);
639 if (inner_error)
640 g_propagate_error (error, inner_error);
641
642 return manager;
643 }
644
645 /**
646 * tracker_miner_manager_get_running:
647 * @manager: a #trackerMinerManager
648 *
649 * Returns a list of references for all active miners. Active miners
650 * are miners which are running within a process.
651 *
652 * Returns: (transfer full) (element-type utf8) (nullable): a #GSList which
653 * must be freed with g_slist_free() and all contained data with g_free().
654 * Otherwise %NULL is returned if there are no miners.
655 *
656 * Since: 0.8
657 **/
658 GSList *
tracker_miner_manager_get_running(TrackerMinerManager * manager)659 tracker_miner_manager_get_running (TrackerMinerManager *manager)
660 {
661 TrackerMinerManagerPrivate *priv;
662 GSList *list = NULL;
663 GError *error = NULL;
664 GVariant *v;
665 GVariantIter *iter;
666 const gchar *str = NULL;
667 gchar *prefix;
668
669 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), NULL);
670
671 priv = tracker_miner_manager_get_instance_private (manager);
672
673 if (!priv->connection) {
674 return NULL;
675 }
676
677 v = g_dbus_connection_call_sync (priv->connection,
678 "org.freedesktop.DBus",
679 "/org/freedesktop/DBus",
680 "org.freedesktop.DBus",
681 "ListNames",
682 NULL,
683 G_VARIANT_TYPE ("(as)"),
684 G_DBUS_CALL_FLAGS_NONE,
685 -1,
686 NULL,
687 &error);
688
689 if (error) {
690 g_critical ("Could not get a list of names registered on the session bus, %s",
691 error ? error->message : "no error given");
692 g_clear_error (&error);
693 return NULL;
694 }
695
696 prefix = tracker_domain_ontology_get_domain (priv->domain_ontology, "Tracker1.Miner");
697
698 g_variant_get (v, "(as)", &iter);
699 while (g_variant_iter_loop (iter, "&s", &str)) {
700 if (!g_str_has_prefix (str, prefix)) {
701 continue;
702 }
703
704 list = g_slist_prepend (list, g_strdup (str));
705 }
706
707 g_variant_iter_free (iter);
708 g_variant_unref (v);
709 g_free (prefix);
710
711 list = g_slist_reverse (list);
712
713 return list;
714 }
715
716 static void
check_file(GFile * file,gpointer user_data)717 check_file (GFile *file,
718 gpointer user_data)
719 {
720 TrackerMinerManager *manager;
721 TrackerMinerManagerPrivate *priv;
722 GKeyFile *key_file;
723 gchar *path, *dbus_path, *display_name, *name_suffix, *full_name_suffix, *description;
724 GError *error = NULL;
725 MinerData *data;
726
727 manager = user_data;
728 path = g_file_get_path (file);
729 priv = tracker_miner_manager_get_instance_private (manager);
730
731 key_file = g_key_file_new ();
732 g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
733
734 if (error) {
735 g_warning ("Error parsing miner .desktop file: %s", error->message);
736 g_error_free (error);
737 g_key_file_free (key_file);
738 return;
739 }
740
741 dbus_path = g_key_file_get_string (key_file, DESKTOP_ENTRY_GROUP, DBUS_PATH_KEY, NULL);
742 display_name = g_key_file_get_locale_string (key_file, DESKTOP_ENTRY_GROUP, DISPLAY_NAME_KEY, NULL, NULL);
743 name_suffix = g_key_file_get_string (key_file, DESKTOP_ENTRY_GROUP, DBUS_NAME_SUFFIX_KEY, NULL);
744
745 if (!dbus_path || !display_name || !name_suffix) {
746 g_warning ("Essential data (DBusPath, NameSuffix or Name) are missing in miner .desktop file");
747 g_key_file_free (key_file);
748 g_free (dbus_path);
749 g_free (display_name);
750 g_free (name_suffix);
751 return;
752 }
753
754 if (!tracker_domain_ontology_uses_miner (priv->domain_ontology, name_suffix)) {
755 /* Silently ignore, this domain ontology is not meant to use this miner */
756 g_key_file_free (key_file);
757 g_free (dbus_path);
758 g_free (display_name);
759 g_free (name_suffix);
760 return;
761 }
762
763 description = g_key_file_get_locale_string (key_file, DESKTOP_ENTRY_GROUP, DESCRIPTION_KEY, NULL, NULL);
764
765 data = g_slice_new0 (MinerData);
766 data->dbus_path = dbus_path;
767 data->name_suffix = name_suffix;
768
769 full_name_suffix = g_strconcat ("Tracker1.", name_suffix, NULL);
770 data->dbus_name = tracker_domain_ontology_get_domain (priv->domain_ontology,
771 full_name_suffix);
772 g_free (full_name_suffix);
773
774 data->display_name = display_name;
775 data->description = description; /* In .desktop file as _comment */
776
777 priv->miners = g_list_prepend (priv->miners, data);
778
779 g_key_file_free (key_file);
780 g_free (path);
781
782 return;
783 }
784
785 static void
directory_foreach(GFile * file,gchar * suffix,GFunc func,gpointer user_data)786 directory_foreach (GFile *file,
787 gchar *suffix,
788 GFunc func,
789 gpointer user_data)
790 {
791 GFileEnumerator *enumerator;
792 GFileInfo *info;
793 GFile *child;
794
795 enumerator = g_file_enumerate_children (file,
796 G_FILE_ATTRIBUTE_STANDARD_NAME,
797 G_FILE_QUERY_INFO_NONE,
798 NULL,
799 NULL);
800
801 if (!enumerator) {
802 return;
803 }
804
805 while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) {
806
807 if (!suffix || g_str_has_suffix (g_file_info_get_name (info), suffix)) {
808 child = g_file_enumerator_get_child (enumerator, info);
809 (func) (child, user_data);
810 g_object_unref (child);
811 }
812
813 g_object_unref (info);
814 }
815
816 g_object_unref (enumerator);
817 }
818
819 static void
initialize_miners_data(TrackerMinerManager * manager)820 initialize_miners_data (TrackerMinerManager *manager)
821 {
822 GFile *file;
823
824 /* Go through service files */
825 file = g_file_new_for_path (TRACKER_MINERS_DIR);
826 directory_foreach (file, ".service", (GFunc) check_file, manager);
827 g_object_unref (file);
828 }
829
830 /**
831 * tracker_miner_manager_get_available:
832 * @manager: a #TrackerMinerManager
833 *
834 * Returns a list of references for all available miners. Available
835 * miners are miners which may or may not be running in a process at
836 * the current time.
837 *
838 * Returns: (transfer full) (element-type utf8) (nullable): a #GSList which
839 * must be freed with g_slist_free() and all contained data with g_free().
840 * Otherwise %NULL is returned if there are no miners.
841 *
842 * Since: 0.8
843 **/
844 GSList *
tracker_miner_manager_get_available(TrackerMinerManager * manager)845 tracker_miner_manager_get_available (TrackerMinerManager *manager)
846 {
847 TrackerMinerManagerPrivate *priv;
848 GSList *list = NULL;
849 GList *m;
850
851 priv = tracker_miner_manager_get_instance_private (manager);
852
853 for (m = priv->miners; m; m = m->next) {
854 MinerData *data = m->data;
855
856 list = g_slist_prepend (list, g_strdup (data->dbus_name));
857 }
858
859 return g_slist_reverse (list);
860 }
861
862 /**
863 * tracker_miner_manager_pause:
864 * @manager: a #TrackerMinerManager.
865 * @miner: miner reference
866 * @reason: reason to pause
867 * @cookie: (out) (allow-none): return location for the pause cookie ID
868 *
869 * Asks @miner to pause. a miner could be paused by
870 * several reasons, and its activity won't be resumed
871 * until all pause requests have been resumed.
872 *
873 * Returns: %TRUE if the miner was paused successfully, otherwise
874 * %FALSE.
875 *
876 * Since: 0.8
877 **/
878 gboolean
tracker_miner_manager_pause(TrackerMinerManager * manager,const gchar * miner,const gchar * reason,guint32 * cookie)879 tracker_miner_manager_pause (TrackerMinerManager *manager,
880 const gchar *miner,
881 const gchar *reason,
882 guint32 *cookie)
883 {
884 GDBusProxy *proxy;
885 const gchar *app_name;
886 GError *error = NULL;
887 GVariant *v;
888
889 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
890 g_return_val_if_fail (miner != NULL, FALSE);
891 g_return_val_if_fail (reason != NULL, FALSE);
892
893 proxy = find_miner_proxy (manager, miner, TRUE);
894
895 if (!proxy) {
896 g_critical ("No D-Bus proxy found for miner '%s'", miner);
897 return FALSE;
898 }
899
900 /* Find a reasonable app name */
901 app_name = g_get_application_name ();
902
903 if (!app_name) {
904 app_name = g_get_prgname ();
905 }
906
907 if (!app_name) {
908 app_name = "TrackerMinerManager client";
909 }
910
911 v = g_dbus_proxy_call_sync (proxy,
912 "Pause",
913 g_variant_new ("(ss)", app_name, reason),
914 G_DBUS_CALL_FLAGS_NONE,
915 -1,
916 NULL,
917 &error);
918
919 if (error) {
920 g_critical ("Could not pause miner '%s': %s", miner, error->message);
921 g_error_free (error);
922 return FALSE;
923 }
924
925 if (cookie) {
926 g_variant_get (v, "(i)", cookie);
927 }
928
929 g_variant_unref (v);
930
931 return TRUE;
932 }
933
934 /**
935 * tracker_miner_manager_pause_for_process:
936 * @manager: a #TrackerMinerManager.
937 * @miner: miner reference
938 * @reason: reason to pause
939 * @cookie: (out) (allow-none): return location for the pause cookie ID
940 *
941 * This function operates exactly the same way as
942 * tracker_miner_manager_pause() with the exception that if the calling
943 * process dies, the pause is resumed. This API is useful for cases
944 * where the calling process has a risk of crashing without resuming
945 * the pause.
946 *
947 * NOTE: If you call g_object_unref() on the @manager before you
948 * intend to resume the pause and it finalizes, it will automatically
949 * resume.
950 *
951 * Returns: %TRUE if the miner was paused successfully, otherwise
952 * %FALSE.
953 *
954 * Since: 0.10.15
955 **/
956 gboolean
tracker_miner_manager_pause_for_process(TrackerMinerManager * manager,const gchar * miner,const gchar * reason,guint32 * cookie)957 tracker_miner_manager_pause_for_process (TrackerMinerManager *manager,
958 const gchar *miner,
959 const gchar *reason,
960 guint32 *cookie)
961 {
962 GDBusProxy *proxy;
963 const gchar *app_name;
964 GError *error = NULL;
965 GVariant *v;
966
967 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
968 g_return_val_if_fail (miner != NULL, FALSE);
969 g_return_val_if_fail (reason != NULL, FALSE);
970
971 proxy = find_miner_proxy (manager, miner, TRUE);
972
973 if (!proxy) {
974 g_critical ("No D-Bus proxy found for miner '%s'", miner);
975 return FALSE;
976 }
977
978 /* Find a reasonable app name */
979 app_name = g_get_application_name ();
980
981 if (!app_name) {
982 app_name = g_get_prgname ();
983 }
984
985 if (!app_name) {
986 app_name = "TrackerMinerManager client";
987 }
988
989 v = g_dbus_proxy_call_sync (proxy,
990 "PauseForProcess",
991 g_variant_new ("(ss)", app_name, reason),
992 G_DBUS_CALL_FLAGS_NONE,
993 -1,
994 NULL,
995 &error);
996
997 if (error) {
998 g_critical ("Could not pause miner '%s': %s", miner, error->message);
999 g_error_free (error);
1000 return FALSE;
1001 }
1002
1003 if (cookie) {
1004 g_variant_get (v, "(i)", cookie);
1005 }
1006
1007 g_variant_unref (v);
1008
1009 return TRUE;
1010 }
1011
1012 /**
1013 * tracker_miner_manager_resume:
1014 * @manager: a #TrackerMinerManager
1015 * @miner: miner reference
1016 * @cookie: pause cookie
1017 *
1018 * Tells @miner to resume activity. The miner won't actually resume
1019 * operations until all pause requests have been resumed.
1020 *
1021 * Returns: %TRUE if the miner was successfully resumed, otherwise
1022 * %FALSE.
1023 *
1024 * Since: 0.8
1025 **/
1026 gboolean
tracker_miner_manager_resume(TrackerMinerManager * manager,const gchar * miner,guint32 cookie)1027 tracker_miner_manager_resume (TrackerMinerManager *manager,
1028 const gchar *miner,
1029 guint32 cookie)
1030 {
1031 GDBusProxy *proxy;
1032 GError *error = NULL;
1033 GVariant *v;
1034
1035 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
1036 g_return_val_if_fail (miner != NULL, FALSE);
1037 proxy = find_miner_proxy (manager, miner, TRUE);
1038
1039 if (!proxy) {
1040 g_critical ("No D-Bus proxy found for miner '%s'", miner);
1041 return FALSE;
1042 }
1043
1044 v = g_dbus_proxy_call_sync (proxy,
1045 "Resume",
1046 g_variant_new ("(i)", (gint) cookie),
1047 G_DBUS_CALL_FLAGS_NONE,
1048 -1,
1049 NULL,
1050 &error);
1051
1052 if (error) {
1053 g_critical ("Could not resume miner '%s': %s", miner, error->message);
1054 g_error_free (error);
1055 return FALSE;
1056 }
1057
1058 g_variant_unref (v);
1059
1060 return TRUE;
1061 }
1062
1063 /**
1064 * tracker_miner_manager_is_active:
1065 * @manager: a #TrackerMinerManager
1066 * @miner: miner reference
1067 *
1068 * Returns the miner's current activity.
1069 *
1070 * Returns: %TRUE if the @miner is active, otherwise %FALSE.
1071 *
1072 * Since: 0.8
1073 **/
1074 gboolean
tracker_miner_manager_is_active(TrackerMinerManager * manager,const gchar * miner)1075 tracker_miner_manager_is_active (TrackerMinerManager *manager,
1076 const gchar *miner)
1077 {
1078 TrackerMinerManagerPrivate *priv;
1079 GError *error = NULL;
1080 gboolean active = FALSE;
1081 GVariant *v;
1082
1083 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
1084 g_return_val_if_fail (miner != NULL, FALSE);
1085
1086 priv = tracker_miner_manager_get_instance_private (manager);
1087
1088 v = g_dbus_connection_call_sync (priv->connection,
1089 "org.freedesktop.DBus",
1090 "/org/freedesktop/DBus",
1091 "org.freedesktop.DBus",
1092 "NameHasOwner",
1093 g_variant_new ("(s)", miner),
1094 (GVariantType *) "(b)",
1095 G_DBUS_CALL_FLAGS_NONE,
1096 -1,
1097 NULL,
1098 &error);
1099
1100 if (error) {
1101 g_critical ("Could not check whether miner '%s' is currently active: %s",
1102 miner, error ? error->message : "no error given");
1103 g_error_free (error);
1104 return FALSE;
1105 }
1106
1107 g_variant_get (v, "(b)", &active);
1108 g_variant_unref (v);
1109
1110 return active;
1111 }
1112
1113 /**
1114 * tracker_miner_manager_get_status:
1115 * @manager: a #TrackerMinerManager
1116 * @miner: miner reference
1117 * @status: (out) (allow-none): return location for status
1118 * @progress: (out) (allow-none): return location for progress
1119 * @remaining_time: (out) (allow-none): return location for remaining time
1120 *
1121 * Returns the current status, progress and remaining time for @miner.
1122 * @remaining_time will be 0 if not possible to compute it yet,
1123 * and less than zero if it is not applicable.
1124 *
1125 * Returns: %TRUE if the status could be retrieved successfully,
1126 * otherwise %FALSE
1127 *
1128 * Since: 0.12
1129 **/
1130 gboolean
tracker_miner_manager_get_status(TrackerMinerManager * manager,const gchar * miner,gchar ** status,gdouble * progress,gint * remaining_time)1131 tracker_miner_manager_get_status (TrackerMinerManager *manager,
1132 const gchar *miner,
1133 gchar **status,
1134 gdouble *progress,
1135 gint *remaining_time)
1136 {
1137 GDBusProxy *proxy;
1138
1139 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
1140 g_return_val_if_fail (miner != NULL, FALSE);
1141 /* At least one of them should be asked */
1142 g_return_val_if_fail (status != NULL ||
1143 progress != NULL ||
1144 remaining_time != NULL, FALSE);
1145
1146 proxy = find_miner_proxy (manager, miner, TRUE);
1147
1148 if (!proxy) {
1149 g_critical ("No D-Bus proxy found for miner '%s'", miner);
1150 return FALSE;
1151 }
1152
1153 if (progress) {
1154 GError *error = NULL;
1155 GVariant *v;
1156
1157 v = g_dbus_proxy_call_sync (proxy,
1158 "GetProgress",
1159 NULL,
1160 G_DBUS_CALL_FLAGS_NONE,
1161 -1,
1162 NULL,
1163 &error);
1164 if (error) {
1165 /* We handle this error as a special case, some
1166 * plugins don't have .service files.
1167 */
1168 if (error->code != G_DBUS_ERROR_SERVICE_UNKNOWN) {
1169 g_critical ("Could not get miner progress for '%s': %s", miner,
1170 error->message);
1171 }
1172
1173 g_error_free (error);
1174
1175 return FALSE;
1176 }
1177
1178 g_variant_get (v, "(d)", progress);
1179 g_variant_unref (v);
1180 }
1181
1182 if (status) {
1183 GError *error = NULL;
1184 GVariant *v;
1185
1186 v = g_dbus_proxy_call_sync (proxy,
1187 "GetStatus",
1188 NULL,
1189 G_DBUS_CALL_FLAGS_NONE,
1190 -1,
1191 NULL,
1192 &error);
1193 if (error) {
1194 g_critical ("Could not get miner status for '%s': %s", miner,
1195 error->message);
1196 g_error_free (error);
1197 return FALSE;
1198 }
1199
1200 g_variant_get (v, "(s)", status);
1201 g_variant_unref (v);
1202 }
1203
1204 if (remaining_time) {
1205 GError *error = NULL;
1206 GVariant *v;
1207
1208 v = g_dbus_proxy_call_sync (proxy,
1209 "GetRemainingTime",
1210 NULL,
1211 G_DBUS_CALL_FLAGS_NONE,
1212 -1,
1213 NULL,
1214 &error);
1215 if (error) {
1216 g_critical ("Could not get miner remaining processing "
1217 "time for '%s': %s", miner,
1218 error->message);
1219 g_error_free (error);
1220 return FALSE;
1221 }
1222
1223 g_variant_get (v, "(i)", remaining_time);
1224 g_variant_unref (v);
1225 }
1226
1227 return TRUE;
1228 }
1229
1230 /**
1231 * tracker_miner_manager_is_paused:
1232 * @manager: a #TrackerMinerManager
1233 * @miner: miner reference
1234 * @applications: (out callee-allocates) (allow-none) (transfer full):
1235 * return location for application names.
1236 * @reasons: (out callee-allocates) (allow-none) (transfer full):
1237 * return location for pause reasons.
1238 *
1239 * This function either returns %FALSE if the miner is not paused,
1240 * or returns %TRUE and fills in @applications and @reasons with
1241 * the pause reasons and the applications that asked for it. Both
1242 * arrays will have the same lengh, and will be sorted so the
1243 * application/pause reason pairs have the same index.
1244 *
1245 * Returns: %TRUE if @miner is paused, otherwise %FALSE.
1246 *
1247 * Since: 0.8
1248 **/
1249 gboolean
tracker_miner_manager_is_paused(TrackerMinerManager * manager,const gchar * miner,GStrv * applications,GStrv * reasons)1250 tracker_miner_manager_is_paused (TrackerMinerManager *manager,
1251 const gchar *miner,
1252 GStrv *applications,
1253 GStrv *reasons)
1254 {
1255 GDBusProxy *proxy;
1256 GStrv apps, r;
1257 GError *error = NULL;
1258 gboolean paused;
1259 GVariant *v;
1260
1261 if (applications) {
1262 *applications = NULL;
1263 }
1264
1265 if (reasons) {
1266 *reasons = NULL;
1267 }
1268
1269 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), TRUE);
1270 g_return_val_if_fail (miner != NULL, TRUE);
1271
1272 proxy = find_miner_proxy (manager, miner, TRUE);
1273
1274 if (!proxy) {
1275 g_critical ("No D-Bus proxy found for miner '%s'", miner);
1276 return FALSE;
1277 }
1278
1279 v = g_dbus_proxy_call_sync (proxy,
1280 "GetPauseDetails",
1281 NULL,
1282 G_DBUS_CALL_FLAGS_NONE,
1283 -1,
1284 NULL,
1285 &error);
1286
1287 if (error) {
1288 g_critical ("Could not get pause details for miner '%s': %s", miner,
1289 error->message);
1290 g_error_free (error);
1291 return FALSE;
1292 }
1293
1294 g_variant_get (v, "(^as^as)", &apps, &r);
1295 g_variant_unref (v);
1296
1297 paused = (g_strv_length (apps) > 0);
1298
1299 if (applications) {
1300 *applications = apps;
1301 } else {
1302 g_strfreev (apps);
1303 }
1304
1305 if (reasons) {
1306 *reasons = r;
1307 } else {
1308 g_strfreev (r);
1309 }
1310
1311 return paused;
1312 }
1313
1314 /**
1315 * tracker_miner_manager_get_display_name:
1316 * @manager: a #TrackerMinerManager
1317 * @miner: miner reference
1318 *
1319 * Returns a translated display name for @miner.
1320 *
1321 * Returns: (transfer none): A string which should not be freed or %NULL.
1322 *
1323 * Since: 0.8
1324 **/
1325 const gchar *
tracker_miner_manager_get_display_name(TrackerMinerManager * manager,const gchar * miner)1326 tracker_miner_manager_get_display_name (TrackerMinerManager *manager,
1327 const gchar *miner)
1328 {
1329 TrackerMinerManagerPrivate *priv;
1330 GList *m;
1331
1332 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), NULL);
1333 g_return_val_if_fail (miner != NULL, NULL);
1334
1335 priv = tracker_miner_manager_get_instance_private (manager);
1336
1337 for (m = priv->miners; m; m = m->next) {
1338 MinerData *data = m->data;
1339
1340 if (strcmp (miner, data->dbus_name) == 0) {
1341 return data->display_name;
1342 }
1343 }
1344
1345 return NULL;
1346 }
1347
1348 /**
1349 * tracker_miner_manager_get_description:
1350 * @manager: a #TrackerMinerManager
1351 * @miner: miner reference
1352 *
1353 * Returns the description for the given @miner.
1354 *
1355 * Returns: (transfer none): A string which should not be freed or %NULL if none is specified.
1356 *
1357 * Since: 0.8
1358 **/
1359 const gchar *
tracker_miner_manager_get_description(TrackerMinerManager * manager,const gchar * miner)1360 tracker_miner_manager_get_description (TrackerMinerManager *manager,
1361 const gchar *miner)
1362 {
1363 TrackerMinerManagerPrivate *priv;
1364 GList *m;
1365
1366 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), NULL);
1367 g_return_val_if_fail (miner != NULL, NULL);
1368
1369 priv = tracker_miner_manager_get_instance_private (manager);
1370
1371 for (m = priv->miners; m; m = m->next) {
1372 MinerData *data = m->data;
1373
1374 if (strcmp (miner, data->dbus_name) == 0) {
1375 return data->description;
1376 }
1377 }
1378
1379 return NULL;
1380 }
1381
1382 /**
1383 * tracker_miner_manager_error_quark:
1384 *
1385 * Returns: the #GQuark used to identify miner manager errors in
1386 * GError structures.
1387 *
1388 * Since: 0.8
1389 **/
1390 GQuark
tracker_miner_manager_error_quark(void)1391 tracker_miner_manager_error_quark (void)
1392 {
1393 static GQuark error_quark = 0;
1394
1395 if (G_UNLIKELY (error_quark == 0)) {
1396 error_quark = g_quark_from_static_string ("tracker-miner-manager-error-quark");
1397 }
1398
1399 return error_quark;
1400 }
1401
1402 /**
1403 * tracker_miner_manager_reindex_by_mimetype:
1404 * @manager: a #TrackerMinerManager
1405 * @mimetypes: (in): an array of mimetypes (E.G. "text/plain"). All items
1406 * with a mimetype in that list will be reindexed.
1407 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
1408 *
1409 * Tells the filesystem miner to reindex any file with a mimetype in
1410 * the @mimetypes list.
1411 *
1412 * On failure @error will be set.
1413 *
1414 * Returns: %TRUE on success, otherwise %FALSE.
1415 *
1416 * Since: 0.10
1417 **/
1418 gboolean
tracker_miner_manager_reindex_by_mimetype(TrackerMinerManager * manager,const GStrv mimetypes,GError ** error)1419 tracker_miner_manager_reindex_by_mimetype (TrackerMinerManager *manager,
1420 const GStrv mimetypes,
1421 GError **error)
1422 {
1423 TrackerMinerManagerPrivate *priv;
1424 GVariant *v;
1425 GError *new_error = NULL;
1426
1427 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
1428 g_return_val_if_fail (mimetypes != NULL, FALSE);
1429
1430 if (!tracker_miner_manager_is_active (manager,
1431 "org.freedesktop.Tracker1.Miner.Files")) {
1432 g_set_error_literal (error,
1433 TRACKER_MINER_MANAGER_ERROR,
1434 TRACKER_MINER_MANAGER_ERROR_NOT_AVAILABLE,
1435 "Filesystem miner is not active");
1436 return FALSE;
1437 }
1438
1439 priv = tracker_miner_manager_get_instance_private (manager);
1440
1441 v = g_dbus_connection_call_sync (priv->connection,
1442 "org.freedesktop.Tracker1.Miner.Files",
1443 "/org/freedesktop/Tracker1/Miner/Files/Index",
1444 "org.freedesktop.Tracker1.Miner.Files.Index",
1445 "ReindexMimeTypes",
1446 g_variant_new ("(^as)", mimetypes),
1447 NULL,
1448 G_DBUS_CALL_FLAGS_NONE,
1449 -1,
1450 NULL,
1451 &new_error);
1452
1453 if (new_error) {
1454 g_propagate_error (error, new_error);
1455 return FALSE;
1456 }
1457
1458 g_variant_unref (v);
1459
1460 return FALSE;
1461 }
1462
1463 static gboolean
miner_manager_index_file_sync(TrackerMinerManager * manager,const gchar * method_name,GFile * file,GCancellable * cancellable,GError ** error)1464 miner_manager_index_file_sync (TrackerMinerManager *manager,
1465 const gchar *method_name,
1466 GFile *file,
1467 GCancellable *cancellable,
1468 GError **error)
1469 {
1470 TrackerMinerManagerPrivate *priv;
1471 gchar *uri;
1472 GVariant *v;
1473 GError *new_error = NULL;
1474
1475 if (!g_file_query_exists (file, cancellable)) {
1476 g_set_error_literal (error,
1477 TRACKER_MINER_MANAGER_ERROR,
1478 TRACKER_MINER_MANAGER_ERROR_NOENT,
1479 "File or directory does not exist");
1480 return FALSE;
1481 }
1482
1483 if (!tracker_miner_manager_is_active (manager,
1484 "org.freedesktop.Tracker1.Miner.Files")) {
1485 g_set_error_literal (error,
1486 TRACKER_MINER_MANAGER_ERROR,
1487 TRACKER_MINER_MANAGER_ERROR_NOT_AVAILABLE,
1488 "Filesystem miner is not active");
1489 return FALSE;
1490 }
1491
1492 priv = tracker_miner_manager_get_instance_private (manager);
1493
1494 uri = g_file_get_uri (file);
1495
1496 v = g_dbus_connection_call_sync (priv->connection,
1497 "org.freedesktop.Tracker1.Miner.Files",
1498 "/org/freedesktop/Tracker1/Miner/Files/Index",
1499 "org.freedesktop.Tracker1.Miner.Files.Index",
1500 method_name,
1501 g_variant_new ("(s)", uri),
1502 NULL,
1503 G_DBUS_CALL_FLAGS_NONE,
1504 -1,
1505 cancellable,
1506 &new_error);
1507
1508 g_free (uri);
1509
1510 if (new_error) {
1511 g_propagate_error (error, new_error);
1512 return FALSE;
1513 }
1514
1515 g_variant_unref (v);
1516
1517 return TRUE;
1518 }
1519
1520 static void
miner_manager_index_file_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1521 miner_manager_index_file_thread (GTask *task,
1522 gpointer source_object,
1523 gpointer task_data,
1524 GCancellable *cancellable)
1525 {
1526 TrackerMinerManager *manager = source_object;
1527 GFile *file = task_data;
1528 GError *error = NULL;
1529
1530 miner_manager_index_file_sync (manager, METHOD_INDEX_FILE,
1531 file, cancellable, &error);
1532 if (error != NULL) {
1533 g_task_return_error (task, error);
1534 } else {
1535 g_task_return_boolean (task, TRUE);
1536 }
1537 }
1538
1539 /**
1540 * tracker_miner_manager_index_file:
1541 * @manager: a #TrackerMinerManager
1542 * @file: a URL valid in GIO of a file to give to the miner for processing
1543 * @cancellable: (allow-none): a #GCancellable, or %NULL
1544 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
1545 *
1546 * Tells the filesystem miner to start indexing the @file.
1547 *
1548 * On failure @error will be set.
1549 *
1550 * Returns: %TRUE on success, otherwise %FALSE.
1551 *
1552 * Since: 2.0
1553 **/
1554 gboolean
tracker_miner_manager_index_file(TrackerMinerManager * manager,GFile * file,GCancellable * cancellable,GError ** error)1555 tracker_miner_manager_index_file (TrackerMinerManager *manager,
1556 GFile *file,
1557 GCancellable *cancellable,
1558 GError **error)
1559 {
1560 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
1561 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1562 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1563
1564 return miner_manager_index_file_sync (manager, METHOD_INDEX_FILE,
1565 file, cancellable, error);
1566 }
1567
1568 /**
1569 * tracker_miner_manager_index_file_async:
1570 * @manager: a #TrackerMinerManager
1571 * @file: a URL valid in GIO of a file to give to the miner for processing
1572 * @cancellable: (allow-none): a #GCancellable, or %NULL
1573 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
1574 * @user_data: the data to pass to the callback function
1575 *
1576 * Tells the filesystem miner to start indexing the @file. Once the message has been sent,
1577 * @callback will be called. You can then call tracker_miner_manager_index_file_finish()
1578 * to get the result.
1579 *
1580 * Since: 0.16
1581 **/
1582 void
tracker_miner_manager_index_file_async(TrackerMinerManager * manager,GFile * file,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1583 tracker_miner_manager_index_file_async (TrackerMinerManager *manager,
1584 GFile *file,
1585 GCancellable *cancellable,
1586 GAsyncReadyCallback callback,
1587 gpointer user_data)
1588 {
1589 GTask *task = g_task_new (manager, cancellable, callback, user_data);
1590 g_task_set_task_data (task, g_object_ref (file), (GDestroyNotify) g_object_unref);
1591 g_task_run_in_thread (task, miner_manager_index_file_thread);
1592 g_object_unref (task);
1593 }
1594
1595 /**
1596 * tracker_miner_manager_index_file_finish:
1597 * @manager: a #TrackerMinerManager
1598 * @result: a #GAsyncResult
1599 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
1600 *
1601 * Finishes a request to index a file. See tracker_miner_manager_index_file_async()
1602 *
1603 * On failure @error will be set.
1604 *
1605 * Returns: %TRUE on success, otherwise %FALSE.
1606 *
1607 * Since: 0.16
1608 **/
1609 gboolean
tracker_miner_manager_index_file_finish(TrackerMinerManager * manager,GAsyncResult * result,GError ** error)1610 tracker_miner_manager_index_file_finish (TrackerMinerManager *manager,
1611 GAsyncResult *result,
1612 GError **error)
1613 {
1614 return g_task_propagate_boolean (G_TASK (result), error);
1615 }
1616
1617 static void
miner_manager_index_file_for_process_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1618 miner_manager_index_file_for_process_thread (GTask *task,
1619 gpointer source_object,
1620 gpointer task_data,
1621 GCancellable *cancellable)
1622 {
1623 TrackerMinerManager *manager = source_object;
1624 GFile *file = task_data;
1625 GError *error = NULL;
1626
1627 miner_manager_index_file_sync (manager, METHOD_INDEX_FILE_FOR_PROCESS,
1628 file, cancellable, &error);
1629 if (error != NULL) {
1630 g_task_return_error (task, error);
1631 } else {
1632 g_task_return_boolean (task, TRUE);
1633 }
1634 }
1635
1636 /**
1637 * tracker_miner_manager_index_file_for_process:
1638 * @manager: a #TrackerMinerManager
1639 * @file: a URL valid in GIO of a file to give to the miner for processing
1640 * @cancellable: (allow-none): a #GCancellable, or %NULL
1641 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
1642 *
1643 * This function operates exactly the same way as
1644 * tracker_miner_manager_index_file() with the exception that if the
1645 * calling process dies, the indexing is cancelled. This API is useful
1646 * for cases where the calling process wants to tie the indexing
1647 * operation closely to its own lifetime.
1648 *
1649 * On failure @error will be set.
1650 *
1651 * Returns: %TRUE on success, otherwise %FALSE.
1652 *
1653 * Since: 1.10
1654 **/
1655 gboolean
tracker_miner_manager_index_file_for_process(TrackerMinerManager * manager,GFile * file,GCancellable * cancellable,GError ** error)1656 tracker_miner_manager_index_file_for_process (TrackerMinerManager *manager,
1657 GFile *file,
1658 GCancellable *cancellable,
1659 GError **error)
1660 {
1661 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
1662 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1663 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1664 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1665
1666 return miner_manager_index_file_sync (manager, METHOD_INDEX_FILE_FOR_PROCESS,
1667 file, cancellable, error);
1668 }
1669
1670 /**
1671 * tracker_miner_manager_index_file_for_process_async:
1672 * @manager: a #TrackerMinerManager
1673 * @file: a URL valid in GIO of a file to give to the miner for processing
1674 * @cancellable: (allow-none): a #GCancellable, or %NULL
1675 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
1676 * @user_data: the data to pass to the callback function
1677 *
1678 * This function operates exactly the same way as
1679 * tracker_miner_manager_index_file() with the exception that if the
1680 * calling process dies, the indexing is cancelled. This API is useful
1681 * for cases where the calling process wants to tie the indexing
1682 * operation closely to its own lifetime.
1683 *
1684 * When the operation is finished, @callback will be called. You can
1685 * then call tracker_miner_manager_index_file_for_process_finish() to
1686 * get the result of the operation.
1687 *
1688 * Since: 1.10
1689 **/
1690 void
tracker_miner_manager_index_file_for_process_async(TrackerMinerManager * manager,GFile * file,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1691 tracker_miner_manager_index_file_for_process_async (TrackerMinerManager *manager,
1692 GFile *file,
1693 GCancellable *cancellable,
1694 GAsyncReadyCallback callback,
1695 gpointer user_data)
1696 {
1697 GTask *task;
1698
1699 g_return_if_fail (TRACKER_IS_MINER_MANAGER (manager));
1700 g_return_if_fail (G_IS_FILE (file));
1701 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1702
1703 task = g_task_new (manager, cancellable, callback, user_data);
1704 g_task_set_task_data (task, g_object_ref (file), (GDestroyNotify) g_object_unref);
1705 g_task_run_in_thread (task, miner_manager_index_file_for_process_thread);
1706 g_object_unref (task);
1707 }
1708
1709 /**
1710 * tracker_miner_manager_index_file_for_process_finish:
1711 * @manager: a #TrackerMinerManager
1712 * @result: a #GAsyncResult
1713 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
1714 *
1715 * Finishes a request to index a file. See tracker_miner_manager_index_file_for_process_async()
1716 *
1717 * On failure @error will be set.
1718 *
1719 * Returns: %TRUE on success, otherwise %FALSE.
1720 *
1721 * Since: 1.10
1722 **/
1723 gboolean
tracker_miner_manager_index_file_for_process_finish(TrackerMinerManager * manager,GAsyncResult * result,GError ** error)1724 tracker_miner_manager_index_file_for_process_finish (TrackerMinerManager *manager,
1725 GAsyncResult *result,
1726 GError **error)
1727 {
1728 g_return_val_if_fail (TRACKER_IS_MINER_MANAGER (manager), FALSE);
1729 g_return_val_if_fail (g_task_is_valid (result, manager), FALSE);;
1730 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1731
1732 return g_task_propagate_boolean (G_TASK (result), error);
1733 }
1734