1 /*
2 * GNOME Online Miners - crawls through your online content
3 * Copyright (C) 2012 Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
19 *
20 * Author: Cosimo Cecchi <cosimoc@redhat.com>
21 * Author: Jasper St. Pierre <jstpierre@mecheye.net>
22 *
23 */
24
25 #include "config.h"
26
27 #include <stdio.h>
28
29 #include "gom-miner.h"
30
31 G_DEFINE_TYPE (GomMiner, gom_miner, G_TYPE_OBJECT)
32
33 struct _GomMinerPrivate {
34 GoaClient *client;
35 GError *client_error;
36
37 TrackerSparqlConnection *connection;
38 GError *connection_error;
39
40 gchar *display_name;
41 gchar **index_types;
42 };
43
44 typedef struct {
45 GomMiner *self;
46 GList *content_objects;
47 GList *acc_objects;
48 GList *old_datasources;
49 GList *pending_jobs;
50 } CleanupJob;
51
52 typedef struct {
53 GomMiner *self;
54 gchar *account_id;
55 gchar *shared_id;
56 gchar *shared_type;
57 gchar *source_urn;
58 gpointer service;
59 } InsertSharedContentData;
60
61 static GThreadPool *cleanup_pool;
62
63 static void cleanup_job (gpointer data, gpointer user_data);
64
65 static void
gom_account_miner_job_free(GomAccountMinerJob * job)66 gom_account_miner_job_free (GomAccountMinerJob *job)
67 {
68 g_hash_table_unref (job->services);
69 g_clear_object (&job->miner);
70 g_clear_object (&job->account);
71 g_clear_object (&job->connection);
72 g_clear_object (&job->task);
73 g_clear_object (&job->parent_task);
74
75 g_free (job->datasource_urn);
76 g_free (job->root_element_urn);
77
78 g_hash_table_unref (job->previous_resources);
79
80 g_slice_free (GomAccountMinerJob, job);
81 }
82
83 static void
gom_insert_shared_content_data_free(InsertSharedContentData * data)84 gom_insert_shared_content_data_free (InsertSharedContentData *data)
85 {
86 GOM_MINER_GET_CLASS (data->self)->destroy_service (data->self, data->service);
87
88 g_object_unref (data->self);
89 g_free (data->account_id);
90 g_free (data->shared_id);
91 g_free (data->shared_type);
92 g_free (data->source_urn);
93
94 g_slice_free (InsertSharedContentData, data);
95 }
96
97 static InsertSharedContentData *
gom_insert_shared_content_data_new(GomMiner * self,const gchar * account_id,const gchar * shared_id,const gchar * shared_type,const gchar * source_urn,gpointer service)98 gom_insert_shared_content_data_new (GomMiner *self,
99 const gchar *account_id,
100 const gchar *shared_id,
101 const gchar *shared_type,
102 const gchar *source_urn,
103 gpointer service)
104 {
105 InsertSharedContentData *retval;
106
107 retval = g_slice_new0 (InsertSharedContentData);
108 retval->self = g_object_ref (self);
109 retval->account_id = g_strdup (account_id);
110 retval->shared_id = g_strdup (shared_id);
111 retval->shared_type = g_strdup (shared_type);
112 retval->source_urn = g_strdup (source_urn);
113 retval->service = service;
114
115 return retval;
116 }
117
118 static void
gom_miner_dispose(GObject * object)119 gom_miner_dispose (GObject *object)
120 {
121 GomMiner *self = GOM_MINER (object);
122
123 g_clear_object (&self->priv->client);
124 g_clear_object (&self->priv->connection);
125
126 g_free (self->priv->display_name);
127 g_strfreev (self->priv->index_types);
128 g_clear_error (&self->priv->client_error);
129 g_clear_error (&self->priv->connection_error);
130
131 G_OBJECT_CLASS (gom_miner_parent_class)->dispose (object);
132 }
133
134 static void
gom_miner_init_goa(GomMiner * self)135 gom_miner_init_goa (GomMiner *self)
136 {
137 GoaAccount *account;
138 GoaObject *object;
139 const gchar *provider_type;
140 GList *accounts, *l;
141 GomMinerClass *miner_class = GOM_MINER_GET_CLASS (self);
142
143 self->priv->client = goa_client_new_sync (NULL, &self->priv->client_error);
144
145 if (self->priv->client_error != NULL)
146 {
147 g_critical ("Unable to create GoaClient: %s - indexing for %s will not work",
148 self->priv->client_error->message, miner_class->goa_provider_type);
149 return;
150 }
151
152 accounts = goa_client_get_accounts (self->priv->client);
153 for (l = accounts; l != NULL; l = l->next)
154 {
155 object = l->data;
156
157 account = goa_object_peek_account (object);
158 if (account == NULL)
159 continue;
160
161 provider_type = goa_account_get_provider_type (account);
162 if (g_strcmp0 (provider_type, miner_class->goa_provider_type) == 0)
163 {
164 g_free (self->priv->display_name);
165 self->priv->display_name = goa_account_dup_provider_name (account);
166 break;
167 }
168 }
169
170 g_list_free_full (accounts, g_object_unref);
171 }
172
173 static void
gom_miner_constructed(GObject * obj)174 gom_miner_constructed (GObject *obj)
175 {
176 GomMiner *self = GOM_MINER (obj);
177
178 G_OBJECT_CLASS (gom_miner_parent_class)->constructed (obj);
179
180 gom_miner_init_goa (self);
181 }
182
183 static void
gom_miner_init(GomMiner * self)184 gom_miner_init (GomMiner *self)
185 {
186 GomMinerClass *klass = GOM_MINER_GET_CLASS (self);
187
188 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GOM_TYPE_MINER, GomMinerPrivate);
189 self->priv->display_name = g_strdup ("");
190
191 self->priv->connection = tracker_sparql_connection_get (NULL, &self->priv->connection_error);
192 if (self->priv->connection_error != NULL)
193 {
194 g_critical ("Unable to create TrackerSparqlConnection: %s - indexing for %s will not work",
195 self->priv->connection_error->message,
196 klass->goa_provider_type);
197 }
198 }
199
200 static void
gom_miner_class_init(GomMinerClass * klass)201 gom_miner_class_init (GomMinerClass *klass)
202 {
203 GObjectClass *oclass = G_OBJECT_CLASS (klass);
204
205 oclass->constructed = gom_miner_constructed;
206 oclass->dispose = gom_miner_dispose;
207
208 cleanup_pool = g_thread_pool_new (cleanup_job, NULL, 1, FALSE, NULL);
209
210 g_type_class_add_private (klass, sizeof (GomMinerPrivate));
211 }
212
213 static void
gom_miner_check_pending_jobs(GTask * task)214 gom_miner_check_pending_jobs (GTask *task)
215 {
216 CleanupJob *cleanup_job;
217
218 cleanup_job = (CleanupJob *) g_task_get_task_data (task);
219
220 if (g_list_length (cleanup_job->pending_jobs) > 0)
221 return;
222
223 g_task_return_boolean (task, TRUE);
224 g_slice_free (CleanupJob, cleanup_job);
225 }
226
227 static void
gom_miner_ensure_datasource(GomMiner * self,const gchar * datasource_urn,const gchar * root_element_urn,GCancellable * cancellable,GError ** error)228 gom_miner_ensure_datasource (GomMiner *self,
229 const gchar *datasource_urn,
230 const gchar *root_element_urn,
231 GCancellable *cancellable,
232 GError **error)
233 {
234 GString *datasource_insert;
235 GomMinerClass *klass = GOM_MINER_GET_CLASS (self);
236
237 datasource_insert = g_string_new (NULL);
238 g_string_append_printf (datasource_insert,
239 "INSERT OR REPLACE INTO <%s> {"
240 " <%s> a nie:DataSource ; nao:identifier \"%s\" . "
241 " <%s> a nie:InformationElement ; nie:rootElementOf <%s> ; nie:version \"%d\""
242 "}",
243 datasource_urn,
244 datasource_urn, klass->miner_identifier,
245 root_element_urn, datasource_urn, klass->version);
246
247 tracker_sparql_connection_update (self->priv->connection,
248 datasource_insert->str,
249 G_PRIORITY_DEFAULT,
250 cancellable,
251 error);
252
253 g_string_free (datasource_insert, TRUE);
254 }
255
256 static void
gom_account_miner_job_query_existing(GomAccountMinerJob * job,GError ** error)257 gom_account_miner_job_query_existing (GomAccountMinerJob *job,
258 GError **error)
259 {
260 GCancellable *cancellable;
261 GString *select;
262 TrackerSparqlCursor *cursor;
263
264 cancellable = g_task_get_cancellable (job->task);
265
266 select = g_string_new (NULL);
267 g_string_append_printf (select,
268 "SELECT ?urn nao:identifier(?urn) WHERE { ?urn nie:dataSource <%s> }",
269 job->datasource_urn);
270
271 cursor = tracker_sparql_connection_query (job->connection,
272 select->str,
273 cancellable,
274 error);
275 g_string_free (select, TRUE);
276
277 if (cursor == NULL)
278 return;
279
280 while (tracker_sparql_cursor_next (cursor, cancellable, error))
281 {
282 g_hash_table_insert (job->previous_resources,
283 g_strdup (tracker_sparql_cursor_get_string (cursor, 1, NULL)),
284 g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)));
285 }
286
287 g_object_unref (cursor);
288 }
289
290 static void
previous_resources_cleanup_foreach(gpointer key,gpointer value,gpointer user_data)291 previous_resources_cleanup_foreach (gpointer key,
292 gpointer value,
293 gpointer user_data)
294 {
295 const gchar *resource = value;
296 GString *delete = user_data;
297
298 g_string_append_printf (delete, "<%s> a rdfs:Resource . ", resource);
299 }
300
301 static void
gom_account_miner_job_cleanup_previous(GomAccountMinerJob * job,GError ** error)302 gom_account_miner_job_cleanup_previous (GomAccountMinerJob *job,
303 GError **error)
304 {
305 GCancellable *cancellable;
306 GString *delete;
307
308 cancellable = g_task_get_cancellable (job->task);
309
310 delete = g_string_new (NULL);
311 g_string_append (delete, "DELETE { ");
312
313 /* the resources left here are those who were in the database,
314 * but were not found during the query; remove them from the database.
315 */
316 g_hash_table_foreach (job->previous_resources,
317 previous_resources_cleanup_foreach,
318 delete);
319
320 g_string_append (delete, "}");
321
322 tracker_sparql_connection_update (job->connection,
323 delete->str,
324 G_PRIORITY_DEFAULT,
325 cancellable,
326 error);
327
328 g_string_free (delete, TRUE);
329 }
330
331 static void
gom_account_miner_job_query(GomAccountMinerJob * job,GError ** error)332 gom_account_miner_job_query (GomAccountMinerJob *job,
333 GError **error)
334 {
335 GomMinerClass *miner_class = GOM_MINER_GET_CLASS (job->miner);
336 GCancellable *cancellable;
337
338 cancellable = g_task_get_cancellable (job->task);
339 miner_class->query (job, job->connection, job->previous_resources, job->datasource_urn, cancellable, error);
340 }
341
342 static void
gom_account_miner_job(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)343 gom_account_miner_job (GTask *task,
344 gpointer source_object,
345 gpointer task_data,
346 GCancellable *cancellable)
347 {
348 GomAccountMinerJob *job = task_data;
349 GError *error = NULL;
350
351 gom_miner_ensure_datasource (job->miner, job->datasource_urn, job->root_element_urn, cancellable, &error);
352
353 if (error != NULL)
354 goto out;
355
356 gom_account_miner_job_query_existing (job, &error);
357
358 if (error != NULL)
359 goto out;
360
361 gom_account_miner_job_query (job, &error);
362
363 if (error != NULL)
364 goto out;
365
366 gom_account_miner_job_cleanup_previous (job, &error);
367
368 if (error != NULL)
369 goto out;
370
371 out:
372 if (error != NULL)
373 g_task_return_error (job->task, error);
374 else
375 g_task_return_boolean (job->task, TRUE);
376 }
377
378 static void
gom_account_miner_job_process_async(GomAccountMinerJob * job,GAsyncReadyCallback callback,gpointer user_data)379 gom_account_miner_job_process_async (GomAccountMinerJob *job,
380 GAsyncReadyCallback callback,
381 gpointer user_data)
382 {
383 GCancellable *cancellable;
384
385 g_assert (job->task == NULL);
386
387 cancellable = g_task_get_cancellable (job->parent_task);
388
389 job->task = g_task_new (NULL, cancellable, callback, user_data);
390 g_task_set_source_tag (job->task, gom_account_miner_job_process_async);
391 g_task_set_task_data (job->task, job, NULL);
392 g_task_run_in_thread (job->task, gom_account_miner_job);
393 }
394
395 static gboolean
gom_account_miner_job_process_finish(GAsyncResult * res,GError ** error)396 gom_account_miner_job_process_finish (GAsyncResult *res,
397 GError **error)
398 {
399 GTask *task;
400
401 g_assert (g_task_is_valid (res, NULL));
402 task = G_TASK (res);
403
404 g_assert (g_task_get_source_tag (task) == gom_account_miner_job_process_async);
405
406 return g_task_propagate_boolean (task, error);
407 }
408
409 static GomAccountMinerJob *
gom_account_miner_job_new(GomMiner * self,GoaObject * object,GTask * parent_task)410 gom_account_miner_job_new (GomMiner *self,
411 GoaObject *object,
412 GTask *parent_task)
413 {
414 GomAccountMinerJob *retval;
415 GoaAccount *account;
416 GomMinerClass *miner_class = GOM_MINER_GET_CLASS (self);
417
418 account = goa_object_get_account (object);
419 g_assert (account != NULL);
420
421 retval = g_slice_new0 (GomAccountMinerJob);
422 retval->miner = g_object_ref (self);
423 retval->parent_task = g_object_ref (parent_task);
424 retval->account = account;
425 retval->connection = g_object_ref (self->priv->connection);
426 retval->previous_resources =
427 g_hash_table_new_full (g_str_hash, g_str_equal,
428 (GDestroyNotify) g_free, (GDestroyNotify) g_free);
429
430 retval->services = miner_class->create_services (self, object);
431 retval->datasource_urn = g_strdup_printf ("gd:goa-account:%s",
432 goa_account_get_id (retval->account));
433 retval->root_element_urn = g_strdup_printf ("gd:goa-account:%s:root-element",
434 goa_account_get_id (retval->account));
435
436 return retval;
437 }
438
439 static void
miner_job_process_ready_cb(GObject * source,GAsyncResult * res,gpointer user_data)440 miner_job_process_ready_cb (GObject *source,
441 GAsyncResult *res,
442 gpointer user_data)
443 {
444 CleanupJob *cleanup_job;
445 GomAccountMinerJob *account_miner_job = user_data;
446 GomMiner *self = account_miner_job->miner;
447 GError *error = NULL;
448
449 cleanup_job = (CleanupJob *) g_task_get_task_data (account_miner_job->parent_task);
450
451 gom_account_miner_job_process_finish (res, &error);
452
453 if (error != NULL)
454 {
455 g_printerr ("Error while refreshing account %s: %s",
456 goa_account_get_id (account_miner_job->account), error->message);
457
458 g_error_free (error);
459 }
460
461 cleanup_job->pending_jobs = g_list_remove (cleanup_job->pending_jobs,
462 account_miner_job);
463
464 gom_miner_check_pending_jobs (account_miner_job->parent_task);
465 gom_account_miner_job_free (account_miner_job);
466 }
467
468 static void
gom_miner_setup_account(GomMiner * self,GoaObject * object,GTask * task)469 gom_miner_setup_account (GomMiner *self,
470 GoaObject *object,
471 GTask *task)
472 {
473 CleanupJob *cleanup_job;
474 GomAccountMinerJob *account_miner_job;
475
476 cleanup_job = (CleanupJob *) g_task_get_task_data (task);
477
478 account_miner_job = gom_account_miner_job_new (self, object, task);
479 cleanup_job->pending_jobs = g_list_prepend (cleanup_job->pending_jobs, account_miner_job);
480
481 gom_account_miner_job_process_async (account_miner_job, miner_job_process_ready_cb, account_miner_job);
482 }
483
484 static gboolean
cleanup_old_accounts_done(gpointer data)485 cleanup_old_accounts_done (gpointer data)
486 {
487 GTask *task = G_TASK (data);
488 CleanupJob *job;
489 GList *l;
490 GoaObject *object;
491 GomMiner *self;
492
493 job = (CleanupJob *) g_task_get_task_data (task);
494 self = job->self;
495
496 /* now setup all the current accounts */
497 for (l = job->content_objects; l != NULL; l = l->next)
498 {
499 object = l->data;
500 gom_miner_setup_account (self, object, task);
501
502 g_object_unref (object);
503 }
504
505 if (job->content_objects != NULL)
506 {
507 g_list_free (job->content_objects);
508 job->content_objects = NULL;
509 }
510
511 if (job->acc_objects != NULL)
512 {
513 g_list_free_full (job->acc_objects, g_object_unref);
514 job->acc_objects = NULL;
515 }
516
517 if (job->old_datasources != NULL)
518 {
519 g_list_free_full (job->old_datasources, g_free);
520 job->old_datasources = NULL;
521 }
522
523 gom_miner_check_pending_jobs (task);
524
525 g_clear_object (&job->self);
526
527 return FALSE;
528 }
529
530 static void
cleanup_job_do_cleanup(CleanupJob * job,GCancellable * cancellable)531 cleanup_job_do_cleanup (CleanupJob *job, GCancellable *cancellable)
532 {
533 GomMiner *self = job->self;
534 GList *l;
535 GString *update;
536 GError *error = NULL;
537
538 if (job->old_datasources == NULL)
539 return;
540
541 update = g_string_new (NULL);
542
543 for (l = job->old_datasources; l != NULL; l = l->next)
544 {
545 const gchar *resource;
546
547 resource = l->data;
548 g_debug ("Cleaning up old datasource %s", resource);
549
550 g_string_append_printf (update,
551 "DELETE {"
552 " ?u a rdfs:Resource"
553 "} WHERE {"
554 " ?u nie:dataSource <%s>"
555 "}",
556 resource);
557 }
558
559 tracker_sparql_connection_update (self->priv->connection,
560 update->str,
561 G_PRIORITY_DEFAULT,
562 cancellable,
563 &error);
564 g_string_free (update, TRUE);
565
566 if (error != NULL)
567 {
568 g_printerr ("Error while cleaning up old accounts: %s\n", error->message);
569 g_error_free (error);
570 }
571 }
572
573 static gint
cleanup_datasource_compare(gconstpointer a,gconstpointer b)574 cleanup_datasource_compare (gconstpointer a,
575 gconstpointer b)
576 {
577 GoaObject *object = GOA_OBJECT (a);
578 const gchar *datasource = b;
579 gint res;
580
581 GoaAccount *account;
582 gchar *object_datasource;
583
584 account = goa_object_peek_account (object);
585 g_assert (account != NULL);
586
587 object_datasource = g_strdup_printf ("gd:goa-account:%s", goa_account_get_id (account));
588 res = g_strcmp0 (datasource, object_datasource);
589
590 g_free (object_datasource);
591
592 return res;
593 }
594
595 static void
cleanup_job(gpointer data,gpointer user_data)596 cleanup_job (gpointer data,
597 gpointer user_data)
598 {
599 GCancellable *cancellable;
600 GSource *source;
601 GString *select;
602 GTask *task = G_TASK (data);
603 GError *error = NULL;
604 TrackerSparqlCursor *cursor;
605 const gchar *datasource, *old_version_str;
606 gint old_version;
607 GList *element;
608 CleanupJob *job;
609 GomMiner *self;
610 GomMinerClass *klass;
611
612 cancellable = g_task_get_cancellable (task);
613 job = (CleanupJob *) g_task_get_task_data (task);
614 self = job->self;
615 klass = GOM_MINER_GET_CLASS (self);
616
617 /* find all our datasources in the tracker DB */
618 select = g_string_new (NULL);
619 g_string_append_printf (select, "SELECT ?datasource nie:version(?root) WHERE { "
620 "?datasource a nie:DataSource . "
621 "?datasource nao:identifier \"%s\" . "
622 "OPTIONAL { ?root nie:rootElementOf ?datasource } }",
623 klass->miner_identifier);
624
625 cursor = tracker_sparql_connection_query (self->priv->connection,
626 select->str,
627 cancellable,
628 &error);
629 g_string_free (select, TRUE);
630
631 if (error != NULL)
632 {
633 g_printerr ("Error while cleaning up old accounts: %s\n", error->message);
634 goto out;
635 }
636
637 while (tracker_sparql_cursor_next (cursor, cancellable, NULL))
638 {
639 /* If the source we found is not in the current list, add
640 * it to the cleanup list.
641 * Note that the objects here in the list might *not* support
642 * documents, in case the switch has been disabled in System Settings.
643 * In fact, we only remove all the account data in case the account
644 * is really removed from the panel.
645 *
646 * Also, cleanup sources for which the version has increased.
647 */
648 datasource = tracker_sparql_cursor_get_string (cursor, 0, NULL);
649 element = g_list_find_custom (job->acc_objects, datasource,
650 cleanup_datasource_compare);
651
652 if (element == NULL)
653 job->old_datasources = g_list_prepend (job->old_datasources,
654 g_strdup (datasource));
655
656 old_version_str = tracker_sparql_cursor_get_string (cursor, 1, NULL);
657 if (old_version_str == NULL)
658 old_version = 1;
659 else
660 sscanf (old_version_str, "%d", &old_version);
661
662 g_debug ("Stored version: %d - new version %d", old_version, klass->version);
663
664 if ((element == NULL) || (old_version < klass->version))
665 {
666 job->old_datasources = g_list_prepend (job->old_datasources,
667 g_strdup (datasource));
668 }
669 }
670
671 g_object_unref (cursor);
672
673 /* cleanup the DB */
674 cleanup_job_do_cleanup (job, cancellable);
675
676 out:
677 source = g_idle_source_new ();
678 g_source_set_name (source, "[gnome-online-miners] cleanup_old_accounts_done");
679 g_task_attach_source (task, source, cleanup_old_accounts_done);
680 g_source_unref (source);
681
682 g_object_unref (task);
683 }
684
685 static void
gom_miner_cleanup_old_accounts(GomMiner * self,GList * content_objects,GList * acc_objects,GTask * task)686 gom_miner_cleanup_old_accounts (GomMiner *self,
687 GList *content_objects,
688 GList *acc_objects,
689 GTask *task)
690 {
691 CleanupJob *job = g_slice_new0 (CleanupJob);
692
693 job->self = g_object_ref (self);
694 job->content_objects = content_objects;
695 job->acc_objects = acc_objects;
696
697 g_task_set_task_data (task, job, NULL);
698 g_thread_pool_push (cleanup_pool, g_object_ref (task), NULL);
699 }
700
701 static void
gom_miner_refresh_db_real(GomMiner * self,GTask * task)702 gom_miner_refresh_db_real (GomMiner *self, GTask *task)
703 {
704 GoaFiles *files;
705 GoaPhotos *photos;
706 GoaAccount *account;
707 GoaObject *object;
708 const gchar *provider_type;
709 GList *accounts, *content_objects, *acc_objects, *l;
710 GomMinerClass *miner_class = GOM_MINER_GET_CLASS (self);
711 gboolean skip_photos, skip_documents;
712
713 content_objects = NULL;
714 acc_objects = NULL;
715
716 accounts = goa_client_get_accounts (self->priv->client);
717 for (l = accounts; l != NULL; l = l->next)
718 {
719 object = l->data;
720
721 account = goa_object_peek_account (object);
722 if (account == NULL)
723 continue;
724
725 provider_type = goa_account_get_provider_type (account);
726 if (g_strcmp0 (provider_type, miner_class->goa_provider_type) != 0)
727 continue;
728
729 acc_objects = g_list_append (acc_objects, g_object_ref (object));
730 skip_photos = skip_documents = TRUE;
731
732 files = goa_object_peek_files (object);
733 photos = goa_object_peek_photos (object);
734
735 if (gom_miner_supports_type (self, "photos") && photos != NULL)
736 skip_photos = FALSE;
737
738 if (gom_miner_supports_type (self, "documents") && files != NULL)
739 skip_documents = FALSE;
740
741 if (skip_photos && skip_documents)
742 continue;
743
744 content_objects = g_list_append (content_objects, g_object_ref (object));
745 }
746
747 g_list_free_full (accounts, g_object_unref);
748
749 gom_miner_cleanup_old_accounts (self, content_objects, acc_objects, task);
750 }
751
752 const gchar *
gom_miner_get_display_name(GomMiner * self)753 gom_miner_get_display_name (GomMiner *self)
754 {
755 return self->priv->display_name;
756 }
757
758 static void
gom_miner_insert_shared_content_in_thread_func(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)759 gom_miner_insert_shared_content_in_thread_func (GTask *task,
760 gpointer source_object,
761 gpointer task_data,
762 GCancellable *cancellable)
763 {
764 GomMiner *self = GOM_MINER (source_object);
765 GError *error;
766 InsertSharedContentData *data = (InsertSharedContentData *) task_data;
767 gchar *datasource_urn = NULL;
768 gchar *root_element_urn = NULL;
769
770 datasource_urn = g_strdup_printf ("gd:goa-account:%s", data->account_id);
771 root_element_urn = g_strdup_printf ("gd:goa-account:%s:root-element", data->account_id);
772
773 error = NULL;
774 gom_miner_ensure_datasource (self, datasource_urn, root_element_urn, cancellable, &error);
775 if (error != NULL)
776 {
777 g_task_return_error (task, error);
778 goto out;
779 }
780
781 error = NULL;
782 GOM_MINER_GET_CLASS (self)->insert_shared_content (self,
783 data->service,
784 self->priv->connection,
785 datasource_urn,
786 data->shared_id,
787 data->shared_type,
788 data->source_urn,
789 cancellable,
790 &error);
791 if (error != NULL)
792 {
793 g_task_return_error (task, error);
794 goto out;
795 }
796
797 g_task_return_boolean (task, TRUE);
798
799 out:
800 g_free (datasource_urn);
801 g_free (root_element_urn);
802 }
803
804 void
gom_miner_insert_shared_content_async(GomMiner * self,const gchar * account_id,const gchar * shared_id,const gchar * shared_type,const gchar * source_urn,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)805 gom_miner_insert_shared_content_async (GomMiner *self,
806 const gchar *account_id,
807 const gchar *shared_id,
808 const gchar *shared_type,
809 const gchar *source_urn,
810 GCancellable *cancellable,
811 GAsyncReadyCallback callback,
812 gpointer user_data)
813 {
814 GTask *task = NULL;
815 GoaFiles *files;
816 GoaObject *object = NULL;
817 GoaPhotos *photos;
818 InsertSharedContentData *data;
819 gpointer service;
820
821 task = g_task_new (self, cancellable, callback, user_data);
822 g_task_set_source_tag (task, gom_miner_insert_shared_content_async);
823
824 if (self->priv->client_error != NULL)
825 {
826 g_task_return_error (task, g_error_copy (self->priv->client_error));
827 goto out;
828 }
829
830 if (self->priv->connection_error != NULL)
831 {
832 g_task_return_error (task, g_error_copy (self->priv->connection_error));
833 goto out;
834 }
835
836 object = goa_client_lookup_by_id (self->priv->client, account_id);
837 if (object == NULL)
838 {
839 /* throw error */
840 goto out;
841 }
842
843 files = goa_object_peek_files (object);
844 photos = goa_object_peek_photos (object);
845
846 if (g_strcmp0 (shared_type, "documents") == 0 && files == NULL)
847 {
848 /* throw error */
849 goto out;
850 }
851
852 if (g_strcmp0 (shared_type, "photos") == 0 && photos == NULL)
853 {
854 /* throw error */
855 goto out;
856 }
857
858 service = GOM_MINER_GET_CLASS (self)->create_service (self, object, shared_type);
859 if (service == NULL)
860 {
861 /* throw error */
862 goto out;
863 }
864
865 data = gom_insert_shared_content_data_new (self, account_id, shared_id, shared_type, source_urn, service);
866 g_task_set_task_data (task, data, (GDestroyNotify) gom_insert_shared_content_data_free);
867
868 g_task_run_in_thread (task, gom_miner_insert_shared_content_in_thread_func);
869
870 out:
871 g_clear_object (&object);
872 g_clear_object (&task);
873 }
874
875 gboolean
gom_miner_insert_shared_content_finish(GomMiner * self,GAsyncResult * res,GError ** error)876 gom_miner_insert_shared_content_finish (GomMiner *self, GAsyncResult *res, GError **error)
877 {
878 GTask *task;
879
880 g_assert (g_task_is_valid (res, self));
881 task = G_TASK (res);
882
883 g_assert (g_task_get_source_tag (task) == gom_miner_insert_shared_content_async);
884
885 return g_task_propagate_boolean (task, error);
886 }
887
888 void
gom_miner_refresh_db_async(GomMiner * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)889 gom_miner_refresh_db_async (GomMiner *self,
890 GCancellable *cancellable,
891 GAsyncReadyCallback callback,
892 gpointer user_data)
893 {
894 GTask *task = NULL;
895
896 task = g_task_new (self, cancellable, callback, user_data);
897 g_task_set_source_tag (task, gom_miner_refresh_db_async);
898
899 if (self->priv->client_error != NULL)
900 {
901 g_task_return_error (task, g_error_copy (self->priv->client_error));
902 goto out;
903 }
904
905 if (self->priv->connection_error != NULL)
906 {
907 g_task_return_error (task, g_error_copy (self->priv->connection_error));
908 goto out;
909 }
910
911 gom_miner_refresh_db_real (self, task);
912
913 out:
914 g_clear_object (&task);
915 }
916
917 gboolean
gom_miner_refresh_db_finish(GomMiner * self,GAsyncResult * res,GError ** error)918 gom_miner_refresh_db_finish (GomMiner *self,
919 GAsyncResult *res,
920 GError **error)
921 {
922 GTask *task;
923
924 g_assert (g_task_is_valid (res, self));
925 task = G_TASK (res);
926
927 g_assert (g_task_get_source_tag (task) == gom_miner_refresh_db_async);
928
929 return g_task_propagate_boolean (task, error);
930 }
931
932 void
gom_miner_set_index_types(GomMiner * self,const char ** index_types)933 gom_miner_set_index_types (GomMiner *self, const char **index_types)
934 {
935 g_strfreev (self->priv->index_types);
936 self->priv->index_types = g_strdupv ((gchar **) index_types);
937 }
938
939 const gchar **
gom_miner_get_index_types(GomMiner * self)940 gom_miner_get_index_types (GomMiner *self)
941 {
942 return (const gchar **) self->priv->index_types;
943 }
944
945 gboolean
gom_miner_supports_type(GomMiner * self,gchar * type)946 gom_miner_supports_type (GomMiner *self, gchar *type)
947 {
948 gboolean retval = FALSE;
949 guint i;
950
951 for (i = 0; self->priv->index_types[i] != NULL; i++)
952 {
953 if (g_strcmp0 (self->priv->index_types[i], type) == 0)
954 {
955 retval = TRUE;
956 break;
957 }
958 }
959
960 return retval;
961 }
962