tracker-0.16.2/src/libtracker-miner/tracker-miner-object.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   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 }