1 /* biji-tracker.c
2  * Copyright (C) Pierre-Yves LUYTEN 2012, 2013 <py@luyten.fr>
3  *
4  * bijiben is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * bijiben is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include "biji-item.h"
21 #include "biji-tracker.h"
22 
23 
24 
25 typedef enum
26 {
27   BIJI_URN_COL,
28   BIJI_TITLE_COL,
29   BIJI_MTIME_COL,
30   BIJI_CONTENT_COL,
31   BIJI_CREATED_COL,
32   BIJI_NO_COL
33 
34 } BijiTrackerColumns;
35 
36 
37 
38 /* To perform something after async tracker query
39  * TODO : implemet this with GObject */
40 typedef struct {
41 
42   BijiManager *manager;
43 
44   /* usually a query */
45 
46   gchar *str;
47   BijiInfoSet *info;
48 
49   /* after the query, _one of_ the callbacks */
50 
51   BijiBoolCallback        bool_cb;
52   BijiInfoCallback        info_cb;
53   BijiItemCallback        item_cb;
54   BijiItemsListCallback   list_cb;
55   BijiInfoSetsHCallback   hash_cb;
56 
57 
58   gpointer user_data;
59 
60 } BijiTrackerFinisher;
61 
62 
63 /* finisher stores _one of the possible callbacks _
64  * we could cast as well */
65 
66 
67 static BijiTrackerFinisher *
biji_tracker_finisher_new(BijiManager * manager,gchar * str,BijiInfoSet * info,BijiBoolCallback bool_cb,BijiInfoCallback info_cb,BijiItemCallback item_cb,BijiItemsListCallback list_cb,BijiInfoSetsHCallback hash_cb,gpointer user_data)68 biji_tracker_finisher_new (BijiManager          *manager,
69                            gchar                 *str,
70                            BijiInfoSet           *info,
71                            BijiBoolCallback       bool_cb,
72                            BijiInfoCallback       info_cb,
73                            BijiItemCallback       item_cb,
74                            BijiItemsListCallback  list_cb,
75                            BijiInfoSetsHCallback  hash_cb,
76                            gpointer               user_data)
77 {
78   BijiTrackerFinisher *retval = g_slice_new (BijiTrackerFinisher);
79 
80   retval->manager = manager;
81   retval->str = str;
82   retval->info = info;
83   retval->bool_cb = bool_cb;
84   retval->info_cb = info_cb;
85   retval->item_cb = item_cb;
86   retval->list_cb = list_cb;
87   retval->hash_cb = hash_cb;
88   retval->user_data = user_data;
89 
90   return retval;
91 }
92 
93 
94 /* Only heap is str */
95 
96 static void
biji_tracker_finisher_free(BijiTrackerFinisher * f)97 biji_tracker_finisher_free (BijiTrackerFinisher *f)
98 {
99   g_clear_pointer (&f->str, g_free);
100   g_slice_free (BijiTrackerFinisher, f);
101 }
102 
103 
104 static TrackerSparqlConnection*
get_connection(BijiManager * manager)105 get_connection (BijiManager *manager)
106 {
107   return biji_manager_get_tracker_connection (manager);
108 }
109 
110 
111 /* TODO : populate the boolean */
112 
113 static void
biji_finish_update(GObject * source_object,GAsyncResult * res,gpointer user_data)114 biji_finish_update (GObject *source_object,
115                     GAsyncResult *res,
116                     gpointer user_data)
117 {
118   TrackerSparqlConnection *self;
119   BijiTrackerFinisher *finisher;
120   GError *error;
121   gchar *query;
122 
123 
124   self = TRACKER_SPARQL_CONNECTION (source_object);
125   finisher = user_data;
126   error = NULL;
127   query = finisher->str;
128 
129   tracker_sparql_connection_update_finish (self, res, &error);
130 
131   if (error)
132   {
133     g_warning ("%s : query=|||%s|||", error->message, query);
134     g_error_free (error);
135   }
136 
137   /* See if the query has something to perform afterward */
138   if (finisher->bool_cb)
139     finisher->bool_cb (TRUE, finisher->user_data);
140 
141   biji_tracker_finisher_free (finisher);
142 }
143 
144 
145 static void
biji_perform_update_async_and_free(TrackerSparqlConnection * connection,gchar * query,BijiBoolCallback f,gpointer user_data)146 biji_perform_update_async_and_free (TrackerSparqlConnection *connection,
147                                     gchar *query,
148                                     BijiBoolCallback f,
149                                     gpointer user_data)
150 {
151   BijiTrackerFinisher *finisher;
152 
153   finisher = biji_tracker_finisher_new
154               (NULL, query, NULL, f, NULL, NULL, NULL, NULL, user_data);
155   tracker_sparql_connection_update_async (connection,
156                                           query,
157 #if !HAVE_TRACKER3
158                                           0,     // priority
159 #endif
160                                           NULL,
161                                           biji_finish_update,
162                                           finisher);
163 }
164 
165 
166 /* Don't worry too much. We just want plain text here */
167 static gchar *
tracker_str(const gchar * string)168 tracker_str (const gchar * string )
169 {
170   g_return_val_if_fail (string != NULL, g_strdup (""));
171 
172   return biji_str_mass_replace (string, "\n", " ", "'", " ", NULL);
173 }
174 
175 
176 
177 static gchar *
get_note_url(BijiNoteObj * note)178 get_note_url (BijiNoteObj *note)
179 {
180   return g_strdup_printf ("file://%s", biji_item_get_uuid (BIJI_ITEM (note)));
181 }
182 
183 
184 
185 static void
biji_query_info_hash_finish(GObject * source_object,GAsyncResult * res,gpointer user_data)186 biji_query_info_hash_finish (GObject      *source_object,
187                              GAsyncResult *res,
188                              gpointer      user_data)
189 {
190   TrackerSparqlConnection *self;
191   TrackerSparqlCursor *cursor;
192   GError *error;
193   GHashTable *result;
194   BijiTrackerFinisher *finisher;
195 
196   self = TRACKER_SPARQL_CONNECTION (source_object);
197   finisher = (BijiTrackerFinisher*) user_data;
198   error = NULL;
199   result = g_hash_table_new_full (
200     g_str_hash, g_str_equal, NULL, (GDestroyNotify) biji_info_set_free);
201 
202   cursor = tracker_sparql_connection_query_finish (self,
203                                                    res,
204                                                    &error);
205 
206   if (error)
207   {
208     g_warning ("%s", error->message);
209     g_error_free (error);
210   }
211 
212   if (cursor)
213   {
214 
215     while (tracker_sparql_cursor_next (cursor, NULL, NULL))
216     {
217       BijiInfoSet *set = biji_info_set_new ();
218 
219       set->tracker_urn = g_strdup (tracker_sparql_cursor_get_string (cursor, BIJI_URN_COL, NULL));
220       set->title = g_strdup (tracker_sparql_cursor_get_string (cursor, BIJI_TITLE_COL, NULL));
221       set->mtime = iso8601_to_gint64 (tracker_sparql_cursor_get_string (cursor, BIJI_MTIME_COL, NULL));
222 
223       g_hash_table_replace (result, set->tracker_urn, set);
224     }
225 
226     g_object_unref (cursor);
227   }
228 
229   finisher->hash_cb (result, finisher->user_data);
230   biji_tracker_finisher_free (finisher);
231   return;
232 }
233 
234 
235 static void
biji_query_items_list_finish(GObject * source_object,GAsyncResult * res,gpointer user_data)236 biji_query_items_list_finish (GObject              *source_object,
237                               GAsyncResult         *res,
238                               gpointer              user_data)
239 {
240   TrackerSparqlConnection *self;
241   TrackerSparqlCursor *cursor;
242   BijiTrackerFinisher  *finisher;
243   GError *error;
244   GList *result;
245 
246   self =  TRACKER_SPARQL_CONNECTION (source_object);
247   result = NULL;
248   error = NULL;
249   finisher = (BijiTrackerFinisher *) user_data;
250 
251   if (finisher->list_cb == NULL)
252     return;
253 
254   cursor = tracker_sparql_connection_query_finish (self, res, &error);
255 
256   if (error)
257   {
258     g_warning ("%s", error->message);
259     g_error_free (error);
260   }
261 
262   if (cursor)
263   {
264     const gchar *full_path;
265     gchar *path;
266     BijiItem *item = NULL;
267 
268     while (tracker_sparql_cursor_next (cursor, NULL, NULL))
269     {
270       full_path = tracker_sparql_cursor_get_string (cursor, 0, NULL);
271 
272       if (g_str_has_prefix (full_path, "file://"))
273       {
274         GString *string;
275 
276         string = g_string_new (full_path);
277         g_string_erase (string, 0, 7);
278         path = g_string_free (string, FALSE);
279       }
280 
281       else
282       {
283         path = g_strdup (full_path);
284       }
285 
286       item = biji_manager_get_item_at_path (finisher->manager, path);
287 
288       /* Sorting is done in another place */
289       if (item)
290         result = g_list_prepend (result, item);
291     }
292 
293     g_object_unref (cursor);
294   }
295 
296   finisher->list_cb (result, finisher->user_data);
297   biji_tracker_finisher_free (finisher);
298 }
299 
300 
301 
302 static void
bjb_query_async(BijiManager * manager,gchar * query,BijiInfoSetsHCallback hash_cb,BijiItemsListCallback list_cb,gpointer user_data)303 bjb_query_async (BijiManager           *manager,
304                  gchar                  *query,
305                  BijiInfoSetsHCallback   hash_cb,
306                  BijiItemsListCallback  list_cb,
307                  gpointer                user_data)
308 {
309   BijiTrackerFinisher     *finisher;
310   GAsyncReadyCallback     callback = NULL;
311 
312   finisher = biji_tracker_finisher_new (manager, NULL, NULL, NULL, NULL, NULL, list_cb, hash_cb, user_data);
313 
314   if (hash_cb != NULL)
315     callback = biji_query_info_hash_finish;
316 
317   else if (list_cb != NULL)
318     callback = biji_query_items_list_finish;
319 
320   if (callback)
321    tracker_sparql_connection_query_async (
322       get_connection (manager), query, NULL, callback, finisher);
323 }
324 
325 
326 void
biji_get_all_notebooks_async(BijiManager * manager,BijiInfoSetsHCallback cb,gpointer user_data)327 biji_get_all_notebooks_async (BijiManager *manager,
328                                 BijiInfoSetsHCallback cb,
329                                 gpointer user_data)
330 {
331   gchar *query = g_strconcat (
332     "SELECT ?c ?title ?mtime ",
333     "WHERE { ?c a nfo:DataContainer ;",
334     "nie:title ?title ; ",
335     "nie:contentLastModified ?mtime ;"
336     "nie:generator 'Bijiben'}",
337     NULL);
338 
339   bjb_query_async (manager, query, cb, NULL, user_data);
340 
341   g_free (query);
342 }
343 
344 
345 
346 
347 /* FIXME: returns file://$PATH while we want $PATH
348  *        workaround in biji_query_items_list_finish */
349 void
biji_get_items_with_notebook_async(BijiManager * manager,const gchar * notebook,BijiItemsListCallback list_cb,gpointer user_data)350 biji_get_items_with_notebook_async (BijiManager          *manager,
351                                       const gchar           *notebook,
352                                       BijiItemsListCallback  list_cb,
353                                       gpointer               user_data)
354 {
355   gchar *query;
356 
357   query = g_strdup_printf ("SELECT ?s WHERE {?c nie:isPartOf ?s; nie:title '%s'}",
358                            notebook);
359 
360   bjb_query_async (manager, query, NULL, list_cb, user_data);
361 }
362 
363 
364 
365 
366 void
biji_get_items_matching_async(BijiManager * manager,BijiItemsGroup group,gchar * needle,BijiItemsListCallback list_cb,gpointer user_data)367 biji_get_items_matching_async (BijiManager           *manager,
368                                BijiItemsGroup         group,
369                                gchar                 *needle,
370                                BijiItemsListCallback  list_cb,
371                                gpointer               user_data)
372 {
373   gchar *lower;
374   gchar *query;
375 
376 
377   lower = g_utf8_strdown (needle, -1);
378 
379   /* We want to retrieve the key that noteBook uses.
380    * for notes: that is url. A file path is unique.
381    * for notebooks: we have no url, directly use urn:uuid */
382 
383   query = g_strconcat (
384     "SELECT tracker:coalesce (?url, ?urn) WHERE ",
385     "{",
386     "  {  ?urn a nfo:Note",
387     "    .?urn nie:title ?title",
388     "    .?urn nie:plainTextContent ?content",
389     "    .?urn nie:url ?url",
390     "    .?urn nie:generator 'Bijiben'",
391     "    .FILTER (",
392     "    fn:contains (fn:lower-case (?content), '", lower, "' ) || ",
393     "    fn:contains (fn:lower-case (?title)  , '", lower, "'))} ",
394     "UNION",
395     "  {  ?urn a nfo:DataContainer",
396     "    .?urn nie:title ?title",
397     "    .?urn nie:generator 'Bijiben'",
398     "    .FILTER (",
399     "    fn:contains (fn:lower-case (?title), '", lower, "'))}",
400     "}",
401     NULL);
402 
403   g_free (lower);
404   bjb_query_async (manager, query, NULL, list_cb, user_data);
405 }
406 
407 
408 static void
on_new_notebook_query_executed(GObject * source_object,GAsyncResult * res,gpointer user_data)409 on_new_notebook_query_executed (GObject *source_object, GAsyncResult *res, gpointer user_data)
410 {
411   BijiTrackerFinisher *finisher = user_data;
412   TrackerSparqlConnection *connection = TRACKER_SPARQL_CONNECTION (source_object);
413   GError *error;
414   GVariant *variant;
415   GVariant *child;
416   gchar *key = NULL;
417   gchar *val = NULL;
418   gchar *urn = NULL;
419   BijiNotebook *notebook = NULL;
420 
421   error = NULL;
422   variant = tracker_sparql_connection_update_blank_finish (connection, res, &error);
423   if (error != NULL)
424     {
425       g_warning ("Unable to create notebook: %s", error->message);
426       g_error_free (error);
427       goto out;
428     }
429 
430   child = g_variant_get_child_value (variant, 0); /* variant is now aa{ss} */
431   g_variant_unref (variant);
432   variant = child;
433 
434   child = g_variant_get_child_value (variant, 0); /* variant is now s{ss} */
435   g_variant_unref (variant);
436   variant = child;
437 
438   child = g_variant_get_child_value (variant, 0); /* variant is now {ss} */
439   g_variant_unref (variant);
440   variant = child;
441 
442   child = g_variant_get_child_value (variant, 0);
443   key = g_variant_dup_string (child, NULL);
444   g_variant_unref (child);
445 
446   child = g_variant_get_child_value (variant, 1);
447   val = g_variant_dup_string (child, NULL);
448   g_variant_unref (child);
449 
450   g_variant_unref (variant);
451 
452   if (g_strcmp0 (key, "res") == 0)
453     urn = val;
454 
455   /* Update the note manager */
456   if (urn)
457   {
458     notebook = biji_notebook_new (
459                        G_OBJECT (finisher->manager),
460                        urn,
461                        finisher->str,
462                        g_get_real_time () / G_USEC_PER_SEC);
463     biji_manager_add_item (finisher->manager, BIJI_ITEM (notebook), BIJI_LIVING_ITEMS, TRUE);
464   }
465 
466   /* Run the callback from the caller */
467 
468  out:
469   if (finisher->item_cb != NULL)
470     (*finisher->item_cb) (BIJI_ITEM (notebook), finisher->user_data);
471 
472   g_free (val);
473   g_free (key);
474   biji_tracker_finisher_free (finisher);
475 }
476 
477 
478 /* This func creates the notebook,
479  * gives the urn to the notemanager,
480  * then run the 'afterward' callback */
481 void
biji_create_new_notebook_async(BijiManager * manager,const gchar * name,BijiItemCallback item_cb,gpointer user_data)482 biji_create_new_notebook_async (BijiManager     *manager,
483                                 const gchar      *name,
484                                 BijiItemCallback  item_cb,
485                                 gpointer          user_data)
486 {
487   gchar *query;
488   g_autoptr(GDateTime) dt = g_date_time_new_now_utc ();
489   g_autofree char *time = g_date_time_format_iso8601 (dt);
490   BijiTrackerFinisher *finisher;
491 
492   query = g_strdup_printf ("INSERT { _:res a nfo:DataContainer ; a nie:DataObject ; "
493                             "nie:contentLastModified '%s' ; "
494                             "nie:title '%s' ; "
495                             "nie:generator 'Bijiben' }",
496                             time,
497                             name);
498 
499   /* The finisher has all the pointers we want.
500    * And the callback will free it */
501   finisher = biji_tracker_finisher_new (manager, g_strdup (name), NULL, NULL, NULL, item_cb, NULL, NULL, user_data);
502   tracker_sparql_connection_update_blank_async (get_connection (manager),
503                                                 query,
504 #if !HAVE_TRACKER3
505                                                 G_PRIORITY_DEFAULT,
506 #endif
507                                                 NULL,
508                                                 on_new_notebook_query_executed,
509                                                 finisher);
510 }
511 
512 
513 /* removes the tag EVEN if files associated. */
514 
515 void
biji_remove_notebook_from_tracker(BijiManager * manager,const gchar * urn)516 biji_remove_notebook_from_tracker (BijiManager *manager, const gchar *urn)
517 {
518   gchar *query;
519 
520   query = g_strdup_printf ("DELETE {'%s' a nfo:DataContainer}", urn);
521   biji_perform_update_async_and_free (get_connection (manager), query, NULL, NULL);
522 }
523 
524 
525 void
biji_push_existing_notebook_to_note(BijiNoteObj * note,gchar * title,BijiBoolCallback afterward,gpointer user_data)526 biji_push_existing_notebook_to_note (BijiNoteObj       *note,
527                                        gchar             *title,
528                                        BijiBoolCallback   afterward,
529                                        gpointer           user_data)
530 {
531   gchar *url, *query;
532 
533   url = get_note_url (note);
534   query = g_strdup_printf ("INSERT {?urn nie:isPartOf '%s'} WHERE {?urn a nfo:DataContainer; nie:title '%s'; nie:generator 'Bijiben'}",
535                            url, title);
536 
537   biji_perform_update_async_and_free (
538       get_connection (biji_item_get_manager (BIJI_ITEM (note))), query, afterward, user_data);
539   g_free (url);
540 }
541 
542 
543 
544 void
biji_remove_notebook_from_note(BijiNoteObj * note,BijiItem * coll,BijiBoolCallback afterward,gpointer user_data)545 biji_remove_notebook_from_note (BijiNoteObj       *note,
546                                   BijiItem          *coll,
547                                   BijiBoolCallback   afterward,
548                                   gpointer           user_data)
549 {
550   gchar *url, *query;
551 
552   url = get_note_url (note);
553 
554   query = g_strdup_printf (
555     "DELETE {'%s' nie:isPartOf '%s'}",
556     biji_item_get_uuid (coll), url);
557 
558 
559   biji_perform_update_async_and_free (get_connection (biji_item_get_manager (coll)), query, afterward, user_data);
560   g_free (url);
561 }
562 
563 
564 void
biji_note_delete_from_tracker(BijiNoteObj * note)565 biji_note_delete_from_tracker (BijiNoteObj *note)
566 {
567   BijiItem *item;
568   gchar *query;
569   const gchar *uuid;
570   BijiManager *manager;
571 
572   item = BIJI_ITEM (note);
573   manager = biji_item_get_manager (item);
574   uuid = biji_item_get_uuid (item);
575   query = g_strdup_printf ("DELETE { <%s> a rdfs:Resource }", uuid);
576   biji_perform_update_async_and_free (get_connection (manager), query, NULL, NULL);
577 }
578 
579 
580 
581 void
biji_tracker_trash_resource(BijiManager * manager,gchar * tracker_urn)582 biji_tracker_trash_resource (BijiManager *manager,
583                               gchar *tracker_urn)
584 {
585   gchar *query;
586 
587   query = g_strdup_printf ("DELETE { <%s> a rdfs:Resource }", tracker_urn);
588   biji_perform_update_async_and_free (get_connection (manager), query, NULL, NULL);
589 }
590 
591 
592 static void
update_resource(BijiTrackerFinisher * finisher,gchar * tracker_urn_uuid)593 update_resource (BijiTrackerFinisher *finisher, gchar *tracker_urn_uuid )
594 {
595   BijiManager *manager = finisher->manager;
596   BijiInfoSet *info = finisher->info;
597   g_autoptr(GDateTime) dt_created = g_date_time_new_from_unix_utc (info->created);
598   g_autoptr(GDateTime) dt_mtime = g_date_time_new_from_unix_utc (info->mtime);
599   g_autofree char *created = g_date_time_format_iso8601 (dt_created);
600   g_autofree char *mtime = g_date_time_format_iso8601 (dt_mtime);
601   char *query, *content;
602 
603   content = tracker_str (info->content);
604 
605   g_message ("Updating resource <%s> %s", info->title, tracker_urn_uuid);
606 
607   query = g_strdup_printf (
608       "INSERT OR REPLACE { <%s> a nfo:Note , nie:DataObject ; "
609       "nie:url '%s' ; "
610       "nie:contentLastModified '%s' ; "
611       "nie:contentCreated '%s' ; "
612       "nie:title '%s' ; "
613       "nie:plainTextContent '%s' ; "
614       "nie:dataSource '%s' ;"
615       "nie:generator 'Bijiben' . }",
616       tracker_urn_uuid,
617       info->url,
618       mtime,
619       created,
620       info->title,
621       content,
622       info->datasource_urn);
623 
624   biji_perform_update_async_and_free (get_connection (manager), query, NULL, NULL);
625 
626   g_free (tracker_urn_uuid);
627   g_free (content);
628   biji_tracker_finisher_free (finisher);
629 }
630 
631 
632 static void
push_new_note(BijiTrackerFinisher * finisher)633 push_new_note (BijiTrackerFinisher *finisher)
634 {
635   BijiManager *manager = finisher->manager;
636   BijiInfoSet *info = finisher->info;
637   g_autoptr(GDateTime) dt_created = g_date_time_new_from_unix_utc (info->created);
638   g_autoptr(GDateTime) dt_mtime = g_date_time_new_from_unix_utc (info->mtime);
639   g_autofree char *created_time = g_date_time_format_iso8601 (dt_created);
640   g_autofree char *mtime = g_date_time_format_iso8601 (dt_mtime);
641   gchar *query, *content;
642 
643   g_message ("Creating resource <%s> %s", info->title, info->url);
644 
645   content = tracker_str (info->content);
646 
647   query = g_strconcat (
648     "INSERT { _:res a nfo:Note ; ",
649     "     a nie:DataObject ; ",
650     "     nie:contentLastModified '", mtime,                "' ;",
651     "     nie:contentCreated      '", created_time,         "' ;",
652     "     nie:title               '", info->title,          "' ;",
653     "     nie:url                 '", info->url,            "' ;",
654     "     nie:plainTextContent    '", content,              "' ;",
655     "     nie:dataSource          '", info->datasource_urn, "' ;",
656     "     nie:generator                              'Bijiben' }",
657     NULL);
658 
659 
660   g_debug ("%s", query);
661 
662   tracker_sparql_connection_update_blank_async (get_connection (manager),
663                                                 query,
664 #if !HAVE_TRACKER3
665                                                 G_PRIORITY_DEFAULT,
666 #endif
667                                                 NULL,
668                                                 NULL,  // callback,
669                                                 NULL); // user_data);
670 
671 
672   g_free (query);
673   g_free (content);
674   biji_tracker_finisher_free (finisher);
675 }
676 
677 
678 static void
ensure_resource_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)679 ensure_resource_callback (GObject *source_object,
680                            GAsyncResult *res,
681                            gpointer user_data)
682 {
683   TrackerSparqlConnection *connection;
684   TrackerSparqlCursor     *cursor;
685   BijiTrackerFinisher     *finisher;
686   GError                  *error;
687   gchar                   *urn_found;
688 
689 
690   connection = TRACKER_SPARQL_CONNECTION (source_object);
691   finisher = user_data;
692   error = NULL;
693   urn_found = NULL;
694   cursor = tracker_sparql_connection_query_finish (connection, res, &error);
695 
696   if (error)
697   {
698     g_warning ("ENSURE RESOURCE : error %s", error->message);
699     g_error_free (error);
700     biji_tracker_finisher_free (finisher);
701     return;
702   }
703 
704   /* Queried resource found into tracker */
705 
706   if (cursor)
707   {
708 
709     if (tracker_sparql_cursor_next (cursor, NULL, NULL))
710       urn_found = g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL));
711 
712     g_object_unref (cursor);
713   }
714 
715 
716   if (urn_found != NULL)
717     update_resource (finisher, urn_found);
718 
719   else
720     push_new_note (finisher);
721 }
722 
723 
724 
725 void
biji_tracker_ensure_resource_from_info(BijiManager * manager,BijiInfoSet * info)726 biji_tracker_ensure_resource_from_info (BijiManager *manager,
727                                          BijiInfoSet *info)
728 {
729   gchar *query;
730   BijiTrackerFinisher *finisher;
731 
732 
733   query = g_strconcat (
734     "SELECT ?urn ?time WHERE { ?urn a nfo:Note ;",
735     "                          nie:title ?title ;",
736     "                          nie:contentLastModified ?time ;",
737     "                          nie:url '", info->url, "' }",
738                                NULL);
739 
740 
741   /* No matter user callback or not,
742    * we'll need our own to push if needed */
743 
744   finisher = biji_tracker_finisher_new (
745                manager,
746                NULL,
747                info,
748                NULL,
749                NULL,
750                NULL,
751                NULL,
752                NULL,
753                NULL);  // user_data);
754 
755   tracker_sparql_connection_query_async (
756       get_connection (manager), query, NULL, ensure_resource_callback, finisher);
757 
758   g_free (query);
759 }
760 
761 
762 
763 
764 
765 void
biji_tracker_ensure_datasource(BijiManager * manager,const gchar * datasource,const gchar * identifier,BijiBoolCallback cb,gpointer user_data)766 biji_tracker_ensure_datasource (BijiManager *manager,
767                                 const gchar *datasource,
768                                 const gchar *identifier,
769                                 BijiBoolCallback cb,
770                                 gpointer user_data)
771 {
772   gchar *query;
773 
774 
775   query = g_strdup_printf (
776     "INSERT OR REPLACE INTO <%s> {"
777     "  <%s> a nie:DataSource ; nao:identifier \"%s\" }",
778     datasource,
779     datasource,
780     identifier);
781 
782   biji_perform_update_async_and_free (
783     get_connection (manager), query, cb, user_data);
784 }
785 
786 
787 
788 static void
on_info_queried(GObject * source_object,GAsyncResult * res,gpointer user_data)789 on_info_queried (GObject *source_object,
790                  GAsyncResult *res,
791                  gpointer user_data)
792 {
793   TrackerSparqlConnection *connection;
794   TrackerSparqlCursor     *cursor;
795   BijiTrackerFinisher     *finisher;
796   GError                  *error;
797   BijiInfoSet             *retval;
798 
799   connection = TRACKER_SPARQL_CONNECTION (source_object);
800   finisher = user_data;
801   error = NULL;
802   retval = NULL;
803   cursor = tracker_sparql_connection_query_finish (connection, res, &error);
804 
805   if (error)
806   {
807     g_warning ("Check for Info : error %s", error->message);
808     g_error_free (error);
809 
810     /* Something went wrong, callback and free memory
811        & leave tracker alone */
812     if (finisher->info_cb != NULL)
813       finisher->info_cb (retval, finisher->user_data);
814     biji_tracker_finisher_free (finisher);
815     return;
816   }
817 
818   /* Queried resource found into tracker */
819   if (cursor)
820   {
821     if (tracker_sparql_cursor_next (cursor, NULL, NULL))
822     {
823       retval = biji_info_set_new ();
824 
825       retval->url = g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL));
826       retval->title = g_strdup (tracker_sparql_cursor_get_string (cursor, 1, NULL));
827       retval->mtime = iso8601_to_gint64 (tracker_sparql_cursor_get_string (cursor, 2, NULL));
828 
829       retval->content = biji_str_replace (
830         tracker_sparql_cursor_get_string (cursor, 3, NULL), "b&lt;br/&gt", "\n");
831 
832       retval->created = iso8601_to_gint64 (tracker_sparql_cursor_get_string (cursor, 4, NULL));
833 
834 
835       /* Check if the resource is up to date */
836 
837       if (finisher->info->mtime != retval->mtime)
838         g_clear_pointer (&retval, biji_info_set_free);
839     }
840 
841     g_object_unref (cursor);
842   }
843 
844 
845   /* No matter retval or not, we are supposed to callback
846    * (REMEMBER CALLER IS RESPONSIBLE FOR FREEING INFO SET) */
847   if (finisher->info_cb != NULL)
848     finisher->info_cb (retval, finisher->user_data);
849 
850 
851   biji_tracker_finisher_free (finisher);
852 }
853 
854 
855 void
biji_tracker_check_for_info(BijiManager * manager,gchar * url,gint64 mtime,BijiInfoCallback callback,gpointer user_data)856 biji_tracker_check_for_info                (BijiManager *manager,
857                                             gchar *url,
858                                             gint64 mtime,
859                                             BijiInfoCallback callback,
860                                             gpointer user_data)
861 {
862   BijiInfoSet *info;
863   BijiTrackerFinisher *finisher;
864   gchar *query;
865 
866   query = g_strconcat (
867     " SELECT ?urn ?title ?time ?content ?created",
868     " WHERE { ?urn a nfo:Note ;",
869     "         nie:title ?title ;",
870     "         nie:contentLastModified ?time ;",
871     "         nie:plainTextContent ?content ;",
872     "         nie:contentCreated ?created ;",
873     "         nie:url '", url, "' }",
874     NULL);
875 
876   /* No matter user callback or not,
877    * we'll need our own to push if needed */
878   info = biji_info_set_new ();
879   info->url = url;
880   info->mtime = mtime;
881 
882   finisher = biji_tracker_finisher_new (
883                manager,
884                NULL,
885                info,
886                NULL,
887                callback,
888                NULL,
889                NULL,
890                NULL,
891                user_data);
892 
893   tracker_sparql_connection_query_async (
894       get_connection (manager), query, NULL, on_info_queried, finisher);
895 
896 
897   g_free (query);
898 }
899