goa-mc-plugin: Remove Facebook chat using Jabber
[empathy.git] / goa-mc-plugin / mcp-account-manager-goa.c
1 /*
2  * mcp-account-manager-goa.c
3  *
4  * McpAccountManagerGoa - a Mission Control plugin to expose GNOME Online
5  * Accounts with chat capabilities (e.g. Facebook) to Mission Control
6  *
7  * Copyright (C) 2010-2014 Collabora Ltd.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21  *
22  * Authors:
23  *    Danielle Madeley <danielle.madeley@collabora.co.uk>
24  */
25
26 #include "config.h"
27 #include "mcp-account-manager-goa.h"
28
29 #define GOA_API_IS_SUBJECT_TO_CHANGE /* awesome! */
30 #include <goa/goa.h>
31
32 #define DEBUG g_debug
33 #define GET_PRIVATE(self) (((McpAccountManagerGoa *) self)->priv)
34 #define DECLARE_GASYNC_CALLBACK(name) \
35   static void name (GObject *, GAsyncResult *, gpointer);
36
37 #define PLUGIN_NAME "goa"
38 #define PLUGIN_DESCRIPTION "Provide Telepathy Accounts from GOA"
39 #define PLUGIN_PROVIDER EMPATHY_GOA_PROVIDER
40
41 #define INITIAL_COMMENT "Parameters of GOA Telepathy accounts"
42
43 #ifdef MCP_API_VERSION_5_18
44
45 # define RESTRICTIONS TpStorageRestrictionFlags
46 # define WAS_CONST /* nothing */
47   /* Its historical value was based on the KEYRING priority which no longer
48    * exists. Using a large number is OK, because it uses unusual account names
49    * which are unlikely to collide. */
50 # define PLUGIN_PRIORITY (10010)
51   /* McpAccountStorageSetResult enum is defined by MC */
52
53 #else /* MC 5.16 or older */
54
55 # define RESTRICTIONS guint
56 # define WAS_CONST const
57 # define PLUGIN_PRIORITY (MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_KEYRING + 10)
58
59   /* we use this in helper functions */
60   typedef enum {
61       MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED,
62       MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED,
63       MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED
64   } McpAccountStorageSetResult;
65
66 #endif /* MC 5.16 or older */
67
68 static void account_storage_iface_init (McpAccountStorageIface *iface);
69
70 G_DEFINE_TYPE_WITH_CODE (McpAccountManagerGoa,
71     mcp_account_manager_goa,
72     G_TYPE_OBJECT,
73     G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_STORAGE,
74       account_storage_iface_init))
75
76 struct _McpAccountManagerGoaPrivate
77 {
78   gboolean ready;
79
80   GoaClient *client;
81   GHashTable *accounts; /* alloc'ed string -> ref'ed GoaObject */
82
83   GKeyFile *store;
84   gchar *filename;
85 };
86
87
88 static void
89 mcp_account_manager_goa_dispose (GObject *self)
90 {
91   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
92
93   tp_clear_object (&priv->client);
94
95   G_OBJECT_CLASS (mcp_account_manager_goa_parent_class)->dispose (self);
96 }
97
98
99 static void
100 mcp_account_manager_goa_finalize (GObject *self)
101 {
102   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
103
104   g_hash_table_unref (priv->accounts);
105   g_key_file_free (priv->store);
106   g_free (priv->filename);
107
108   G_OBJECT_CLASS (mcp_account_manager_goa_parent_class)->finalize (self);
109 }
110
111
112 static void
113 mcp_account_manager_goa_class_init (McpAccountManagerGoaClass *klass)
114 {
115   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
116
117   gobject_class->dispose = mcp_account_manager_goa_dispose;
118   gobject_class->finalize = mcp_account_manager_goa_finalize;
119
120   g_type_class_add_private (gobject_class,
121       sizeof (McpAccountManagerGoaPrivate));
122 }
123
124 static GHashTable *
125 get_tp_parameters (GoaAccount *account)
126 {
127   GHashTable *params = g_hash_table_new_full (g_str_hash, g_str_equal,
128       NULL, g_free);
129   const char *type = goa_account_get_provider_type (account);
130
131 #define PARAM(key, value) g_hash_table_insert (params, key, g_strdup (value));
132
133   if (!tp_strdiff (type, "google"))
134     {
135       PARAM ("manager", "gabble");
136       PARAM ("protocol", "jabber");
137       PARAM ("Icon", "im-google-talk");
138       PARAM ("Service", "google-talk");
139
140       PARAM ("param-account", goa_account_get_identity (account));
141       PARAM ("param-server", "talk.google.com");
142       PARAM ("param-fallback-servers",
143           "talkx.l.google.com;"
144           "talkx.l.google.com:443,oldssl;"
145           "talkx.l.google.com:80");
146       PARAM ("param-extra-certificate-identities", "talk.google.com");
147       PARAM ("param-require-encryption", "true");
148     }
149   else
150     {
151       DEBUG ("Unknown account type %s", type);
152       g_hash_table_unref (params);
153       return NULL;
154     }
155
156   /* generic properties */
157   PARAM ("DisplayName", goa_account_get_presentation_identity (account));
158
159 #undef PARAM
160
161   return params;
162 }
163
164
165 static char *
166 get_tp_account_name (GoaAccount *account)
167 {
168   GHashTable *params = get_tp_parameters (account);
169   const char *type = goa_account_get_provider_type (account);
170   const char *id = goa_account_get_id (account);
171   char *name;
172
173   if (params == NULL)
174     return NULL;
175
176   name = g_strdup_printf ("%s/%s/goa_%s_%s",
177       (char *) g_hash_table_lookup (params, "manager"),
178       (char *) g_hash_table_lookup (params, "protocol"),
179       type, id);
180
181   g_hash_table_unref (params);
182
183   return name;
184 }
185
186 static void
187 object_chat_changed_cb (GoaObject *object,
188     GParamSpec *spec,
189     McpAccountManagerGoa *self)
190 {
191   GoaAccount *account = goa_object_peek_account (object);
192   char *name = get_tp_account_name (account);
193   gboolean enabled;
194
195   if (name == NULL)
196     return;
197
198   enabled = (goa_object_peek_chat (object) != NULL);
199
200   DEBUG ("%s %s", name, enabled ? "enabled" : "disabled");
201
202   if (self->priv->ready)
203     mcp_account_storage_emit_toggled (MCP_ACCOUNT_STORAGE (self),
204         name, enabled);
205 }
206
207 static void
208 _new_account (McpAccountManagerGoa *self,
209     GoaObject *object)
210 {
211   GoaAccount *account = goa_object_peek_account (object);
212   char *account_name = get_tp_account_name (account);
213
214   if (account_name == NULL)
215     return;
216
217   /* @account_name now is owned by the hash table */
218   g_hash_table_insert (self->priv->accounts, account_name,
219       g_object_ref (object));
220
221   if (self->priv->ready)
222     mcp_account_storage_emit_created (MCP_ACCOUNT_STORAGE (self),
223         account_name);
224
225   tp_g_signal_connect_object (object, "notify::chat",
226       G_CALLBACK (object_chat_changed_cb), self, 0);
227 }
228
229
230 DECLARE_GASYNC_CALLBACK (_goa_client_new_cb);
231
232 static void
233 load_store (McpAccountManagerGoa *self)
234 {
235   GError *error = NULL;
236
237   if (!g_key_file_load_from_file (self->priv->store, self->priv->filename,
238         G_KEY_FILE_KEEP_COMMENTS, &error))
239     {
240       gchar *dir;
241
242       DEBUG ("Failed to load keyfile, creating a new one: %s", error->message);
243
244       dir = g_path_get_dirname (self->priv->filename);
245
246       g_mkdir_with_parents (dir, 0700);
247       g_free (dir);
248
249       g_key_file_set_comment (self->priv->store, NULL, NULL, INITIAL_COMMENT,
250           NULL);
251
252       g_error_free (error);
253     }
254 }
255
256 static void
257 mcp_account_manager_goa_init (McpAccountManagerGoa *self)
258 {
259   DEBUG ("GOA MC plugin initialised");
260
261   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
262       MCP_TYPE_ACCOUNT_MANAGER_GOA, McpAccountManagerGoaPrivate);
263
264 #ifdef MCP_API_VERSION_5_18
265   /* the ready callback no longer exists, we may emit signals at any time */
266   self->priv->ready = TRUE;
267 #endif
268
269   self->priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
270       g_free, g_object_unref);
271
272   goa_client_new (NULL, _goa_client_new_cb, self);
273
274   /* key file store */
275   self->priv->store = g_key_file_new ();
276   self->priv->filename = g_build_filename (g_get_user_data_dir (), "telepathy",
277       "mission-control", "accounts-goa.cfg", NULL);
278
279   load_store (self);
280 }
281
282
283 static void
284 _account_added_cb (GoaClient *client,
285     GoaObject *object,
286     McpAccountManagerGoa *self)
287 {
288   _new_account (self, object);
289 }
290
291
292 static void
293 _account_removed_cb (GoaClient *client,
294     GoaObject *object,
295     McpAccountManagerGoa *self)
296 {
297   GoaAccount *account = goa_object_peek_account (object);
298   char *name = get_tp_account_name (account);
299
300   if (name == NULL)
301     return;
302
303   if (self->priv->ready)
304     mcp_account_storage_emit_deleted (MCP_ACCOUNT_STORAGE (self), name);
305
306   g_hash_table_remove (self->priv->accounts, name);
307
308   g_free (name);
309 }
310
311 static void
312 _goa_client_new_cb (GObject *obj,
313     GAsyncResult *result,
314     gpointer user_data)
315 {
316   McpAccountManagerGoa *self = user_data;
317   GList *accounts, *ptr;
318   GError *error = NULL;
319
320   self->priv->client = goa_client_new_finish (result, &error);
321
322   if (error != NULL)
323     {
324       DEBUG ("Failed to connect to GOA");
325       return;
326     }
327
328   accounts = goa_client_get_accounts (self->priv->client);
329
330   for (ptr = accounts; ptr != NULL; ptr = ptr->next)
331     {
332       _new_account (self, ptr->data);
333     }
334
335   g_list_free_full (accounts, g_object_unref);
336
337   g_signal_connect (self->priv->client, "account-added",
338       G_CALLBACK (_account_added_cb), self);
339   g_signal_connect (self->priv->client, "account-removed",
340       G_CALLBACK (_account_removed_cb), self);
341 }
342
343
344 static GList *
345 mcp_account_manager_goa_list (WAS_CONST McpAccountStorage *self,
346     WAS_CONST McpAccountManager *am)
347 {
348   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
349   GList *accounts = NULL;
350   GHashTableIter iter;
351   gpointer key;
352
353   DEBUG (G_STRFUNC);
354
355   g_hash_table_iter_init (&iter, priv->accounts);
356   while (g_hash_table_iter_next (&iter, &key, NULL))
357     accounts = g_list_prepend (accounts, g_strdup (key));
358
359   return accounts;
360 }
361
362
363 #ifdef MCP_API_VERSION_5_18
364
365 static GVariant *
366 get_item (McpAccountManagerGoa *self,
367     McpAccountManager *am,
368     const gchar *acc,
369     const gchar *key,
370     const GVariantType *type)
371 {
372   GoaObject *object;
373   GoaAccount *account;
374   GHashTable *bits;
375   gchar *esc;
376   GVariant *ret = NULL;
377
378   DEBUG ("%s: %s, %s", G_STRFUNC, acc, key);
379
380   object = g_hash_table_lookup (self->priv->accounts, acc);
381
382   g_return_val_if_fail (object != NULL, NULL);
383
384   account = goa_object_peek_account (object);
385
386   g_return_val_if_fail (account != NULL, NULL);
387
388   if (!tp_strdiff (key, "Enabled"))
389     {
390       return g_variant_ref_sink (g_variant_new_boolean (
391             !goa_account_get_chat_disabled (account)));
392     }
393
394   bits = get_tp_parameters (account);
395
396   esc = g_hash_table_lookup (bits, key);
397
398   if (esc == NULL)
399     esc = g_key_file_get_value (self->priv->store, acc, key, NULL);
400   else
401     esc = g_strdup (esc);
402
403   if (esc != NULL)
404     {
405       ret = mcp_account_manager_unescape_variant_from_keyfile (am,
406           esc, type, NULL);
407
408       g_free (esc);
409     }
410
411   g_hash_table_unref (bits);
412   return ret;
413 }
414
415 static GVariant *
416 mcp_account_manager_goa_get_attribute (McpAccountStorage *self,
417     McpAccountManager *am,
418     const gchar *acc,
419     const gchar *attribute,
420     const GVariantType *type,
421     McpAttributeFlags *flags)
422 {
423   return get_item (MCP_ACCOUNT_MANAGER_GOA (self), am, acc, attribute, type);
424 }
425
426 static GVariant *
427 mcp_account_manager_goa_get_parameter (McpAccountStorage *storage,
428     McpAccountManager *am,
429     const gchar *acc,
430     const gchar *parameter,
431     const GVariantType *type,
432     McpParameterFlags *flags)
433 {
434   gchar *key;
435   GVariant *ret;
436
437   key = g_strdup_printf ("param-%s", parameter);
438
439   ret = get_item (MCP_ACCOUNT_MANAGER_GOA (storage), am, acc, key, type);
440   g_free (key);
441   return ret;
442 }
443
444 #else /* MC 5.16 or older */
445
446 static void
447 get_enabled (WAS_CONST McpAccountStorage *self,
448     WAS_CONST McpAccountManager *am,
449     const gchar *acc,
450     GoaAccount *account)
451 {
452   mcp_account_manager_set_value (am, acc, "Enabled",
453       goa_account_get_chat_disabled (account) == FALSE ? "true" : "false");
454 }
455
456 static gboolean
457 mcp_account_manager_goa_get (WAS_CONST McpAccountStorage *self,
458     WAS_CONST McpAccountManager *am,
459     const gchar *acc,
460     const gchar *key)
461 {
462   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
463   GoaObject *object;
464   GoaAccount *account;
465
466   DEBUG ("%s: %s, %s", G_STRFUNC, acc, key);
467
468   object = g_hash_table_lookup (priv->accounts, acc);
469
470   if (object == NULL)
471     return FALSE;
472
473   account = goa_object_peek_account (object);
474
475   if (account == NULL)
476     return FALSE;
477
478   if (key == NULL)
479     {
480       /* load all keys */
481       GHashTable *params = get_tp_parameters (account);
482       GHashTableIter iter;
483       gpointer k, value;
484       GStrv keys;
485       guint i;
486       gsize nkeys = 0;
487
488       /* Properties from GOA */
489       g_hash_table_iter_init (&iter, params);
490       while (g_hash_table_iter_next (&iter, &k, &value))
491         mcp_account_manager_set_value (am, acc, k, value);
492
493       g_hash_table_unref (params);
494
495       /* Stored properties */
496       keys = g_key_file_get_keys (priv->store, acc, &nkeys, NULL);
497
498       for (i = 0; i < nkeys; i++)
499         {
500           gchar *v = g_key_file_get_value (priv->store, acc, keys[i], NULL);
501
502           if (v != NULL)
503             {
504               mcp_account_manager_set_value (am, acc, keys[i], v);
505               g_free (v);
506             }
507         }
508
509       g_strfreev (keys);
510
511       /* Enabled */
512       get_enabled (self, am, acc, account);
513     }
514   else if (!tp_strdiff (key, "Enabled"))
515     {
516       get_enabled (self, am, acc, account);
517     }
518   else
519     {
520       /* get a specific key */
521       GHashTable *params = get_tp_parameters (account);
522       gchar *value;
523
524       value = g_hash_table_lookup (params, key);
525
526       if (value == NULL)
527         value = g_key_file_get_value (priv->store, acc, key, NULL);
528       else
529         value = g_strdup (value);
530
531       mcp_account_manager_set_value (am, acc, key, value);
532
533       g_hash_table_unref (params);
534       g_free (value);
535     }
536
537   return TRUE;
538 }
539
540 #endif /* MC 5.16 or older */
541
542
543 static gboolean
544 account_is_in_goa (WAS_CONST McpAccountStorage *self,
545     const gchar *account)
546 {
547   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
548
549   return (g_hash_table_lookup (priv->accounts, account) != NULL);
550 }
551
552 static McpAccountStorageSetResult
553 mcp_account_manager_goa_set_enabled (McpAccountStorage *self,
554     const gchar *account,
555     gboolean enabled)
556 {
557   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
558   GoaObject *object;
559   GoaAccount *acc;
560
561   object = g_hash_table_lookup (priv->accounts, account);
562
563   if (object == NULL)
564     return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
565
566   acc = goa_object_peek_account (object);
567
568   if (acc == NULL)
569     return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
570
571   if (goa_account_get_chat_disabled (acc) == !enabled)
572     return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
573
574   goa_account_set_chat_disabled (acc, !enabled);
575   return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
576 }
577
578 #ifdef MCP_API_VERSION_5_18
579
580 static McpAccountStorageSetResult
581 mcp_account_manager_goa_set_attribute (McpAccountStorage *storage,
582     McpAccountManager *am,
583     const gchar *account_name,
584     const gchar *attribute,
585     GVariant *value,
586     McpAttributeFlags flags)
587 {
588   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (storage);
589   McpAccountStorageSetResult ret = MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
590
591   g_return_val_if_fail (account_is_in_goa (storage, account_name),
592       MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
593
594   if (!tp_strdiff (attribute, "Enabled"))
595     {
596       g_return_val_if_fail (
597           g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN,
598           MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
599
600       return mcp_account_manager_goa_set_enabled (storage, account_name,
601             g_variant_get_boolean (value));
602     }
603   /* FIXME: filter out manager, protocol, Icon, Service? */
604   else if (value != NULL)
605     {
606       gchar *esc = mcp_account_manager_escape_variant_for_keyfile (am,
607           value);
608       gchar *old;
609
610       if (esc == NULL)
611         return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
612
613       old = g_key_file_get_value (priv->store, account_name, attribute, NULL);
614
615       if (tp_strdiff (old, esc))
616         {
617           g_key_file_set_value (priv->store, account_name, attribute, esc);
618           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
619         }
620       else
621         {
622           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
623         }
624
625       g_free (esc);
626       g_free (old);
627     }
628   else
629     {
630       if (g_key_file_has_key (priv->store, account_name, attribute, NULL))
631         {
632           g_key_file_remove_key (priv->store, account_name, attribute, NULL);
633           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
634         }
635       else
636         {
637           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
638         }
639     }
640
641   return ret;
642 }
643
644 static McpAccountStorageSetResult
645 mcp_account_manager_goa_set_parameter (McpAccountStorage *storage,
646     McpAccountManager *am,
647     const gchar *account_name,
648     const gchar *parameter,
649     GVariant *value,
650     McpParameterFlags flags)
651 {
652   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (storage);
653   McpAccountStorageSetResult ret = MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
654   gchar *key = NULL;
655   gchar *esc = NULL;
656   gchar *old = NULL;
657
658   g_return_val_if_fail (account_is_in_goa (storage, account_name),
659       MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
660
661   key = g_strdup_printf ("param-%s", parameter);
662
663   /* FIXME: filter out reserved keys for this account? */
664   if (value != NULL)
665     {
666       esc = mcp_account_manager_escape_variant_for_keyfile (am,
667           value);
668
669       if (esc == NULL)
670         goto out;
671
672       old = g_key_file_get_value (priv->store, account_name, key, NULL);
673
674       if (tp_strdiff (esc, old))
675         {
676           g_key_file_set_value (priv->store, account_name, key, esc);
677           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
678         }
679       else
680         {
681           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
682         }
683     }
684   else
685     {
686       if (g_key_file_has_key (priv->store, account_name, key, NULL))
687         {
688           g_key_file_remove_key (priv->store, account_name, key, NULL);
689           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
690         }
691       else
692         {
693           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
694         }
695
696     }
697
698 out:
699   g_free (key);
700   g_free (esc);
701   g_free (old);
702   return ret;
703 }
704
705 #else /* MC 5.16 or older */
706
707 static gboolean
708 mcp_account_manager_goa_set (const McpAccountStorage *self,
709     const McpAccountManager *am,
710     const gchar *account,
711     const gchar *key,
712     const gchar *val)
713 {
714   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
715
716   if (!account_is_in_goa (self, account))
717     return FALSE;
718
719   DEBUG ("%s: (%s, %s, %s)", G_STRFUNC, account, key, val);
720
721   if (!tp_strdiff (key, "Enabled"))
722     {
723       if (mcp_account_manager_goa_set_enabled ((McpAccountStorage *) self,
724           account,
725           !tp_strdiff (val, "true")) != MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED)
726         return TRUE;
727       else
728         return FALSE;
729     }
730
731   if (val != NULL)
732     g_key_file_set_value (priv->store, account, key, val);
733   else
734     g_key_file_remove_key (priv->store, account, key, NULL);
735
736   /* Pretend we save everything so MC won't save this in accounts.cfg */
737   return TRUE;
738 }
739
740 #endif /* MC 5.16 or older */
741
742
743 static gboolean
744 mcp_account_manager_goa_delete (WAS_CONST McpAccountStorage *self,
745     WAS_CONST McpAccountManager *am,
746     const gchar *account,
747     const gchar *key)
748 {
749   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
750
751   if (!account_is_in_goa (self, account))
752     return FALSE;
753
754   DEBUG ("%s: (%s, %s)", G_STRFUNC, account, key);
755
756   if (key == NULL)
757     {
758       g_key_file_remove_group (priv->store, account, NULL);
759     }
760   else
761     {
762       g_key_file_remove_key (priv->store, account, key, NULL);
763     }
764
765   /* Pretend we deleted everything */
766   return TRUE;
767 }
768
769
770 #ifdef MCP_API_VERSION_5_18
771 static void
772 mcp_account_manager_goa_delete_async (McpAccountStorage *self,
773     McpAccountManager *am,
774     const gchar *account_name,
775     GCancellable *cancellable,
776     GAsyncReadyCallback callback,
777     gpointer user_data)
778 {
779   GTask *task = g_task_new (self, cancellable, callback, user_data);
780
781   if (mcp_account_manager_goa_delete (self, am, account_name, NULL))
782     {
783       g_task_return_boolean (task, TRUE);
784     }
785   else
786     {
787       g_task_return_new_error (task, TP_ERROR, TP_ERROR_DOES_NOT_EXIST,
788           "Account does not exist in GOA");
789     }
790
791   g_object_unref (task);
792 }
793
794 static gboolean
795 mcp_account_manager_goa_delete_finish (McpAccountStorage *self,
796     GAsyncResult *res,
797     GError **error)
798 {
799   return g_task_propagate_boolean (G_TASK (res), error);
800 }
801 #endif /* MC >= 5.18 API */
802
803 static gboolean
804 commit (McpAccountManagerGoa *self)
805 {
806   McpAccountManagerGoaPrivate *priv = self->priv;
807   gchar *data;
808   gsize len;
809   GError *error = NULL;
810
811   DEBUG ("Save config to %s", priv->filename);
812
813   data = g_key_file_to_data (priv->store, &len, &error);
814   if (data == NULL)
815     {
816       DEBUG ("Failed to get data from store: %s", error->message);
817
818       g_error_free (error);
819       return FALSE;
820     }
821
822   if (!g_file_set_contents (priv->filename, data, len, &error))
823     {
824       DEBUG ("Failed to write file: %s", error->message);
825
826       g_free (data);
827       g_error_free (error);
828       return FALSE;
829     }
830
831   g_free (data);
832
833   return TRUE;
834 }
835
836 #ifdef MCP_API_VERSION_5_18
837 static gboolean
838 mcp_account_manager_goa_commit (McpAccountStorage *self,
839   McpAccountManager *am,
840   const gchar *account)
841 {
842   return commit (MCP_ACCOUNT_MANAGER_GOA (self));
843 }
844 #else
845 static gboolean
846 mcp_account_manager_goa_commit (const McpAccountStorage *self,
847   const McpAccountManager *am)
848 {
849   return commit (MCP_ACCOUNT_MANAGER_GOA (self));
850 }
851 #endif
852
853
854 #ifndef MCP_API_VERSION_5_18
855 /* removed in 5.18, MC should now be ready to receive signals at any time */
856 static void
857 mcp_account_manager_goa_ready (WAS_CONST McpAccountStorage *self,
858     WAS_CONST McpAccountManager *am)
859 {
860   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
861
862   priv->ready = TRUE;
863 }
864 #endif
865
866
867 static RESTRICTIONS
868 mcp_account_manager_goa_get_restrictions (WAS_CONST McpAccountStorage *self,
869     const gchar *account)
870 {
871   return TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PARAMETERS |
872          TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_SERVICE;
873 }
874
875
876 static void
877 mcp_account_manager_goa_get_identifier (WAS_CONST McpAccountStorage *self,
878     const gchar *acc,
879     GValue *identifier)
880 {
881   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
882   GoaObject *object;
883   GoaAccount *account;
884
885   object = g_hash_table_lookup (priv->accounts, acc);
886   g_return_if_fail (object != NULL);
887
888   account = goa_object_peek_account (object);
889   g_return_if_fail (account != NULL);
890
891   g_value_init (identifier, G_TYPE_STRING);
892   g_value_set_string (identifier, goa_account_get_id (account));
893 }
894
895
896 static void
897 account_storage_iface_init (McpAccountStorageIface *iface)
898 {
899   iface->name = PLUGIN_NAME;
900   iface->desc = PLUGIN_DESCRIPTION;
901   iface->priority = PLUGIN_PRIORITY;
902   iface->provider = PLUGIN_PROVIDER;
903
904 #define IMPLEMENT(x) iface->x = mcp_account_manager_goa_##x
905
906   IMPLEMENT (list);
907   IMPLEMENT (commit);
908   IMPLEMENT (get_restrictions);
909   IMPLEMENT (get_identifier);
910
911 #ifdef MCP_API_VERSION_5_18
912   IMPLEMENT (delete_async);
913   IMPLEMENT (delete_finish);
914   IMPLEMENT (get_attribute);
915   IMPLEMENT (get_parameter);
916   IMPLEMENT (set_attribute);
917   IMPLEMENT (set_parameter);
918 #else
919   IMPLEMENT (get);
920   IMPLEMENT (set);
921   IMPLEMENT (delete);
922   IMPLEMENT (ready);
923 #endif
924
925 #undef IMPLEMENT
926 }