1 /*
2 * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
3 * Copyright (C) 2014, Lanedo <martyn@lanedo.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config-miners.h"
22
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include <glib.h>
27 #include <gio/gio.h>
28
29 #define G_SETTINGS_ENABLE_BACKEND
30 #include <gio/gsettingsbackend.h>
31
32 #include <libtracker-miners-common/tracker-common.h>
33
34 #include "tracker-config.h"
35
36 #define CONFIG_SCHEMA "org.freedesktop.Tracker.Miner.Files"
37 #define CONFIG_PATH "/org/freedesktop/tracker/miner/files/"
38
39 /* Default values */
40 #define DEFAULT_VERBOSITY 0
41 #define DEFAULT_SCHED_IDLE 1
42 #define DEFAULT_INITIAL_SLEEP 15 /* 0->1000 */
43 #define DEFAULT_ENABLE_MONITORS TRUE
44 #define DEFAULT_THROTTLE 0 /* 0->20 */
45 #define DEFAULT_INDEX_REMOVABLE_DEVICES FALSE
46 #define DEFAULT_INDEX_OPTICAL_DISCS FALSE
47 #define DEFAULT_INDEX_ON_BATTERY FALSE
48 #define DEFAULT_INDEX_ON_BATTERY_FIRST_TIME TRUE
49 #define DEFAULT_LOW_DISK_SPACE_LIMIT 1 /* 0->100 / -1 */
50 #define DEFAULT_CRAWLING_INTERVAL -1 /* 0->365 / -1 / -2 */
51 #define DEFAULT_REMOVABLE_DAYS_THRESHOLD 3 /* 1->365 / 0 */
52 #define DEFAULT_ENABLE_WRITEBACK FALSE
53
54 typedef struct {
55 /* IMPORTANT: There are 3 versions of the directories:
56 * 1. a GStrv stored in GSettings
57 * 2. a GSList stored here which is the GStrv without any
58 * aliases or duplicates resolved.
59 * 3. a GSList stored here which has duplicates and aliases
60 * resolved.
61 */
62 GSList *index_recursive_directories;
63 GSList *index_recursive_directories_unfiltered;
64 GSList *index_single_directories;
65 GSList *index_single_directories_unfiltered;
66 GSList *ignored_directories;
67 GSList *ignored_directories_with_content;
68 GSList *ignored_files;
69
70 /* Convenience data */
71 GSList *ignored_directory_patterns;
72 GSList *ignored_directory_paths;
73 GSList *ignored_file_patterns;
74 GSList *ignored_file_paths;
75 } TrackerConfigPrivate;
76
77 static void config_set_property (GObject *object,
78 guint param_id,
79 const GValue *value,
80 GParamSpec *pspec);
81 static void config_get_property (GObject *object,
82 guint param_id,
83 GValue *value,
84 GParamSpec *pspec);
85 static void config_finalize (GObject *object);
86 static void config_constructed (GObject *object);
87 static void config_set_index_recursive_directories (TrackerConfig *config,
88 GSList *roots);
89 static void config_set_index_single_directories (TrackerConfig *config,
90 GSList *roots);
91 static void config_set_ignored_directories (TrackerConfig *config,
92 GSList *roots);
93 static void config_set_ignored_directories_with_content (TrackerConfig *config,
94 GSList *roots);
95 static void config_set_ignored_files (TrackerConfig *config,
96 GSList *files);
97
98 enum {
99 PROP_0,
100
101 /* General */
102 PROP_VERBOSITY,
103 PROP_SCHED_IDLE,
104 PROP_INITIAL_SLEEP,
105
106 /* Monitors */
107 PROP_ENABLE_MONITORS,
108
109 /* Indexing */
110 PROP_THROTTLE,
111 PROP_INDEX_ON_BATTERY,
112 PROP_INDEX_ON_BATTERY_FIRST_TIME,
113 PROP_INDEX_REMOVABLE_DEVICES,
114 PROP_INDEX_OPTICAL_DISCS,
115 PROP_LOW_DISK_SPACE_LIMIT,
116 PROP_INDEX_RECURSIVE_DIRECTORIES,
117 PROP_INDEX_SINGLE_DIRECTORIES,
118 PROP_IGNORED_DIRECTORIES,
119 PROP_IGNORED_DIRECTORIES_WITH_CONTENT,
120 PROP_IGNORED_FILES,
121 PROP_CRAWLING_INTERVAL,
122 PROP_REMOVABLE_DAYS_THRESHOLD,
123
124 /* Writeback */
125 PROP_ENABLE_WRITEBACK
126
127 };
128
G_DEFINE_TYPE_WITH_PRIVATE(TrackerConfig,tracker_config,G_TYPE_SETTINGS)129 G_DEFINE_TYPE_WITH_PRIVATE (TrackerConfig, tracker_config, G_TYPE_SETTINGS)
130
131 static void
132 tracker_config_class_init (TrackerConfigClass *klass)
133 {
134 GObjectClass *object_class = G_OBJECT_CLASS (klass);
135
136 object_class->set_property = config_set_property;
137 object_class->get_property = config_get_property;
138 object_class->finalize = config_finalize;
139 object_class->constructed = config_constructed;
140
141 /* General */
142 g_object_class_install_property (object_class,
143 PROP_VERBOSITY,
144 g_param_spec_enum ("verbosity",
145 "Log verbosity",
146 "Log verbosity (0=errors, 1=minimal, 2=detailed, 3=debug)",
147 TRACKER_TYPE_VERBOSITY,
148 DEFAULT_VERBOSITY,
149 G_PARAM_READWRITE));
150 g_object_class_install_property (object_class,
151 PROP_SCHED_IDLE,
152 g_param_spec_enum ("sched-idle",
153 "Scheduler priority when idle",
154 "Scheduler priority when idle (0=always, 1=first-index, 2=never)",
155 TRACKER_TYPE_SCHED_IDLE,
156 DEFAULT_SCHED_IDLE,
157 G_PARAM_READWRITE));
158 g_object_class_install_property (object_class,
159 PROP_INITIAL_SLEEP,
160 g_param_spec_int ("initial-sleep",
161 "Initial sleep",
162 "Time in seconds before crawling filesystem (0->1000)",
163 0,
164 1000,
165 DEFAULT_INITIAL_SLEEP,
166 G_PARAM_READWRITE));
167
168 /* Monitors */
169 g_object_class_install_property (object_class,
170 PROP_ENABLE_MONITORS,
171 g_param_spec_boolean ("enable-monitors",
172 "Enable monitors",
173 "Set to false to completely disable any monitoring",
174 DEFAULT_ENABLE_MONITORS,
175 G_PARAM_READWRITE));
176
177 /* Indexing */
178 g_object_class_install_property (object_class,
179 PROP_THROTTLE,
180 g_param_spec_int ("throttle",
181 "Throttle",
182 "Sets the indexing speed (0->20, where 20=slowest speed)",
183 0,
184 20,
185 DEFAULT_THROTTLE,
186 G_PARAM_READWRITE));
187 g_object_class_install_property (object_class,
188 PROP_INDEX_ON_BATTERY,
189 g_param_spec_boolean ("index-on-battery",
190 "Index on battery",
191 "Set to true to index while running on battery",
192 DEFAULT_INDEX_ON_BATTERY,
193 G_PARAM_READWRITE));
194 g_object_class_install_property (object_class,
195 PROP_INDEX_ON_BATTERY_FIRST_TIME,
196 g_param_spec_boolean ("index-on-battery-first-time",
197 "Index on battery first time",
198 "Set to true to index while running on battery for the first time only",
199 DEFAULT_INDEX_ON_BATTERY_FIRST_TIME,
200 G_PARAM_READWRITE));
201 g_object_class_install_property (object_class,
202 PROP_INDEX_REMOVABLE_DEVICES,
203 g_param_spec_boolean ("index-removable-devices",
204 "index removable devices",
205 "Set to true to enable traversing mounted directories for removable devices\n"
206 "(this includes optical discs)",
207 DEFAULT_INDEX_REMOVABLE_DEVICES,
208 G_PARAM_READWRITE));
209 g_object_class_install_property (object_class,
210 PROP_INDEX_OPTICAL_DISCS,
211 g_param_spec_boolean ("index-optical-discs",
212 "index optical discs",
213 "Set to true to enable traversing CDs, DVDs, and generally optical media\n"
214 "(if removable devices are not indexed, optical discs won't be either)",
215 DEFAULT_INDEX_OPTICAL_DISCS,
216 G_PARAM_READWRITE));
217 g_object_class_install_property (object_class,
218 PROP_LOW_DISK_SPACE_LIMIT,
219 g_param_spec_int ("low-disk-space-limit",
220 "Low disk space limit",
221 "Pause indexer when disk space is <= this value\n"
222 "(0->100, value is in % of $HOME file system, -1=disable pausing)",
223 -1,
224 100,
225 DEFAULT_LOW_DISK_SPACE_LIMIT,
226 G_PARAM_READWRITE));
227 g_object_class_install_property (object_class,
228 PROP_INDEX_RECURSIVE_DIRECTORIES,
229 g_param_spec_boxed ("index-recursive-directories",
230 "Index recursive directories",
231 " List of directories to crawl recursively for indexing (separator=;)\n"
232 " Special values include: (see /etc/xdg/user-dirs.defaults & $HOME/.config/user-dirs.default)\n"
233 " &DESKTOP\n"
234 " &DOCUMENTS\n"
235 " &DOWNLOAD\n"
236 " &MUSIC\n"
237 " &PICTURES\n"
238 " &PUBLIC_SHARE\n"
239 " &TEMPLATES\n"
240 " &VIDEOS\n"
241 " If $HOME is the default below, it is because $HOME/.config/user-dirs.default was missing.",
242 G_TYPE_STRV,
243 G_PARAM_READWRITE));
244 g_object_class_install_property (object_class,
245 PROP_INDEX_SINGLE_DIRECTORIES,
246 g_param_spec_boxed ("index-single-directories",
247 "Index single directories",
248 " List of directories to index but not sub-directories for changes (separator=;)\n"
249 " Special values used for IndexRecursiveDirectories can also be used here",
250 G_TYPE_STRV,
251 G_PARAM_READWRITE));
252 g_object_class_install_property (object_class,
253 PROP_IGNORED_DIRECTORIES,
254 g_param_spec_boxed ("ignored-directories",
255 "Ignored directories",
256 " List of directories to NOT crawl for indexing (separator=;)",
257 G_TYPE_STRV,
258 G_PARAM_READWRITE));
259 g_object_class_install_property (object_class,
260 PROP_IGNORED_DIRECTORIES_WITH_CONTENT,
261 g_param_spec_boxed ("ignored-directories-with-content",
262 "Ignored directories with content",
263 " List of directories to NOT crawl for indexing based on child files (separator=;)",
264 G_TYPE_STRV,
265 G_PARAM_READWRITE));
266 g_object_class_install_property (object_class,
267 PROP_IGNORED_FILES,
268 g_param_spec_boxed ("ignored-files",
269 "Ignored files",
270 " List of files to NOT index (separator=;)",
271 G_TYPE_STRV,
272 G_PARAM_READWRITE));
273 g_object_class_install_property (object_class,
274 PROP_CRAWLING_INTERVAL,
275 g_param_spec_int ("crawling-interval",
276 "Crawling interval",
277 " Interval in days to check the filesystem is up to date in the database,"
278 " maximum is 365, default is -1.\n"
279 " -2 = crawling is disabled entirely\n"
280 " -1 = crawling *may* occur on startup (if not cleanly shutdown)\n"
281 " 0 = crawling is forced",
282 -2,
283 365,
284 DEFAULT_CRAWLING_INTERVAL,
285 G_PARAM_READWRITE));
286 g_object_class_install_property (object_class,
287 PROP_REMOVABLE_DAYS_THRESHOLD,
288 g_param_spec_int ("removable-days-threshold",
289 "Removable days threshold",
290 " Threshold in days after which files from removables devices"
291 " will be removed from database if not mounted. 0 means never, "
292 " maximum is 365.",
293 0,
294 365,
295 DEFAULT_REMOVABLE_DAYS_THRESHOLD,
296 G_PARAM_READWRITE));
297
298 /* Writeback */
299 g_object_class_install_property (object_class,
300 PROP_ENABLE_WRITEBACK,
301 g_param_spec_boolean ("enable-writeback",
302 "Enable Writeback",
303 "Set to false to disable writeback",
304 DEFAULT_ENABLE_WRITEBACK,
305 G_PARAM_READWRITE));
306 }
307
308 static void
tracker_config_init(TrackerConfig * object)309 tracker_config_init (TrackerConfig *object)
310 {
311 }
312
313 static void
config_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)314 config_set_property (GObject *object,
315 guint param_id,
316 const GValue *value,
317 GParamSpec *pspec)
318 {
319 TrackerConfig *config = TRACKER_CONFIG (object);
320
321 switch (param_id) {
322 /* General */
323 /* NOTE: We handle these because we have to be able
324 * to save these based on command line overrides.
325 */
326 case PROP_VERBOSITY:
327 tracker_config_set_verbosity (config, g_value_get_enum (value));
328 break;
329 case PROP_INITIAL_SLEEP:
330 tracker_config_set_initial_sleep (config, g_value_get_int (value));
331 break;
332
333 /* Indexing */
334 /* NOTE: We handle these specifically because we
335 * create convenience data around these lists.
336 */
337 case PROP_INDEX_RECURSIVE_DIRECTORIES: {
338 GStrv strv = g_value_get_boxed (value);
339 GSList *dirs = tracker_string_list_to_gslist (strv, -1);
340
341 config_set_index_recursive_directories (config, dirs);
342
343 g_slist_foreach (dirs, (GFunc) g_free, NULL);
344 g_slist_free (dirs);
345
346 break;
347 }
348 case PROP_INDEX_SINGLE_DIRECTORIES: {
349 GStrv strv = g_value_get_boxed (value);
350 GSList *dirs = tracker_string_list_to_gslist (strv, -1);
351
352 config_set_index_single_directories (config, dirs);
353
354 g_slist_foreach (dirs, (GFunc) g_free, NULL);
355 g_slist_free (dirs);
356 break;
357 }
358 case PROP_IGNORED_DIRECTORIES: {
359 GStrv strv = g_value_get_boxed (value);
360 GSList *dirs = tracker_string_list_to_gslist (strv, -1);
361
362 config_set_ignored_directories (config, dirs);
363
364 g_slist_foreach (dirs, (GFunc) g_free, NULL);
365 g_slist_free (dirs);
366 break;
367 }
368 case PROP_IGNORED_DIRECTORIES_WITH_CONTENT: {
369 GStrv strv = g_value_get_boxed (value);
370 GSList *dirs = tracker_string_list_to_gslist (strv, -1);
371
372 config_set_ignored_directories_with_content (config, dirs);
373
374 g_slist_foreach (dirs, (GFunc) g_free, NULL);
375 g_slist_free (dirs);
376 break;
377 }
378 case PROP_IGNORED_FILES: {
379 GStrv strv = g_value_get_boxed (value);
380 GSList *files = tracker_string_list_to_gslist (strv, -1);
381
382 config_set_ignored_files (config, files);
383
384 g_slist_foreach (files, (GFunc) g_free, NULL);
385 g_slist_free (files);
386 break;
387 }
388 default:
389 /* We don't care about the others... we don't save anyway. */
390 break;
391 };
392 }
393
394 static void
config_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)395 config_get_property (GObject *object,
396 guint param_id,
397 GValue *value,
398 GParamSpec *pspec)
399 {
400 TrackerConfig *config = TRACKER_CONFIG (object);
401 TrackerConfigPrivate *priv = tracker_config_get_instance_private (config);
402
403 switch (param_id) {
404 /* General */
405 case PROP_VERBOSITY:
406 g_value_set_enum (value, tracker_config_get_verbosity (config));
407 break;
408 case PROP_SCHED_IDLE:
409 g_value_set_enum (value, tracker_config_get_sched_idle (config));
410 break;
411 case PROP_INITIAL_SLEEP:
412 g_value_set_int (value, tracker_config_get_initial_sleep (config));
413 break;
414
415 /* Montors */
416 case PROP_ENABLE_MONITORS:
417 g_value_set_boolean (value, tracker_config_get_enable_monitors (config));
418 break;
419
420 /* Indexing */
421 case PROP_THROTTLE:
422 g_value_set_int (value, tracker_config_get_throttle (config));
423 break;
424 case PROP_INDEX_ON_BATTERY:
425 g_value_set_boolean (value, tracker_config_get_index_on_battery (config));
426 break;
427 case PROP_INDEX_ON_BATTERY_FIRST_TIME:
428 g_value_set_boolean (value, tracker_config_get_index_on_battery_first_time (config));
429 break;
430 case PROP_INDEX_REMOVABLE_DEVICES:
431 g_value_set_boolean (value, tracker_config_get_index_removable_devices (config));
432 break;
433 case PROP_INDEX_OPTICAL_DISCS:
434 g_value_set_boolean (value, tracker_config_get_index_optical_discs (config));
435 break;
436 case PROP_LOW_DISK_SPACE_LIMIT:
437 g_value_set_int (value, tracker_config_get_low_disk_space_limit (config));
438 break;
439 case PROP_INDEX_RECURSIVE_DIRECTORIES:
440 g_value_take_boxed (value, tracker_gslist_to_string_list (priv->index_recursive_directories_unfiltered));
441 break;
442 case PROP_INDEX_SINGLE_DIRECTORIES:
443 g_value_take_boxed (value, tracker_gslist_to_string_list (priv->index_single_directories_unfiltered));
444 break;
445 case PROP_IGNORED_DIRECTORIES:
446 g_value_take_boxed (value, tracker_gslist_to_string_list (priv->ignored_directories));
447 break;
448 case PROP_IGNORED_DIRECTORIES_WITH_CONTENT:
449 g_value_take_boxed (value, tracker_gslist_to_string_list (priv->ignored_directories_with_content));
450 break;
451 case PROP_IGNORED_FILES:
452 g_value_take_boxed (value, tracker_gslist_to_string_list (priv->ignored_files));
453 break;
454 case PROP_CRAWLING_INTERVAL:
455 g_value_set_int (value, tracker_config_get_crawling_interval (config));
456 break;
457 case PROP_REMOVABLE_DAYS_THRESHOLD:
458 g_value_set_int (value, tracker_config_get_removable_days_threshold (config));
459 break;
460
461 /* Writeback */
462 case PROP_ENABLE_WRITEBACK:
463 g_value_set_boolean (value, tracker_config_get_enable_writeback (config));
464 break;
465
466 /* Did we miss any new properties? */
467 default:
468 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
469 break;
470 };
471 }
472
473 static void
config_finalize(GObject * object)474 config_finalize (GObject *object)
475 {
476 TrackerConfigPrivate *priv;
477
478 priv = tracker_config_get_instance_private (TRACKER_CONFIG (object));
479
480 g_slist_foreach (priv->ignored_file_patterns,
481 (GFunc) g_pattern_spec_free,
482 NULL);
483 g_slist_free (priv->ignored_file_patterns);
484
485 g_slist_foreach (priv->ignored_file_paths,
486 (GFunc) g_free,
487 NULL);
488 g_slist_free (priv->ignored_file_paths);
489
490 g_slist_foreach (priv->ignored_directory_patterns,
491 (GFunc) g_pattern_spec_free,
492 NULL);
493 g_slist_free (priv->ignored_directory_patterns);
494
495 g_slist_foreach (priv->ignored_directory_paths,
496 (GFunc) g_free,
497 NULL);
498 g_slist_free (priv->ignored_directory_paths);
499
500 g_slist_foreach (priv->ignored_files, (GFunc) g_free, NULL);
501 g_slist_free (priv->ignored_files);
502
503 g_slist_foreach (priv->ignored_directories_with_content, (GFunc) g_free, NULL);
504 g_slist_free (priv->ignored_directories_with_content);
505
506 g_slist_foreach (priv->ignored_directories, (GFunc) g_free, NULL);
507 g_slist_free (priv->ignored_directories);
508
509 g_slist_foreach (priv->index_single_directories, (GFunc) g_free, NULL);
510 g_slist_free (priv->index_single_directories);
511
512 g_slist_foreach (priv->index_single_directories_unfiltered, (GFunc) g_free, NULL);
513 g_slist_free (priv->index_single_directories_unfiltered);
514
515 g_slist_foreach (priv->index_recursive_directories, (GFunc) g_free, NULL);
516 g_slist_free (priv->index_recursive_directories);
517
518 g_slist_foreach (priv->index_recursive_directories_unfiltered, (GFunc) g_free, NULL);
519 g_slist_free (priv->index_recursive_directories_unfiltered);
520
521 (G_OBJECT_CLASS (tracker_config_parent_class)->finalize) (object);
522 }
523
524 static GSList *
dir_mapping_get(GSList * dirs,gboolean is_recursive)525 dir_mapping_get (GSList *dirs,
526 gboolean is_recursive)
527 {
528 GSList *filtered = NULL;
529 GSList *evaluated_dirs, *l;
530
531 if (dirs) {
532 filtered = tracker_path_list_filter_duplicates (dirs, ".", is_recursive);
533 }
534
535 evaluated_dirs = NULL;
536
537 for (l = filtered; l; l = l->next) {
538 gchar *path_to_use;
539
540 path_to_use = tracker_path_evaluate_name (l->data);
541
542 if (path_to_use) {
543 evaluated_dirs = g_slist_prepend (evaluated_dirs, path_to_use);
544 }
545 }
546
547 g_slist_foreach (filtered, (GFunc) g_free, NULL);
548 g_slist_free (filtered);
549
550 return g_slist_reverse (evaluated_dirs);
551 }
552
553 static void
config_set_ignored_file_conveniences(TrackerConfig * config)554 config_set_ignored_file_conveniences (TrackerConfig *config)
555 {
556 TrackerConfigPrivate *priv;
557 GSList *l;
558 GSList *paths = NULL;
559 GSList *patterns = NULL;
560
561 priv = tracker_config_get_instance_private (config);
562
563 g_slist_foreach (priv->ignored_file_patterns,
564 (GFunc) g_pattern_spec_free,
565 NULL);
566 g_slist_free (priv->ignored_file_patterns);
567
568 g_slist_foreach (priv->ignored_file_paths,
569 (GFunc) g_free,
570 NULL);
571 g_slist_free (priv->ignored_file_paths);
572
573 for (l = priv->ignored_files; l; l = l->next) {
574 const gchar *str = l->data;
575
576 if (!str) {
577 continue;
578 }
579
580 if (G_LIKELY (*str != G_DIR_SEPARATOR)) {
581 GPatternSpec *spec;
582
583 spec = g_pattern_spec_new (l->data);
584 patterns = g_slist_prepend (patterns, spec);
585 } else {
586 paths = g_slist_prepend (paths, g_strdup (l->data));
587 }
588 }
589
590 priv->ignored_file_patterns = g_slist_reverse (patterns);
591 priv->ignored_file_paths = g_slist_reverse (paths);
592 }
593
594 static void
config_set_ignored_directory_conveniences(TrackerConfig * config)595 config_set_ignored_directory_conveniences (TrackerConfig *config)
596 {
597 TrackerConfigPrivate *priv;
598 GSList *l;
599 GSList *patterns = NULL;
600 GSList *paths = NULL;
601
602 priv = tracker_config_get_instance_private (config);
603
604 g_slist_foreach (priv->ignored_directory_patterns,
605 (GFunc) g_pattern_spec_free,
606 NULL);
607 g_slist_free (priv->ignored_directory_patterns);
608
609 g_slist_foreach (priv->ignored_directory_paths,
610 (GFunc) g_free,
611 NULL);
612 g_slist_free (priv->ignored_directory_paths);
613
614 for (l = priv->ignored_directories; l; l = l->next) {
615 const gchar *str = l->data;
616
617 if (!str) {
618 continue;
619 }
620
621 if (G_LIKELY (*str != G_DIR_SEPARATOR)) {
622 GPatternSpec *spec;
623
624 spec = g_pattern_spec_new (l->data);
625 patterns = g_slist_prepend (patterns, spec);
626 } else {
627 paths = g_slist_prepend (paths, g_strdup (l->data));
628 }
629 }
630
631 priv->ignored_directory_patterns = g_slist_reverse (patterns);
632 priv->ignored_directory_paths = g_slist_reverse (paths);
633 }
634
635 static void
config_constructed(GObject * object)636 config_constructed (GObject *object)
637 {
638 GSettings *settings;
639
640 (G_OBJECT_CLASS (tracker_config_parent_class)->constructed) (object);
641
642 settings = G_SETTINGS (object);
643
644 /* NOTE: Without the _delay() call the updates to settings
645 * from tracker-preferences may not happen before we notify
646 * about the property change from _set_*() APIs. This is
647 * because the GValue in set_property() is not up to date at
648 * the time we are called back. Quite fscking stupid really if
649 * you ask me.
650 *
651 * NOTE: We need this. If we don't we can't have local
652 * settings which are *NOT* stored in the GSettings database.
653 * We need this for overriding things like verbosity on start
654 * up.
655 */
656 if (G_LIKELY (!g_getenv ("TRACKER_USE_CONFIG_FILES"))) {
657 g_settings_delay (settings);
658 }
659
660 /* Set up bindings:
661 *
662 * What's interesting here is that 'verbosity' and
663 * 'initial-sleep' are command line arguments that can be
664 * overridden, so we don't update the config when we set them
665 * from main() because it's a session configuration only, not
666 * a permanent one. To do this we use the flag
667 * G_SETTINGS_BIND_GET_NO_CHANGES.
668 *
669 * For the other settings, we don't bind the
670 * G_SETTINGS_BIND_SET because we don't want to save anything,
671 * ever, we only want to know about updates to the settings as
672 * they're changed externally. The only time this may be
673 * different is where we use the environment variable
674 * TRACKER_USE_CONFIG_FILES and we want to write a config
675 * file for convenience. But this is only necessary if the
676 * config is different to the default.
677 */
678 g_settings_bind (settings, "verbosity", object, "verbosity", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_GET_NO_CHANGES);
679 g_settings_bind (settings, "sched-idle", object, "sched-idle", G_SETTINGS_BIND_GET);
680 g_settings_bind (settings, "initial-sleep", object, "initial-sleep", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_GET_NO_CHANGES);
681 g_settings_bind (settings, "throttle", object, "throttle", G_SETTINGS_BIND_GET);
682 g_settings_bind (settings, "low-disk-space-limit", object, "low-disk-space-limit", G_SETTINGS_BIND_GET);
683 g_settings_bind (settings, "crawling-interval", object, "crawling-interval", G_SETTINGS_BIND_GET);
684 g_settings_bind (settings, "low-disk-space-limit", object, "low-disk-space-limit", G_SETTINGS_BIND_GET);
685 g_settings_bind (settings, "removable-days-threshold", object, "removable-days-threshold", G_SETTINGS_BIND_GET);
686 g_settings_bind (settings, "enable-monitors", object, "enable-monitors", G_SETTINGS_BIND_GET);
687 g_settings_bind (settings, "enable-writeback", object, "enable-writeback", G_SETTINGS_BIND_GET);
688 g_settings_bind (settings, "index-removable-devices", object, "index-removable-devices", G_SETTINGS_BIND_GET);
689 g_settings_bind (settings, "index-optical-discs", object, "index-optical-discs", G_SETTINGS_BIND_GET);
690 g_settings_bind (settings, "index-on-battery", object, "index-on-battery", G_SETTINGS_BIND_GET);
691 g_settings_bind (settings, "index-on-battery-first-time", object, "index-on-battery-first-time", G_SETTINGS_BIND_GET);
692 g_settings_bind (settings, "index-recursive-directories", object, "index-recursive-directories", G_SETTINGS_BIND_GET);
693 g_settings_bind (settings, "index-single-directories", object, "index-single-directories", G_SETTINGS_BIND_GET);
694 g_settings_bind (settings, "ignored-files", object, "ignored-files", G_SETTINGS_BIND_GET);
695 g_settings_bind (settings, "ignored-directories", object, "ignored-directories", G_SETTINGS_BIND_GET);
696 g_settings_bind (settings, "ignored-directories-with-content", object, "ignored-directories-with-content", G_SETTINGS_BIND_GET);
697
698 config_set_ignored_file_conveniences (TRACKER_CONFIG (object));
699 config_set_ignored_directory_conveniences (TRACKER_CONFIG (object));
700 }
701
702 TrackerConfig *
tracker_config_new(void)703 tracker_config_new (void)
704 {
705 TrackerConfig *config = NULL;
706
707 /* FIXME: should we unset GSETTINGS_BACKEND env var? */
708
709 if (G_UNLIKELY (g_getenv ("TRACKER_USE_CONFIG_FILES"))) {
710 GSettingsBackend *backend;
711 gchar *filename, *basename;
712 gboolean need_to_save;
713
714 basename = g_strdup_printf ("%s.cfg", g_get_prgname ());
715 filename = g_build_filename (g_get_user_config_dir (), "tracker", basename, NULL);
716 g_free (basename);
717
718 need_to_save = g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE;
719
720 backend = g_keyfile_settings_backend_new (filename, CONFIG_PATH, "General");
721 g_info ("Using config file '%s'", filename);
722 g_free (filename);
723
724 config = g_object_new (TRACKER_TYPE_CONFIG,
725 "backend", backend,
726 "schema-id", CONFIG_SCHEMA,
727 "path", CONFIG_PATH,
728 NULL);
729 g_object_unref (backend);
730
731 if (need_to_save) {
732 g_info (" Config file does not exist, using default values...");
733 }
734 } else {
735 config = g_object_new (TRACKER_TYPE_CONFIG,
736 "schema-id", CONFIG_SCHEMA,
737 "path", CONFIG_PATH,
738 NULL);
739 }
740
741 return config;
742 }
743
744 gint
tracker_config_get_verbosity(TrackerConfig * config)745 tracker_config_get_verbosity (TrackerConfig *config)
746 {
747 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_VERBOSITY);
748
749 return g_settings_get_enum (G_SETTINGS (config), "verbosity");
750 }
751
752 gint
tracker_config_get_sched_idle(TrackerConfig * config)753 tracker_config_get_sched_idle (TrackerConfig *config)
754 {
755 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_SCHED_IDLE);
756
757 return g_settings_get_enum (G_SETTINGS (config), "sched-idle");
758 }
759
760 gint
tracker_config_get_initial_sleep(TrackerConfig * config)761 tracker_config_get_initial_sleep (TrackerConfig *config)
762 {
763 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_INITIAL_SLEEP);
764
765 return g_settings_get_int (G_SETTINGS (config), "initial-sleep");
766 }
767
768 gboolean
tracker_config_get_enable_monitors(TrackerConfig * config)769 tracker_config_get_enable_monitors (TrackerConfig *config)
770 {
771 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_ENABLE_MONITORS);
772
773 return g_settings_get_boolean (G_SETTINGS (config), "enable-monitors");
774 }
775
776 gboolean
tracker_config_get_enable_writeback(TrackerConfig * config)777 tracker_config_get_enable_writeback (TrackerConfig *config)
778 {
779 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_ENABLE_WRITEBACK);
780
781 return g_settings_get_boolean (G_SETTINGS (config), "enable-writeback");
782 }
783
784 gint
tracker_config_get_throttle(TrackerConfig * config)785 tracker_config_get_throttle (TrackerConfig *config)
786 {
787 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_THROTTLE);
788
789 return g_settings_get_int (G_SETTINGS (config), "throttle");
790 }
791
792 gboolean
tracker_config_get_index_on_battery(TrackerConfig * config)793 tracker_config_get_index_on_battery (TrackerConfig *config)
794 {
795 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_INDEX_ON_BATTERY);
796
797 return g_settings_get_boolean (G_SETTINGS (config), "index-on-battery");
798 }
799
800 gboolean
tracker_config_get_index_on_battery_first_time(TrackerConfig * config)801 tracker_config_get_index_on_battery_first_time (TrackerConfig *config)
802 {
803 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_INDEX_ON_BATTERY_FIRST_TIME);
804
805 return g_settings_get_boolean (G_SETTINGS (config), "index-on-battery-first-time");
806 }
807
808 gboolean
tracker_config_get_index_removable_devices(TrackerConfig * config)809 tracker_config_get_index_removable_devices (TrackerConfig *config)
810 {
811 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_INDEX_REMOVABLE_DEVICES);
812
813 return g_settings_get_boolean (G_SETTINGS (config), "index-removable-devices");
814 }
815
816 gboolean
tracker_config_get_index_optical_discs(TrackerConfig * config)817 tracker_config_get_index_optical_discs (TrackerConfig *config)
818 {
819 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_INDEX_OPTICAL_DISCS);
820
821 return g_settings_get_boolean (G_SETTINGS (config), "index-optical-discs");
822 }
823
824 gint
tracker_config_get_low_disk_space_limit(TrackerConfig * config)825 tracker_config_get_low_disk_space_limit (TrackerConfig *config)
826 {
827 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_LOW_DISK_SPACE_LIMIT);
828
829 return g_settings_get_int (G_SETTINGS (config), "low-disk-space-limit");
830 }
831
832 GSList *
tracker_config_get_index_recursive_directories(TrackerConfig * config)833 tracker_config_get_index_recursive_directories (TrackerConfig *config)
834 {
835 TrackerConfigPrivate *priv;
836
837 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
838
839 priv = tracker_config_get_instance_private (config);
840
841 return priv->index_recursive_directories;
842 }
843
844 GSList *
tracker_config_get_index_single_directories(TrackerConfig * config)845 tracker_config_get_index_single_directories (TrackerConfig *config)
846 {
847 TrackerConfigPrivate *priv;
848
849 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
850
851 priv = tracker_config_get_instance_private (config);
852
853 return priv->index_single_directories;
854 }
855
856 GSList *
tracker_config_get_ignored_directories(TrackerConfig * config)857 tracker_config_get_ignored_directories (TrackerConfig *config)
858 {
859 TrackerConfigPrivate *priv;
860
861 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
862
863 priv = tracker_config_get_instance_private (config);
864
865 return priv->ignored_directories;
866 }
867
868 GSList *
tracker_config_get_ignored_directories_with_content(TrackerConfig * config)869 tracker_config_get_ignored_directories_with_content (TrackerConfig *config)
870 {
871 TrackerConfigPrivate *priv;
872
873 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
874
875 priv = tracker_config_get_instance_private (config);
876
877 return priv->ignored_directories_with_content;
878 }
879
880 GSList *
tracker_config_get_ignored_files(TrackerConfig * config)881 tracker_config_get_ignored_files (TrackerConfig *config)
882 {
883 TrackerConfigPrivate *priv;
884
885 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
886
887 priv = tracker_config_get_instance_private (config);
888
889 return priv->ignored_files;
890 }
891
892 gint
tracker_config_get_crawling_interval(TrackerConfig * config)893 tracker_config_get_crawling_interval (TrackerConfig *config)
894 {
895 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_CRAWLING_INTERVAL);
896
897 return g_settings_get_int (G_SETTINGS (config), "crawling-interval");
898 }
899
900 gint
tracker_config_get_removable_days_threshold(TrackerConfig * config)901 tracker_config_get_removable_days_threshold (TrackerConfig *config)
902 {
903 g_return_val_if_fail (TRACKER_IS_CONFIG (config), DEFAULT_REMOVABLE_DAYS_THRESHOLD);
904
905 return g_settings_get_int (G_SETTINGS (config), "removable-days-threshold");
906 }
907
908 void
tracker_config_set_verbosity(TrackerConfig * config,gint value)909 tracker_config_set_verbosity (TrackerConfig *config,
910 gint value)
911 {
912 g_return_if_fail (TRACKER_IS_CONFIG (config));
913
914 g_settings_set_enum (G_SETTINGS (config), "verbosity", value);
915 g_object_notify (G_OBJECT (config), "verbosity");
916 }
917
918 void
tracker_config_set_initial_sleep(TrackerConfig * config,gint value)919 tracker_config_set_initial_sleep (TrackerConfig *config,
920 gint value)
921 {
922 g_return_if_fail (TRACKER_IS_CONFIG (config));
923
924 g_settings_set_int (G_SETTINGS (config), "initial-sleep", value);
925 g_object_notify (G_OBJECT (config), "initial-sleep");
926 }
927
928 static void
rebuild_filtered_lists(TrackerConfig * config)929 rebuild_filtered_lists (TrackerConfig *config)
930 {
931 TrackerConfigPrivate *priv;
932 GSList *old_list;
933
934 /* This function does 3 things:
935 * 1. Convert aliases like &DESKTOP to real paths
936 * 2. Filter and remove duplicates
937 * 3. Save the new list to the lists we return with public API
938 *
939 * Importantly, we:
940 * 1. Only notify on changes.
941 * 2. Don't update the unfiltered lists (since they have aliases)
942 */
943 priv = tracker_config_get_instance_private (config);
944
945 /* Filter single directories first, checking duplicates */
946 old_list = priv->index_single_directories;
947 priv->index_single_directories = NULL;
948
949 if (priv->index_single_directories_unfiltered) {
950 GSList *mapped_dirs = dir_mapping_get (priv->index_single_directories_unfiltered, FALSE);
951
952 priv->index_single_directories =
953 tracker_path_list_filter_duplicates (mapped_dirs, ".", FALSE);
954
955 if (mapped_dirs) {
956 g_slist_foreach (mapped_dirs, (GFunc) g_free, NULL);
957 g_slist_free (mapped_dirs);
958 }
959 }
960
961 if (!tracker_gslist_with_string_data_equal (old_list, priv->index_single_directories)) {
962 g_object_notify (G_OBJECT (config), "index-single-directories");
963 }
964
965 if (old_list) {
966 g_slist_foreach (old_list, (GFunc) g_free, NULL);
967 g_slist_free (old_list);
968 }
969
970 /* Filter recursive directories */
971 old_list = priv->index_recursive_directories;
972 priv->index_recursive_directories = NULL;
973
974 if (priv->index_recursive_directories_unfiltered) {
975 GSList *l, *checked_dirs = NULL;
976 GSList *mapped_dirs;
977
978 /* First, translate aliases */
979 mapped_dirs = dir_mapping_get (priv->index_recursive_directories_unfiltered, TRUE);
980
981 /* Second, remove elements already in single directories */
982 for (l = mapped_dirs; l; l = l->next) {
983 if (g_slist_find_custom (priv->index_single_directories,
984 l->data,
985 (GCompareFunc) g_strcmp0) != NULL) {
986 g_message ("Path '%s' being removed from recursive directories "
987 "list, as it also exists in single directories list",
988 (gchar *) l->data);
989 } else {
990 checked_dirs = g_slist_prepend (checked_dirs, l->data);
991 }
992 }
993
994 g_slist_free (mapped_dirs);
995 checked_dirs = g_slist_reverse (checked_dirs);
996
997 /* Third, clean up any duplicates */
998 priv->index_recursive_directories =
999 tracker_path_list_filter_duplicates (checked_dirs, ".", TRUE);
1000
1001 g_slist_foreach (checked_dirs, (GFunc) g_free, NULL);
1002 g_slist_free (checked_dirs);
1003 }
1004
1005 if (!tracker_gslist_with_string_data_equal (old_list, priv->index_recursive_directories)) {
1006 g_object_notify (G_OBJECT (config), "index-recursive-directories");
1007 }
1008
1009 if (old_list) {
1010 g_slist_foreach (old_list, (GFunc) g_free, NULL);
1011 g_slist_free (old_list);
1012 }
1013 }
1014
1015 static void
config_set_index_recursive_directories(TrackerConfig * config,GSList * roots)1016 config_set_index_recursive_directories (TrackerConfig *config,
1017 GSList *roots)
1018 {
1019 TrackerConfigPrivate *priv;
1020 GSList *l;
1021 gboolean equal;
1022
1023 g_return_if_fail (TRACKER_IS_CONFIG (config));
1024
1025 priv = tracker_config_get_instance_private (config);
1026
1027 l = priv->index_recursive_directories_unfiltered;
1028
1029 equal = tracker_gslist_with_string_data_equal (roots, l);
1030
1031 if (!roots) {
1032 priv->index_recursive_directories_unfiltered = NULL;
1033 } else {
1034 priv->index_recursive_directories_unfiltered =
1035 tracker_gslist_copy_with_string_data (roots);
1036 }
1037
1038 g_slist_foreach (l, (GFunc) g_free, NULL);
1039 g_slist_free (l);
1040
1041 if (equal) {
1042 return;
1043 }
1044
1045 rebuild_filtered_lists (config);
1046 }
1047
1048 static void
config_set_index_single_directories(TrackerConfig * config,GSList * roots)1049 config_set_index_single_directories (TrackerConfig *config,
1050 GSList *roots)
1051 {
1052 TrackerConfigPrivate *priv;
1053 GSList *l;
1054 gboolean equal;
1055
1056 g_return_if_fail (TRACKER_IS_CONFIG (config));
1057
1058 priv = tracker_config_get_instance_private (config);
1059
1060 l = priv->index_single_directories_unfiltered;
1061
1062 equal = tracker_gslist_with_string_data_equal (roots, l);
1063
1064 if (!roots) {
1065 priv->index_single_directories_unfiltered = NULL;
1066 } else {
1067 priv->index_single_directories_unfiltered =
1068 tracker_gslist_copy_with_string_data (roots);
1069 }
1070
1071 g_slist_foreach (l, (GFunc) g_free, NULL);
1072 g_slist_free (l);
1073
1074 if (equal) {
1075 return;
1076 }
1077
1078 rebuild_filtered_lists (config);
1079 }
1080
1081 static void
config_set_ignored_directories(TrackerConfig * config,GSList * roots)1082 config_set_ignored_directories (TrackerConfig *config,
1083 GSList *roots)
1084 {
1085 TrackerConfigPrivate *priv;
1086 GSList *l;
1087 gboolean equal;
1088
1089 g_return_if_fail (TRACKER_IS_CONFIG (config));
1090
1091 priv = tracker_config_get_instance_private (config);
1092
1093 l = priv->ignored_directories;
1094
1095 equal = tracker_gslist_with_string_data_equal (roots, l);
1096
1097 if (!roots) {
1098 priv->ignored_directories = NULL;
1099 } else {
1100 priv->ignored_directories =
1101 tracker_gslist_copy_with_string_data (roots);
1102 }
1103
1104 g_slist_foreach (l, (GFunc) g_free, NULL);
1105 g_slist_free (l);
1106
1107 if (equal) {
1108 return;
1109 }
1110
1111 /* Re-set up the GPatternSpec list */
1112 config_set_ignored_directory_conveniences (config);
1113
1114 g_object_notify (G_OBJECT (config), "ignored-directories");
1115 }
1116
1117 static void
config_set_ignored_directories_with_content(TrackerConfig * config,GSList * roots)1118 config_set_ignored_directories_with_content (TrackerConfig *config,
1119 GSList *roots)
1120 {
1121 TrackerConfigPrivate *priv;
1122 GSList *l;
1123 gboolean equal;
1124
1125 g_return_if_fail (TRACKER_IS_CONFIG (config));
1126
1127 priv = tracker_config_get_instance_private (config);
1128
1129 l = priv->ignored_directories_with_content;
1130
1131 equal = tracker_gslist_with_string_data_equal (roots, l);
1132
1133 if (!roots) {
1134 priv->ignored_directories_with_content = NULL;
1135 } else {
1136 priv->ignored_directories_with_content =
1137 tracker_gslist_copy_with_string_data (roots);
1138 }
1139
1140 g_slist_foreach (l, (GFunc) g_free, NULL);
1141 g_slist_free (l);
1142
1143 if (equal) {
1144 return;
1145 }
1146
1147 g_object_notify (G_OBJECT (config), "ignored-directories-with-content");
1148 }
1149
1150 static void
config_set_ignored_files(TrackerConfig * config,GSList * files)1151 config_set_ignored_files (TrackerConfig *config,
1152 GSList *files)
1153 {
1154 TrackerConfigPrivate *priv;
1155 GSList *l;
1156 gboolean equal;
1157
1158 g_return_if_fail (TRACKER_IS_CONFIG (config));
1159
1160 priv = tracker_config_get_instance_private (config);
1161
1162 l = priv->ignored_files;
1163
1164 equal = tracker_gslist_with_string_data_equal (files, l);
1165
1166 if (!files) {
1167 priv->ignored_files = NULL;
1168 } else {
1169 priv->ignored_files =
1170 tracker_gslist_copy_with_string_data (files);
1171 }
1172
1173 g_slist_foreach (l, (GFunc) g_free, NULL);
1174 g_slist_free (l);
1175
1176 if (equal) {
1177 return;
1178 }
1179
1180 /* Re-set up the GPatternSpec list */
1181 config_set_ignored_file_conveniences (config);
1182
1183 g_object_notify (G_OBJECT (config), "ignored-files");
1184 }
1185
1186 /*
1187 * Convenience functions
1188 */
1189
1190 GSList *
tracker_config_get_ignored_directory_patterns(TrackerConfig * config)1191 tracker_config_get_ignored_directory_patterns (TrackerConfig *config)
1192 {
1193 TrackerConfigPrivate *priv;
1194
1195 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
1196
1197 priv = tracker_config_get_instance_private (config);
1198
1199 return priv->ignored_directory_patterns;
1200 }
1201
1202 GSList *
tracker_config_get_ignored_file_patterns(TrackerConfig * config)1203 tracker_config_get_ignored_file_patterns (TrackerConfig *config)
1204 {
1205 TrackerConfigPrivate *priv;
1206
1207 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
1208
1209 priv = tracker_config_get_instance_private (config);
1210
1211 return priv->ignored_file_patterns;
1212 }
1213
1214 GSList *
tracker_config_get_ignored_directory_paths(TrackerConfig * config)1215 tracker_config_get_ignored_directory_paths (TrackerConfig *config)
1216 {
1217 TrackerConfigPrivate *priv;
1218
1219 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
1220
1221 priv = tracker_config_get_instance_private (config);
1222
1223 return priv->ignored_directory_paths;
1224 }
1225
1226 GSList *
tracker_config_get_ignored_file_paths(TrackerConfig * config)1227 tracker_config_get_ignored_file_paths (TrackerConfig *config)
1228 {
1229 TrackerConfigPrivate *priv;
1230
1231 g_return_val_if_fail (TRACKER_IS_CONFIG (config), NULL);
1232
1233 priv = tracker_config_get_instance_private (config);
1234
1235 return priv->ignored_file_paths;
1236 }
1237