No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | tracker-miner-object.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include <math.h>
23
24 #include <glib/gi18n.h>
25
26 #include <libtracker-common/tracker-dbus.h>
27 #include <libtracker-common/tracker-type-utils.h>
28
29 #include "tracker-marshal.h"
30 #include "tracker-miner-object.h"
31 #include "tracker-miner-dbus.h"
32
33 /* Here we use ceil() to eliminate decimal points beyond what we're
34 * interested in, which is 2 decimal places for the progress. The
35 * ceil() call will also round up the last decimal place.
36 *
37 * The 0.49 value is used for rounding correctness, because ceil()
38 * rounds up if the number is > 0.0.
39 */
40 #define PROGRESS_ROUNDED(x) ((x) < 0.01 ? 0.00 : (ceil (((x) * 100) - 0.49) / 100))
41
42 #define TRACKER_SERVICE "org.freedesktop.Tracker1"
43
44 #ifdef MINER_STATUS_ENABLE_TRACE
45 #warning Miner status traces are enabled
46 #define trace(message, ...) g_debug (message, ##__VA_ARGS__)
47 #else
48 #define trace(...)
49 #endif /* MINER_STATUS_ENABLE_TRACE */
50
51 /**
52 * SECTION:tracker-miner-object
53 * @short_description: Abstract base class for data miners
54 * @include: libtracker-miner/tracker-miner.h
55 *
56 * #TrackerMiner is an abstract base class to help developing data miners
57 * for tracker-store, being an abstract class it doesn't do much by itself,
58 * but provides the basic signaling and operation control so the miners
59 * implementing this class are properly recognized by Tracker, and can be
60 * controlled properly by external means such as #TrackerMinerManager.
61 *
62 * #TrackerMiner implements the #GInitable interface, and thus, all objects of
63 * types inheriting from #TrackerMiner must be initialized with g_initable_init()
64 * just after creation (or directly created with g_initable_new()).
65 **/
66
67 #define TRACKER_MINER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_MINER, TrackerMinerPrivate))
68
69 static GQuark miner_error_quark = 0;
70
71 /* Introspection data for the service we are exporting */
72 static const gchar introspection_xml[] =
73 "<node>"
74 " <interface name='org.freedesktop.Tracker1.Miner'>"
75 " <method name='GetStatus'>"
76 " <arg type='s' name='status' direction='out' />"
77 " </method>"
78 " <method name='GetProgress'>"
79 " <arg type='d' name='progress' direction='out' />"
80 " </method>"
81 " <method name='GetRemainingTime'>"
82 " <arg type='i' name='remaining_time' direction='out' />"
83 " </method>"
84 " <method name='GetPauseDetails'>"
85 " <arg type='as' name='pause_applications' direction='out' />"
86 " <arg type='as' name='pause_reasons' direction='out' />"
87 " </method>"
88 " <method name='Pause'>"
89 " <arg type='s' name='application' direction='in' />"
90 " <arg type='s' name='reason' direction='in' />"
91 " <arg type='i' name='cookie' direction='out' />"
92 " </method>"
93 " <method name='PauseForProcess'>"
94 " <arg type='s' name='application' direction='in' />"
95 " <arg type='s' name='reason' direction='in' />"
96 " <arg type='i' name='cookie' direction='out' />"
97 " </method>"
98 " <method name='Resume'>"
99 " <arg type='i' name='cookie' direction='in' />"
100 " </method>"
101 " <method name='IgnoreNextUpdate'>"
102 " <arg type='as' name='urls' direction='in' />"
103 " </method>"
104 " <signal name='Started' />"
105 " <signal name='Stopped' />"
106 " <signal name='Paused' />"
107 " <signal name='Resumed' />"
108 " <signal name='Progress'>"
109 " <arg type='s' name='status' />"
110 " <arg type='d' name='progress' />"
111 " <arg type='i' name='remaining_time' />"
112 " </signal>"
113 " </interface>"
114 "</node>";
115
116 struct _TrackerMinerPrivate {
117 TrackerSparqlConnection *connection;
118 GHashTable *pauses;
119 gboolean started;
120 gchar *name;
121 gchar *status;
122 gdouble progress;
123 gint remaining_time;
124 gint availability_cookie;
125 GDBusConnection *d_connection;
126 GDBusNodeInfo *introspection_data;
127 guint watch_name_id;
128 guint registration_id;
129 gchar *full_name;
130 gchar *full_path;
131 guint update_id;
132 };
133
134 typedef struct {
135 gint cookie;
136 gchar *application;
137 gchar *reason;
138 gchar *watch_name;
139 guint watch_name_id;
140 } PauseData;
141
142 enum {
143 PROP_0,
144 PROP_NAME,
145 PROP_STATUS,
146 PROP_PROGRESS,
147 PROP_REMAINING_TIME
148 };
149
150 enum {
151 STARTED,
152 STOPPED,
153 PAUSED,
154 RESUMED,
155 PROGRESS,
156 IGNORE_NEXT_UPDATE,
157 LAST_SIGNAL
158 };
159
160 static guint signals[LAST_SIGNAL] = { 0 };
161
162 static void miner_set_property (GObject *object,
163 guint param_id,
164 const GValue *value,
165 GParamSpec *pspec);
166 static void miner_get_property (GObject *object,
167 guint param_id,
168 GValue *value,
169 GParamSpec *pspec);
170 static void miner_finalize (GObject *object);
171 static void miner_initable_iface_init (GInitableIface *iface);
172 static gboolean miner_initable_init (GInitable *initable,
173 GCancellable *cancellable,
174 GError **error);
175 static void pause_data_destroy (gpointer data);
176 static PauseData *pause_data_new (const gchar *application,
177 const gchar *reason,
178 const gchar *watch_name,
179 guint watch_name_id);
180 static void handle_method_call (GDBusConnection *connection,
181 const gchar *sender,
182 const gchar *object_path,
183 const gchar *interface_name,
184 const gchar *method_name,
185 GVariant *parameters,
186 GDBusMethodInvocation *invocation,
187 gpointer user_data);
188 static GVariant *handle_get_property (GDBusConnection *connection,
189 const gchar *sender,
190 const gchar *object_path,
191 const gchar *interface_name,
192 const gchar *property_name,
193 GError **error,
194 gpointer user_data);
195 static gboolean handle_set_property (GDBusConnection *connection,
196 const gchar *sender,
197 const gchar *object_path,
198 const gchar *interface_name,
199 const gchar *property_name,
200 GVariant *value,
201 GError **error,
202 gpointer user_data);
203 static void on_tracker_store_appeared (GDBusConnection *connection,
204 const gchar *name,
205 const gchar *name_owner,
206 gpointer user_data);
207 static void on_tracker_store_disappeared (GDBusConnection *connection,
208 const gchar *name,
209 gpointer user_data);
210
211 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (TrackerMiner, tracker_miner, G_TYPE_OBJECT,
212 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
213 miner_initable_iface_init));
214
215 static void
216 tracker_miner_class_init (TrackerMinerClass *klass)
217 {
218 GObjectClass *object_class = G_OBJECT_CLASS (klass);
219
220 object_class->set_property = miner_set_property;
221 object_class->get_property = miner_get_property;
222 object_class->finalize = miner_finalize;
223
224 /**
225 * TrackerMiner::started:
226 * @miner: the #TrackerMiner
227 *
228 * the ::started signal is emitted in the miner
229 * right after it has been started through
230 * tracker_miner_start().
231 *
232 * Since: 0.8
233 **/
234 signals[STARTED] =
235 g_signal_new ("started",
236 G_OBJECT_CLASS_TYPE (object_class),
237 G_SIGNAL_RUN_LAST,
238 G_STRUCT_OFFSET (TrackerMinerClass, started),
239 NULL, NULL,
240 g_cclosure_marshal_VOID__VOID,
241 G_TYPE_NONE, 0);
242 /**
243 * TrackerMiner::stopped:
244 * @miner: the #TrackerMiner
245 *
246 * the ::stopped signal is emitted in the miner
247 * right after it has been stopped through
248 * tracker_miner_stop().
249 *
250 * Since: 0.8
251 **/
252 signals[STOPPED] =
253 g_signal_new ("stopped",
254 G_OBJECT_CLASS_TYPE (object_class),
255 G_SIGNAL_RUN_LAST,
256 G_STRUCT_OFFSET (TrackerMinerClass, stopped),
257 NULL, NULL,
258 g_cclosure_marshal_VOID__VOID,
259 G_TYPE_NONE, 0);
260 /**
261 * TrackerMiner::paused:
262 * @miner: the #TrackerMiner
263 *
264 * the ::paused signal is emitted whenever
265 * there is any reason to pause, either
266 * internal (through tracker_miner_pause()) or
267 * external (through DBus, see #TrackerMinerManager).
268 *
269 * Since: 0.8
270 **/
271 signals[PAUSED] =
272 g_signal_new ("paused",
273 G_OBJECT_CLASS_TYPE (object_class),
274 G_SIGNAL_RUN_LAST,
275 G_STRUCT_OFFSET (TrackerMinerClass, paused),
276 NULL, NULL,
277 g_cclosure_marshal_VOID__VOID,
278 G_TYPE_NONE, 0);
279 /**
280 * TrackerMiner::resumed:
281 * @miner: the #TrackerMiner
282 *
283 * the ::resumed signal is emitted whenever
284 * all reasons to pause have disappeared, see
285 * tracker_miner_resume() and #TrackerMinerManager.
286 *
287 * Since: 0.8
288 **/
289 signals[RESUMED] =
290 g_signal_new ("resumed",
291 G_OBJECT_CLASS_TYPE (object_class),
292 G_SIGNAL_RUN_LAST,
293 G_STRUCT_OFFSET (TrackerMinerClass, resumed),
294 NULL, NULL,
295 g_cclosure_marshal_VOID__VOID,
296 G_TYPE_NONE, 0);
297 /**
298 * TrackerMiner::progress:
299 * @miner: the #TrackerMiner
300 * @status: miner status
301 * @progress: a #gdouble indicating miner progress, from 0 to 1.
302 * @remaining_time: a #gint indicating the reamaining processing time, in
303 * seconds.
304 *
305 * the ::progress signal will be emitted by TrackerMiner implementations
306 * to indicate progress about the data mining process. @status will
307 * contain a translated string with the current miner status and @progress
308 * will indicate how much has been processed so far. @remaining_time will
309 * give the number expected of seconds to finish processing, 0 if the
310 * value cannot be estimated, and -1 if its not applicable.
311 *
312 * Since: 0.12
313 **/
314 signals[PROGRESS] =
315 g_signal_new ("progress",
316 G_OBJECT_CLASS_TYPE (object_class),
317 G_SIGNAL_RUN_LAST,
318 G_STRUCT_OFFSET (TrackerMinerClass, progress),
319 NULL, NULL,
320 tracker_marshal_VOID__STRING_DOUBLE_INT,
321 G_TYPE_NONE, 3,
322 G_TYPE_STRING,
323 G_TYPE_DOUBLE,
324 G_TYPE_INT);
325
326 /**
327 * TrackerMiner::ignore-next-update:
328 * @miner: the #TrackerMiner
329 * @urls: the urls to mark as ignore on next update
330 *
331 * the ::ignore-next-update signal is emitted in the miner
332 * right after it has been asked to mark @urls as to ignore on next update
333 * through tracker_miner_ignore_next_update().
334 *
335 * Since: 0.8
336 **/
337 signals[IGNORE_NEXT_UPDATE] =
338 g_signal_new ("ignore-next-update",
339 G_OBJECT_CLASS_TYPE (object_class),
340 G_SIGNAL_RUN_LAST,
341 G_STRUCT_OFFSET (TrackerMinerClass, ignore_next_update),
342 NULL, NULL,
343 g_cclosure_marshal_VOID__BOXED,
344 G_TYPE_NONE, 1,
345 G_TYPE_STRV);
346
347 g_object_class_install_property (object_class,
348 PROP_NAME,
349 g_param_spec_string ("name",
350 "Miner name",
351 "Miner name",
352 NULL,
353 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
354 g_object_class_install_property (object_class,
355 PROP_STATUS,
356 g_param_spec_string ("status",
357 "Status",
358 "Translatable string with status description",
359 "Idle",
360 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
361 g_object_class_install_property (object_class,
362 PROP_PROGRESS,
363 g_param_spec_double ("progress",
364 "Progress",
365 "Miner progress",
366 0.0,
367 1.0,
368 0.0,
369 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
370
371 g_object_class_install_property (object_class,
372 PROP_REMAINING_TIME,
373 g_param_spec_int ("remaining-time",
374 "Remaining time",
375 "Estimated remaining time to finish processing",
376 -1,
377 G_MAXINT,
378 -1,
379 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
380
381 g_type_class_add_private (object_class, sizeof (TrackerMinerPrivate));
382
383 miner_error_quark = g_quark_from_static_string ("TrackerMiner");
384 }
385
386 static void
387 miner_initable_iface_init (GInitableIface *iface)
388 {
389 iface->init = miner_initable_init;
390 }
391
392 static gboolean
393 miner_initable_init (GInitable *initable,
394 GCancellable *cancellable,
395 GError **error)
396 {
397 TrackerMiner *miner = TRACKER_MINER (initable);
398 GError *inner_error = NULL;
399 GVariant *reply;
400 guint32 rval;
401 GDBusInterfaceVTable interface_vtable = {
402 handle_method_call,
403 handle_get_property,
404 handle_set_property
405 };
406
407 /* Try to get SPARQL connection... */
408 miner->priv->connection = tracker_sparql_connection_get (NULL, &inner_error);
409 if (!miner->priv->connection) {
410 g_propagate_error (error, inner_error);
411 return FALSE;
412 }
413
414 /* Try to get DBus connection... */
415 miner->priv->d_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &inner_error);
416 if (!miner->priv->d_connection) {
417 g_propagate_error (error, inner_error);
418 return FALSE;
419 }
420
421 /* Setup introspection data */
422 miner->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &inner_error);
423 if (!miner->priv->introspection_data) {
424 g_propagate_error (error, inner_error);
425 return FALSE;
426 }
427
428 /* Check miner has a proper name */
429 if (!miner->priv->name) {
430 g_set_error (error,
431 TRACKER_MINER_ERROR,
432 0,
433 "Miner '%s' should have been given a name, bailing out",
434 G_OBJECT_TYPE_NAME (miner));
435 return FALSE;
436 }
437
438 /* Setup full name */
439 miner->priv->full_name = g_strconcat (TRACKER_MINER_DBUS_NAME_PREFIX,
440 miner->priv->name,
441 NULL);
442
443 /* Register the D-Bus object */
444 miner->priv->full_path = g_strconcat (TRACKER_MINER_DBUS_PATH_PREFIX,
445 miner->priv->name,
446 NULL);
447
448 g_message ("Registering D-Bus object...");
449 g_message (" Path:'%s'", miner->priv->full_path);
450 g_message (" Object Type:'%s'", G_OBJECT_TYPE_NAME (miner));
451
452 miner->priv->registration_id =
453 g_dbus_connection_register_object (miner->priv->d_connection,
454 miner->priv->full_path,
455 miner->priv->introspection_data->interfaces[0],
456 &interface_vtable,
457 miner,
458 NULL,
459 &inner_error);
460 if (inner_error) {
461 g_propagate_error (error, inner_error);
462 g_prefix_error (error,
463 "Could not register the D-Bus object '%s'. ",
464 miner->priv->full_path);
465 return FALSE;
466 }
467
468 /* Request the D-Bus name */
469 reply = g_dbus_connection_call_sync (miner->priv->d_connection,
470 "org.freedesktop.DBus",
471 "/org/freedesktop/DBus",
472 "org.freedesktop.DBus",
473 "RequestName",
474 g_variant_new ("(su)",
475 miner->priv->full_name,
476 0x4 /* DBUS_NAME_FLAG_DO_NOT_QUEUE */),
477 G_VARIANT_TYPE ("(u)"),
478 0, -1, NULL, &inner_error);
479 if (inner_error) {
480 g_propagate_error (error, inner_error);
481 g_prefix_error (error,
482 "Could not acquire name:'%s'. ",
483 miner->priv->full_name);
484 return FALSE;
485 }
486
487 g_variant_get (reply, "(u)", &rval);
488 g_variant_unref (reply);
489
490 if (rval != 1 /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */) {
491 g_set_error (error,
492 TRACKER_MINER_ERROR,
493 0,
494 "D-Bus service name:'%s' is already taken, "
495 "perhaps the application is already running?",
496 miner->priv->full_name);
497 return FALSE;
498 }
499
500 miner->priv->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
501 TRACKER_SERVICE,
502 G_BUS_NAME_WATCHER_FLAGS_NONE,
503 on_tracker_store_appeared,
504 on_tracker_store_disappeared,
505 miner,
506 NULL);
507
508 return TRUE;
509 }
510
511 static void
512 tracker_miner_init (TrackerMiner *miner)
513 {
514 TrackerMinerPrivate *priv;
515
516 miner->priv = priv = TRACKER_MINER_GET_PRIVATE (miner);
517
518 priv->pauses = g_hash_table_new_full (g_direct_hash,
519 g_direct_equal,
520 NULL,
521 pause_data_destroy);
522 }
523
524 static gboolean
525 miner_update_progress_cb (gpointer data)
526 {
527 TrackerMiner *miner = data;
528
529 trace ("(Miner:'%s') UPDATE PROGRESS SIGNAL", miner->priv->name);
530
531 g_signal_emit (miner, signals[PROGRESS], 0,
532 miner->priv->status,
533 miner->priv->progress,
534 miner->priv->remaining_time);
535
536 if (miner->priv->d_connection) {
537 g_dbus_connection_emit_signal (miner->priv->d_connection,
538 NULL,
539 miner->priv->full_path,
540 TRACKER_MINER_DBUS_INTERFACE,
541 "Progress",
542 g_variant_new ("(sdi)",
543 miner->priv->status,
544 miner->priv->progress,
545 miner->priv->remaining_time),
546 NULL);
547 }
548
549 miner->priv->update_id = 0;
550
551 return FALSE;
552 }
553
554 static void
555 miner_set_property (GObject *object,
556 guint prop_id,
557 const GValue *value,
558 GParamSpec *pspec)
559 {
560 TrackerMiner *miner = TRACKER_MINER (object);
561
562 /* Quite often, we see status of 100% and still have
563 * status messages saying Processing... which is not
564 * true. So we use an idle timeout to help that situation.
565 * Additionally we can't force both properties are correct
566 * with the GObject API, so we have to do some checks our
567 * selves. The g_object_bind_property() API also isn't
568 * sufficient here.
569 */
570
571 switch (prop_id) {
572 case PROP_NAME:
573 g_free (miner->priv->name);
574 miner->priv->name = g_value_dup_string (value);
575 break;
576 case PROP_STATUS: {
577 const gchar *new_status;
578
579 new_status = g_value_get_string (value);
580
581 trace ("(Miner:'%s') Set property:'status' to '%s'",
582 miner->priv->name,
583 new_status);
584
585 if (miner->priv->status && new_status &&
586 strcmp (miner->priv->status, new_status) == 0) {
587 /* Same, do nothing */
588 break;
589 }
590
591 g_free (miner->priv->status);
592 miner->priv->status = g_strdup (new_status);
593
594 /* Check progress matches special statuses */
595 if (new_status != NULL) {
596 if (g_ascii_strcasecmp (new_status, "Initializing") == 0 &&
597 miner->priv->progress != 0.0) {
598 trace ("(Miner:'%s') Set progress to 0.0 from status:'Initializing'",
599 miner->priv->name);
600 miner->priv->progress = 0.0;
601 } else if (g_ascii_strcasecmp (new_status, "Idle") == 0 &&
602 miner->priv->progress != 1.0) {
603 trace ("(Miner:'%s') Set progress to 1.0 from status:'Idle'",
604 miner->priv->name);
605 miner->priv->progress = 1.0;
606 }
607 }
608
609 if (miner->priv->update_id == 0) {
610 miner->priv->update_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
611 miner_update_progress_cb,
612 miner,
613 NULL);
614 }
615
616 break;
617 }
618 case PROP_PROGRESS: {
619 gdouble new_progress;
620
621 new_progress = PROGRESS_ROUNDED (g_value_get_double (value));
622 trace ("(Miner:'%s') Set property:'progress' to '%2.2f' (%2.2f before rounded)",
623 miner->priv->name,
624 new_progress,
625 g_value_get_double (value));
626
627 /* NOTE: We don't round the current progress before
628 * comparison because we use the rounded value when
629 * we set it last.
630 *
631 * Only notify 1% changes
632 */
633 if (new_progress == miner->priv->progress) {
634 /* Same, do nothing */
635 break;
636 }
637
638 miner->priv->progress = new_progress;
639
640 /* Check status matches special progress values */
641 if (new_progress == 0.0) {
642 if (miner->priv->status == NULL ||
643 g_ascii_strcasecmp (miner->priv->status, "Initializing") != 0) {
644 trace ("(Miner:'%s') Set status:'Initializing' from progress:0.0",
645 miner->priv->name);
646 g_free (miner->priv->status);
647 miner->priv->status = g_strdup ("Initializing");
648 }
649 } else if (new_progress == 1.0) {
650 if (miner->priv->status == NULL ||
651 g_ascii_strcasecmp (miner->priv->status, "Idle") != 0) {
652 trace ("(Miner:'%s') Set status:'Idle' from progress:1.0",
653 miner->priv->name);
654 g_free (miner->priv->status);
655 miner->priv->status = g_strdup ("Idle");
656 }
657 }
658
659 if (miner->priv->update_id == 0) {
660 miner->priv->update_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
661 miner_update_progress_cb,
662 miner,
663 NULL);
664 }
665
666 break;
667 }
668 case PROP_REMAINING_TIME: {
669 gint new_remaining_time;
670
671 new_remaining_time = g_value_get_int (value);
672 if (new_remaining_time != miner->priv->remaining_time) {
673 /* Just set the new remaining time, don't notify it */
674 miner->priv->remaining_time = new_remaining_time;
675 }
676 break;
677 }
678 default:
679 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
680 break;
681 }
682 }
683
684 static void
685 miner_get_property (GObject *object,
686 guint prop_id,
687 GValue *value,
688 GParamSpec *pspec)
689 {
690 TrackerMiner *miner = TRACKER_MINER (object);
691
692 switch (prop_id) {
693 case PROP_NAME:
694 g_value_set_string (value, miner->priv->name);
695 break;
696 case PROP_STATUS:
697 g_value_set_string (value, miner->priv->status);
698 break;
699 case PROP_PROGRESS:
700 g_value_set_double (value, miner->priv->progress);
701 break;
702 case PROP_REMAINING_TIME:
703 g_value_set_int (value, miner->priv->remaining_time);
704 break;
705 default:
706 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
707 break;
708 }
709 }
710
711 static PauseData *
712 pause_data_new (const gchar *application,
713 const gchar *reason,
714 const gchar *watch_name,
715 guint watch_name_id)
716 {
717 PauseData *data;
718 static gint cookie = 1;
719
720 data = g_slice_new0 (PauseData);
721
722 data->cookie = cookie++;
723 data->application = g_strdup (application);
724 data->reason = g_strdup (reason);
725 data->watch_name = g_strdup (watch_name);
726 data->watch_name_id = watch_name_id;
727
728 return data;
729 }
730
731 static void
732 pause_data_destroy (gpointer data)
733 {
734 PauseData *pd;
735
736 pd = data;
737
738 if (pd->watch_name_id) {
739 g_bus_unwatch_name (pd->watch_name_id);
740 }
741
742 g_free (pd->watch_name);
743
744 g_free (pd->reason);
745 g_free (pd->application);
746
747 g_slice_free (PauseData, pd);
748 }
749
750 /**
751 * tracker_miner_error_quark:
752 *
753 * Returns the #GQuark used to identify miner errors in GError structures.
754 *
755 * Returns: the error #GQuark
756 *
757 * Since: 0.8
758 **/
759 GQuark
760 tracker_miner_error_quark (void)
761 {
762 return g_quark_from_static_string (TRACKER_MINER_ERROR_DOMAIN);
763 }
764
765 /**
766 * tracker_miner_start:
767 * @miner: a #TrackerMiner
768 *
769 * Tells the miner to start processing data.
770 *
771 * Since: 0.8
772 **/
773 void
774 tracker_miner_start (TrackerMiner *miner)
775 {
776 g_return_if_fail (TRACKER_IS_MINER (miner));
777 g_return_if_fail (miner->priv->started == FALSE);
778
779 miner->priv->started = TRUE;
780
781 g_signal_emit (miner, signals[STARTED], 0);
782
783 if (miner->priv->d_connection) {
784 g_dbus_connection_emit_signal (miner->priv->d_connection,
785 NULL,
786 miner->priv->full_path,
787 TRACKER_MINER_DBUS_INTERFACE,
788 "Started",
789 NULL,
790 NULL);
791 }
792 }
793
794 /**
795 * tracker_miner_stop:
796 * @miner: a #TrackerMiner
797 *
798 * Tells the miner to stop processing data.
799 *
800 * Since: 0.8
801 **/
802 void
803 tracker_miner_stop (TrackerMiner *miner)
804 {
805 g_return_if_fail (TRACKER_IS_MINER (miner));
806 g_return_if_fail (miner->priv->started == TRUE);
807
808 miner->priv->started = FALSE;
809
810 g_signal_emit (miner, signals[STOPPED], 0);
811
812 if (miner->priv->d_connection) {
813 g_dbus_connection_emit_signal (miner->priv->d_connection,
814 NULL,
815 miner->priv->full_path,
816 TRACKER_MINER_DBUS_INTERFACE,
817 "Stopped",
818 NULL,
819 NULL);
820 }
821 }
822
823 /**
824 * tracker_miner_ignore_next_update:
825 * @miner: a #TrackerMiner
826 * @urls: (in): the urls to mark as to ignore on next update
827 *
828 * Tells the miner to mark @urls are to ignore on next update.
829 *
830 * Since: 0.8
831 **/
832 void
833 tracker_miner_ignore_next_update (TrackerMiner *miner,
834 const GStrv urls)
835 {
836 g_return_if_fail (TRACKER_IS_MINER (miner));
837
838 g_signal_emit (miner, signals[IGNORE_NEXT_UPDATE], 0, urls);
839 }
840
841 /**
842 * tracker_miner_is_started:
843 * @miner: a #TrackerMiner
844 *
845 * Returns #TRUE if the miner has been started.
846 *
847 * Returns: #TRUE if the miner is already started.
848 *
849 * Since: 0.8
850 **/
851 gboolean
852 tracker_miner_is_started (TrackerMiner *miner)
853 {
854 g_return_val_if_fail (TRACKER_IS_MINER (miner), TRUE);
855
856 return miner->priv->started;
857 }
858
859 /**
860 * tracker_miner_is_paused:
861 * @miner: a #TrackerMiner
862 *
863 * Returns #TRUE if the miner is paused.
864 *
865 * Returns: #TRUE if the miner is paused.
866 *
867 * Since: 0.10
868 **/
869 gboolean
870 tracker_miner_is_paused (TrackerMiner *miner)
871 {
872 g_return_val_if_fail (TRACKER_IS_MINER (miner), TRUE);
873
874 return g_hash_table_size (miner->priv->pauses) > 0 ? TRUE : FALSE;
875 }
876
877 /**
878 * tracker_miner_get_n_pause_reasons:
879 * @miner: a #TrackerMiner
880 *
881 * Returns the number of pause reasons holding @miner from
882 * indexing contents.
883 *
884 * Returns: The number of current pause reasons
885 *
886 * Since: 0.10.5
887 **/
888 guint
889 tracker_miner_get_n_pause_reasons (TrackerMiner *miner)
890 {
891 g_return_val_if_fail (TRACKER_IS_MINER (miner), 0);
892
893 return g_hash_table_size (miner->priv->pauses);
894 }
895
896 static void
897 pause_process_disappeared_cb (GDBusConnection *connection,
898 const gchar *name,
899 gpointer user_data)
900 {
901 TrackerMiner *miner;
902 PauseData *pd = NULL;
903 GError *error = NULL;
904 GHashTableIter iter;
905 gpointer key, value;
906
907 miner = user_data;
908
909 g_message ("Process with name:'%s' has disappeared", name);
910
911 g_hash_table_iter_init (&iter, miner->priv->pauses);
912 while (g_hash_table_iter_next (&iter, &key, &value)) {
913 PauseData *pd_iter = value;
914
915 if (g_strcmp0 (name, pd_iter->watch_name) == 0) {
916 pd = pd_iter;
917 break;
918 }
919 }
920
921 if (!pd) {
922 g_critical ("Could not find PauseData for process with name:'%s'", name);
923 return;
924 }
925
926 /* Resume */
927 g_message ("Resuming pause associated with process");
928
929 tracker_miner_resume (miner, pd->cookie, &error);
930
931 if (error) {
932 g_warning ("Could not resume miner, %s", error->message);
933 g_error_free (error);
934 }
935 }
936
937 static gint
938 miner_pause_internal (TrackerMiner *miner,
939 const gchar *application,
940 const gchar *reason,
941 const gchar *calling_name,
942 GError **error)
943 {
944 PauseData *pd;
945 GHashTableIter iter;
946 gpointer key, value;
947 guint watch_name_id = 0;
948
949 /* Check this is not a duplicate pause */
950 g_hash_table_iter_init (&iter, miner->priv->pauses);
951 while (g_hash_table_iter_next (&iter, &key, &value)) {
952 PauseData *pd = value;
953
954 if (g_strcmp0 (application, pd->application) == 0 &&
955 g_strcmp0 (reason, pd->reason) == 0) {
956 /* Can't use duplicate pauses */
957 g_set_error_literal (error, TRACKER_MINER_ERROR, 0,
958 _("Pause application and reason match an already existing pause request"));
959 return -1;
960 }
961 }
962
963 if (calling_name) {
964 g_message ("Watching process with name:'%s'", calling_name);
965 watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
966 calling_name,
967 G_BUS_NAME_WATCHER_FLAGS_NONE,
968 NULL,
969 pause_process_disappeared_cb,
970 miner,
971 NULL);
972 }
973
974 pd = pause_data_new (application, reason, calling_name, watch_name_id);
975
976 g_hash_table_insert (miner->priv->pauses,
977 GINT_TO_POINTER (pd->cookie),
978 pd);
979
980 if (g_hash_table_size (miner->priv->pauses) == 1) {
981 /* Pause */
982 g_message ("Miner:'%s' is pausing", miner->priv->name);
983 g_signal_emit (miner, signals[PAUSED], 0);
984
985 if (miner->priv->d_connection) {
986 g_dbus_connection_emit_signal (miner->priv->d_connection,
987 NULL,
988 miner->priv->full_path,
989 TRACKER_MINER_DBUS_INTERFACE,
990 "Paused",
991 NULL,
992 NULL);
993 }
994 }
995
996 return pd->cookie;
997 }
998
999 /**
1000 * tracker_miner_pause:
1001 * @miner: a #TrackerMiner
1002 * @reason: reason to pause
1003 * @error: (out callee-allocates) (transfer full) (allow-none): return location for errors
1004 *
1005 * Asks @miner to pause. On success the cookie ID is returned,
1006 * this is what must be used in tracker_miner_resume() to resume
1007 * operations. On failure @error will be set and -1 will be returned.
1008 *
1009 * Returns: The pause cookie ID.
1010 *
1011 * Since: 0.8
1012 **/
1013 gint
1014 tracker_miner_pause (TrackerMiner *miner,
1015 const gchar *reason,
1016 GError **error)
1017 {
1018 const gchar *application;
1019
1020 g_return_val_if_fail (TRACKER_IS_MINER (miner), -1);
1021 g_return_val_if_fail (reason != NULL, -1);
1022
1023 application = g_get_application_name ();
1024
1025 if (!application) {
1026 application = miner->priv->name;
1027 }
1028
1029 return miner_pause_internal (miner, application, reason, NULL, error);
1030 }
1031
1032 /**
1033 * tracker_miner_resume:
1034 * @miner: a #TrackerMiner
1035 * @cookie: pause cookie
1036 * @error: (out) (transfer full) (allow-none): return location for errors
1037 *
1038 * Asks the miner to resume processing. The cookie must be something
1039 * returned by tracker_miner_pause(). The miner won't actually resume
1040 * operations until all pause requests have been resumed.
1041 *
1042 * Returns: #TRUE if the cookie was valid.
1043 *
1044 * Since: 0.8
1045 **/
1046 gboolean
1047 tracker_miner_resume (TrackerMiner *miner,
1048 gint cookie,
1049 GError **error)
1050 {
1051 g_return_val_if_fail (TRACKER_IS_MINER (miner), FALSE);
1052
1053 if (!g_hash_table_remove (miner->priv->pauses, GINT_TO_POINTER (cookie))) {
1054 g_set_error_literal (error, TRACKER_MINER_ERROR, 0,
1055 _("Cookie not recognized to resume paused miner"));
1056 return FALSE;
1057 }
1058
1059 if (g_hash_table_size (miner->priv->pauses) == 0) {
1060 /* Resume */
1061 g_message ("Miner:'%s' is resuming", miner->priv->name);
1062 g_signal_emit (miner, signals[RESUMED], 0);
1063
1064 if (miner->priv->d_connection) {
1065 g_dbus_connection_emit_signal (miner->priv->d_connection,
1066 NULL,
1067 miner->priv->full_path,
1068 TRACKER_MINER_DBUS_INTERFACE,
1069 "Resumed",
1070 NULL,
1071 NULL);
1072 }
1073 }
1074
1075 return TRUE;
1076 }
1077
1078 /**
1079 * tracker_miner_get_connection:
1080 * @miner: a #TrackerMiner
1081 *
1082 * Gets the #TrackerSparqlConnection initialized by @miner
1083 *
1084 * Returns: (transfer none): a #TrackerSparqlConnection.
1085 *
1086 * Since: 0.10
1087 **/
1088 TrackerSparqlConnection *
1089 tracker_miner_get_connection (TrackerMiner *miner)
1090 {
1091 return miner->priv->connection;
1092 }
1093
1094 /**
1095 * tracker_miner_get_dbus_connection:
1096 * @miner: a #TrackerMiner
1097 *
1098 * Gets the #GDBusConnection initialized by @miner
1099 *
1100 * Returns: (transfer none): a #GDBusConnection.
1101 *
1102 * Since: 0.10
1103 **/
1104 GDBusConnection *
1105 tracker_miner_get_dbus_connection (TrackerMiner *miner)
1106 {
1107 return miner->priv->d_connection;
1108 }
1109
1110 /**
1111 * tracker_miner_get_dbus_full_name:
1112 * @miner: a #TrackerMiner
1113 *
1114 * Gets the DBus name registered by @miner
1115 *
1116 * Returns: a constant string which should not be modified by the caller.
1117 *
1118 * Since: 0.10
1119 **/
1120 const gchar *
1121 tracker_miner_get_dbus_full_name (TrackerMiner *miner)
1122 {
1123 return miner->priv->full_name;
1124 }
1125
1126 /**
1127 * tracker_miner_get_dbus_full_path:
1128 * @miner: a #TrackerMiner
1129 *
1130 * Gets the DBus path registered by @miner
1131 *
1132 * Returns: a constant string which should not be modified by the caller.
1133 *
1134 * Since: 0.10
1135 **/
1136 const gchar *
1137 tracker_miner_get_dbus_full_path (TrackerMiner *miner)
1138 {
1139 return miner->priv->full_path;
1140 }
1141
1142 static void
1143 miner_finalize (GObject *object)
1144 {
1145 TrackerMiner *miner = TRACKER_MINER (object);
1146
1147 if (miner->priv->update_id != 0) {
1148 g_source_remove (miner->priv->update_id);
1149 }
1150
1151 if (miner->priv->watch_name_id != 0) {
1152 g_bus_unwatch_name (miner->priv->watch_name_id);
1153 }
1154
1155 if (miner->priv->registration_id != 0) {
1156 g_dbus_connection_unregister_object (miner->priv->d_connection,
1157 miner->priv->registration_id);
1158 }
1159
1160 if (miner->priv->introspection_data) {
1161 g_dbus_node_info_unref (miner->priv->introspection_data);
1162 }
1163
1164 if (miner->priv->d_connection) {
1165 g_object_unref (miner->priv->d_connection);
1166 }
1167
1168 g_free (miner->priv->status);
1169 g_free (miner->priv->name);
1170 g_free (miner->priv->full_name);
1171 g_free (miner->priv->full_path);
1172
1173 if (miner->priv->connection) {
1174 g_object_unref (miner->priv->connection);
1175 }
1176
1177 if (miner->priv->pauses) {
1178 g_hash_table_unref (miner->priv->pauses);
1179 }
1180
1181 G_OBJECT_CLASS (tracker_miner_parent_class)->finalize (object);
1182 }
1183
1184 static void
1185 handle_method_call_ignore_next_update (TrackerMiner *miner,
1186 GDBusMethodInvocation *invocation,
1187 GVariant *parameters)
1188 {
1189 GStrv urls = NULL;
1190 TrackerDBusRequest *request;
1191
1192 g_variant_get (parameters, "(^a&s)", &urls);
1193
1194 request = tracker_g_dbus_request_begin (invocation,
1195 "%s", __PRETTY_FUNCTION__);
1196
1197 tracker_miner_ignore_next_update (miner, urls);
1198
1199 tracker_dbus_request_end (request, NULL);
1200 g_dbus_method_invocation_return_value (invocation, NULL);
1201 g_free (urls);
1202 }
1203
1204 static void
1205 handle_method_call_resume (TrackerMiner *miner,
1206 GDBusMethodInvocation *invocation,
1207 GVariant *parameters)
1208 {
1209 GError *local_error = NULL;
1210 gint cookie;
1211 TrackerDBusRequest *request;
1212
1213 g_variant_get (parameters, "(i)", &cookie);
1214
1215 request = tracker_g_dbus_request_begin (invocation,
1216 "%s(cookie:%d)",
1217 __PRETTY_FUNCTION__,
1218 cookie);
1219
1220 if (!tracker_miner_resume (miner, cookie, &local_error)) {
1221 tracker_dbus_request_end (request, local_error);
1222
1223 g_dbus_method_invocation_return_gerror (invocation, local_error);
1224
1225 g_error_free (local_error);
1226 return;
1227 }
1228
1229 tracker_dbus_request_end (request, NULL);
1230 g_dbus_method_invocation_return_value (invocation, NULL);
1231 }
1232
1233 static void
1234 handle_method_call_pause (TrackerMiner *miner,
1235 GDBusMethodInvocation *invocation,
1236 GVariant *parameters)
1237 {
1238 GError *local_error = NULL;
1239 gint cookie;
1240 const gchar *application = NULL, *reason = NULL;
1241 TrackerDBusRequest *request;
1242
1243 g_variant_get (parameters, "(&s&s)", &application, &reason);
1244
1245 tracker_gdbus_async_return_if_fail (application != NULL, invocation);
1246 tracker_gdbus_async_return_if_fail (reason != NULL, invocation);
1247
1248 request = tracker_g_dbus_request_begin (invocation,
1249 "%s(application:'%s', reason:'%s')",
1250 __PRETTY_FUNCTION__,
1251 application,
1252 reason);
1253
1254 cookie = miner_pause_internal (miner, application, reason, NULL, &local_error);
1255 if (cookie == -1) {
1256 tracker_dbus_request_end (request, local_error);
1257
1258 g_dbus_method_invocation_return_gerror (invocation, local_error);
1259
1260 g_error_free (local_error);
1261
1262 return;
1263 }
1264
1265 tracker_dbus_request_end (request, NULL);
1266 g_dbus_method_invocation_return_value (invocation,
1267 g_variant_new ("(i)", cookie));
1268 }
1269
1270 static void
1271 handle_method_call_pause_for_process (TrackerMiner *miner,
1272 GDBusMethodInvocation *invocation,
1273 GVariant *parameters)
1274 {
1275 GError *local_error = NULL;
1276 gint cookie;
1277 const gchar *application = NULL, *reason = NULL;
1278 TrackerDBusRequest *request;
1279
1280 g_variant_get (parameters, "(&s&s)", &application, &reason);
1281
1282 tracker_gdbus_async_return_if_fail (application != NULL, invocation);
1283 tracker_gdbus_async_return_if_fail (reason != NULL, invocation);
1284
1285 request = tracker_g_dbus_request_begin (invocation,
1286 "%s(application:'%s', reason:'%s')",
1287 __PRETTY_FUNCTION__,
1288 application,
1289 reason);
1290
1291 cookie = miner_pause_internal (miner,
1292 application,
1293 reason,
1294 g_dbus_method_invocation_get_sender (invocation),
1295 &local_error);
1296 if (cookie == -1) {
1297 tracker_dbus_request_end (request, local_error);
1298
1299 g_dbus_method_invocation_return_gerror (invocation, local_error);
1300
1301 g_error_free (local_error);
1302
1303 return;
1304 }
1305
1306 tracker_dbus_request_end (request, NULL);
1307 g_dbus_method_invocation_return_value (invocation,
1308 g_variant_new ("(i)", cookie));
1309 }
1310
1311 static void
1312 handle_method_call_get_pause_details (TrackerMiner *miner,
1313 GDBusMethodInvocation *invocation,
1314 GVariant *parameters)
1315 {
1316 GSList *applications, *reasons;
1317 GStrv applications_strv, reasons_strv;
1318 GHashTableIter iter;
1319 gpointer key, value;
1320 TrackerDBusRequest *request;
1321
1322 request = tracker_g_dbus_request_begin (invocation, "%s()", __PRETTY_FUNCTION__);
1323
1324 applications = NULL;
1325 reasons = NULL;
1326 g_hash_table_iter_init (&iter, miner->priv->pauses);
1327 while (g_hash_table_iter_next (&iter, &key, &value)) {
1328 PauseData *pd = value;
1329
1330 applications = g_slist_prepend (applications, pd->application);
1331 reasons = g_slist_prepend (reasons, pd->reason);
1332 }
1333 applications = g_slist_reverse (applications);
1334 reasons = g_slist_reverse (reasons);
1335 applications_strv = tracker_gslist_to_string_list (applications);
1336 reasons_strv = tracker_gslist_to_string_list (reasons);
1337
1338 tracker_dbus_request_end (request, NULL);
1339 g_dbus_method_invocation_return_value (invocation,
1340 g_variant_new ("(^as^as)",
1341 applications_strv,
1342 reasons_strv));
1343
1344 g_strfreev (applications_strv);
1345 g_strfreev (reasons_strv);
1346 g_slist_free (applications);
1347 g_slist_free (reasons);
1348 }
1349
1350 static void
1351 handle_method_call_get_remaining_time (TrackerMiner *miner,
1352 GDBusMethodInvocation *invocation,
1353 GVariant *parameters)
1354 {
1355 TrackerDBusRequest *request;
1356
1357 request = tracker_g_dbus_request_begin (invocation, "%s()", __PRETTY_FUNCTION__);
1358
1359 tracker_dbus_request_end (request, NULL);
1360 g_dbus_method_invocation_return_value (invocation,
1361 g_variant_new ("(i)",
1362 miner->priv->remaining_time));
1363 }
1364
1365 static void
1366 handle_method_call_get_progress (TrackerMiner *miner,
1367 GDBusMethodInvocation *invocation,
1368 GVariant *parameters)
1369 {
1370 TrackerDBusRequest *request;
1371
1372 request = tracker_g_dbus_request_begin (invocation, "%s()", __PRETTY_FUNCTION__);
1373
1374 tracker_dbus_request_end (request, NULL);
1375 g_dbus_method_invocation_return_value (invocation,
1376 g_variant_new ("(d)",
1377 miner->priv->progress));
1378 }
1379
1380 static void
1381 handle_method_call_get_status (TrackerMiner *miner,
1382 GDBusMethodInvocation *invocation,
1383 GVariant *parameters)
1384 {
1385 TrackerDBusRequest *request;
1386
1387 request = tracker_g_dbus_request_begin (invocation, "%s()", __PRETTY_FUNCTION__);
1388
1389 tracker_dbus_request_end (request, NULL);
1390 g_dbus_method_invocation_return_value (invocation,
1391 g_variant_new ("(s)",
1392 miner->priv->status ? miner->priv->status : ""));
1393
1394 }
1395
1396 static void
1397 handle_method_call (GDBusConnection *connection,
1398 const gchar *sender,
1399 const gchar *object_path,
1400 const gchar *interface_name,
1401 const gchar *method_name,
1402 GVariant *parameters,
1403 GDBusMethodInvocation *invocation,
1404 gpointer user_data)
1405 {
1406 TrackerMiner *miner = user_data;
1407
1408 tracker_gdbus_async_return_if_fail (miner != NULL, invocation);
1409
1410 if (g_strcmp0 (method_name, "IgnoreNextUpdate") == 0) {
1411 handle_method_call_ignore_next_update (miner, invocation, parameters);
1412 } else if (g_strcmp0 (method_name, "Resume") == 0) {
1413 handle_method_call_resume (miner, invocation, parameters);
1414 } else if (g_strcmp0 (method_name, "Pause") == 0) {
1415 handle_method_call_pause (miner, invocation, parameters);
1416 } else if (g_strcmp0 (method_name, "PauseForProcess") == 0) {
1417 handle_method_call_pause_for_process (miner, invocation, parameters);
1418 } else if (g_strcmp0 (method_name, "GetPauseDetails") == 0) {
1419 handle_method_call_get_pause_details (miner, invocation, parameters);
1420 } else if (g_strcmp0 (method_name, "GetRemainingTime") == 0) {
1421 handle_method_call_get_remaining_time (miner, invocation, parameters);
1422 } else if (g_strcmp0 (method_name, "GetProgress") == 0) {
1423 handle_method_call_get_progress (miner, invocation, parameters);
1424 } else if (g_strcmp0 (method_name, "GetStatus") == 0) {
1425 handle_method_call_get_status (miner, invocation, parameters);
1426 } else {
1427 g_assert_not_reached ();
1428 }
1429 }
1430
1431 static GVariant *
1432 handle_get_property (GDBusConnection *connection,
1433 const gchar *sender,
1434 const gchar *object_path,
1435 const gchar *interface_name,
1436 const gchar *property_name,
1437 GError **error,
1438 gpointer user_data)
1439 {
1440 g_assert_not_reached ();
1441 return NULL;
1442 }
1443
1444 static gboolean
1445 handle_set_property (GDBusConnection *connection,
1446 const gchar *sender,
1447 const gchar *object_path,
1448 const gchar *interface_name,
1449 const gchar *property_name,
1450 GVariant *value,
1451 GError **error,
1452 gpointer user_data)
1453 {
1454 g_assert_not_reached ();
1455 return TRUE;
1456 }
1457
1458 static void
1459 on_tracker_store_appeared (GDBusConnection *connection,
1460 const gchar *name,
1461 const gchar *name_owner,
1462 gpointer user_data)
1463
1464 {
1465 TrackerMiner *miner = user_data;
1466
1467 g_debug ("Miner:'%s' noticed store availability has changed to AVAILABLE",
1468 miner->priv->name);
1469
1470 if (miner->priv->availability_cookie != 0) {
1471 GError *error = NULL;
1472
1473 tracker_miner_resume (miner,
1474 miner->priv->availability_cookie,
1475 &error);
1476
1477 if (error) {
1478 g_warning ("Error happened resuming miner, %s", error->message);
1479 g_error_free (error);
1480 }
1481
1482 miner->priv->availability_cookie = 0;
1483 }
1484 }
1485
1486 static void
1487 on_tracker_store_disappeared (GDBusConnection *connection,
1488 const gchar *name,
1489 gpointer user_data)
1490 {
1491 TrackerMiner *miner = user_data;
1492
1493 g_debug ("Miner:'%s' noticed store availability has changed to UNAVAILABLE",
1494 miner->priv->name);
1495
1496 if (miner->priv->availability_cookie == 0) {
1497 GError *error = NULL;
1498 gint cookie_id;
1499
1500 cookie_id = tracker_miner_pause (miner,
1501 _("Data store is not available"),
1502 &error);
1503
1504 if (error) {
1505 g_warning ("Could not pause, %s", error->message);
1506 g_error_free (error);
1507 } else {
1508 miner->priv->availability_cookie = cookie_id;
1509 }
1510 }
1511 }