/* * GNOME Online Miners - crawls through your online content * Copyright (c) 2011, 2012 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * Author: Cosimo Cecchi * */ #include #include "gom-tracker.h" #include "gom-utils.h" static gchar * _tracker_utils_format_into_graph (const gchar *graph) { return (graph != NULL) ? g_strdup_printf ("INTO <%s> ", graph) : g_strdup (""); } static gboolean gom_tracker_sparql_connection_get_string_attribute (TrackerSparqlConnection *connection, GCancellable *cancellable, GError **error, const gchar *resource, const gchar *attribute, gchar **value) { GString *select = g_string_new (NULL); TrackerSparqlCursor *cursor; const gchar *string_value = NULL; gboolean res; g_string_append_printf (select, "SELECT ?val { <%s> %s ?val }", resource, attribute); cursor = tracker_sparql_connection_query (connection, select->str, cancellable, error); g_string_free (select, TRUE); if (*error != NULL) goto out; res = tracker_sparql_cursor_next (cursor, cancellable, error); if (*error != NULL) goto out; if (res) { string_value = tracker_sparql_cursor_get_string (cursor, 0, NULL); goto out; } out: if (string_value != NULL && value != NULL) *value = g_strdup (string_value); else if (string_value == NULL) res = FALSE; g_clear_object (&cursor); return res; } gchar * gom_tracker_sparql_connection_ensure_resource (TrackerSparqlConnection *connection, GCancellable *cancellable, GError **error, gboolean *resource_exists, const gchar *graph, const gchar *identifier, const gchar *class, ...) { GString *select, *insert, *inner; va_list args; const gchar *arg; TrackerSparqlCursor *cursor; gboolean res; gchar *retval = NULL; gchar *graph_str; GVariant *insert_res; GVariantIter *iter; gchar *key = NULL, *val = NULL; gboolean exists = FALSE; /* build the inner query with all the classes */ va_start (args, class); inner = g_string_new (NULL); for (arg = class; arg != NULL; arg = va_arg (args, const gchar *)) g_string_append_printf (inner, " a %s; ", arg); g_string_append_printf (inner, "nao:identifier \"%s\"", identifier); va_end (args); /* query if such a resource is already in the DB */ select = g_string_new (NULL); g_string_append_printf (select, "SELECT ?urn WHERE { ?urn %s }", inner->str); cursor = tracker_sparql_connection_query (connection, select->str, cancellable, error); g_string_free (select, TRUE); if (*error != NULL) goto out; res = tracker_sparql_cursor_next (cursor, cancellable, error); if (*error != NULL) goto out; if (res) { /* return the found resource */ retval = g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)); exists = TRUE; g_debug ("Found resource in the store: %s", retval); goto out; } /* not found, create the resource */ insert = g_string_new (NULL); graph_str = _tracker_utils_format_into_graph (graph); g_string_append_printf (insert, "INSERT %s { _:res %s }", graph_str, inner->str); g_free (graph_str); g_string_free (inner, TRUE); insert_res = tracker_sparql_connection_update_blank (connection, insert->str, G_PRIORITY_DEFAULT, NULL, error); g_string_free (insert, TRUE); if (*error != NULL) goto out; /* the result is an "aaa{ss}" variant */ g_variant_get (insert_res, "aaa{ss}", &iter); g_variant_iter_next (iter, "aa{ss}", &iter); g_variant_iter_next (iter, "a{ss}", &iter); g_variant_iter_next (iter, "{ss}", &key, &val); g_variant_iter_free (iter); g_variant_unref (insert_res); if (g_strcmp0 (key, "res") == 0) { retval = val; } else { g_free (val); goto out; } g_debug ("Created a new resource: %s", retval); out: if (resource_exists) *resource_exists = exists; g_clear_object (&cursor); return retval; } gboolean gom_tracker_sparql_connection_insert_or_replace_triple (TrackerSparqlConnection *connection, GCancellable *cancellable, GError **error, const gchar *graph, const gchar *resource, const gchar *property_name, const gchar *property_value) { GString *insert; gchar *graph_str, *quoted; gboolean retval = TRUE; graph_str = _tracker_utils_format_into_graph (graph); /* the "null" value must not be quoted */ if (property_value == NULL) quoted = g_strdup ("null"); else quoted = g_strdup_printf ("\"%s\"", property_value); insert = g_string_new (NULL); g_string_append_printf (insert, "INSERT OR REPLACE %s { <%s> a nie:InformationElement ; %s %s }", graph_str, resource, property_name, quoted); g_free (quoted); g_debug ("Insert or replace triple: query %s", insert->str); tracker_sparql_connection_update (connection, insert->str, G_PRIORITY_DEFAULT, cancellable, error); g_string_free (insert, TRUE); if (*error != NULL) retval = FALSE; g_free (graph_str); return retval; } gboolean gom_tracker_sparql_connection_set_triple (TrackerSparqlConnection *connection, GCancellable *cancellable, GError **error, const gchar *graph, const gchar *resource, const gchar *property_name, const gchar *property_value) { GString *delete; gboolean retval = TRUE; delete = g_string_new (NULL); g_string_append_printf (delete, "DELETE { <%s> %s ?val } WHERE { <%s> %s ?val }", resource, property_name, resource, property_name); tracker_sparql_connection_update (connection, delete->str, G_PRIORITY_DEFAULT, cancellable, error); g_string_free (delete, TRUE); if (*error != NULL) { retval = FALSE; goto out; } retval = gom_tracker_sparql_connection_insert_or_replace_triple (connection, cancellable, error, graph, resource, property_name, property_value); out: return retval; } gboolean gom_tracker_sparql_connection_toggle_favorite (TrackerSparqlConnection *connection, GCancellable *cancellable, GError **error, const gchar *resource, gboolean favorite) { GString *update; const gchar *op_str = NULL; gboolean retval = TRUE; if (favorite) op_str = "INSERT OR REPLACE"; else op_str = "DELETE"; update = g_string_new (NULL); g_string_append_printf (update, "%s { <%s> nao:hasTag nao:predefined-tag-favorite }", op_str, resource); g_debug ("Toggle favorite: query %s", update->str); tracker_sparql_connection_update (connection, update->str, G_PRIORITY_DEFAULT, cancellable, error); g_string_free (update, TRUE); if (*error != NULL) retval = FALSE; return retval; } gchar* gom_tracker_utils_ensure_contact_resource (TrackerSparqlConnection *connection, GCancellable *cancellable, GError **error, const gchar *email, const gchar *fullname) { GString *select, *insert; TrackerSparqlCursor *cursor = NULL; gchar *retval = NULL, *mail_uri = NULL; gboolean res; GVariant *insert_res; GVariantIter *iter; gchar *key = NULL, *val = NULL; mail_uri = g_strconcat ("mailto:", email, NULL); select = g_string_new (NULL); g_string_append_printf (select, "SELECT ?urn WHERE { ?urn a nco:Contact . " "?urn nco:hasEmailAddress ?mail . " "FILTER (fn:contains(?mail, \"%s\" )) }", mail_uri); cursor = tracker_sparql_connection_query (connection, select->str, cancellable, error); g_string_free (select, TRUE); if (*error != NULL) goto out; res = tracker_sparql_cursor_next (cursor, cancellable, error); if (*error != NULL) goto out; if (res) { /* return the found resource */ retval = g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)); g_debug ("Found resource in the store: %s", retval); goto out; } /* not found, create the resource */ insert = g_string_new (NULL); g_string_append_printf (insert, "INSERT { <%s> a nco:EmailAddress ; nco:emailAddress \"%s\" . " "_:res a nco:Contact ; nco:hasEmailAddress <%s> ; nco:fullname \"%s\" . }", mail_uri, email, mail_uri, fullname); insert_res = tracker_sparql_connection_update_blank (connection, insert->str, G_PRIORITY_DEFAULT, cancellable, error); g_string_free (insert, TRUE); if (*error != NULL) goto out; /* the result is an "aaa{ss}" variant */ g_variant_get (insert_res, "aaa{ss}", &iter); g_variant_iter_next (iter, "aa{ss}", &iter); g_variant_iter_next (iter, "a{ss}", &iter); g_variant_iter_next (iter, "{ss}", &key, &val); g_variant_iter_free (iter); g_variant_unref (insert_res); if (g_strcmp0 (key, "res") == 0) { retval = val; } else { g_free (val); goto out; } g_debug ("Created a new contact resource: %s", retval); out: g_clear_object (&cursor); g_free (mail_uri); return retval; } gchar * gom_tracker_utils_ensure_equipment_resource (TrackerSparqlConnection *connection, GCancellable *cancellable, GError **error, const gchar *make, const gchar *model) { GError *local_error; TrackerSparqlCursor *cursor = NULL; gboolean res; gchar *equip_uri = NULL; gchar *insert = NULL; gchar *retval = NULL; gchar *select = NULL; g_return_val_if_fail (TRACKER_SPARQL_IS_CONNECTION (connection), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); g_return_val_if_fail (make != NULL || model != NULL, NULL); equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:", make != NULL ? make : "", model != NULL ? model : ""); select = g_strdup_printf ("SELECT <%s> WHERE { }", equip_uri); local_error = NULL; cursor = tracker_sparql_connection_query (connection, select, cancellable, &local_error); if (local_error != NULL) { g_propagate_error (error, local_error); goto out; } local_error = NULL; res = tracker_sparql_cursor_next (cursor, cancellable, &local_error); if (local_error != NULL) { g_propagate_error (error, local_error); goto out; } if (res) { const gchar *cursor_uri; cursor_uri = tracker_sparql_cursor_get_string (cursor, 0, NULL); if (g_strcmp0 (cursor_uri, equip_uri) == 0) { /* return the found resource */ retval = g_strdup (cursor_uri); g_debug ("Found resource in the store: %s", retval); goto out; } } /* not found, create the resource */ insert = g_strdup_printf ("INSERT { <%s> a nfo:Equipment ; nfo:manufacturer \"%s\" ; nfo:model \"%s\" }", equip_uri, make, model); local_error = NULL; tracker_sparql_connection_update (connection, insert, G_PRIORITY_DEFAULT, cancellable, &local_error); if (local_error != NULL) { g_propagate_error (error, local_error); goto out; } retval = equip_uri; equip_uri = NULL; g_debug ("Created a new equipment resource: %s", retval); out: g_clear_object (&cursor); g_free (equip_uri); g_free (insert); g_free (select); return retval; } void gom_tracker_update_datasource (TrackerSparqlConnection *connection, const gchar *datasource_urn, gboolean resource_exists, const gchar *identifier, const gchar *resource, GCancellable *cancellable, GError **error) { gboolean set_datasource; /* only set the datasource again if it has changed; this avoids touching the * DB completely if the entry didn't change at all, since we later also check * the mtime. */ set_datasource = TRUE; if (resource_exists) { gboolean res; gchar *old_value; res = gom_tracker_sparql_connection_get_string_attribute (connection, cancellable, error, resource, "nie:dataSource", &old_value); g_clear_error (error); if (res) { res = g_str_equal (old_value, datasource_urn); g_free (old_value); } if (res) set_datasource = FALSE; } if (set_datasource) gom_tracker_sparql_connection_set_triple (connection, cancellable, error, identifier, resource, "nie:dataSource", datasource_urn); } gboolean gom_tracker_update_mtime (TrackerSparqlConnection *connection, gint64 new_mtime, gboolean resource_exists, const gchar *identifier, const gchar *resource, GCancellable *cancellable, GError **error) { GTimeVal old_mtime; gboolean res; gchar *old_value; gchar *date; if (resource_exists) { res = gom_tracker_sparql_connection_get_string_attribute (connection, cancellable, error, resource, "nie:contentLastModified", &old_value); g_clear_error (error); if (res) { res = g_time_val_from_iso8601 (old_value, &old_mtime); g_free (old_value); } if (res && (new_mtime == old_mtime.tv_sec)) return FALSE; } date = gom_iso8601_from_timestamp (new_mtime); gom_tracker_sparql_connection_insert_or_replace_triple (connection, cancellable, error, identifier, resource, "nie:contentLastModified", date); g_free (date); return TRUE; }