1 /*
2 * Copyright (C) 2009-2011 Collabora Ltd.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 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 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
19 */
20
21 #include "config.h"
22 #include "dbus-service-internal.h"
23
24 #include <string.h>
25 #include <sys/stat.h>
26
27 #include <glib.h>
28 #include <telepathy-glib/telepathy-glib.h>
29 #include <telepathy-glib/telepathy-glib-dbus.h>
30
31 #include <telepathy-logger/event-internal.h>
32 #include <telepathy-logger/text-event.h>
33 #include <telepathy-logger/log-manager.h>
34 #include <telepathy-logger/log-manager-internal.h>
35
36 #include <extensions/extensions.h>
37
38 #define DEBUG_FLAG TPL_DEBUG_DBUS_SERVICE
39 #include <telepathy-logger/action-chain-internal.h>
40 #include <telepathy-logger/debug-internal.h>
41 #include <telepathy-logger/util-internal.h>
42
43 #define FAVOURITE_CONTACTS_FILENAME "favourite-contacts.txt"
44
45 static void tpl_logger_iface_init (gpointer iface, gpointer iface_data);
46
47 struct _TplDBusServicePriv
48 {
49 TplLogManager *manager;
50 /* map of (string) account name -> (string set) contact ID */
51 /* (the set is implemented as a hash table) */
52 GHashTable *accounts_contacts_map;
53 TplActionChain *favourite_contacts_actions;
54 };
55
56 G_DEFINE_TYPE_WITH_CODE (TplDBusService, _tpl_dbus_service, G_TYPE_OBJECT,
57 G_IMPLEMENT_INTERFACE (TPL_TYPE_SVC_LOGGER, tpl_logger_iface_init));
58
59 typedef struct _FavouriteContactClosure FavouriteContactClosure;
60 typedef void (*FavouriteContactCallback) (gboolean success,
61 FavouriteContactClosure *closure);
62
63
64 struct _FavouriteContactClosure {
65 TplDBusService *service;
66 gchar *account;
67 gchar *contact_id;
68 gchar *file_contents;
69 DBusGMethodInvocation *context;
70 FavouriteContactCallback cb;
71 };
72
73
74 static void
favourite_contact_closure_free(FavouriteContactClosure * closure)75 favourite_contact_closure_free (FavouriteContactClosure *closure)
76 {
77 if (closure == NULL)
78 return;
79
80 if (closure->service != NULL)
81 g_object_unref (closure->service);
82
83 g_free (closure->account);
84 g_free (closure->contact_id);
85 g_free (closure->file_contents);
86 g_slice_free (FavouriteContactClosure, closure);
87 }
88
89
90 static FavouriteContactClosure *
favourite_contact_closure_new(TplDBusService * self,const gchar * account,const gchar * contact_id,DBusGMethodInvocation * context)91 favourite_contact_closure_new (TplDBusService *self,
92 const gchar *account,
93 const gchar *contact_id,
94 DBusGMethodInvocation *context)
95 {
96 FavouriteContactClosure *closure;
97
98 closure = g_slice_new0 (FavouriteContactClosure);
99 closure->service = g_object_ref (G_OBJECT (self));
100 closure->account = g_strdup (account);
101 closure->contact_id = g_strdup (contact_id);
102 /* XXX: ideally we'd up the ref count or duplicate this */
103 closure->context = context;
104
105 return closure;
106 }
107
108
109 static gboolean
favourite_contacts_add_event(TplDBusService * self,const gchar * account,const gchar * contact_id)110 favourite_contacts_add_event (TplDBusService *self,
111 const gchar *account,
112 const gchar *contact_id)
113 {
114 GHashTable *contacts;
115 gboolean new_event = FALSE;
116 TplDBusServicePriv *priv;
117
118 g_return_val_if_fail (TPL_IS_DBUS_SERVICE (self), FALSE);
119 g_return_val_if_fail (account != NULL, FALSE);
120 g_return_val_if_fail (contact_id != NULL, FALSE);
121
122 priv = self->priv;
123
124 DEBUG ("adding favourite contact: account '%s', ID '%s'",
125 account, contact_id);
126
127 contacts = g_hash_table_lookup (priv->accounts_contacts_map, account);
128 if (contacts == NULL)
129 {
130 contacts = g_hash_table_new_full (g_str_hash, g_str_equal,
131 (GDestroyNotify) g_free, NULL);
132 g_hash_table_insert (priv->accounts_contacts_map, g_strdup (account),
133 contacts);
134 new_event = TRUE;
135 }
136 else if (g_hash_table_lookup (contacts, contact_id) == NULL)
137 {
138 new_event = TRUE;
139 }
140
141 if (new_event)
142 {
143 /* add dummy string for the value just for the convenience of looking up
144 * whether the key already exists */
145 g_hash_table_insert (contacts, g_strdup (contact_id),
146 GINT_TO_POINTER (TRUE));
147 }
148
149 return new_event;
150 }
151
152
153 static const gchar *
favourite_contacts_get_filename(void)154 favourite_contacts_get_filename (void)
155 {
156 static gchar *filename = NULL;
157
158 if (filename == NULL)
159 {
160 filename = g_build_filename (g_get_user_data_dir (), TPL_DATA_DIR,
161 FAVOURITE_CONTACTS_FILENAME, NULL);
162 }
163
164 return filename;
165 }
166
167
168 static gboolean
favourite_contacts_parse_line(TplDBusService * self,const gchar * line)169 favourite_contacts_parse_line (TplDBusService *self,
170 const gchar *line)
171 {
172 gboolean success = TRUE;
173 gchar **elements;
174
175 if (line == NULL || line[0] == '\0')
176 return TRUE;
177
178 /* this works on the assumption that account names can't have spaces in them
179 */
180 elements = g_strsplit (line, " ", 2);
181 if (g_strv_length (elements) < 2)
182 {
183 DEBUG ("invalid number of elements on favourite contacts file line:\n"
184 "%s\n", line);
185 success = FALSE;
186 }
187 else
188 favourite_contacts_add_event (self, elements[0], elements[1]);
189
190 g_strfreev (elements);
191
192 return success;
193 }
194
195
196 static void
favourite_contacts_file_read_line_cb(GObject * object,GAsyncResult * result,gpointer user_data)197 favourite_contacts_file_read_line_cb (GObject *object,
198 GAsyncResult *result,
199 gpointer user_data)
200 {
201 GDataInputStream *data_stream = G_DATA_INPUT_STREAM (object);
202 TplActionChain *action_chain = (TplActionChain *) (user_data);
203 TplDBusService *self = _tpl_action_chain_get_object (action_chain);
204 gchar *line;
205 GError *error = NULL;
206
207 line = g_data_input_stream_read_line_finish (data_stream, result, NULL, &error);
208
209 if (error != NULL)
210 {
211 g_prefix_error (&error, "failed to open favourite contacts file: ");
212 _tpl_action_chain_terminate (action_chain, error);
213 g_clear_error (&error);
214 }
215 else if (line != NULL)
216 {
217 favourite_contacts_parse_line (self, line);
218
219 g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT,
220 NULL, favourite_contacts_file_read_line_cb, action_chain);
221 }
222 else
223 _tpl_action_chain_continue (action_chain);
224 }
225
226
227 static void
favourite_contacts_file_open_cb(GObject * object,GAsyncResult * result,gpointer user_data)228 favourite_contacts_file_open_cb (GObject *object,
229 GAsyncResult *result,
230 gpointer user_data)
231 {
232 GFile *file = G_FILE (object);
233 TplActionChain *action_chain = (TplActionChain *) user_data;
234 GFileInputStream *stream;
235 GError *error = NULL;
236
237 if ((stream = g_file_read_finish (file, result, &error)))
238 {
239 GDataInputStream *data_stream = g_data_input_stream_new (
240 G_INPUT_STREAM (stream));
241
242 g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT,
243 NULL, favourite_contacts_file_read_line_cb, action_chain);
244
245 g_object_unref (stream);
246 }
247 else if (error->code == G_IO_ERROR_NOT_FOUND)
248 {
249 DEBUG ("Favourite contacts file doesn't exist yet. Will create as "
250 "necessary.");
251
252 g_clear_error (&error);
253 _tpl_action_chain_continue (action_chain);
254 }
255 else
256 {
257 g_prefix_error (&error, "Failed to open the favourite contacts file: ");
258 _tpl_action_chain_terminate (action_chain, error);
259 g_clear_error (&error);
260 }
261 }
262
263
264 static void
pendingproc_favourite_contacts_file_open(TplActionChain * action_chain,gpointer user_data)265 pendingproc_favourite_contacts_file_open (TplActionChain *action_chain,
266 gpointer user_data)
267 {
268 const gchar *filename;
269 GFile *file;
270
271 filename = favourite_contacts_get_filename ();
272 file = g_file_new_for_path (filename);
273
274 g_file_read_async (file, G_PRIORITY_DEFAULT, NULL,
275 favourite_contacts_file_open_cb, action_chain);
276
277 g_object_unref (G_OBJECT (file));
278 }
279
280
281 static void
tpl_dbus_service_dispose(GObject * obj)282 tpl_dbus_service_dispose (GObject *obj)
283 {
284 TplDBusServicePriv *priv = TPL_DBUS_SERVICE (obj)->priv;
285
286 if (priv->accounts_contacts_map != NULL)
287 {
288 g_hash_table_unref (priv->accounts_contacts_map);
289 priv->accounts_contacts_map = NULL;
290 }
291
292 if (priv->favourite_contacts_actions != NULL)
293 priv->favourite_contacts_actions = NULL;
294
295 G_OBJECT_CLASS (_tpl_dbus_service_parent_class)->dispose (obj);
296 }
297
298
299 static void
favourite_contacts_file_parsed_cb(GObject * object,GAsyncResult * result,gpointer user_data)300 favourite_contacts_file_parsed_cb (GObject *object,
301 GAsyncResult *result,
302 gpointer user_data)
303 {
304 TplDBusService *self = TPL_DBUS_SERVICE (object);
305 TplDBusServicePriv *priv = self->priv;
306 GError *error = NULL;
307
308 if (!_tpl_action_chain_new_finish (object, result, &error))
309 {
310 DEBUG ("Failed to parse the favourite contacts file and/or execute "
311 "subsequent queued method calls: %s", error->message);
312 g_error_free (error);
313 }
314
315 priv->favourite_contacts_actions = NULL;
316 }
317
318
319 static void
tpl_dbus_service_constructed(GObject * object)320 tpl_dbus_service_constructed (GObject *object)
321 {
322 TplDBusServicePriv *priv = TPL_DBUS_SERVICE (object)->priv;
323
324 priv->favourite_contacts_actions = _tpl_action_chain_new_async (object,
325 favourite_contacts_file_parsed_cb, object);
326
327 _tpl_action_chain_append (priv->favourite_contacts_actions,
328 pendingproc_favourite_contacts_file_open, NULL);
329 _tpl_action_chain_continue (priv->favourite_contacts_actions);
330 }
331
332
333 static void
_tpl_dbus_service_class_init(TplDBusServiceClass * klass)334 _tpl_dbus_service_class_init (TplDBusServiceClass *klass)
335 {
336 GObjectClass* object_class = G_OBJECT_CLASS (klass);
337
338 object_class->constructed = tpl_dbus_service_constructed;
339 object_class->dispose = tpl_dbus_service_dispose;
340
341 g_type_class_add_private (object_class, sizeof (TplDBusServicePriv));
342 }
343
344
345 static void
_tpl_dbus_service_init(TplDBusService * self)346 _tpl_dbus_service_init (TplDBusService *self)
347 {
348 TplDBusServicePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
349 TPL_TYPE_DBUS_SERVICE, TplDBusServicePriv);
350
351 g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
352
353 self->priv = priv;
354 priv->manager = tpl_log_manager_dup_singleton ();
355 priv->accounts_contacts_map = g_hash_table_new_full (g_str_hash, g_str_equal,
356 (GDestroyNotify) g_free, (GDestroyNotify) g_hash_table_unref);
357 priv->favourite_contacts_actions = NULL;
358 }
359
360
361 TplDBusService *
_tpl_dbus_service_new(void)362 _tpl_dbus_service_new (void)
363 {
364 return g_object_new (TPL_TYPE_DBUS_SERVICE, NULL);
365 }
366
367
368 static void
append_favourite_contacts_account_and_contacts(const gchar * account,GHashTable * contacts,GPtrArray * packed)369 append_favourite_contacts_account_and_contacts (const gchar *account,
370 GHashTable *contacts,
371 GPtrArray *packed)
372 {
373 GList *l;
374 gchar **contact_ids;
375 gint i;
376
377 /* this case shouldn't happen, but this is just some basic sanity checking */
378 if (g_hash_table_size (contacts) < 1)
379 return;
380
381 /* includes room for the terminal NULL */
382 contact_ids = g_new0 (gchar *, g_hash_table_size (contacts)+1);
383
384 for (i = 0, l = g_hash_table_get_keys (contacts);
385 l;
386 i++, l = g_list_delete_link (l, l))
387 {
388 contact_ids[i] = l->data;
389 }
390
391 g_ptr_array_add (packed, tp_value_array_build (2,
392 DBUS_TYPE_G_OBJECT_PATH, account,
393 G_TYPE_STRV, contact_ids,
394 G_TYPE_INVALID));
395
396 g_free (contact_ids);
397 }
398
399
400 static void
pendingproc_get_favourite_contacts(TplActionChain * action_chain,gpointer user_data)401 pendingproc_get_favourite_contacts (TplActionChain *action_chain,
402 gpointer user_data)
403 {
404 FavouriteContactClosure *closure = user_data;
405 TplDBusServicePriv *priv;
406 GPtrArray *packed;
407
408 g_return_if_fail (closure);
409 g_return_if_fail (TPL_IS_DBUS_SERVICE (closure->service));
410 g_return_if_fail (closure->context != NULL);
411
412 priv = closure->service->priv;
413
414 packed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
415
416 g_hash_table_foreach (priv->accounts_contacts_map,
417 (GHFunc) append_favourite_contacts_account_and_contacts, packed);
418
419 tpl_svc_logger_return_from_get_favourite_contacts (closure->context, packed);
420
421 g_ptr_array_unref (packed);
422 favourite_contact_closure_free (closure);
423
424 if (action_chain != NULL)
425 _tpl_action_chain_continue (action_chain);
426 }
427
428
429 static void
tpl_dbus_service_get_favourite_contacts(TplSvcLogger * logger,DBusGMethodInvocation * context)430 tpl_dbus_service_get_favourite_contacts (TplSvcLogger *logger,
431 DBusGMethodInvocation *context)
432 {
433 TplDBusService *self;
434 TplDBusServicePriv *priv;
435 FavouriteContactClosure *closure;
436
437 g_return_if_fail (TPL_IS_DBUS_SERVICE (logger));
438 g_return_if_fail (context != NULL);
439
440 self = TPL_DBUS_SERVICE (logger);
441 priv = self->priv;
442
443 closure = favourite_contact_closure_new (self, NULL, NULL, context);
444
445 /* If we're still waiting on the contacts to finish being parsed from disk,
446 * queue this action */
447 if (priv->favourite_contacts_actions != NULL)
448 {
449 _tpl_action_chain_append (priv->favourite_contacts_actions,
450 pendingproc_get_favourite_contacts, closure);
451 }
452 else
453 pendingproc_get_favourite_contacts (NULL, closure);
454 }
455
456
457 static void
append_favourite_contacts_file_entries(const gchar * account,GHashTable * contacts,GString * string)458 append_favourite_contacts_file_entries (const gchar *account,
459 GHashTable *contacts,
460 GString *string)
461 {
462 GList *l;
463
464 for (l = g_hash_table_get_keys (contacts); l; l = g_list_delete_link (l, l))
465 g_string_append_printf (string, "%s %s\n", account, (const gchar*) l->data);
466 }
467
468
469 static gchar *
favourite_contacts_to_string(TplDBusService * self)470 favourite_contacts_to_string (TplDBusService *self)
471 {
472 TplDBusServicePriv *priv = self->priv;
473 GString *string;
474
475 string = g_string_new ("");
476
477 g_hash_table_foreach (priv->accounts_contacts_map,
478 (GHFunc) append_favourite_contacts_file_entries, string);
479
480 return g_string_free (string, FALSE);
481 }
482
483
484 static void
favourite_contacts_file_replace_contents_cb(GObject * object,GAsyncResult * result,gpointer user_data)485 favourite_contacts_file_replace_contents_cb (GObject *object,
486 GAsyncResult *result,
487 gpointer user_data)
488 {
489 GFile *file = G_FILE (object);
490 GError *error = NULL;
491 FavouriteContactClosure *closure = user_data;
492 gboolean success;
493
494 if (g_file_replace_contents_finish (file, result, NULL, &error))
495 {
496 success = TRUE;
497 }
498 else
499 {
500 DEBUG ("Failed to save favourite contacts file: %s", error->message);
501 success = FALSE;
502 g_clear_error (&error);
503 }
504
505 ((FavouriteContactCallback) closure->cb) (success, closure);
506 }
507
508
509 static void
favourite_contacts_file_save_async(TplDBusService * self,FavouriteContactClosure * closure)510 favourite_contacts_file_save_async (TplDBusService *self,
511 FavouriteContactClosure *closure)
512 {
513 gchar *dir;
514 const gchar *filename;
515 GFile *file;
516 gchar *file_contents;
517
518 g_return_if_fail (closure != NULL);
519
520 filename = favourite_contacts_get_filename ();
521 dir = g_path_get_dirname (filename);
522 g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
523 g_free (dir);
524
525 file = g_file_new_for_path (filename);
526
527 file_contents = favourite_contacts_to_string (self);
528
529 closure->file_contents = file_contents;
530
531 g_file_replace_contents_async (file,
532 file_contents, strlen (file_contents), NULL, FALSE,
533 G_FILE_CREATE_REPLACE_DESTINATION, NULL,
534 favourite_contacts_file_replace_contents_cb, closure);
535
536 g_object_unref (file);
537 }
538
539
540 static void
add_favourite_contact_file_save_cb(gboolean added_favourite,FavouriteContactClosure * closure)541 add_favourite_contact_file_save_cb (gboolean added_favourite,
542 FavouriteContactClosure *closure)
543 {
544 TplDBusServicePriv *priv = closure->service->priv;
545 TplActionChain *action_chain = priv->favourite_contacts_actions;
546
547 if (added_favourite)
548 {
549 const gchar *added[] = { NULL, NULL };
550 const gchar *removed[] = { NULL };
551
552 added[0] = closure->contact_id;
553
554 tpl_svc_logger_emit_favourite_contacts_changed (closure->service,
555 closure->account, added, removed);
556 }
557
558 tpl_svc_logger_return_from_add_favourite_contact (closure->context);
559
560 favourite_contact_closure_free (closure);
561 if (action_chain != NULL)
562 _tpl_action_chain_continue (action_chain);
563 }
564
565
566 static void
pendingproc_add_favourite_contact(TplActionChain * action_chain,gpointer user_data)567 pendingproc_add_favourite_contact (TplActionChain *action_chain,
568 gpointer user_data)
569 {
570 FavouriteContactClosure *closure = user_data;
571 gboolean should_add = FALSE;
572 GError *error = NULL;
573
574 g_return_if_fail (closure);
575 g_return_if_fail (TPL_IS_DBUS_SERVICE (closure->service));
576 g_return_if_fail (closure->context != NULL);
577
578 if (!tp_dbus_check_valid_object_path (closure->account, &error))
579 {
580 dbus_g_method_return_error (closure->context, error);
581
582 goto pendingproc_add_favourite_contact_ERROR;
583 }
584
585 should_add = favourite_contacts_add_event (closure->service, closure->account,
586 closure->contact_id);
587
588 closure->cb = add_favourite_contact_file_save_cb;
589
590 if (should_add)
591 favourite_contacts_file_save_async (closure->service, closure);
592 else
593 add_favourite_contact_file_save_cb (FALSE, closure);
594
595 return;
596
597 pendingproc_add_favourite_contact_ERROR:
598 if (action_chain != NULL)
599 _tpl_action_chain_terminate (action_chain, error);
600
601 g_clear_error (&error);
602 }
603
604
605 static void
tpl_dbus_service_add_favourite_contact(TplSvcLogger * logger,const gchar * account,const gchar * contact_id,DBusGMethodInvocation * context)606 tpl_dbus_service_add_favourite_contact (TplSvcLogger *logger,
607 const gchar *account,
608 const gchar *contact_id,
609 DBusGMethodInvocation *context)
610 {
611 TplDBusService *self = TPL_DBUS_SERVICE (logger);
612 TplDBusServicePriv *priv;
613 FavouriteContactClosure *closure;
614
615 g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
616 g_return_if_fail (context != NULL);
617
618 priv = self->priv;
619
620 closure = favourite_contact_closure_new (self, account, contact_id, context);
621
622 /* If we're still waiting on the contacts to finish being parsed from disk,
623 * queue this action */
624 if (priv->favourite_contacts_actions != NULL)
625 {
626 _tpl_action_chain_append (priv->favourite_contacts_actions,
627 pendingproc_add_favourite_contact, closure);
628 }
629 else
630 pendingproc_add_favourite_contact (NULL, closure);
631 }
632
633 static void
remove_favourite_contact_file_save_cb(gboolean removed_favourite,FavouriteContactClosure * closure)634 remove_favourite_contact_file_save_cb (gboolean removed_favourite,
635 FavouriteContactClosure *closure)
636 {
637 TplDBusServicePriv *priv = closure->service->priv;
638 TplActionChain *action_chain = priv->favourite_contacts_actions;
639
640 if (removed_favourite)
641 {
642 const gchar *added[] = { NULL };
643 const gchar *removed[] = { NULL, NULL };
644
645 removed[0] = closure->contact_id;
646
647 tpl_svc_logger_emit_favourite_contacts_changed (closure->service,
648 closure->account, added, removed);
649 }
650
651 tpl_svc_logger_return_from_remove_favourite_contact (closure->context);
652
653 favourite_contact_closure_free (closure);
654 if (action_chain != NULL)
655 _tpl_action_chain_continue (action_chain);
656 }
657
658
659 static void
pendingproc_remove_favourite_contact(TplActionChain * action_chain,gpointer user_data)660 pendingproc_remove_favourite_contact (TplActionChain *action_chain,
661 gpointer user_data)
662 {
663 FavouriteContactClosure *closure = user_data;
664 GHashTable *contacts;
665 gboolean removed = FALSE;
666 GError *error = NULL;
667
668 g_return_if_fail (closure != NULL);
669 g_return_if_fail (TPL_IS_DBUS_SERVICE (closure->service));
670 g_return_if_fail (closure->context != NULL);
671
672 TplDBusServicePriv *priv = closure->service->priv;
673
674 if (!tp_dbus_check_valid_object_path (closure->account, &error))
675 {
676 dbus_g_method_return_error (closure->context, error);
677
678 goto pendingproc_remove_favourite_contact_ERROR;
679 }
680
681 DEBUG ("removing favourite contact: account '%s', ID '%s'",
682 closure->account, closure->contact_id);
683
684 contacts = g_hash_table_lookup (priv->accounts_contacts_map,
685 closure->account);
686 if (contacts != NULL && g_hash_table_remove (contacts, closure->contact_id))
687 removed = TRUE;
688
689 closure->cb = remove_favourite_contact_file_save_cb;
690
691 if (removed)
692 favourite_contacts_file_save_async (closure->service, closure);
693 else
694 remove_favourite_contact_file_save_cb (FALSE, closure);
695
696 return;
697
698 pendingproc_remove_favourite_contact_ERROR:
699 if (action_chain != NULL)
700 _tpl_action_chain_terminate (action_chain, error);
701
702 g_clear_error (&error);
703 }
704
705 static void
tpl_dbus_service_remove_favourite_contact(TplSvcLogger * logger,const gchar * account,const gchar * contact_id,DBusGMethodInvocation * context)706 tpl_dbus_service_remove_favourite_contact (TplSvcLogger *logger,
707 const gchar *account,
708 const gchar *contact_id,
709 DBusGMethodInvocation *context)
710 {
711 TplDBusService *self = TPL_DBUS_SERVICE (logger);
712 TplDBusServicePriv *priv;
713 FavouriteContactClosure *closure;
714
715 g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
716 g_return_if_fail (context != NULL);
717
718 priv = self->priv;
719
720 closure = favourite_contact_closure_new (self, account, contact_id, context);
721
722 /* If we're still waiting on the contacts to finish being parsed from disk,
723 * queue this action */
724 if (priv->favourite_contacts_actions != NULL)
725 {
726 _tpl_action_chain_append (priv->favourite_contacts_actions,
727 pendingproc_remove_favourite_contact, closure);
728 }
729 else
730 pendingproc_remove_favourite_contact (NULL, closure);
731 }
732
733
734 static void
tpl_dbus_service_clear(TplSvcLogger * logger,DBusGMethodInvocation * context)735 tpl_dbus_service_clear (TplSvcLogger *logger,
736 DBusGMethodInvocation *context)
737 {
738 TplDBusService *self = TPL_DBUS_SERVICE (logger);
739
740 g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
741 g_return_if_fail (context != NULL);
742
743 /* We want to clear synchronously to avoid concurent write */
744 _tpl_log_manager_clear (self->priv->manager);
745
746 tpl_svc_logger_return_from_clear (context);
747 }
748
749
750 static void
tpl_dbus_service_clear_account(TplSvcLogger * logger,const gchar * account_path,DBusGMethodInvocation * context)751 tpl_dbus_service_clear_account (TplSvcLogger *logger,
752 const gchar *account_path,
753 DBusGMethodInvocation *context)
754 {
755 TplDBusService *self = TPL_DBUS_SERVICE (logger);
756 TpDBusDaemon *bus;
757 TpAccount *account;
758 GError *error = NULL;
759
760 g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
761 g_return_if_fail (context != NULL);
762
763 bus = tp_dbus_daemon_dup (&error);
764 if (bus == NULL)
765 {
766 DEBUG ("Unable to acquire the bus daemon: %s", error->message);
767 dbus_g_method_return_error (context, error);
768 goto out;
769 }
770
771 account = tp_account_new (bus, account_path, &error);
772 if (account == NULL)
773 {
774 DEBUG ("Unable to acquire the account for %s: %s", account_path,
775 error->message);
776 dbus_g_method_return_error (context, error);
777 goto out;
778 }
779
780 /* We want to clear synchronously to avoid concurent write */
781 _tpl_log_manager_clear_account (self->priv->manager, account);
782 g_object_unref (account);
783
784 tpl_svc_logger_return_from_clear_account (context);
785
786 out:
787 if (bus != NULL)
788 g_object_unref (bus);
789
790 g_clear_error (&error);
791 }
792
793
794 static void
tpl_dbus_service_clear_entity(TplSvcLogger * logger,const gchar * account_path,const gchar * identifier,gint type,DBusGMethodInvocation * context)795 tpl_dbus_service_clear_entity (TplSvcLogger *logger,
796 const gchar *account_path,
797 const gchar *identifier,
798 gint type,
799 DBusGMethodInvocation *context)
800 {
801 TplDBusService *self = TPL_DBUS_SERVICE (logger);
802 TpDBusDaemon *bus;
803 TpAccount *account;
804 TplEntity *entity;
805 GError *error = NULL;
806
807 g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
808 g_return_if_fail (context != NULL);
809 g_return_if_fail (!TPL_STR_EMPTY (identifier));
810
811 bus = tp_dbus_daemon_dup (&error);
812 if (bus == NULL)
813 {
814 DEBUG ("Unable to acquire the bus daemon: %s", error->message);
815 dbus_g_method_return_error (context, error);
816 goto out;
817 }
818
819 account = tp_account_new (bus, account_path, &error);
820 if (account == NULL)
821 {
822 DEBUG ("Unable to acquire the account for %s: %s", account_path,
823 error->message);
824 dbus_g_method_return_error (context, error);
825 goto out;
826 }
827
828 entity = tpl_entity_new (identifier, type, NULL, NULL);
829
830 /* We want to clear synchronously to avoid concurent write */
831 _tpl_log_manager_clear_entity (self->priv->manager, account, entity);
832
833 g_object_unref (account);
834 g_object_unref (entity);
835
836 tpl_svc_logger_return_from_clear_account (context);
837
838 out:
839 if (bus != NULL)
840 g_object_unref (bus);
841
842 g_clear_error (&error);
843 }
844
845 static void
tpl_logger_iface_init(gpointer iface,gpointer iface_data)846 tpl_logger_iface_init (gpointer iface,
847 gpointer iface_data)
848 {
849 TplSvcLoggerClass *klass = (TplSvcLoggerClass *) iface;
850
851 #define IMPLEMENT(x) tpl_svc_logger_implement_##x (klass, tpl_dbus_service_##x)
852 IMPLEMENT (get_favourite_contacts);
853 IMPLEMENT (add_favourite_contact);
854 IMPLEMENT (remove_favourite_contact);
855 IMPLEMENT (clear);
856 IMPLEMENT (clear_account);
857 IMPLEMENT (clear_entity);
858 #undef IMPLEMENT
859 }
860