tracker-0.16.2/src/tracker-utils/tracker-search.c

No issues found

   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 Library General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 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  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Library 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 <stdlib.h>
  23 #include <string.h>
  24 #include <time.h>
  25 #include <locale.h>
  26 
  27 #include <glib.h>
  28 #include <glib/gi18n.h>
  29 
  30 #include <libtracker-sparql/tracker-sparql.h>
  31 
  32 #include <libtracker-common/tracker-common.h>
  33 
  34 #define ABOUT	  \
  35 	"Tracker " PACKAGE_VERSION "\n"
  36 
  37 #define LICENSE	  \
  38 	"This program is free software and comes without any warranty.\n" \
  39 	"It is licensed under version 2 or later of the General Public " \
  40 	"License which can be viewed at:\n" \
  41 	"\n" \
  42 	"  http://www.gnu.org/licenses/gpl.txt\n"
  43 
  44 #define TITLE_BEGIN   "\033[32m"   /* Green */
  45 #define TITLE_END     "\033[0m"
  46 
  47 #define SNIPPET_BEGIN "\033[1;31m" /* Red */
  48 #define SNIPPET_END   "\033[0m"
  49 
  50 #define WARN_BEGIN    "\033[33m"   /* Yellow */
  51 #define WARN_END      "\033[0m"
  52 
  53 static gint limit = -1;
  54 static gint offset;
  55 static gchar **terms;
  56 static gboolean or_operator;
  57 static gboolean detailed;
  58 static gboolean all;
  59 static gboolean disable_snippets;
  60 static gboolean disable_fts;
  61 static gboolean disable_color;
  62 static gboolean files;
  63 static gboolean folders;
  64 static gboolean music_albums;
  65 static gboolean music_artists;
  66 static gboolean music_files;
  67 static gboolean image_files;
  68 static gboolean video_files;
  69 static gboolean document_files;
  70 static gboolean emails;
  71 static gboolean contacts;
  72 static gboolean feeds;
  73 static gboolean software;
  74 static gboolean software_categories;
  75 static gboolean bookmarks;
  76 static gboolean print_version;
  77 
  78 static GOptionEntry semantic_entries[] = {
  79 	{ "limit", 'l', 0, G_OPTION_ARG_INT, &limit,
  80 	  N_("Limit the number of results shown"),
  81 	  N_("512")
  82 	},
  83 	{ "offset", 'o', 0, G_OPTION_ARG_INT, &offset,
  84 	  N_("Offset the results"),
  85 	  N_("0")
  86 	},
  87 	{ "or-operator", 'r', 0, G_OPTION_ARG_NONE, &or_operator,
  88 	  N_("Use OR for search terms instead of AND (the default)"),
  89 	  NULL
  90 	},
  91 	{ "detailed", 'd', 0, G_OPTION_ARG_NONE, &detailed,
  92 	  N_("Show URNs for results (doesn't apply to --music-albums, --music-artists, --feeds, --software, --software-categories)"),
  93 	  NULL
  94 	},
  95 	{ "all", 'a', 0, G_OPTION_ARG_NONE, &all,
  96 	  N_("Return all non-existing matches too (i.e. include unmounted volumes)"),
  97 	  NULL
  98 	},
  99 	{ "disable-snippets", 0, 0, G_OPTION_ARG_NONE, &disable_snippets,
 100 	  N_("Disable showing snippets with results. This is only shown for some categories, e.g. Documents, Music..."),
 101 	  NULL,
 102 	},
 103 	{ "disable-fts", 0, 0, G_OPTION_ARG_NONE, &disable_fts,
 104 	  N_("Disable Full Text Search (FTS). Implies --disable-snippets"),
 105 	  NULL,
 106 	},
 107 	{ "disable-color", 0, 0, G_OPTION_ARG_NONE, &disable_color,
 108 	  N_("Disable color when printing snippets and results"),
 109 	  NULL,
 110 	},
 111 	{ "version", 'V', 0, G_OPTION_ARG_NONE, &print_version,
 112 	  N_("Print version"),
 113 	  NULL
 114 	},
 115 	{ NULL }
 116 };
 117 
 118 static GOptionEntry category_entries[] = {
 119 	{ "files", 'f', 0, G_OPTION_ARG_NONE, &files,
 120 	  N_("Search for files"),
 121 	  NULL
 122 	},
 123 	{ "folders", 's', 0, G_OPTION_ARG_NONE, &folders,
 124 	  N_("Search for folders"),
 125 	  NULL
 126 	},
 127 	{ "music", 'm', 0, G_OPTION_ARG_NONE, &music_files,
 128 	  N_("Search for music files"),
 129 	  NULL
 130 	},
 131 	{ "music-albums", 0, 0, G_OPTION_ARG_NONE, &music_albums,
 132 	  N_("Search for music albums (--all has no effect on this)"),
 133 	  NULL
 134 	},
 135 	{ "music-artists", 0, 0, G_OPTION_ARG_NONE, &music_artists,
 136 	  N_("Search for music artists (--all has no effect on this)"),
 137 	  NULL
 138 	},
 139 	{ "images", 'i', 0, G_OPTION_ARG_NONE, &image_files,
 140 	  N_("Search for image files"),
 141 	  NULL
 142 	},
 143 	{ "videos", 'v', 0, G_OPTION_ARG_NONE, &video_files,
 144 	  N_("Search for video files"),
 145 	  NULL
 146 	},
 147 	{ "documents", 't', 0, G_OPTION_ARG_NONE, &document_files,
 148 	  N_("Search for document files"),
 149 	  NULL
 150 	},
 151 	{ "emails", 'e', 0, G_OPTION_ARG_NONE, &emails,
 152 	  N_("Search for emails"),
 153 	  NULL
 154 	},
 155 	{ "contacts", 'c', 0, G_OPTION_ARG_NONE, &contacts,
 156 	  N_("Search for contacts"),
 157 	  NULL
 158 	},
 159 	{ "software", 0, 0, G_OPTION_ARG_NONE, &software,
 160 	  N_("Search for software (--all has no effect on this)"),
 161 	  NULL
 162 	},
 163 	{ "software-categories", 0, 0, G_OPTION_ARG_NONE, &software_categories,
 164 	  N_("Search for software categories (--all has no effect on this)"),
 165 	  NULL
 166 	},
 167 	{ "feeds", 0, 0, G_OPTION_ARG_NONE, &feeds,
 168 	  N_("Search for feeds (--all has no effect on this)"),
 169 	  NULL
 170 	},
 171 	{ "bookmarks", 'b', 0, G_OPTION_ARG_NONE, &bookmarks,
 172 	  N_("Search for bookmarks (--all has no effect on this)"),
 173 	  NULL
 174 	},
 175 	{ G_OPTION_REMAINING, 0, 0,
 176 	  G_OPTION_ARG_STRING_ARRAY, &terms,
 177 	  N_("search terms"),
 178 	  N_("EXPRESSION")
 179 	},
 180 	{ NULL }
 181 };
 182 
 183 static void
 184 show_limit_warning (void)
 185 {
 186 	/* Display '...' so the user thinks there is
 187 	 * more items.
 188 	 */
 189 	g_print ("  ...\n");
 190 
 191 	/* Display warning so the user knows this is
 192 	 * not the WHOLE data set.
 193 	 */
 194 	g_printerr ("\n%s%s%s\n",
 195 	            disable_color ? "" : WARN_BEGIN,
 196 	            _("NOTE: Limit was reached, there are more items in the database not listed here"),
 197 	            disable_color ? "" : WARN_END);
 198 }
 199 
 200 static gchar *
 201 get_fts_string (GStrv    search_words,
 202                 gboolean use_or_operator)
 203 {
 204 #if HAVE_TRACKER_FTS
 205 	GString *fts;
 206 	gint i, len;
 207 
 208 	if (disable_fts) {
 209 		return NULL;
 210 	}
 211 
 212 	if (!search_words) {
 213 		return NULL;
 214 	}
 215 
 216 	fts = g_string_new ("");
 217 	len = g_strv_length (search_words);
 218 
 219 	for (i = 0; i < len; i++) {
 220 		gchar *escaped;
 221 
 222 		/* Properly escape the input string as it's going to be passed
 223 		 * in a sparql query */
 224 		escaped = tracker_sparql_escape_string (search_words[i]);
 225 
 226 		g_string_append (fts, escaped);
 227 
 228 		if (i < len - 1) {
 229 			if (use_or_operator) {
 230 				g_string_append (fts, " OR ");
 231 			} else {
 232 				g_string_append (fts, " ");
 233 			}
 234 		}
 235 
 236 		g_free (escaped);
 237 	}
 238 
 239 	return g_string_free (fts, FALSE);
 240 #else
 241 	/* If FTS support not enabled, always do non-fts searches */
 242 	return NULL;
 243 #endif
 244 }
 245 
 246 static inline void
 247 print_snippet (const gchar *snippet)
 248 {
 249 	if (disable_snippets) {
 250 		return;
 251 	}
 252 
 253 	if (!snippet || *snippet == '\0') {
 254 		return;
 255 	} else {
 256 		gchar *compressed;
 257 		gchar *p;
 258 
 259 		compressed = g_strdup (snippet);
 260 
 261 		for (p = compressed;
 262 		     p && *p != '\0';
 263 		     p = g_utf8_next_char (p)) {
 264 			if (*p == '\r' || *p == '\n') {
 265 				/* inline \n and \r */
 266 				*p = ' ';
 267 			}
 268 		}
 269 
 270 		g_print ("  %s\n", compressed);
 271 		g_free (compressed);
 272 	}
 273 
 274 	g_print ("\n");
 275 }
 276 
 277 static gboolean
 278 get_contacts_results (TrackerSparqlConnection *connection,
 279                       const gchar             *query,
 280                       gint                     search_limit,
 281                       gboolean                 details)
 282 {
 283 	GError *error = NULL;
 284 	TrackerSparqlCursor *cursor;
 285 
 286 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
 287 
 288 	if (error) {
 289 		g_printerr ("%s, %s\n",
 290 		            _("Could not get search results"),
 291 		            error->message);
 292 		g_error_free (error);
 293 
 294 		return FALSE;
 295 	}
 296 
 297 	if (!cursor) {
 298 		g_print ("%s\n",
 299 		         _("No contacts were found"));
 300 	} else {
 301 		gint count = 0;
 302 
 303 		g_print ("%s:\n", _("Contacts"));
 304 
 305 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
 306 			if (details) {
 307 				g_print ("  '%s%s%s', %s (%s)\n",
 308 		                         disable_color ? "" : TITLE_BEGIN,
 309 				         tracker_sparql_cursor_get_string (cursor, 0, NULL),
 310 		                         disable_color ? "" : TITLE_END,
 311 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 312 				         tracker_sparql_cursor_get_string (cursor, 2, NULL));
 313 			} else {
 314 				g_print ("  '%s%s%s', %s\n",
 315 		                         disable_color ? "" : TITLE_BEGIN,
 316 				         tracker_sparql_cursor_get_string (cursor, 0, NULL),
 317 		                         disable_color ? "" : TITLE_END,
 318 				         tracker_sparql_cursor_get_string (cursor, 1, NULL));
 319 			}
 320 
 321 			count++;
 322 		}
 323 
 324 		g_print ("\n");
 325 
 326 		if (count >= search_limit) {
 327 			show_limit_warning ();
 328 		}
 329 
 330 		g_object_unref (cursor);
 331 	}
 332 
 333 	return TRUE;
 334 }
 335 
 336 static gboolean
 337 get_contacts (TrackerSparqlConnection *connection,
 338               GStrv                    search_terms,
 339               gboolean                 show_all,
 340               gint                     search_offset,
 341               gint                     search_limit,
 342               gboolean                 use_or_operator,
 343               gboolean                 details)
 344 {
 345 	gchar *fts;
 346 	gchar *query;
 347 	gboolean success;
 348 
 349 	fts = get_fts_string (search_terms, use_or_operator);
 350 
 351 	if (fts) {
 352 		query = g_strdup_printf ("SELECT tracker:coalesce(nco:fullname(?contact), fn:concat(nco:nameFamily(?contact), \" \", nco:nameGiven(?contact)),\"%s\") tracker:coalesce(nco:hasEmailAddress(?contact), \"%s\") ?contact "
 353 		                         "WHERE { "
 354 		                         "  ?contact a nco:Contact ;"
 355 		                         "  fts:match \"%s\" ."
 356 		                         "} "
 357 		                         "ORDER BY ASC(nco:fullname(?contact)) ASC(nco:hasEmailAddress(?contact)) "
 358 		                         "OFFSET %d "
 359 		                         "LIMIT %d",
 360                                          _("No name"),
 361                                          _("No E-mail address"),
 362 		                         fts,
 363 		                         search_offset,
 364 		                         search_limit);
 365 	} else {
 366 		query = g_strdup_printf ("SELECT tracker:coalesce(nco:fullname(?contact), fn:concat(nco:nameFamily(?contact), \" \", nco:nameGiven(?contact)), \"%s\") tracker:coalesce(nco:hasEmailAddress(?contact), \"%s\") ?contact "
 367 		                         "WHERE { "
 368 		                         "  ?contact a nco:Contact ."
 369 		                         "} "
 370 		                         "ORDER BY ASC(nco:fullname(?contact)) ASC(nco:hasEmailAddress(?contact)) "
 371 		                         "OFFSET %d "
 372 		                         "LIMIT %d",
 373                                          _("No name"),
 374                                          _("No E-mail address"),
 375 		                         search_offset,
 376 		                         search_limit);
 377 	}
 378 
 379 	success = get_contacts_results (connection, query, search_limit, details);
 380 	g_free (query);
 381 	g_free (fts);
 382 
 383 	return success;
 384 }
 385 
 386 static gboolean
 387 get_emails_results (TrackerSparqlConnection *connection,
 388                     const gchar             *query,
 389                     gint                     search_limit,
 390                     gboolean                 details)
 391 {
 392 	GError *error = NULL;
 393 	TrackerSparqlCursor *cursor;
 394 
 395 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
 396 
 397 	if (error) {
 398 		g_printerr ("%s, %s\n",
 399 		            _("Could not get search results"),
 400 		            error->message);
 401 		g_error_free (error);
 402 
 403 		return FALSE;
 404 	}
 405 
 406 	if (!cursor) {
 407 		g_print ("%s\n",
 408 		         _("No emails were found"));
 409 	} else {
 410 		gint count = 0;
 411 
 412 		g_print ("%s:\n", _("Emails"));
 413 
 414 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
 415 			if (details) {
 416 				g_print ("  %s%s%s, %s (%s)\n",
 417 		                         disable_color ? "" : TITLE_BEGIN,
 418 				         tracker_sparql_cursor_get_string (cursor, 0, NULL),
 419 		                         disable_color ? "" : TITLE_END,
 420 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 421 				         tracker_sparql_cursor_get_string (cursor, 2, NULL));
 422 
 423 				print_snippet (tracker_sparql_cursor_get_string (cursor, 3, NULL));
 424 			} else {
 425 				g_print ("  %s%s%s, %s\n",
 426 		                         disable_color ? "" : TITLE_BEGIN,
 427 				         tracker_sparql_cursor_get_string (cursor, 0, NULL),
 428 		                         disable_color ? "" : TITLE_END,
 429 				         tracker_sparql_cursor_get_string (cursor, 1, NULL));
 430 
 431 				print_snippet (tracker_sparql_cursor_get_string (cursor, 2, NULL));
 432 			}
 433 
 434 			count++;
 435 		}
 436 
 437 		g_print ("\n");
 438 
 439 		if (count >= search_limit) {
 440 			show_limit_warning ();
 441 		}
 442 
 443 		g_object_unref (cursor);
 444 	}
 445 
 446 	return TRUE;
 447 }
 448 
 449 static gboolean
 450 get_emails (TrackerSparqlConnection *connection,
 451             GStrv                    search_terms,
 452             gboolean                 show_all,
 453             gint                     search_offset,
 454             gint                     search_limit,
 455             gboolean                 use_or_operator,
 456             gboolean                 details)
 457 {
 458 	gchar *fts;
 459 	gchar *query;
 460 	gboolean success;
 461 
 462 	fts = get_fts_string (search_terms, use_or_operator);
 463 
 464 	if (fts) {
 465 		query = g_strdup_printf ("SELECT nmo:receivedDate(?email) nmo:messageSubject(?email) nie:url(?email) fts:snippet(?email, \"%s\", \"%s\") "
 466 		                         "WHERE { "
 467 		                         "  ?email a nmo:Email ;"
 468 		                         "  fts:match \"%s\" ."
 469 		                         "} "
 470 		                         "ORDER BY ASC(nmo:messageSubject(?email)) ASC(nmo:receivedDate(?email))"
 471 		                         "OFFSET %d "
 472 		                         "LIMIT %d",
 473 		                         disable_color ? "" : SNIPPET_BEGIN,
 474 		                         disable_color ? "" : SNIPPET_END,
 475 		                         fts,
 476 		                         search_offset,
 477 		                         search_limit);
 478 	} else {
 479 		query = g_strdup_printf ("SELECT nmo:receivedDate(?email) nmo:messageSubject(?email) nie:url(?email) "
 480 		                         "WHERE { "
 481 		                         "  ?email a nmo:Email ."
 482 		                         "} "
 483 		                         "ORDER BY ASC(nmo:messageSubject(?email)) ASC(nmo:receivedDate(?email))"
 484 		                         "OFFSET %d "
 485 		                         "LIMIT %d",
 486 		                         search_offset,
 487 		                         search_limit);
 488 	}
 489 
 490 	success = get_emails_results (connection, query, search_limit, details);
 491 	g_free (query);
 492 	g_free (fts);
 493 
 494 	return success;
 495 }
 496 
 497 static gboolean
 498 get_files_results (TrackerSparqlConnection *connection,
 499                    const gchar             *query,
 500                    gint                     search_limit,
 501                    gboolean                 details)
 502 {
 503 	GError *error = NULL;
 504 	TrackerSparqlCursor *cursor;
 505 
 506 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
 507 
 508 	if (error) {
 509 		g_printerr ("%s, %s\n",
 510 		            _("Could not get search results"),
 511 		            error->message);
 512 		g_error_free (error);
 513 
 514 		return FALSE;
 515 	}
 516 
 517 	if (!cursor) {
 518 		g_print ("%s\n",
 519 		         _("No files were found"));
 520 	} else {
 521 		gint count = 0;
 522 
 523 		g_print ("%s:\n", _("Files"));
 524 
 525 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
 526 			if (details) {
 527 				g_print ("  %s%s%s (%s)\n",
 528 		                         disable_color ? "" : TITLE_BEGIN,
 529 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 530 		                         disable_color ? "" : TITLE_END,
 531 				         tracker_sparql_cursor_get_string (cursor, 0, NULL));
 532 
 533 				print_snippet (tracker_sparql_cursor_get_string (cursor, 2, NULL));
 534 			} else {
 535 				g_print ("  %s%s%s\n",
 536 		                         disable_color ? "" : TITLE_BEGIN,
 537 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 538 				         disable_color ? "" : TITLE_END);
 539 
 540 				print_snippet (tracker_sparql_cursor_get_string (cursor, 2, NULL));
 541 			}
 542 
 543 			count++;
 544 		}
 545 
 546 		g_print ("\n");
 547 
 548 		if (count >= search_limit) {
 549 			show_limit_warning ();
 550 		}
 551 
 552 		g_object_unref (cursor);
 553 	}
 554 
 555 	return TRUE;
 556 }
 557 
 558 static gboolean
 559 get_document_files (TrackerSparqlConnection *connection,
 560                     GStrv                    search_terms,
 561                     gboolean                 show_all,
 562                     gint                     search_offset,
 563                     gint                     search_limit,
 564                     gboolean                 use_or_operator,
 565                     gboolean                 details)
 566 {
 567 	gchar *fts;
 568 	gchar *query;
 569 	const gchar *show_all_str;
 570 	gboolean success;
 571 
 572 	show_all_str = show_all ? "" : "?document tracker:available true .";
 573 	fts = get_fts_string (search_terms, use_or_operator);
 574 
 575 	if (fts) {
 576 		query = g_strdup_printf ("SELECT ?document nie:url(?document) fts:snippet(?document, \"%s\", \"%s\") "
 577 		                         "WHERE { "
 578 		                         "  ?document a nfo:Document ;"
 579 		                         "  fts:match \"%s\" ."
 580 		                         "  %s"
 581 		                         "} "
 582 		                         "ORDER BY ASC(nie:url(?document)) "
 583 		                         "OFFSET %d "
 584 		                         "LIMIT %d",
 585 		                         disable_color ? "" : SNIPPET_BEGIN,
 586 		                         disable_color ? "" : SNIPPET_END,
 587 		                         fts,
 588 		                         show_all_str,
 589 		                         search_offset,
 590 		                         search_limit);
 591 	} else {
 592 		query = g_strdup_printf ("SELECT ?document nie:url(?document) "
 593 		                         "WHERE { "
 594 		                         "  ?document a nfo:Document ."
 595 		                         "  %s"
 596 		                         "} "
 597 		                         "ORDER BY ASC(nie:url(?document)) "
 598 		                         "OFFSET %d "
 599 		                         "LIMIT %d",
 600 		                         show_all_str,
 601 		                         search_offset,
 602 		                         search_limit);
 603 	}
 604 
 605 	success = get_files_results (connection, query, search_limit, details);
 606 	g_free (query);
 607 	g_free (fts);
 608 
 609 	return success;
 610 }
 611 
 612 static gboolean
 613 get_video_files (TrackerSparqlConnection *connection,
 614                  GStrv                    search_terms,
 615                  gboolean                 show_all,
 616                  gint                     search_offset,
 617                  gint                     search_limit,
 618                  gboolean                 use_or_operator,
 619                  gboolean                 details)
 620 {
 621 	gchar *fts;
 622 	gchar *query;
 623 	const gchar *show_all_str;
 624 	gboolean success;
 625 
 626 	show_all_str = show_all ? "" : "?video tracker:available true . ";
 627 	fts = get_fts_string (search_terms, use_or_operator);
 628 
 629 	if (fts) {
 630 		query = g_strdup_printf ("SELECT ?video nie:url(?video) fts:snippet(?video, \"%s\", \"%s\") "
 631 		                         "WHERE { "
 632 		                         "  ?video a nfo:Video ;"
 633 		                         "  fts:match \"%s\" ."
 634 		                         "  %s"
 635 		                         "} "
 636 		                         "ORDER BY ASC(nie:url(?video)) "
 637 		                         "OFFSET %d "
 638 		                         "LIMIT %d",
 639 		                         disable_color ? "" : SNIPPET_BEGIN,
 640 		                         disable_color ? "" : SNIPPET_END,
 641 		                         fts,
 642 		                         show_all_str,
 643 		                         search_offset,
 644 		                         search_limit);
 645 	} else {
 646 		query = g_strdup_printf ("SELECT ?video nie:url(?video) "
 647 		                         "WHERE { "
 648 		                         "  ?video a nfo:Video ."
 649 		                         "  %s"
 650 		                         "} "
 651 		                         "ORDER BY ASC(nie:url(?video)) "
 652 		                         "OFFSET %d "
 653 		                         "LIMIT %d",
 654 		                         show_all_str,
 655 		                         search_offset,
 656 		                         search_limit);
 657 	}
 658 
 659 	success = get_files_results (connection, query, search_limit, details);
 660 	g_free (query);
 661 	g_free (fts);
 662 
 663 	return success;
 664 }
 665 
 666 static gboolean
 667 get_image_files (TrackerSparqlConnection *connection,
 668                  GStrv                    search_terms,
 669                  gboolean                 show_all,
 670                  gint                     search_offset,
 671                  gint                     search_limit,
 672                  gboolean                 use_or_operator,
 673                  gboolean                 details)
 674 {
 675 	gchar *fts;
 676 	gchar *query;
 677 	const gchar *show_all_str;
 678 	gboolean success;
 679 
 680 	show_all_str = show_all ? "" : "?image tracker:available true . ";
 681 	fts = get_fts_string (search_terms, use_or_operator);
 682 
 683 	if (fts) {
 684 		query = g_strdup_printf ("SELECT ?image nie:url(?image) fts:snippet(?image, \"%s\", \"%s\") "
 685 		                         "WHERE { "
 686 		                         "  ?image a nfo:Image ;"
 687 		                         "  fts:match \"%s\" ."
 688 		                         "  %s"
 689 		                         "} "
 690 		                         "ORDER BY ASC(nie:url(?image)) "
 691 		                         "OFFSET %d "
 692 		                         "LIMIT %d",
 693 		                         disable_color ? "" : SNIPPET_BEGIN,
 694 		                         disable_color ? "" : SNIPPET_END,
 695 		                         fts,
 696 		                         show_all_str,
 697 		                         search_offset,
 698 		                         search_limit);
 699 	} else {
 700 		query = g_strdup_printf ("SELECT ?image nie:url(?image) "
 701 		                         "WHERE { "
 702 		                         "  ?image a nfo:Image ."
 703 		                         "  %s"
 704 		                         "} "
 705 		                         "ORDER BY ASC(nie:url(?image)) "
 706 		                         "OFFSET %d "
 707 		                         "LIMIT %d",
 708 		                         show_all_str,
 709 		                         search_offset,
 710 		                         search_limit);
 711 	}
 712 
 713 	success = get_files_results (connection, query, search_limit, details);
 714 	g_free (query);
 715 	g_free (fts);
 716 
 717 	return success;
 718 }
 719 
 720 static gboolean
 721 get_music_files (TrackerSparqlConnection *connection,
 722                  GStrv                    search_terms,
 723                  gboolean                 show_all,
 724                  gint                     search_offset,
 725                  gint                     search_limit,
 726                  gboolean                 use_or_operator,
 727                  gboolean                 details)
 728 {
 729 	gchar *fts;
 730 	gchar *query;
 731 	const gchar *show_all_str;
 732 	gboolean success;
 733 
 734 	show_all_str = show_all ? "" : "?song tracker:available true . ";
 735 	fts = get_fts_string (search_terms, use_or_operator);
 736 
 737 	if (fts) {
 738 		query = g_strdup_printf ("SELECT ?song nie:url(?song) fts:snippet(?song, \"%s\", \"%s\")"
 739 		                         "WHERE { "
 740 		                         "  ?song a nmm:MusicPiece ;"
 741 		                         "  fts:match \"%s\" ."
 742 		                         "  %s"
 743 		                         "} "
 744 		                         "ORDER BY ASC(nie:url(?song)) "
 745 		                         "OFFSET %d "
 746 		                         "LIMIT %d",
 747 		                         disable_color ? "" : SNIPPET_BEGIN,
 748 		                         disable_color ? "" : SNIPPET_END,
 749 		                         fts,
 750 		                         show_all_str,
 751 		                         search_offset,
 752 		                         search_limit);
 753 	} else {
 754 		query = g_strdup_printf ("SELECT ?song nie:url(?song) "
 755 		                         "WHERE { "
 756 		                         "  ?song a nmm:MusicPiece ."
 757 		                         "  %s"
 758 		                         "} "
 759 		                         "ORDER BY ASC(nie:url(?song)) "
 760 		                         "OFFSET %d "
 761 		                         "LIMIT %d",
 762 		                         show_all_str,
 763 		                         search_offset,
 764 		                         search_limit);
 765 	}
 766 
 767 	success = get_files_results (connection, query, search_limit, details);
 768 	g_free (query);
 769 	g_free (fts);
 770 
 771 	return success;
 772 }
 773 
 774 static gboolean
 775 get_music_artists (TrackerSparqlConnection *connection,
 776                    GStrv                    search_terms,
 777                    gint                     search_offset,
 778                    gint                     search_limit,
 779                    gboolean                 use_or_operator,
 780                    gboolean                 details)
 781 {
 782 	GError *error = NULL;
 783 	TrackerSparqlCursor *cursor;
 784 	gchar *fts;
 785 	gchar *query;
 786 
 787 	fts = get_fts_string (search_terms, use_or_operator);
 788 
 789 	if (fts) {
 790 		query = g_strdup_printf ("SELECT ?artist ?title "
 791 		                         "WHERE {"
 792 		                         "  ?artist a nmm:Artist ;"
 793 		                         "  nmm:artistName ?title ;"
 794 		                         "  fts:match \"%s\" . "
 795 		                         "} "
 796 		                         "ORDER BY ASC(?title) "
 797 		                         "OFFSET %d "
 798 		                         "LIMIT %d",
 799 		                         fts,
 800 		                         search_offset,
 801 		                         search_limit);
 802 	} else {
 803 		query = g_strdup_printf ("SELECT ?artist ?title "
 804 		                         "WHERE {"
 805 		                         "  ?artist a nmm:Artist ;"
 806 		                         "  nmm:artistName ?title . "
 807 		                         "} "
 808 		                         "ORDER BY ASC(?title) "
 809 		                         "OFFSET %d "
 810 		                         "LIMIT %d",
 811 		                         search_offset,
 812 		                         search_limit);
 813 	}
 814 
 815 	g_free (fts);
 816 
 817 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
 818 	g_free (query);
 819 
 820 	if (error) {
 821 		g_printerr ("%s, %s\n",
 822 		            _("Could not get search results"),
 823 		            error->message);
 824 		g_error_free (error);
 825 
 826 		return FALSE;
 827 	}
 828 
 829 	if (!cursor) {
 830 		g_print ("%s\n",
 831 		         _("No artists were found"));
 832 	} else {
 833 		gint count = 0;
 834 
 835 		g_print ("%s:\n", _("Artists"));
 836 
 837 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
 838 			if (details) {
 839 				g_print ("  '%s%s%s' (%s)\n",
 840 		                         disable_color ? "" : TITLE_BEGIN,
 841 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 842 		                         disable_color ? "" : TITLE_END,
 843 				         tracker_sparql_cursor_get_string (cursor, 0, NULL));
 844 			} else {
 845 				g_print ("  '%s%s%s'\n",
 846 		                         disable_color ? "" : TITLE_BEGIN,
 847 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 848 				         disable_color ? "" : TITLE_END);
 849 			}
 850 			count++;
 851 		}
 852 
 853 		g_print ("\n");
 854 
 855 		if (count >= search_limit) {
 856 			show_limit_warning ();
 857 		}
 858 
 859 		g_object_unref (cursor);
 860 	}
 861 
 862 	return TRUE;
 863 }
 864 
 865 static gboolean
 866 get_music_albums (TrackerSparqlConnection *connection,
 867                   GStrv                    search_words,
 868                   gint                     search_offset,
 869                   gint                     search_limit,
 870                   gboolean                 use_or_operator,
 871                   gboolean                 details)
 872 {
 873 	GError *error = NULL;
 874 	TrackerSparqlCursor *cursor;
 875 	gchar *fts;
 876 	gchar *query;
 877 
 878 	fts = get_fts_string (search_words, use_or_operator);
 879 
 880 	if (fts) {
 881 		query = g_strdup_printf ("SELECT ?album nie:title(?album) "
 882 		                         "WHERE {"
 883 		                         "  ?album a nmm:MusicAlbum ;"
 884 		                         "  fts:match \"%s\" ."
 885 		                         "} "
 886 		                         "ORDER BY ASC(nie:title(?album)) "
 887 		                         "OFFSET %d "
 888 		                         "LIMIT %d",
 889 		                         fts,
 890 		                         search_offset,
 891 		                         search_limit);
 892 	} else {
 893 		query = g_strdup_printf ("SELECT ?album nie:title(?album) "
 894 		                         "WHERE {"
 895 		                         "  ?album a nmm:MusicAlbum ."
 896 		                         "} "
 897 		                         "ORDER BY ASC(nie:title(?album)) "
 898 		                         "OFFSET %d "
 899 		                         "LIMIT %d",
 900 		                         search_offset,
 901 		                         search_limit);
 902 	}
 903 
 904 	g_free (fts);
 905 
 906 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
 907 	g_free (query);
 908 
 909 	if (error) {
 910 		g_printerr ("%s, %s\n",
 911 		            _("Could not get search results"),
 912 		            error->message);
 913 		g_error_free (error);
 914 
 915 		return FALSE;
 916 	}
 917 
 918 	if (!cursor) {
 919 		g_print ("%s\n",
 920 		         _("No music was found"));
 921 	} else {
 922 		gint count = 0;
 923 
 924 		g_print ("%s:\n", _("Albums"));
 925 
 926 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
 927 			if (details) {
 928 				g_print ("  '%s%s%s' (%s)\n",
 929 		                         disable_color ? "" : TITLE_BEGIN,
 930 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 931 		                         disable_color ? "" : TITLE_END,
 932 				         tracker_sparql_cursor_get_string (cursor, 0, NULL));
 933 			} else {
 934 				g_print ("  '%s%s%s'\n",
 935 		                         disable_color ? "" : TITLE_BEGIN,
 936 				         tracker_sparql_cursor_get_string (cursor, 1, NULL),
 937 				         disable_color ? "" : TITLE_END);
 938 			}
 939 			count++;
 940 		}
 941 
 942 		g_print ("\n");
 943 
 944 		if (count >= search_limit) {
 945 			show_limit_warning ();
 946 		}
 947 
 948 		g_object_unref (cursor);
 949 	}
 950 
 951 	return TRUE;
 952 }
 953 
 954 static gboolean
 955 get_bookmarks (TrackerSparqlConnection *connection,
 956                GStrv                    search_terms,
 957                gint                     search_offset,
 958                gint                     search_limit,
 959                gboolean                 use_or_operator)
 960 {
 961 	GError *error = NULL;
 962 	TrackerSparqlCursor *cursor;
 963 	gchar *fts;
 964 	gchar *query;
 965 
 966 	fts = get_fts_string (search_terms, use_or_operator);
 967 
 968 	if (fts) {
 969 		query = g_strdup_printf ("SELECT nie:title(?urn) nie:url(?bookmark) "
 970 		                         "WHERE {"
 971 		                         "  ?urn a nfo:Bookmark ;"
 972 		                         "       nfo:bookmarks ?bookmark ."
 973 		                         "  ?urn fts:match \"%s\" . "
 974 		                         "} "
 975 		                         "ORDER BY ASC(nie:title(?urn)) "
 976 		                         "OFFSET %d "
 977 		                         "LIMIT %d",
 978 		                         fts,
 979 		                         search_offset,
 980 		                         search_limit);
 981 	} else {
 982 		query = g_strdup_printf ("SELECT nie:title(?urn) nie:url(?bookmark) "
 983 		                         "WHERE {"
 984 		                         "  ?urn a nfo:Bookmark ;"
 985 		                         "       nfo:bookmarks ?bookmark ."
 986 		                         "} "
 987 		                         "ORDER BY ASC(nie:title(?urn)) "
 988 		                         "OFFSET %d "
 989 		                         "LIMIT %d",
 990 		                         search_offset,
 991 		                         search_limit);
 992 	}
 993 
 994 	g_free (fts);
 995 
 996 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
 997 	g_free (query);
 998 
 999 	if (error) {
1000 		g_printerr ("%s, %s\n",
1001 		            _("Could not get search results"),
1002 		            error->message);
1003 		g_error_free (error);
1004 
1005 		return FALSE;
1006 	}
1007 
1008 	if (!cursor) {
1009 		g_print ("%s\n",
1010 		         _("No bookmarks were found"));
1011 	} else {
1012 		gint count = 0;
1013 
1014 		g_print ("%s:\n", _("Bookmarks"));
1015 
1016 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
1017 			g_print ("  %s%s%s (%s)\n",
1018 			         disable_color ? "" : TITLE_BEGIN,
1019 			         tracker_sparql_cursor_get_string (cursor, 0, NULL),
1020 			         disable_color ? "" : TITLE_END,
1021 			         tracker_sparql_cursor_get_string (cursor, 1, NULL));
1022 
1023 			count++;
1024 		}
1025 
1026 		g_print ("\n");
1027 
1028 		if (count >= search_limit) {
1029 			show_limit_warning ();
1030 		}
1031 
1032 		g_object_unref (cursor);
1033 	}
1034 
1035 	return TRUE;
1036 }
1037 
1038 static gboolean
1039 get_feeds (TrackerSparqlConnection *connection,
1040            GStrv                    search_terms,
1041            gint                     search_offset,
1042            gint                     search_limit,
1043            gboolean                 use_or_operator)
1044 {
1045 	GError *error = NULL;
1046 	TrackerSparqlCursor *cursor;
1047 	gchar *fts;
1048 	gchar *query;
1049 
1050 	fts = get_fts_string (search_terms, use_or_operator);
1051 
1052 	if (fts) {
1053 		query = g_strdup_printf ("SELECT ?feed nie:title(?feed) "
1054 		                         "WHERE {"
1055 		                         "  ?feed a mfo:FeedMessage ;"
1056 		                         "  fts:match \"%s\" . "
1057 		                         "} "
1058 		                         "ORDER BY ASC(nie:title(?feed)) "
1059 		                         "OFFSET %d "
1060 		                         "LIMIT %d",
1061 		                         fts,
1062 		                         search_offset,
1063 		                         search_limit);
1064 	} else {
1065 		query = g_strdup_printf ("SELECT ?feed nie:title(?feed) "
1066 		                         "WHERE {"
1067 		                         "  ?feed a mfo:FeedMessage ."
1068 		                         "} "
1069 		                         "ORDER BY ASC(nie:title(?feed)) "
1070 		                         "OFFSET %d "
1071 		                         "LIMIT %d",
1072 		                         search_offset,
1073 		                         search_limit);
1074 	}
1075 
1076 	g_free (fts);
1077 
1078 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
1079 	g_free (query);
1080 
1081 	if (error) {
1082 		g_printerr ("%s, %s\n",
1083 		            _("Could not get search results"),
1084 		            error->message);
1085 		g_error_free (error);
1086 
1087 		return FALSE;
1088 	}
1089 
1090 	if (!cursor) {
1091 		g_print ("%s\n",
1092 		         _("No feeds were found"));
1093 	} else {
1094 		gint count = 0;
1095 
1096 		g_print ("%s:\n", _("Feeds"));
1097 
1098 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
1099 			g_print ("  %s%s%s (%s)\n",
1100 			         disable_color ? "" : TITLE_BEGIN,
1101 			         tracker_sparql_cursor_get_string (cursor, 0, NULL),
1102 			         disable_color ? "" : TITLE_END,
1103 			         tracker_sparql_cursor_get_string (cursor, 1, NULL));
1104 
1105 			count++;
1106 		}
1107 
1108 		g_print ("\n");
1109 
1110 		if (count >= search_limit) {
1111 			show_limit_warning ();
1112 		}
1113 
1114 		g_object_unref (cursor);
1115 	}
1116 
1117 	return TRUE;
1118 }
1119 
1120 static gboolean
1121 get_software (TrackerSparqlConnection *connection,
1122               GStrv                    search_terms,
1123               gint                     search_offset,
1124               gint                     search_limit,
1125               gboolean                 use_or_operator)
1126 {
1127 	GError *error = NULL;
1128 	TrackerSparqlCursor *cursor;
1129 	gchar *fts;
1130 	gchar *query;
1131 
1132 	fts = get_fts_string (search_terms, use_or_operator);
1133 
1134 	if (fts) {
1135 		query = g_strdup_printf ("SELECT ?soft nie:title(?soft) fts:snippet(?soft, \"%s\", \"%s\") "
1136 		                         "WHERE {"
1137 		                         "  ?soft a nfo:Software ;"
1138 		                         "  fts:match \"%s\" . "
1139 		                         "} "
1140 		                         "ORDER BY ASC(nie:title(?soft)) "
1141 		                         "OFFSET %d "
1142 		                         "LIMIT %d",
1143 		                         disable_color ? "" : SNIPPET_BEGIN,
1144 		                         disable_color ? "" : SNIPPET_END,
1145 		                         fts,
1146 		                         search_offset,
1147 		                         search_limit);
1148 	} else {
1149 		query = g_strdup_printf ("SELECT ?soft nie:title(?soft) "
1150 		                         "WHERE {"
1151 		                         "  ?soft a nfo:Software ."
1152 		                         "} "
1153 		                         "ORDER BY ASC(nie:title(?soft)) "
1154 		                         "OFFSET %d "
1155 		                         "LIMIT %d",
1156 		                         search_offset,
1157 		                         search_limit);
1158 	}
1159 
1160 	g_free (fts);
1161 
1162 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
1163 	g_free (query);
1164 
1165 	if (error) {
1166 		g_printerr ("%s, %s\n",
1167 		            _("Could not get search results"),
1168 		            error->message);
1169 		g_error_free (error);
1170 
1171 		return FALSE;
1172 	}
1173 
1174 	if (!cursor) {
1175 		g_print ("%s\n",
1176 		         _("No software was found"));
1177 	} else {
1178 		gint count = 0;
1179 
1180 		g_print ("%s:\n", _("Software"));
1181 
1182 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
1183 			g_print ("  %s%s%s (%s)\n",
1184 			         disable_color ? "" : TITLE_BEGIN,
1185 			         tracker_sparql_cursor_get_string (cursor, 0, NULL),
1186 			         disable_color ? "" : TITLE_END,
1187 			         tracker_sparql_cursor_get_string (cursor, 1, NULL));
1188 			print_snippet (tracker_sparql_cursor_get_string (cursor, 2, NULL));
1189 			count++;
1190 		}
1191 
1192 		g_print ("\n");
1193 
1194 		if (count >= search_limit) {
1195 			show_limit_warning ();
1196 		}
1197 
1198 		g_object_unref (cursor);
1199 	}
1200 
1201 	return TRUE;
1202 }
1203 
1204 static gboolean
1205 get_software_categories (TrackerSparqlConnection *connection,
1206                          GStrv                    search_terms,
1207                          gint                     search_offset,
1208                          gint                     search_limit,
1209                          gboolean                 use_or_operator)
1210 {
1211 	GError *error = NULL;
1212 	TrackerSparqlCursor *cursor;
1213 	gchar *fts;
1214 	gchar *query;
1215 
1216 	fts = get_fts_string (search_terms, use_or_operator);
1217 
1218 	if (fts) {
1219 		query = g_strdup_printf ("SELECT ?cat nie:title(?cat) "
1220 		                         "WHERE {"
1221 		                         "  ?cat a nfo:SoftwareCategory ;"
1222 		                         "  fts:match \"%s\" . "
1223 		                         "} "
1224 		                         "ORDER BY ASC(nie:title(?cat)) "
1225 		                         "OFFSET %d "
1226 		                         "LIMIT %d",
1227 		                         fts,
1228 		                         search_offset,
1229 		                         search_limit);
1230 	} else {
1231 		query = g_strdup_printf ("SELECT ?cat nie:title(?cat) "
1232 		                         "WHERE {"
1233 		                         "  ?cat a nfo:SoftwareCategory ."
1234 		                         "} "
1235 		                         "ORDER BY ASC(nie:title(?cat)) "
1236 		                         "OFFSET %d "
1237 		                         "LIMIT %d",
1238 		                         search_offset,
1239 		                         search_limit);
1240 	}
1241 
1242 	g_free (fts);
1243 
1244 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
1245 	g_free (query);
1246 
1247 	if (error) {
1248 		g_printerr ("%s, %s\n",
1249 		            _("Could not get search results"),
1250 		            error->message);
1251 		g_error_free (error);
1252 
1253 		return FALSE;
1254 	}
1255 
1256 	if (!cursor) {
1257 		g_print ("%s\n",
1258 		         _("No software categories were found"));
1259 	} else {
1260 		gint count = 0;
1261 
1262 		g_print ("%s:\n", _("Software Categories"));
1263 
1264 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
1265 			g_print ("  %s%s%s (%s)\n",
1266 			         disable_color ? "" : TITLE_BEGIN,
1267 			         tracker_sparql_cursor_get_string (cursor, 0, NULL),
1268 			         disable_color ? "" : TITLE_END,
1269 			         tracker_sparql_cursor_get_string (cursor, 1, NULL));
1270 
1271 			count++;
1272 		}
1273 
1274 		g_print ("\n");
1275 
1276 		if (count >= search_limit) {
1277 			show_limit_warning ();
1278 		}
1279 
1280 		g_object_unref (cursor);
1281 	}
1282 
1283 	return TRUE;
1284 }
1285 
1286 static gboolean
1287 get_files (TrackerSparqlConnection *connection,
1288            GStrv                    search_terms,
1289            gboolean                 show_all,
1290            gint                     search_offset,
1291            gint                     search_limit,
1292            gboolean                 use_or_operator,
1293            gboolean                 details)
1294 {
1295 	gchar *fts;
1296 	gchar *query;
1297 	const gchar *show_all_str;
1298 	gboolean success;
1299 
1300 	show_all_str = show_all ? "" : "?u tracker:available true . ";
1301 	fts = get_fts_string (search_terms, use_or_operator);
1302 
1303 	if (fts) {
1304 		query = g_strdup_printf ("SELECT ?u nie:url(?u) "
1305 		                         "WHERE { "
1306 		                         "  ?u a nie:InformationElement ;"
1307 		                         "  fts:match \"%s\" ."
1308 		                         "  %s"
1309 		                         "} "
1310 		                         "ORDER BY ASC(nie:url(?u)) "
1311 		                         "OFFSET %d "
1312 		                         "LIMIT %d",
1313 		                         fts,
1314 		                         show_all_str,
1315 		                         search_offset,
1316 		                         search_limit);
1317 	} else {
1318 		query = g_strdup_printf ("SELECT ?u nie:url(?u) "
1319 		                         "WHERE { "
1320 		                         "  ?u a nie:InformationElement ."
1321 		                         "  %s"
1322 		                         "} "
1323 		                         "ORDER BY ASC(nie:url(?u)) "
1324 		                         "OFFSET %d "
1325 		                         "LIMIT %d",
1326 		                         show_all_str,
1327 		                         search_offset,
1328 		                         search_limit);
1329 	}
1330 
1331 	success = get_files_results (connection, query, search_limit, details);
1332 	g_free (query);
1333 	g_free (fts);
1334 
1335 	return success;
1336 }
1337 
1338 static gboolean
1339 get_folders (TrackerSparqlConnection *connection,
1340              GStrv                    search_terms,
1341              gboolean                 show_all,
1342              gint                     search_offset,
1343              gint                     search_limit,
1344              gboolean                 use_or_operator,
1345              gboolean                 details)
1346 {
1347 	gchar *fts;
1348 	gchar *query;
1349 	const gchar *show_all_str;
1350 	gboolean success;
1351 
1352 	show_all_str = show_all ? "" : "?u tracker:available true . ";
1353 	fts = get_fts_string (search_terms, use_or_operator);
1354 
1355 	if (fts) {
1356 		query = g_strdup_printf ("SELECT ?u nie:url(?u) "
1357 		                         "WHERE { "
1358 		                         "  ?u a nfo:Folder ;"
1359 		                         "  fts:match \"%s\" ."
1360 		                         "  %s"
1361 		                         "} "
1362 		                         "ORDER BY ASC(nie:url(?u)) "
1363 		                         "OFFSET %d "
1364 		                         "LIMIT %d",
1365 		                         fts,
1366 		                         show_all_str,
1367 		                         search_offset,
1368 		                         search_limit);
1369 	} else {
1370 		query = g_strdup_printf ("SELECT ?u nie:url(?u) "
1371 		                         "WHERE { "
1372 		                         "  ?u a nfo:Folder ."
1373 		                         "  %s"
1374 		                         "} "
1375 		                         "ORDER BY ASC(nie:url(?u)) "
1376 		                         "OFFSET %d "
1377 		                         "LIMIT %d",
1378 		                         show_all_str,
1379 		                         search_offset,
1380 		                         search_limit);
1381 	}
1382 
1383 	success = get_files_results (connection, query, search_limit, details);
1384 	g_free (query);
1385 	g_free (fts);
1386 
1387 	return success;
1388 }
1389 
1390 static gboolean
1391 get_all_by_search (TrackerSparqlConnection *connection,
1392                    GStrv                    search_words,
1393                    gboolean                 show_all,
1394                    gint                     search_offset,
1395                    gint                     search_limit,
1396                    gboolean                 use_or_operator,
1397                    gboolean                 details)
1398 {
1399 	GError *error = NULL;
1400 	TrackerSparqlCursor *cursor;
1401 	gchar *fts;
1402 	gchar *query;
1403 	const gchar *show_all_str;
1404 
1405 	fts = get_fts_string (search_words, use_or_operator);
1406 	if (!fts) {
1407 		return FALSE;
1408 	}
1409 
1410 	show_all_str = show_all ? "" : "?s tracker:available true . ";
1411 
1412 	if (details) {
1413 		query = g_strdup_printf ("SELECT tracker:coalesce (nie:url (?s), ?s) nie:mimeType (?s) ?type fts:snippet(?document, \"%s\", \"%s\") "
1414 		                         "WHERE {"
1415 		                         "  ?s fts:match \"%s\" ;"
1416 		                         "  rdf:type ?type ."
1417 		                         "  %s"
1418 		                         "} "
1419 		                         "GROUP BY nie:url(?s) "
1420 		                         "ORDER BY nie:url(?s) "
1421 		                         "OFFSET %d LIMIT %d",
1422 		                         disable_color ? "" : SNIPPET_BEGIN,
1423 		                         disable_color ? "" : SNIPPET_END,
1424 		                         fts,
1425 		                         show_all_str,
1426 		                         search_offset,
1427 		                         search_limit);
1428 	} else {
1429 		query = g_strdup_printf ("SELECT tracker:coalesce (nie:url (?s), ?s) fts:snippet(?document, \"%s\", \"%s\") "
1430 		                         "WHERE {"
1431 		                         "  ?s fts:match \"%s\" ."
1432 		                         "  %s"
1433 		                         "} "
1434 		                         "ORDER BY nie:url(?s) "
1435 		                         "OFFSET %d LIMIT %d",
1436 		                         disable_color ? "" : SNIPPET_BEGIN,
1437 		                         disable_color ? "" : SNIPPET_END,
1438 		                         fts,
1439 		                         show_all_str,
1440 		                         search_offset,
1441 		                         search_limit);
1442 	}
1443 
1444 	g_free (fts);
1445 
1446 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
1447 	g_free (query);
1448 
1449 	if (error) {
1450 		g_printerr ("%s, %s\n",
1451 		            _("Could not get search results"),
1452 		            error->message);
1453 		g_error_free (error);
1454 
1455 		return FALSE;
1456 	}
1457 
1458 	if (!cursor) {
1459 		g_print ("%s\n",
1460 		         _("No results were found matching your query"));
1461 	} else {
1462 		gint count = 0;
1463 
1464 		g_print ("%s:\n", _("Results"));
1465 
1466 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
1467 			if (details) {
1468 				const gchar *urn;
1469 				const gchar *mime_type;
1470 				const gchar *class;
1471 
1472 				g_print ("cols:%d\n", tracker_sparql_cursor_get_n_columns (cursor));
1473 
1474 				urn = tracker_sparql_cursor_get_string (cursor, 0, NULL);
1475 				mime_type = tracker_sparql_cursor_get_string (cursor, 1, NULL);
1476 				class = tracker_sparql_cursor_get_string (cursor, 2, NULL);
1477 
1478 				if (mime_type && mime_type[0] == '\0') {
1479 					mime_type = NULL;
1480 				}
1481 
1482 				if (mime_type) {
1483 					g_print ("  %s%s%s\n"
1484 					         "    %s\n"
1485 					         "    %s\n",
1486 					         disable_color ? "" : TITLE_BEGIN,
1487 					         urn,
1488 					         disable_color ? "" : TITLE_END,
1489 					         mime_type,
1490 					         class);
1491 				} else {
1492 					g_print ("  %s%s%s\n"
1493 					         "    %s\n",
1494 					         disable_color ? "" : TITLE_BEGIN,
1495 					         urn,
1496 					         disable_color ? "" : TITLE_END,
1497 					         class);
1498 				}
1499 				print_snippet (tracker_sparql_cursor_get_string (cursor, 3, NULL));
1500 			} else {
1501 				g_print ("  %s%s%s\n",
1502 		                         disable_color ? "" : TITLE_BEGIN,
1503 				         tracker_sparql_cursor_get_string (cursor, 0, NULL),
1504 				         disable_color ? "" : TITLE_END);
1505 				print_snippet (tracker_sparql_cursor_get_string (cursor, 1, NULL));
1506 			}
1507 
1508 			count++;
1509 		}
1510 
1511 		g_print ("\n");
1512 
1513 		if (count >= search_limit) {
1514 			show_limit_warning ();
1515 		}
1516 
1517 		g_object_unref (cursor);
1518 	}
1519 
1520 	return TRUE;
1521 }
1522 
1523 int
1524 main (int argc, char **argv)
1525 {
1526 	TrackerSparqlConnection *connection;
1527 	GOptionContext *context;
1528 	GOptionGroup *group;
1529 	GError *error = NULL;
1530 	gchar *summary;
1531 
1532 	setlocale (LC_ALL, "");
1533 
1534 	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1535 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1536 	textdomain (GETTEXT_PACKAGE);
1537 
1538 	/* Translators: this messagge will apper immediately after the
1539 	 * usage string - Usage: COMMAND [OPTION]... <THIS_MESSAGE>
1540 	 */
1541 	context = g_option_context_new (_("- Search for terms in all data"));
1542 
1543 	/* Translators: this message will appear after the usage string
1544 	 * and before the list of options.
1545 	 */
1546 	summary = g_strconcat (_("Applies an AND operator to all terms separated "
1547 	                         "by a space (see --or-operator)"),
1548 	                       "\n",
1549 	                       "\n",
1550 	                       _("This means if you search for 'foo' and 'bar', "
1551 	                         "they must BOTH exist (unless you use --or-operator)"),
1552 	                       NULL);
1553 	g_option_context_set_summary (context, summary);
1554 	g_option_context_add_main_entries (context, category_entries, NULL);
1555 
1556 	group = g_option_group_new ("search",
1557 	                            _("Search options"),
1558 	                            _("Show search options"),
1559 	                            NULL,
1560 	                            NULL);
1561 	g_option_group_add_entries (group, semantic_entries);
1562 	g_option_context_add_group (context, group);
1563 
1564 	g_option_context_parse (context, &argc, &argv, NULL);
1565 
1566 	g_free (summary);
1567 
1568 	if (print_version) {
1569 		g_print ("\n" ABOUT "\n" LICENSE "\n");
1570 		g_option_context_free (context);
1571 
1572 		return EXIT_SUCCESS;
1573 	}
1574 
1575 	if (!music_albums && !music_artists && !music_files &&
1576 	    !bookmarks &&
1577 	    !feeds &&
1578 	    !software &&
1579 	    !software_categories &&
1580 	    !image_files &&
1581 	    !video_files &&
1582 	    !document_files &&
1583 	    !emails &&
1584 	    !contacts &&
1585 	    !files && !folders &&
1586 	    !terms) {
1587 		gchar *help;
1588 
1589 		g_printerr ("%s\n\n",
1590 		            _("Search terms are missing"));
1591 
1592 		help = g_option_context_get_help (context, TRUE, NULL);
1593 		g_option_context_free (context);
1594 		g_printerr ("%s", help);
1595 		g_free (help);
1596 
1597 		return EXIT_FAILURE;
1598 	}
1599 
1600 	if (disable_fts) {
1601 		disable_snippets = TRUE;
1602 	}
1603 
1604 #if HAVE_TRACKER_FTS
1605 	/* Only check stopwords if FTS is enabled */
1606 	if (terms) {
1607 		TrackerLanguage *language;
1608 		gboolean stop_words_found;
1609 		gchar **p;
1610 
1611 		/* Check terms don't have additional quotes */
1612 		for (p = terms; *p; p++) {
1613 			gchar *term = *p;
1614 			gint end = strlen (term) - 1;
1615 
1616 			if ((term[0] == '"' && term[end] == '"') ||
1617 			    (term[0] == '\'' && term[end] == '\'')) {
1618 				/* We never have a quote JUST at the end */
1619 				term[0] = term[end] = ' ';
1620 				g_strstrip (term);
1621 			}
1622 		}
1623 
1624 		/* Check if terms are stopwords, and warn if so */
1625 		language = tracker_language_new (NULL);
1626 		stop_words_found = FALSE;
1627 		for (p = terms; *p; p++) {
1628 			gchar *down;
1629 
1630 			down = g_utf8_strdown (*p, -1);
1631 
1632 			if (tracker_language_is_stop_word (language, down)) {
1633 				g_printerr (_("Search term '%s' is a stop word."),
1634 				            down);
1635 				g_printerr ("\n");
1636 
1637 				stop_words_found = TRUE;
1638 			}
1639 
1640 			g_free (down);
1641 		}
1642 
1643 		if (stop_words_found) {
1644 			g_printerr (_("Stop words are common words which "
1645 			              "may be ignored during the indexing "
1646 			              "process."));
1647 			g_printerr ("\n\n");
1648 		}
1649 
1650 		g_object_unref (language);
1651 	}
1652 #else
1653 	disable_snippets = TRUE;
1654 #endif
1655 
1656 	g_option_context_free (context);
1657 
1658 	connection = tracker_sparql_connection_get (NULL, &error);
1659 
1660 	if (!connection) {
1661 		g_printerr ("%s: %s\n",
1662 		            _("Could not establish a connection to Tracker"),
1663 		            error ? error->message : _("No error given"));
1664 		g_clear_error (&error);
1665 		return EXIT_FAILURE;
1666 	}
1667 
1668 	if (limit <= 0) {
1669 		/* Default to 10 for snippets because more is not
1670 		 * useful on the screen. The categories are those not
1671 		 * using snippets yet.
1672 		 */
1673 		if (disable_snippets || !terms ||
1674 		    (files || folders || contacts || emails ||
1675 		     music_albums || music_artists || bookmarks ||
1676 		     feeds)) {
1677 			limit = 512;
1678 		} else {
1679 			limit = 10;
1680 		}
1681 	}
1682 
1683 	if (files) {
1684 		gboolean success;
1685 
1686 		success = get_files (connection, terms, all, offset, limit, or_operator, detailed);
1687 		g_object_unref (connection);
1688 
1689 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1690 	}
1691 
1692 	if (folders) {
1693 		gboolean success;
1694 
1695 		success = get_folders (connection, terms, all, offset, limit, or_operator, detailed);
1696 		g_object_unref (connection);
1697 
1698 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1699 	}
1700 
1701 	if (music_albums) {
1702 		gboolean success;
1703 
1704 		success = get_music_albums (connection, terms, offset, limit, or_operator, detailed);
1705 		g_object_unref (connection);
1706 
1707 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1708 	}
1709 
1710 	if (music_artists) {
1711 		gboolean success;
1712 
1713 		success = get_music_artists (connection, terms, offset, limit, or_operator, detailed);
1714 		g_object_unref (connection);
1715 
1716 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1717 	}
1718 
1719 	if (music_files) {
1720 		gboolean success;
1721 
1722 		success = get_music_files (connection, terms, all, offset, limit, or_operator, detailed);
1723 		g_object_unref (connection);
1724 
1725 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1726 	}
1727 
1728 	if (feeds) {
1729 		gboolean success;
1730 
1731 		success = get_feeds (connection, terms, offset, limit, or_operator);
1732 		g_object_unref (connection);
1733 
1734 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1735 	}
1736 
1737 	if (image_files) {
1738 		gboolean success;
1739 
1740 		success = get_image_files (connection, terms, all, offset, limit, or_operator, detailed);
1741 		g_object_unref (connection);
1742 
1743 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1744 	}
1745 
1746 	if (video_files) {
1747 		gboolean success;
1748 
1749 		success = get_video_files (connection, terms, all, offset, limit, or_operator, detailed);
1750 		g_object_unref (connection);
1751 
1752 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1753 	}
1754 
1755 	if (document_files) {
1756 		gboolean success;
1757 
1758 		success = get_document_files (connection, terms, all, offset, limit, or_operator, detailed);
1759 		g_object_unref (connection);
1760 
1761 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1762 	}
1763 
1764 	if (emails) {
1765 		gboolean success;
1766 
1767 		success = get_emails (connection, terms, all, offset, limit, or_operator, detailed);
1768 		g_object_unref (connection);
1769 
1770 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1771 	}
1772 
1773 	if (contacts) {
1774 		gboolean success;
1775 
1776 		success = get_contacts (connection, terms, all, offset, limit, or_operator, detailed);
1777 		g_object_unref (connection);
1778 
1779 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1780 	}
1781 
1782 	if (software) {
1783 		gboolean success;
1784 
1785 		success = get_software (connection, terms, offset, limit, or_operator);
1786 		g_object_unref (connection);
1787 
1788 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1789 	}
1790 
1791 	if (software_categories) {
1792 		gboolean success;
1793 
1794 		success = get_software_categories (connection, terms, offset, limit, or_operator);
1795 		g_object_unref (connection);
1796 
1797 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1798 	}
1799 
1800 	if (bookmarks) {
1801 		gboolean success;
1802 
1803 		success = get_bookmarks (connection, terms, offset, limit, or_operator);
1804 		g_object_unref (connection);
1805 
1806 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1807 	}
1808 
1809 	if (terms) {
1810 		gboolean success;
1811 
1812 		success = get_all_by_search (connection, terms, all, offset, limit, or_operator, detailed);
1813 		g_object_unref (connection);
1814 
1815 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
1816 	}
1817 
1818 	g_object_unref (connection);
1819 
1820 	return EXIT_SUCCESS;
1821 }