]> git.0d.be Git - empathy.git/blob - goa-mc-plugin/mcp-account-manager-goa.c
870f525d468640965ee12346effc24604c9300b8
[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 if (!tp_strdiff (type, "facebook"))
150     {
151       PARAM ("manager", "gabble");
152       PARAM ("protocol", "jabber");
153       PARAM ("Icon", "im-facebook");
154       PARAM ("Service", "facebook");
155
156       PARAM ("param-account", "chat.facebook.com");
157       PARAM ("param-server", "chat.facebook.com");
158       PARAM ("param-require-encryption", "true");
159       PARAM ("param-fallback-servers",
160           "chat.facebook.com:443");
161     }
162   else if (!tp_strdiff (type, "windows_live"))
163     {
164       PARAM ("manager", "gabble");
165       PARAM ("protocol", "jabber");
166       PARAM ("Icon", "im-msn");
167       PARAM ("Service", "windows-live");
168
169       PARAM ("param-account", "messenger.live.com");
170       PARAM ("param-require-encryption", "true");
171       PARAM ("param-fallback-servers", "xmpp.messenger.live.com");
172       PARAM ("param-extra-certificate-identities",
173           "*.gateway.messenger.live.com");
174     }
175   else
176     {
177       DEBUG ("Unknown account type %s", type);
178       g_hash_table_unref (params);
179       return NULL;
180     }
181
182   /* generic properties */
183   PARAM ("DisplayName", goa_account_get_presentation_identity (account));
184
185 #undef PARAM
186
187   return params;
188 }
189
190
191 static char *
192 get_tp_account_name (GoaAccount *account)
193 {
194   GHashTable *params = get_tp_parameters (account);
195   const char *type = goa_account_get_provider_type (account);
196   const char *id = goa_account_get_id (account);
197   char *name;
198
199   if (params == NULL)
200     return NULL;
201
202   name = g_strdup_printf ("%s/%s/goa_%s_%s",
203       (char *) g_hash_table_lookup (params, "manager"),
204       (char *) g_hash_table_lookup (params, "protocol"),
205       type, id);
206
207   g_hash_table_unref (params);
208
209   return name;
210 }
211
212 static void
213 object_chat_changed_cb (GoaObject *object,
214     GParamSpec *spec,
215     McpAccountManagerGoa *self)
216 {
217   GoaAccount *account = goa_object_peek_account (object);
218   char *name = get_tp_account_name (account);
219   gboolean enabled;
220
221   if (name == NULL)
222     return;
223
224   enabled = (goa_object_peek_chat (object) != NULL);
225
226   DEBUG ("%s %s", name, enabled ? "enabled" : "disabled");
227
228   if (self->priv->ready)
229     mcp_account_storage_emit_toggled (MCP_ACCOUNT_STORAGE (self),
230         name, enabled);
231 }
232
233 static void
234 _new_account (McpAccountManagerGoa *self,
235     GoaObject *object)
236 {
237   GoaAccount *account = goa_object_peek_account (object);
238   char *account_name = get_tp_account_name (account);
239
240   if (account_name == NULL)
241     return;
242
243   /* @account_name now is owned by the hash table */
244   g_hash_table_insert (self->priv->accounts, account_name,
245       g_object_ref (object));
246
247   if (self->priv->ready)
248     mcp_account_storage_emit_created (MCP_ACCOUNT_STORAGE (self),
249         account_name);
250
251   tp_g_signal_connect_object (object, "notify::chat",
252       G_CALLBACK (object_chat_changed_cb), self, 0);
253 }
254
255
256 DECLARE_GASYNC_CALLBACK (_goa_client_new_cb);
257
258 static void
259 load_store (McpAccountManagerGoa *self)
260 {
261   GError *error = NULL;
262
263   if (!g_key_file_load_from_file (self->priv->store, self->priv->filename,
264         G_KEY_FILE_KEEP_COMMENTS, &error))
265     {
266       gchar *dir;
267
268       DEBUG ("Failed to load keyfile, creating a new one: %s", error->message);
269
270       dir = g_path_get_dirname (self->priv->filename);
271
272       g_mkdir_with_parents (dir, 0700);
273       g_free (dir);
274
275       g_key_file_set_comment (self->priv->store, NULL, NULL, INITIAL_COMMENT,
276           NULL);
277
278       g_error_free (error);
279     }
280 }
281
282 static void
283 mcp_account_manager_goa_init (McpAccountManagerGoa *self)
284 {
285   DEBUG ("GOA MC plugin initialised");
286
287   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
288       MCP_TYPE_ACCOUNT_MANAGER_GOA, McpAccountManagerGoaPrivate);
289
290 #ifdef MCP_API_VERSION_5_18
291   /* the ready callback no longer exists, we may emit signals at any time */
292   self->priv->ready = TRUE;
293 #endif
294
295   self->priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
296       g_free, g_object_unref);
297
298   goa_client_new (NULL, _goa_client_new_cb, self);
299
300   /* key file store */
301   self->priv->store = g_key_file_new ();
302   self->priv->filename = g_build_filename (g_get_user_data_dir (), "telepathy",
303       "mission-control", "accounts-goa.cfg", NULL);
304
305   load_store (self);
306 }
307
308
309 static void
310 _account_added_cb (GoaClient *client,
311     GoaObject *object,
312     McpAccountManagerGoa *self)
313 {
314   _new_account (self, object);
315 }
316
317
318 static void
319 _account_removed_cb (GoaClient *client,
320     GoaObject *object,
321     McpAccountManagerGoa *self)
322 {
323   GoaAccount *account = goa_object_peek_account (object);
324   char *name = get_tp_account_name (account);
325
326   if (name == NULL)
327     return;
328
329   if (self->priv->ready)
330     mcp_account_storage_emit_deleted (MCP_ACCOUNT_STORAGE (self), name);
331
332   g_hash_table_remove (self->priv->accounts, name);
333
334   g_free (name);
335 }
336
337 static void
338 _goa_client_new_cb (GObject *obj,
339     GAsyncResult *result,
340     gpointer user_data)
341 {
342   McpAccountManagerGoa *self = user_data;
343   GList *accounts, *ptr;
344   GError *error = NULL;
345
346   self->priv->client = goa_client_new_finish (result, &error);
347
348   if (error != NULL)
349     {
350       DEBUG ("Failed to connect to GOA");
351       return;
352     }
353
354   accounts = goa_client_get_accounts (self->priv->client);
355
356   for (ptr = accounts; ptr != NULL; ptr = ptr->next)
357     {
358       _new_account (self, ptr->data);
359     }
360
361   g_list_free_full (accounts, g_object_unref);
362
363   g_signal_connect (self->priv->client, "account-added",
364       G_CALLBACK (_account_added_cb), self);
365   g_signal_connect (self->priv->client, "account-removed",
366       G_CALLBACK (_account_removed_cb), self);
367 }
368
369
370 static GList *
371 mcp_account_manager_goa_list (WAS_CONST McpAccountStorage *self,
372     WAS_CONST McpAccountManager *am)
373 {
374   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
375   GList *accounts = NULL;
376   GHashTableIter iter;
377   gpointer key;
378
379   DEBUG (G_STRFUNC);
380
381   g_hash_table_iter_init (&iter, priv->accounts);
382   while (g_hash_table_iter_next (&iter, &key, NULL))
383     accounts = g_list_prepend (accounts, g_strdup (key));
384
385   return accounts;
386 }
387
388
389 #ifdef MCP_API_VERSION_5_18
390
391 static GVariant *
392 get_item (McpAccountManagerGoa *self,
393     McpAccountManager *am,
394     const gchar *acc,
395     const gchar *key,
396     const GVariantType *type)
397 {
398   GoaObject *object;
399   GoaAccount *account;
400   GHashTable *bits;
401   gchar *esc;
402   GVariant *ret = NULL;
403
404   DEBUG ("%s: %s, %s", G_STRFUNC, acc, key);
405
406   object = g_hash_table_lookup (self->priv->accounts, acc);
407
408   g_return_val_if_fail (object != NULL, NULL);
409
410   account = goa_object_peek_account (object);
411
412   g_return_val_if_fail (account != NULL, NULL);
413
414   if (!tp_strdiff (key, "Enabled"))
415     {
416       return g_variant_ref_sink (g_variant_new_boolean (
417             !goa_account_get_chat_disabled (account)));
418     }
419
420   bits = get_tp_parameters (account);
421
422   esc = g_hash_table_lookup (bits, key);
423
424   if (esc == NULL)
425     esc = g_key_file_get_value (self->priv->store, acc, key, NULL);
426   else
427     esc = g_strdup (esc);
428
429   if (esc != NULL)
430     {
431       ret = mcp_account_manager_unescape_variant_from_keyfile (am,
432           esc, type, NULL);
433
434       g_free (esc);
435     }
436
437   g_hash_table_unref (bits);
438   return ret;
439 }
440
441 static GVariant *
442 mcp_account_manager_goa_get_attribute (McpAccountStorage *self,
443     McpAccountManager *am,
444     const gchar *acc,
445     const gchar *attribute,
446     const GVariantType *type,
447     McpAttributeFlags *flags)
448 {
449   return get_item (MCP_ACCOUNT_MANAGER_GOA (self), am, acc, attribute, type);
450 }
451
452 static GVariant *
453 mcp_account_manager_goa_get_parameter (McpAccountStorage *storage,
454     McpAccountManager *am,
455     const gchar *acc,
456     const gchar *parameter,
457     const GVariantType *type,
458     McpParameterFlags *flags)
459 {
460   gchar *key;
461   GVariant *ret;
462
463   key = g_strdup_printf ("param-%s", parameter);
464
465   ret = get_item (MCP_ACCOUNT_MANAGER_GOA (storage), am, acc, key, type);
466   g_free (key);
467   return ret;
468 }
469
470 #else /* MC 5.16 or older */
471
472 static void
473 get_enabled (WAS_CONST McpAccountStorage *self,
474     WAS_CONST McpAccountManager *am,
475     const gchar *acc,
476     GoaAccount *account)
477 {
478   mcp_account_manager_set_value (am, acc, "Enabled",
479       goa_account_get_chat_disabled (account) == FALSE ? "true" : "false");
480 }
481
482 static gboolean
483 mcp_account_manager_goa_get (WAS_CONST McpAccountStorage *self,
484     WAS_CONST McpAccountManager *am,
485     const gchar *acc,
486     const gchar *key)
487 {
488   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
489   GoaObject *object;
490   GoaAccount *account;
491
492   DEBUG ("%s: %s, %s", G_STRFUNC, acc, key);
493
494   object = g_hash_table_lookup (priv->accounts, acc);
495
496   if (object == NULL)
497     return FALSE;
498
499   account = goa_object_peek_account (object);
500
501   if (account == NULL)
502     return FALSE;
503
504   if (key == NULL)
505     {
506       /* load all keys */
507       GHashTable *params = get_tp_parameters (account);
508       GHashTableIter iter;
509       gpointer k, value;
510       GStrv keys;
511       guint i;
512       gsize nkeys = 0;
513
514       /* Properties from GOA */
515       g_hash_table_iter_init (&iter, params);
516       while (g_hash_table_iter_next (&iter, &k, &value))
517         mcp_account_manager_set_value (am, acc, k, value);
518
519       g_hash_table_unref (params);
520
521       /* Stored properties */
522       keys = g_key_file_get_keys (priv->store, acc, &nkeys, NULL);
523
524       for (i = 0; i < nkeys; i++)
525         {
526           gchar *v = g_key_file_get_value (priv->store, acc, keys[i], NULL);
527
528           if (v != NULL)
529             {
530               mcp_account_manager_set_value (am, acc, keys[i], v);
531               g_free (v);
532             }
533         }
534
535       g_strfreev (keys);
536
537       /* Enabled */
538       get_enabled (self, am, acc, account);
539     }
540   else if (!tp_strdiff (key, "Enabled"))
541     {
542       get_enabled (self, am, acc, account);
543     }
544   else
545     {
546       /* get a specific key */
547       GHashTable *params = get_tp_parameters (account);
548       gchar *value;
549
550       value = g_hash_table_lookup (params, key);
551
552       if (value == NULL)
553         value = g_key_file_get_value (priv->store, acc, key, NULL);
554       else
555         value = g_strdup (value);
556
557       mcp_account_manager_set_value (am, acc, key, value);
558
559       g_hash_table_unref (params);
560       g_free (value);
561     }
562
563   return TRUE;
564 }
565
566 #endif /* MC 5.16 or older */
567
568
569 static gboolean
570 account_is_in_goa (WAS_CONST McpAccountStorage *self,
571     const gchar *account)
572 {
573   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
574
575   return (g_hash_table_lookup (priv->accounts, account) != NULL);
576 }
577
578 static McpAccountStorageSetResult
579 mcp_account_manager_goa_set_enabled (McpAccountStorage *self,
580     const gchar *account,
581     gboolean enabled)
582 {
583   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
584   GoaObject *object;
585   GoaAccount *acc;
586
587   object = g_hash_table_lookup (priv->accounts, account);
588
589   if (object == NULL)
590     return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
591
592   acc = goa_object_peek_account (object);
593
594   if (acc == NULL)
595     return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
596
597   if (goa_account_get_chat_disabled (acc) == !enabled)
598     return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
599
600   goa_account_set_chat_disabled (acc, !enabled);
601   return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
602 }
603
604 #ifdef MCP_API_VERSION_5_18
605
606 static McpAccountStorageSetResult
607 mcp_account_manager_goa_set_attribute (McpAccountStorage *storage,
608     McpAccountManager *am,
609     const gchar *account_name,
610     const gchar *attribute,
611     GVariant *value,
612     McpAttributeFlags flags)
613 {
614   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (storage);
615   McpAccountStorageSetResult ret = MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
616
617   g_return_val_if_fail (account_is_in_goa (storage, account_name),
618       MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
619
620   if (!tp_strdiff (attribute, "Enabled"))
621     {
622       g_return_val_if_fail (
623           g_variant_classify (value) == G_VARIANT_CLASS_BOOLEAN,
624           MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
625
626       return mcp_account_manager_goa_set_enabled (storage, account_name,
627             g_variant_get_boolean (value));
628     }
629   /* FIXME: filter out manager, protocol, Icon, Service? */
630   else if (value != NULL)
631     {
632       gchar *esc = mcp_account_manager_escape_variant_for_keyfile (am,
633           value);
634       gchar *old;
635
636       if (esc == NULL)
637         return MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
638
639       old = g_key_file_get_value (priv->store, account_name, attribute, NULL);
640
641       if (tp_strdiff (old, esc))
642         {
643           g_key_file_set_value (priv->store, account_name, attribute, esc);
644           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
645         }
646       else
647         {
648           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
649         }
650
651       g_free (esc);
652       g_free (old);
653     }
654   else
655     {
656       if (g_key_file_has_key (priv->store, account_name, attribute, NULL))
657         {
658           g_key_file_remove_key (priv->store, account_name, attribute, NULL);
659           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
660         }
661       else
662         {
663           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
664         }
665     }
666
667   return ret;
668 }
669
670 static McpAccountStorageSetResult
671 mcp_account_manager_goa_set_parameter (McpAccountStorage *storage,
672     McpAccountManager *am,
673     const gchar *account_name,
674     const gchar *parameter,
675     GVariant *value,
676     McpParameterFlags flags)
677 {
678   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (storage);
679   McpAccountStorageSetResult ret = MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED;
680   gchar *key = NULL;
681   gchar *esc = NULL;
682   gchar *old = NULL;
683
684   g_return_val_if_fail (account_is_in_goa (storage, account_name),
685       MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
686
687   key = g_strdup_printf ("param-%s", parameter);
688
689   /* FIXME: filter out reserved keys for this account? */
690   if (value != NULL)
691     {
692       esc = mcp_account_manager_escape_variant_for_keyfile (am,
693           value);
694
695       if (esc == NULL)
696         goto out;
697
698       old = g_key_file_get_value (priv->store, account_name, key, NULL);
699
700       if (tp_strdiff (esc, old))
701         {
702           g_key_file_set_value (priv->store, account_name, key, esc);
703           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
704         }
705       else
706         {
707           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
708         }
709     }
710   else
711     {
712       if (g_key_file_has_key (priv->store, account_name, key, NULL))
713         {
714           g_key_file_remove_key (priv->store, account_name, key, NULL);
715           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED;
716         }
717       else
718         {
719           ret = MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
720         }
721
722     }
723
724 out:
725   g_free (key);
726   g_free (esc);
727   g_free (old);
728   return ret;
729 }
730
731 #else /* MC 5.16 or older */
732
733 static gboolean
734 mcp_account_manager_goa_set (const McpAccountStorage *self,
735     const McpAccountManager *am,
736     const gchar *account,
737     const gchar *key,
738     const gchar *val)
739 {
740   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
741
742   if (!account_is_in_goa (self, account))
743     return FALSE;
744
745   DEBUG ("%s: (%s, %s, %s)", G_STRFUNC, account, key, val);
746
747   if (!tp_strdiff (key, "Enabled"))
748     {
749       if (mcp_account_manager_goa_set_enabled ((McpAccountStorage *) self,
750           account,
751           !tp_strdiff (val, "true")) != MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED)
752         return TRUE;
753       else
754         return FALSE;
755     }
756
757   if (val != NULL)
758     g_key_file_set_value (priv->store, account, key, val);
759   else
760     g_key_file_remove_key (priv->store, account, key, NULL);
761
762   /* Pretend we save everything so MC won't save this in accounts.cfg */
763   return TRUE;
764 }
765
766 #endif /* MC 5.16 or older */
767
768
769 static gboolean
770 mcp_account_manager_goa_delete (WAS_CONST McpAccountStorage *self,
771     WAS_CONST McpAccountManager *am,
772     const gchar *account,
773     const gchar *key)
774 {
775   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
776
777   if (!account_is_in_goa (self, account))
778     return FALSE;
779
780   DEBUG ("%s: (%s, %s)", G_STRFUNC, account, key);
781
782   if (key == NULL)
783     {
784       g_key_file_remove_group (priv->store, account, NULL);
785     }
786   else
787     {
788       g_key_file_remove_key (priv->store, account, key, NULL);
789     }
790
791   /* Pretend we deleted everything */
792   return TRUE;
793 }
794
795
796 #ifdef MCP_API_VERSION_5_18
797 static void
798 mcp_account_manager_goa_delete_async (McpAccountStorage *self,
799     McpAccountManager *am,
800     const gchar *account_name,
801     GCancellable *cancellable,
802     GAsyncReadyCallback callback,
803     gpointer user_data)
804 {
805   GTask *task = g_task_new (self, cancellable, callback, user_data);
806
807   if (mcp_account_manager_goa_delete (self, am, account_name, NULL))
808     {
809       g_task_return_boolean (task, TRUE);
810     }
811   else
812     {
813       g_task_return_new_error (task, TP_ERROR, TP_ERROR_DOES_NOT_EXIST,
814           "Account does not exist in GOA");
815     }
816
817   g_object_unref (task);
818 }
819
820 static gboolean
821 mcp_account_manager_goa_delete_finish (McpAccountStorage *self,
822     GAsyncResult *res,
823     GError **error)
824 {
825   return g_task_propagate_boolean (G_TASK (res), error);
826 }
827 #endif /* MC >= 5.18 API */
828
829 static gboolean
830 commit (McpAccountManagerGoa *self)
831 {
832   McpAccountManagerGoaPrivate *priv = self->priv;
833   gchar *data;
834   gsize len;
835   GError *error = NULL;
836
837   DEBUG ("Save config to %s", priv->filename);
838
839   data = g_key_file_to_data (priv->store, &len, &error);
840   if (data == NULL)
841     {
842       DEBUG ("Failed to get data from store: %s", error->message);
843
844       g_error_free (error);
845       return FALSE;
846     }
847
848   if (!g_file_set_contents (priv->filename, data, len, &error))
849     {
850       DEBUG ("Failed to write file: %s", error->message);
851
852       g_free (data);
853       g_error_free (error);
854       return FALSE;
855     }
856
857   g_free (data);
858
859   return TRUE;
860 }
861
862 #ifdef MCP_API_VERSION_5_18
863 static gboolean
864 mcp_account_manager_goa_commit (McpAccountStorage *self,
865   McpAccountManager *am,
866   const gchar *account)
867 {
868   return commit (MCP_ACCOUNT_MANAGER_GOA (self));
869 }
870 #else
871 static gboolean
872 mcp_account_manager_goa_commit (const McpAccountStorage *self,
873   const McpAccountManager *am)
874 {
875   return commit (MCP_ACCOUNT_MANAGER_GOA (self));
876 }
877 #endif
878
879
880 #ifndef MCP_API_VERSION_5_18
881 /* removed in 5.18, MC should now be ready to receive signals at any time */
882 static void
883 mcp_account_manager_goa_ready (WAS_CONST McpAccountStorage *self,
884     WAS_CONST McpAccountManager *am)
885 {
886   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
887
888   priv->ready = TRUE;
889 }
890 #endif
891
892
893 static RESTRICTIONS
894 mcp_account_manager_goa_get_restrictions (WAS_CONST McpAccountStorage *self,
895     const gchar *account)
896 {
897   return TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PARAMETERS |
898          TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_SERVICE;
899 }
900
901
902 static void
903 mcp_account_manager_goa_get_identifier (WAS_CONST McpAccountStorage *self,
904     const gchar *acc,
905     GValue *identifier)
906 {
907   McpAccountManagerGoaPrivate *priv = GET_PRIVATE (self);
908   GoaObject *object;
909   GoaAccount *account;
910
911   object = g_hash_table_lookup (priv->accounts, acc);
912   g_return_if_fail (object != NULL);
913
914   account = goa_object_peek_account (object);
915   g_return_if_fail (account != NULL);
916
917   g_value_init (identifier, G_TYPE_STRING);
918   g_value_set_string (identifier, goa_account_get_id (account));
919 }
920
921
922 static void
923 account_storage_iface_init (McpAccountStorageIface *iface)
924 {
925   iface->name = PLUGIN_NAME;
926   iface->desc = PLUGIN_DESCRIPTION;
927   iface->priority = PLUGIN_PRIORITY;
928   iface->provider = PLUGIN_PROVIDER;
929
930 #define IMPLEMENT(x) iface->x = mcp_account_manager_goa_##x
931
932   IMPLEMENT (list);
933   IMPLEMENT (commit);
934   IMPLEMENT (get_restrictions);
935   IMPLEMENT (get_identifier);
936
937 #ifdef MCP_API_VERSION_5_18
938   IMPLEMENT (delete_async);
939   IMPLEMENT (delete_finish);
940   IMPLEMENT (get_attribute);
941   IMPLEMENT (get_parameter);
942   IMPLEMENT (set_attribute);
943   IMPLEMENT (set_parameter);
944 #else
945   IMPLEMENT (get);
946   IMPLEMENT (set);
947   IMPLEMENT (delete);
948   IMPLEMENT (ready);
949 #endif
950
951 #undef IMPLEMENT
952 }