tracker-0.16.2/src/tracker-utils/tracker-tag.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 <time.h>
 24 #include <locale.h>
 25 
 26 #include <glib.h>
 27 #include <glib/gi18n.h>
 28 #include <gio/gio.h>
 29 
 30 #include <libtracker-sparql/tracker-sparql.h>
 31 
 32 #define ABOUT \
 33 	"Tracker " PACKAGE_VERSION "\n"
 34 
 35 #define LICENSE \
 36 	"This program is free software and comes without any warranty.\n" \
 37 	"It is licensed under version 2 or later of the General Public " \
 38 	"License which can be viewed at:\n" \
 39 	"\n" \
 40 	"  http://www.gnu.org/licenses/gpl.txt\n"
 41 
 42 static gint limit = 512;
 43 static gint offset;
 44 static gchar **files;
 45 static gboolean or_operator;
 46 static gchar *add_tag;
 47 static gchar *remove_tag;
 48 static gchar *description;
 49 static gboolean *list;
 50 static gboolean show_files;
 51 static gboolean print_version;
 52 
 53 static GOptionEntry entries[] = {
 54 	{ "limit", 'l', 0, G_OPTION_ARG_INT, &limit,
 55 	  N_("Limit the number of results shown"),
 56 	  N_("512")
 57 	},
 58 	{ "offset", 'o', 0, G_OPTION_ARG_INT, &offset,
 59 	  N_("Offset the results"),
 60 	  N_("0")
 61 	},
 62 	{ "or-operator", 'r', 0, G_OPTION_ARG_NONE, &or_operator,
 63 	  N_("Use OR for search terms instead of AND (the default)"),
 64 	  NULL
 65 	},
 66 	{ "list", 't', 0, G_OPTION_ARG_NONE, &list,
 67 	  N_("List all tags (using FILTER if specified; FILTER always uses logical OR)"),
 68 	  N_("FILTER"),
 69 	},
 70 	{ "show-files", 's', 0, G_OPTION_ARG_NONE, &show_files,
 71 	  N_("Show files associated with each tag (this is only used with --list)"),
 72 	  NULL
 73 	},
 74 	{ "add", 'a', 0, G_OPTION_ARG_STRING, &add_tag,
 75 	  N_("Add a tag (if FILEs are omitted, TAG is not associated with any files)"),
 76 	  N_("TAG")
 77 	},
 78 	{ "delete", 'd', 0, G_OPTION_ARG_STRING, &remove_tag,
 79 	  N_("Delete a tag (if FILEs are omitted, TAG is removed for all files)"),
 80 	  N_("TAG")
 81 	},
 82 	{ "description", 'e', 0, G_OPTION_ARG_STRING, &description,
 83 	  N_("Description for a tag (this is only used with --add)"),
 84 	  N_("STRING")
 85 	},
 86 	{ "version", 'V', 0, G_OPTION_ARG_NONE, &print_version,
 87 	  N_("Print version"),
 88 	  NULL
 89 	},
 90 	{ G_OPTION_REMAINING, 0, 0,
 91 	  G_OPTION_ARG_FILENAME_ARRAY, &files,
 92 	  N_("FILE…"),
 93 	  N_("FILE [FILE…]")},
 94 	{ NULL }
 95 };
 96 
 97 static void
 98 show_limit_warning (void)
 99 {
100 	/* Display '...' so the user thinks there is
101 	 * more items.
102 	 */
103 	g_print ("  ...\n");
104 
105 	/* Display warning so the user knows this is
106 	 * not the WHOLE data set.
107 	 */
108 	g_printerr ("\n%s\n",
109 	            _("NOTE: Limit was reached, there are more items in the database not listed here"));
110 }
111 
112 static gchar *
113 get_escaped_sparql_string (const gchar *str)
114 {
115 	GString *sparql;
116 
117 	sparql = g_string_new ("");
118 	g_string_append_c (sparql, '"');
119 
120 	while (*str != '\0') {
121 		gsize len = strcspn (str, "\t\n\r\"\\");
122 		g_string_append_len (sparql, str, len);
123 		str += len;
124 		switch (*str) {
125 		case '\t':
126 			g_string_append (sparql, "\\t");
127 			break;
128 		case '\n':
129 			g_string_append (sparql, "\\n");
130 			break;
131 		case '\r':
132 			g_string_append (sparql, "\\r");
133 			break;
134 		case '"':
135 			g_string_append (sparql, "\\\"");
136 			break;
137 		case '\\':
138 			g_string_append (sparql, "\\\\");
139 			break;
140 		default:
141 			continue;
142 		}
143 		str++;
144 	}
145 
146 	g_string_append_c (sparql, '"');
147 
148 	return g_string_free (sparql, FALSE);
149 }
150 
151 static gchar *
152 get_filter_string (GStrv        files,
153                    gboolean     files_are_urns,
154                    const gchar *tag)
155 {
156 	GString *filter;
157 	gint i, len;
158 
159 	if (!files) {
160 		return NULL;
161 	}
162 
163 	len = g_strv_length (files);
164 
165 	if (len < 1) {
166 		return NULL;
167 	}
168 
169 	filter = g_string_new ("");
170 
171 	g_string_append_printf (filter, "FILTER (");
172 
173 	if (tag) {
174 		g_string_append (filter, "(");
175 	}
176 
177 	for (i = 0; i < len; i++) {
178 		if (files_are_urns) {
179 			g_string_append_printf (filter, "?urn = <%s>", files[i]);
180 		} else {
181 			g_string_append_printf (filter, "?f = \"%s\"", files[i]);
182 		}
183 
184 		if (i < len - 1) {
185 			g_string_append (filter, " || ");
186 		}
187 	}
188 
189 	if (tag) {
190 		g_string_append_printf (filter, ") && ?t = <%s>", tag);
191 	}
192 
193 	g_string_append (filter, ")");
194 
195 	return g_string_free (filter, FALSE);
196 }
197 
198 static GStrv
199 get_uris (GStrv files)
200 {
201 	GStrv uris;
202 	gint len, i;
203 
204 	if (!files) {
205 		return NULL;
206 	}
207 
208 	len = g_strv_length (files);
209 
210 	if (len < 1) {
211 		return NULL;
212 	}
213 
214 	uris = g_new0 (gchar *, len + 1);
215 
216 	for (i = 0; files[i]; i++) {
217 		GFile *file;
218 
219 		file = g_file_new_for_commandline_arg (files[i]);
220 		uris[i] = g_file_get_uri (file);
221 		g_object_unref (file);
222 	}
223 
224 	return uris;
225 }
226 
227 static TrackerSparqlCursor *
228 get_file_urns (TrackerSparqlConnection *connection,
229 	       GStrv                    uris,
230 	       const gchar             *tag)
231 {
232 	TrackerSparqlCursor *cursor;
233 	gchar *query, *filter;
234 	GError *error = NULL;
235 
236 	filter = get_filter_string (uris, FALSE, tag);
237 	query = g_strdup_printf ("SELECT ?urn ?f "
238 	                         "WHERE { "
239 	                         "  ?urn "
240 	                         "    %s "
241 	                         "    nie:url ?f . "
242 	                         "  %s "
243 	                         "}",
244 	                         tag ? "nao:hasTag ?t ; " : "",
245 	                         filter ? filter : "");
246 
247 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
248 
249 	g_free (query);
250 	g_free (filter);
251 
252 	if (error) {
253 		g_print ("    %s, %s\n",
254 		         _("Could not get file URNs"),
255 		         error->message);
256 		g_error_free (error);
257 		return NULL;
258 	}
259 
260 	return cursor;
261 }
262 
263 static GStrv
264 result_to_strv (TrackerSparqlCursor *cursor,
265                 gint                 n_col)
266 {
267 	GStrv strv;
268 	gint count, i;
269 
270 	if (!cursor) {
271 		return NULL;
272 	}
273 
274 	i = 0;
275 	count = 0;
276 
277 	/* Really no other option here, but we iterate the cursor
278 	 * first to get the length.
279 	 */
280 	while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
281 		count++;
282 	}
283 
284 	strv = g_new0 (gchar *, count + 1);
285 
286 	tracker_sparql_cursor_rewind (cursor);
287 
288 	while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
289 		const gchar *str;
290 
291 		str = tracker_sparql_cursor_get_string (cursor, n_col, NULL);
292 		strv[i++] = g_strdup (str);
293 	}
294 
295 	return strv;
296 }
297 
298 static void
299 get_all_tags_show_tag_id (TrackerSparqlConnection *connection,
300                           const gchar             *id)
301 {
302 	TrackerSparqlCursor *cursor;
303 	GError *error = NULL;
304 	gchar *query;
305 
306 	/* Get files associated */
307 	query = g_strdup_printf ("SELECT ?uri WHERE {"
308 	                         "  ?urn a rdfs:Resource; "
309 	                         "  nie:url ?uri ; "
310 	                         "  nao:hasTag \"%s\" . "
311 	                         "}",
312 	                         id);
313 
314 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
315 	g_free (query);
316 
317 	if (error) {
318 		g_printerr ("    %s, %s\n",
319 		            _("Could not get files related to tag"),
320 		            error->message);
321 		g_error_free (error);
322 		return;
323 	}
324 
325 	if (!cursor) {
326 		g_print ("    %s\n", _("None"));
327 		return;
328 	}
329 
330 
331 	while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
332 		g_print ("    %s\n", tracker_sparql_cursor_get_string (cursor, 0, NULL));
333 	}
334 
335 	g_object_unref (cursor);
336 }
337 
338 static gboolean
339 get_all_tags (TrackerSparqlConnection *connection,
340               GStrv                    files,
341               gint                     search_offset,
342               gint                     search_limit,
343               gboolean                 use_or_operator,
344               gboolean                 show_files)
345 {
346 	TrackerSparqlCursor *cursor;
347 	GError *error = NULL;
348 	gchar *query;
349 
350 	if (files && g_strv_length (files) > 0) {
351 		gchar *filter;
352 
353 		/* e.g. '?label IN ("foo", "bar")' */
354 		filter = g_strjoinv ("\",\"", files);
355 
356 		/* You might be asking, why not logical AND here, why
357 		 * logical OR for FILTER, well, tags can't have
358 		 * multiple labels is the simple answer.
359 		 */
360 		query = g_strdup_printf ("SELECT ?tag ?label nao:description(?tag) COUNT(?urns) AS urns "
361 		                         "WHERE {"
362 		                         "  ?tag a nao:Tag ;"
363 		                         "  nao:prefLabel ?label ."
364 		                         "  OPTIONAL {"
365 		                         "     ?urns nao:hasTag ?tag"
366 		                         "  } ."
367 		                         "  FILTER (?label IN (\"%s\"))"
368 		                         "} "
369 		                         "GROUP BY ?tag "
370 		                         "ORDER BY ASC(?label) "
371 		                         "OFFSET %d "
372 		                         "LIMIT %d",
373 		                         filter,
374 		                         search_offset,
375 		                         search_limit);
376 		g_free (filter);
377 	} else {
378 		query = g_strdup_printf ("SELECT ?tag ?label nao:description(?tag) COUNT(?urns) AS urns "
379 		                         "WHERE {"
380 		                         "  ?tag a nao:Tag ;"
381 		                         "  nao:prefLabel ?label ."
382 		                         "  OPTIONAL {"
383 		                         "     ?urns nao:hasTag ?tag"
384 		                         "  }"
385 		                         "} "
386 		                         "GROUP BY ?tag "
387 		                         "ORDER BY ASC(?label) "
388 		                         "OFFSET %d "
389 		                         "LIMIT %d",
390 		                         search_offset,
391 		                         search_limit);
392 	}
393 
394 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
395 	g_free (query);
396 
397 	if (error) {
398 		g_printerr ("%s, %s\n",
399 		            _("Could not get all tags"),
400 		            error->message);
401 		g_error_free (error);
402 
403 		return FALSE;
404 	}
405 
406 	if (!cursor) {
407 		g_print ("%s\n",
408 		         _("No tags were found"));
409 	} else {
410 		gint count = 0;
411 
412 		g_print ("%s:\n", _("Tags (shown by name)"));
413 
414 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
415 			const gchar *id;
416 			const gchar *tag;
417 			const gchar *description;
418 			const gchar *files;
419 			gint n_files = 0;
420 
421 			id = tracker_sparql_cursor_get_string (cursor, 0, NULL);
422 			files = tracker_sparql_cursor_get_string (cursor, 3, NULL);
423 			n_files = atoi (files);
424 
425 			tag = tracker_sparql_cursor_get_string (cursor, 1, NULL);
426 			description = tracker_sparql_cursor_get_string (cursor, 2, NULL);
427 
428 			if (description && *description == '\0') {
429 				description = NULL;
430 			}
431 
432 			g_print ("  %s %s%s%s\n",
433 			         tag,
434 			         description ? "(" : "",
435 			         description ? description : "",
436 			         description ? ")" : "");
437 
438 			if (show_files && n_files > 0) {
439 				get_all_tags_show_tag_id (connection, id);
440 			} else {
441 				g_print ("    %s\n", id);
442 				g_print ("    ");
443 				g_print (g_dngettext (NULL,
444 				                      "%d file",
445 				                      "%d files",
446 				                      n_files),
447 				         n_files);
448 				g_print ("\n");
449 			}
450 
451 			count++;
452 		}
453 
454 		if (count == 0) {
455 			g_print ("  %s\n", _("None"));
456 		}
457 
458 		g_print ("\n");
459 
460 		if (count >= search_limit) {
461 			show_limit_warning ();
462 		}
463 
464 		g_object_unref (cursor);
465 	}
466 
467 	return TRUE;
468 }
469 
470 static void
471 print_file_report (TrackerSparqlCursor *cursor,
472                    GStrv                uris,
473                    const gchar         *found_msg,
474                    const gchar         *not_found_msg)
475 {
476 	gint i;
477 
478 	if (!cursor || !uris) {
479 		g_print ("  %s\n", _("No files were modified"));
480 		return;
481 	}
482 
483 	for (i = 0; uris[i]; i++) {
484 		gboolean found = FALSE;
485 
486 		tracker_sparql_cursor_rewind (cursor);
487 
488 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
489 			const gchar *str;
490 
491 			str = tracker_sparql_cursor_get_string (cursor, 1, NULL);
492 
493 			if (g_strcmp0 (str, uris[i]) == 0) {
494 				found = TRUE;
495 				break;
496 			}
497 		}
498 
499 		g_print ("  %s: %s\n",
500 		         found ? found_msg : not_found_msg,
501 		         uris[i]);
502 	}
503 }
504 
505 static gboolean
506 add_tag_for_urns (TrackerSparqlConnection *connection,
507                   GStrv                    files,
508                   const gchar             *tag,
509                   const gchar             *description)
510 {
511 	TrackerSparqlCursor *cursor = NULL;
512 	GError *error = NULL;
513 	GStrv  uris = NULL, urns_strv = NULL;
514 	gchar *tag_escaped;
515 	gchar *query;
516 
517 	tag_escaped = get_escaped_sparql_string (tag);
518 
519 	if (files) {
520 		uris = get_uris (files);
521 
522 		if (!uris) {
523 			return FALSE;
524 		}
525 
526 		cursor = get_file_urns (connection, uris, NULL);
527 
528 		if (!cursor) {
529 			g_printerr ("Files do not exist or aren't indexed\n");
530 			g_strfreev (uris);
531 			return FALSE;
532 		}
533 
534 		urns_strv = result_to_strv (cursor, 0);
535 
536 		if (!urns_strv || g_strv_length (urns_strv) < 1) {
537 			g_printerr ("Files do not exist or aren't indexed\n");
538 			g_object_unref (cursor);
539 			g_strfreev (uris);
540 
541 			return FALSE;
542 		}
543 	}
544 
545 	if (description) {
546 		gchar *description_escaped;
547 
548 		description_escaped = get_escaped_sparql_string (description);
549 
550 		query = g_strdup_printf ("INSERT { "
551 					 "  _:tag a nao:Tag;"
552 					 "  nao:prefLabel %s ;"
553 					 "  nao:description %s ."
554 					 "} "
555 					 "WHERE {"
556 					 "  OPTIONAL {"
557 					 "     ?tag a nao:Tag ;"
558 					 "     nao:prefLabel %s ."
559 					 "  } ."
560 					 "  FILTER (!bound(?tag)) "
561 					 "}",
562 					 tag_escaped,
563 					 description_escaped,
564 					 tag_escaped);
565 
566 		g_free (description_escaped);
567 	} else {
568 		query = g_strdup_printf ("INSERT { "
569 					 "  _:tag a nao:Tag;"
570 					 "  nao:prefLabel %s ."
571 					 "} "
572 					 "WHERE {"
573 					 "  OPTIONAL {"
574 					 "     ?tag a nao:Tag ;"
575 					 "     nao:prefLabel %s ."
576 					 "  } ."
577 					 "  FILTER (!bound(?tag)) "
578 					 "}",
579 					 tag_escaped,
580 					 tag_escaped);
581 	}
582 
583 	tracker_sparql_connection_update (connection, query, 0, NULL, &error);
584 	g_free (query);
585 
586 	if (error) {
587 		g_printerr ("%s, %s\n",
588 		            _("Could not add tag"),
589 		            error->message);
590 
591 		if (cursor) {
592 			g_object_unref (cursor);
593 		}
594 
595 		g_error_free (error);
596 		g_free (tag_escaped);
597 		g_strfreev (urns_strv);
598 		g_strfreev (uris);
599 
600 		return FALSE;
601 	}
602 
603 	g_print ("%s\n",
604 	         _("Tag was added successfully"));
605 
606 	/* First we check if the tag is already set and only add if it
607 	 * is, then we add the urns specified to the new tag.
608 	 */
609 	if (urns_strv) {
610 		gchar *filter;
611 
612 		filter = get_filter_string (urns_strv, TRUE, NULL);
613 
614 		/* Add tag to specific urns */
615 		query = g_strdup_printf ("INSERT { "
616 		                         "  ?urn nao:hasTag ?id "
617 		                         "} "
618 		                         "WHERE {"
619 		                         "  ?urn nie:url ?f ."
620 		                         "  ?id nao:prefLabel %s "
621 		                         "  %s "
622 		                         "}",
623 		                         tag_escaped,
624 		                         filter ? filter : "");
625 
626 		tracker_sparql_connection_update (connection, query, 0, NULL, &error);
627 		g_strfreev (urns_strv);
628 		g_free (filter);
629 		g_free (query);
630 
631 		if (error) {
632 			g_printerr ("%s, %s\n",
633 			            _("Could not add tag to files"),
634 			            error->message);
635 			g_object_unref (cursor);
636 			g_error_free (error);
637 			g_free (tag_escaped);
638 			g_strfreev (uris);
639 
640 			return FALSE;
641 		}
642 
643 		print_file_report (cursor, uris, _("Tagged"),
644 		                   _("Not tagged, file is not indexed"));
645 	}
646 
647 	g_strfreev (uris);
648 	g_free (tag_escaped);
649 
650 	if (cursor) {
651 		g_object_unref (cursor);
652 	}
653 
654 	return TRUE;
655 }
656 
657 static gboolean
658 remove_tag_for_urns (TrackerSparqlConnection *connection,
659                      GStrv                    files,
660                      const gchar             *tag)
661 {
662 	TrackerSparqlCursor *urns_cursor = NULL;
663 	GError *error = NULL;
664 	gchar *tag_escaped;
665 	gchar *query;
666 	GStrv uris;
667 
668 	tag_escaped = get_escaped_sparql_string (tag);
669 	uris = get_uris (files);
670 
671 	if (uris && *uris) {
672 		TrackerSparqlCursor *tag_cursor;
673 		gchar *filter;
674 		const gchar *urn;
675 		GStrv urns_strv;
676 
677 		/* Get all tags urns */
678 		query = g_strdup_printf ("SELECT ?tag "
679 		                         "WHERE {"
680 		                         "  ?tag a nao:Tag ."
681 		                         "  ?tag nao:prefLabel %s "
682 		                         "}",
683 		                         tag_escaped);
684 
685 		tag_cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
686 		g_free (query);
687 
688 		if (error) {
689 			g_printerr ("%s, %s\n",
690 			            _("Could not get tag by label"),
691 			            error->message);
692 			g_error_free (error);
693 			g_free (tag_escaped);
694 			g_strfreev (uris);
695 
696 			return FALSE;
697 		}
698 
699 		if (!tag_cursor || !tracker_sparql_cursor_next (tag_cursor, NULL, NULL)) {
700 			g_print ("%s\n",
701 			         _("No tags were found by that name"));
702 
703 			g_free (tag_escaped);
704 			g_strfreev (uris);
705 
706 			if (tag_cursor) {
707 				g_object_unref (tag_cursor);
708 			}
709 
710 			return TRUE;
711 		}
712 
713 		urn = tracker_sparql_cursor_get_string (tag_cursor, 0, NULL);
714 		urns_cursor = get_file_urns (connection, uris, urn);
715 
716 		if (!urns_cursor || !tracker_sparql_cursor_next (urns_cursor, NULL, NULL)) {
717 			g_print ("%s\n",
718 			         _("None of the files had this tag set"));
719 
720 			g_strfreev (uris);
721 			g_free (tag_escaped);
722 			g_object_unref (tag_cursor);
723 
724 			if (urns_cursor) {
725 				g_object_unref (urns_cursor);
726 			}
727 
728 			return TRUE;
729 		}
730 
731 		urns_strv = result_to_strv (urns_cursor, 0);
732 		filter = get_filter_string (urns_strv, TRUE, urn);
733 		g_strfreev (urns_strv);
734 
735 		query = g_strdup_printf ("DELETE { "
736 		                         "  ?urn nao:hasTag ?t "
737 		                         "} "
738 		                         "WHERE { "
739 		                         "  ?urn nao:hasTag ?t . "
740 		                         "  %s "
741 		                         "}",
742 		                         filter ? filter : "");
743 		g_free (filter);
744 
745 		g_object_unref (tag_cursor);
746 	} else {
747 		/* Remove tag completely */
748 		query = g_strdup_printf ("DELETE { "
749 		                         "  ?tag a nao:Tag "
750 		                         "} "
751 		                         "WHERE {"
752 		                         "  ?tag nao:prefLabel %s "
753 		                         "}",
754 		                         tag_escaped);
755 	}
756 
757 	g_free (tag_escaped);
758 
759 	tracker_sparql_connection_update (connection, query, 0, NULL, &error);
760 	g_free (query);
761 
762 	if (error) {
763 		g_printerr ("%s, %s\n",
764 		            _("Could not remove tag"),
765 		            error->message);
766 		g_error_free (error);
767 
768 		return FALSE;
769 	}
770 
771 	g_print ("%s\n", _("Tag was removed successfully"));
772 
773 	if (urns_cursor) {
774 		print_file_report (urns_cursor, uris,
775 		                   _("Untagged"),
776 		                   _("File not indexed or already untagged"));
777 		g_object_unref (urns_cursor);
778 	}
779 
780 	g_strfreev (uris);
781 
782 	return TRUE;
783 }
784 
785 static gboolean
786 get_tags_by_file (TrackerSparqlConnection *connection,
787                   const gchar             *uri)
788 {
789 	TrackerSparqlCursor *cursor;
790 	GError *error = NULL;
791 	gchar *query;
792 
793 	query = g_strdup_printf ("SELECT ?tags ?labels "
794 	                         "WHERE {"
795 	                         "  ?urn nao:hasTag ?tags ;"
796 	                         "  nie:url <%s> ."
797 	                         "  ?tags a nao:Tag ;"
798 	                         "  nao:prefLabel ?labels "
799 	                         "} "
800 	                         "ORDER BY ASC(?labels)",
801 	                         uri);
802 
803 	cursor = tracker_sparql_connection_query (connection, query, NULL, &error);
804 	g_free (query);
805 
806 	if (error) {
807 		g_printerr ("%s, %s\n",
808 		            _("Could not get all tags"),
809 		            error->message);
810 		g_error_free (error);
811 
812 		return FALSE;
813 	}
814 
815 	if (!cursor) {
816 		g_print ("  %s\n",
817 		         _("No tags were found"));
818 	} else {
819 		gint count = 0;
820 
821 		while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
822 			g_print ("  %s\n", tracker_sparql_cursor_get_string (cursor, 1, NULL));
823 			count++;
824 		}
825 
826 		if (count == 0) {
827 			g_print ("  %s\n", _("None"));
828 		}
829 
830 		g_print ("\n");
831 
832 		g_object_unref (cursor);
833 	}
834 
835 	return TRUE;
836 }
837 
838 int
839 main (int argc, char **argv)
840 {
841 	TrackerSparqlConnection *connection;
842 	GOptionContext *context;
843 	GError *error = NULL;
844 	const gchar *failed = NULL;
845 
846 	setlocale (LC_ALL, "");
847 
848 	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
849 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
850 	textdomain (GETTEXT_PACKAGE);
851 
852 	/* Translators: this messagge will apper immediately after the
853 	 * usage string - Usage: COMMAND [OPTION]... <THIS_MESSAGE>
854 	 */
855 	context = g_option_context_new (_("Add, remove or list tags"));
856 
857 	/* Translators: this message will appear after the usage string
858 	 * and before the list of options, showing an usage example.
859 	 */
860 	g_option_context_add_main_entries (context, entries, NULL);
861 	g_option_context_parse (context, &argc, &argv, NULL);
862 
863 	if (print_version) {
864 		g_print ("\n" ABOUT "\n" LICENSE "\n");
865 		g_option_context_free (context);
866 
867 		return EXIT_SUCCESS;
868 	}
869 
870 	if (!list && show_files) {
871 		failed = _("The --list option is required for --show-files");
872 	} else if (add_tag && remove_tag) {
873 		failed = _("Add and delete actions can not be used together");
874 	} else if (!list && !add_tag && !remove_tag && !files) {
875 		failed = _("No arguments were provided");
876 	} else if (description && !add_tag) {
877 		failed = _("The --description option can only be used with --add");
878 	}
879 
880 	if (failed) {
881 		gchar *help;
882 
883 		g_printerr ("%s\n\n", failed);
884 
885 		help = g_option_context_get_help (context, TRUE, NULL);
886 		g_option_context_free (context);
887 		g_printerr ("%s", help);
888 		g_free (help);
889 
890 		return EXIT_FAILURE;
891 	}
892 
893 	g_option_context_free (context);
894 
895 	connection = tracker_sparql_connection_get (NULL, &error);
896 
897 	if (!connection) {
898 		g_printerr ("%s: %s\n",
899 		            _("Could not establish a connection to Tracker"),
900 		            error ? error->message : _("No error given"));
901 		g_clear_error (&error);
902 		return EXIT_FAILURE;
903 	}
904 
905 	if (list) {
906 		gboolean success;
907 
908 		success = get_all_tags (connection, files, offset, limit, or_operator, show_files);
909 		g_object_unref (connection);
910 
911 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
912 	}
913 
914 	if (add_tag) {
915 		gboolean success;
916 
917 		success = add_tag_for_urns (connection, files, add_tag, description);
918 		g_object_unref (connection);
919 
920 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
921 	}
922 
923 	if (remove_tag) {
924 		gboolean success;
925 
926 		success = remove_tag_for_urns (connection, files, remove_tag);
927 		g_object_unref (connection);
928 
929 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
930 	}
931 
932 	if (files) {
933 		gboolean success = TRUE;
934 		gchar **p;
935 
936 		for (p = files; *p; p++) {
937 			GFile *file;
938 			gchar *uri;
939 			
940 			file = g_file_new_for_commandline_arg (*p);
941 			uri = g_file_get_uri (file);
942 			g_object_unref (file);
943 
944 			g_print ("%s\n", uri);
945 			success &= get_tags_by_file (connection, uri);
946 
947 			g_free (uri);
948 		}
949 
950 		g_object_unref (connection);
951 
952 		return success ? EXIT_SUCCESS : EXIT_FAILURE;
953 	}
954 
955 	g_object_unref (connection);
956 
957 	/* This is a failure because we should have done something.
958 	 * This code should never be reached in practise.
959 	 */
960 	return EXIT_FAILURE;
961 }