]> git.0d.be Git - empathy.git/blob - ubuntu-online-accounts/mc-plugin/mcp-account-manager-uoa.c
Center the 'smiley images' inside the menu items
[empathy.git] / ubuntu-online-accounts / mc-plugin / mcp-account-manager-uoa.c
1 /*
2  * Copyright © 2012 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
19 #include "config.h"
20 #include "mcp-account-manager-uoa.h"
21
22 #include <telepathy-glib/telepathy-glib.h>
23 #include <libaccounts-glib/ag-account.h>
24 #include <libaccounts-glib/ag-account-service.h>
25 #include <libaccounts-glib/ag-manager.h>
26 #include <libaccounts-glib/ag-service.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #include "empathy-webcredentials-monitor.h"
31
32 #define PLUGIN_NAME "uoa"
33 #define PLUGIN_PRIORITY (MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_KEYRING + 10)
34 #define PLUGIN_DESCRIPTION "Provide Telepathy Accounts from UOA via libaccounts-glib"
35 #define PLUGIN_PROVIDER EMPATHY_UOA_PROVIDER
36
37 #define DEBUG g_debug
38
39 #define SERVICE_TYPE "IM"
40 #define KEY_PREFIX "telepathy/"
41 #define KEY_ACCOUNT_NAME "mc-account-name"
42 #define KEY_READONLY_PARAMS "mc-readonly-params"
43
44 static void account_storage_iface_init (McpAccountStorageIface *iface);
45
46 G_DEFINE_TYPE_WITH_CODE (McpAccountManagerUoa, mcp_account_manager_uoa,
47     G_TYPE_OBJECT,
48     G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_STORAGE,
49         account_storage_iface_init));
50
51 struct _McpAccountManagerUoaPrivate
52 {
53   McpAccountManager *am;
54
55   AgManager *manager;
56   EmpathyWebcredentialsMonitor *monitor;
57
58   /* alloc'ed string -> ref'ed AgAccountService
59    * The key is the account_name, an MC unique identifier.
60    * Note: There could be multiple services in this table having the same
61    * AgAccount, even if unlikely. */
62   GHashTable *accounts;
63
64   /* Queue of owned DelayedSignalData */
65   GQueue *pending_signals;
66
67   gboolean loaded;
68   gboolean ready;
69 };
70
71 typedef enum {
72   DELAYED_CREATE,
73   DELAYED_DELETE,
74 } DelayedSignal;
75
76 typedef struct {
77   DelayedSignal signal;
78   AgAccountId account_id;
79 } DelayedSignalData;
80
81
82 static gchar *
83 _service_dup_tp_value (AgAccountService *service,
84     const gchar *key)
85 {
86   gchar *real_key = g_strdup_printf (KEY_PREFIX "%s", key);
87   GVariant *value;
88
89   value = ag_account_service_get_variant (service, real_key, NULL);
90   g_free (real_key);
91   if (value == NULL)
92     return NULL;
93
94   return g_variant_dup_string (value, NULL);
95 }
96
97 static void
98 _service_set_tp_value (AgAccountService *service,
99     const gchar *key,
100     const gchar *value)
101 {
102   gchar *real_key = g_strdup_printf (KEY_PREFIX "%s", key);
103
104   if (value != NULL)
105     {
106       GVariant *gvariant = g_variant_new_string (value);
107       ag_account_service_set_variant (service, real_key, gvariant);
108     }
109   else
110     {
111       ag_account_service_set_variant (service, real_key, NULL);
112     }
113   g_free (real_key);
114 }
115
116 /* Returns NULL if the account never has been imported into MC before */
117 static gchar *
118 _service_dup_tp_account_name (AgAccountService *service)
119 {
120   return _service_dup_tp_value (service, KEY_ACCOUNT_NAME);
121 }
122
123 static void
124 _service_set_tp_account_name (AgAccountService *service,
125     const gchar *account_name)
126 {
127   _service_set_tp_value (service, KEY_ACCOUNT_NAME, account_name);
128 }
129
130 static void
131 _service_enabled_cb (AgAccountService *service,
132     gboolean enabled,
133     McpAccountManagerUoa *self)
134 {
135   gchar *account_name = _service_dup_tp_account_name (service);
136
137   if (!self->priv->ready || account_name == NULL)
138     return;
139
140   DEBUG ("UOA account %s toggled: %s", account_name,
141       enabled ? "enabled" : "disabled");
142
143   g_signal_emit_by_name (self, "toggled", account_name, enabled);
144
145   g_free (account_name);
146 }
147
148 static void
149 _service_changed_cb (AgAccountService *service,
150     McpAccountManagerUoa *self)
151 {
152   gchar *account_name = _service_dup_tp_account_name (service);
153
154   if (!self->priv->ready || account_name == NULL)
155     return;
156
157   DEBUG ("UOA account %s changed", account_name);
158
159   /* FIXME: Could use ag_account_service_get_changed_fields()
160    * and emit "altered-one" */
161   g_signal_emit_by_name (self, "altered", account_name);
162
163   g_free (account_name);
164 }
165
166 static void
167 _account_stored_cb (GObject *source_object,
168     GAsyncResult *res,
169     gpointer user_data)
170 {
171   AgAccount *account = AG_ACCOUNT(source_object);
172   GError *error = NULL;
173
174   if (!ag_account_store_finish (account, res, &error))
175     {
176       g_assert (error != NULL);
177       DEBUG ("Error storing UOA account '%s': %s",
178           ag_account_get_display_name (account),
179           error->message);
180       g_error_free (error);
181     }
182 }
183
184 static gboolean
185 _add_service (McpAccountManagerUoa *self,
186     AgAccountService *service,
187     const gchar *account_name)
188 {
189   DEBUG ("UOA account %s added", account_name);
190
191   if (g_hash_table_contains (self->priv->accounts, account_name))
192     {
193       DEBUG ("Already exists, ignoring");
194       return FALSE;
195     }
196
197   g_hash_table_insert (self->priv->accounts,
198       g_strdup (account_name),
199       g_object_ref (service));
200
201   g_signal_connect (service, "enabled",
202       G_CALLBACK (_service_enabled_cb), self);
203   g_signal_connect (service, "changed",
204       G_CALLBACK (_service_changed_cb), self);
205
206   return TRUE;
207 }
208
209 static void
210 _account_created_cb (AgManager *manager,
211     AgAccountId id,
212     McpAccountManagerUoa *self)
213 {
214   AgAccount *account;
215   GList *l;
216
217   if (!self->priv->ready)
218     {
219       DelayedSignalData *data = g_slice_new0 (DelayedSignalData);
220
221       data->signal = DELAYED_CREATE;
222       data->account_id = id;
223
224       g_queue_push_tail (self->priv->pending_signals, data);
225       return;
226     }
227
228   account = ag_manager_get_account (self->priv->manager, id);
229
230   l = ag_account_list_services_by_type (account, SERVICE_TYPE);
231   while (l != NULL)
232     {
233       AgAccountService *service = ag_account_service_new (account, l->data);
234       gchar *account_name = _service_dup_tp_account_name (service);
235
236       /* If this is the first time we see this service, we have to generate an
237        * account_name for it. */
238       if (account_name == NULL)
239         {
240           gchar *cm_name = NULL;
241           gchar *protocol_name = NULL;
242           gchar *account_param = NULL;
243
244           cm_name = _service_dup_tp_value (service, "manager");
245           protocol_name = _service_dup_tp_value (service, "protocol");
246           account_param = _service_dup_tp_value (service, "param-account");
247
248           if (!tp_str_empty (cm_name) &&
249               !tp_str_empty (protocol_name) &&
250               !tp_str_empty (account_param))
251             {
252               GHashTable *params;
253
254               params = tp_asv_new (
255                   "account", G_TYPE_STRING, account_param,
256                   NULL);
257
258               account_name = mcp_account_manager_get_unique_name (self->priv->am,
259                   cm_name, protocol_name, params);
260               _service_set_tp_account_name (service, account_name);
261
262               ag_account_store_async (account, NULL, _account_stored_cb, self);
263
264               g_hash_table_unref (params);
265             }
266
267           g_free (cm_name);
268           g_free (protocol_name);
269           g_free (account_param);
270         }
271
272       if (account_name != NULL)
273         {
274           if (_add_service (self, service, account_name))
275             g_signal_emit_by_name (self, "created", account_name);
276         }
277
278       g_free (account_name);
279       g_object_unref (service);
280       ag_service_unref (l->data);
281       l = g_list_delete_link (l, l);
282     }
283
284   g_object_unref (account);
285 }
286
287 static void
288 _account_deleted_cb (AgManager *manager,
289     AgAccountId id,
290     McpAccountManagerUoa *self)
291 {
292   GHashTableIter iter;
293   gpointer value;
294
295   if (!self->priv->ready)
296     {
297       DelayedSignalData *data = g_slice_new0 (DelayedSignalData);
298
299       data->signal = DELAYED_DELETE;
300       data->account_id = id;
301
302       g_queue_push_tail (self->priv->pending_signals, data);
303       return;
304     }
305
306   g_hash_table_iter_init (&iter, self->priv->accounts);
307   while (g_hash_table_iter_next (&iter, NULL, &value))
308     {
309       AgAccountService *service = value;
310       AgAccount *account = ag_account_service_get_account (service);
311       gchar *account_name;
312
313       if (account->id != id)
314         continue;
315
316       account_name = _service_dup_tp_account_name (service);
317       if (account_name == NULL)
318         continue;
319
320       DEBUG ("UOA account %s deleted", account_name);
321
322       g_hash_table_iter_remove (&iter);
323       g_signal_emit_by_name (self, "deleted", account_name);
324
325       g_free (account_name);
326     }
327 }
328
329 static void
330 mcp_account_manager_uoa_dispose (GObject *object)
331 {
332   McpAccountManagerUoa *self = (McpAccountManagerUoa *) object;
333
334   tp_clear_object (&self->priv->am);
335   tp_clear_object (&self->priv->manager);
336   tp_clear_pointer (&self->priv->accounts, g_hash_table_unref);
337   tp_clear_object (&self->priv->monitor);
338
339   G_OBJECT_CLASS (mcp_account_manager_uoa_parent_class)->dispose (object);
340 }
341
342 static void
343 mcp_account_manager_uoa_init (McpAccountManagerUoa *self)
344 {
345   DEBUG ("UOA MC plugin initialised");
346
347   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
348       MCP_TYPE_ACCOUNT_MANAGER_UOA, McpAccountManagerUoaPrivate);
349
350   self->priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
351       g_free, g_object_unref);
352   self->priv->pending_signals = g_queue_new ();
353
354   self->priv->manager = ag_manager_new_for_service_type (SERVICE_TYPE);
355   g_return_if_fail (self->priv->manager != NULL);
356
357   g_signal_connect (self->priv->manager, "account-created",
358       G_CALLBACK (_account_created_cb), self);
359   g_signal_connect (self->priv->manager, "account-deleted",
360       G_CALLBACK (_account_deleted_cb), self);
361
362   self->priv->monitor = empathy_webcredentials_monitor_new (
363       self->priv->manager);
364 }
365
366 static void
367 mcp_account_manager_uoa_class_init (McpAccountManagerUoaClass *klass)
368 {
369   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
370
371   gobject_class->dispose = mcp_account_manager_uoa_dispose;
372
373   g_type_class_add_private (gobject_class,
374       sizeof (McpAccountManagerUoaPrivate));
375 }
376
377 static void
378 _ensure_loaded (McpAccountManagerUoa *self)
379 {
380   GList *services;
381
382   if (self->priv->loaded)
383     return;
384
385   self->priv->loaded = TRUE;
386
387   g_assert (!self->priv->ready);
388
389   services = ag_manager_get_account_services (self->priv->manager);
390   while (services != NULL)
391     {
392       AgAccountService *service = services->data;
393       AgAccount *account = ag_account_service_get_account (service);
394       gchar *account_name = _service_dup_tp_account_name (service);
395
396       if (account_name != NULL)
397         {
398           /* This service was already known, we can add it now */
399           _add_service (self, service, account_name);
400           g_free (account_name);
401         }
402       else
403         {
404           DelayedSignalData *data = g_slice_new0 (DelayedSignalData);
405
406           /* This service was created while MC was not running, delay its
407            * creation until MC is ready */
408           data->signal = DELAYED_CREATE;
409           data->account_id = account->id;
410
411           g_queue_push_tail (self->priv->pending_signals, data);
412         }
413
414       g_object_unref (services->data);
415       services = g_list_delete_link (services, services);
416     }
417 }
418
419 static GList *
420 account_manager_uoa_list (const McpAccountStorage *storage,
421     const McpAccountManager *am)
422 {
423   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
424   GList *accounts = NULL;
425   GHashTableIter iter;
426   gpointer key;
427
428   DEBUG (G_STRFUNC);
429
430   g_return_val_if_fail (self->priv->manager != NULL, NULL);
431
432   _ensure_loaded (self);
433
434   g_hash_table_iter_init (&iter, self->priv->accounts);
435   while (g_hash_table_iter_next (&iter, &key, NULL))
436     accounts = g_list_prepend (accounts, g_strdup (key));
437
438   return accounts;
439 }
440
441 static const gchar *
442 provider_to_tp_service_name (const gchar *provider_name)
443 {
444   /* Well known services are defined in Telepathy spec:
445    * http://telepathy.freedesktop.org/spec/Account.html#Property:Service */
446   if (!tp_strdiff (provider_name, "google"))
447     return "google-talk";
448
449   return provider_name;
450 }
451
452 static gboolean
453 account_manager_uoa_get (const McpAccountStorage *storage,
454     const McpAccountManager *am,
455     const gchar *account_name,
456     const gchar *key)
457 {
458   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
459   AgAccountService *service;
460   AgAccount *account;
461   AgService *s;
462   gboolean handled = FALSE;
463
464   g_return_val_if_fail (self->priv->manager != NULL, FALSE);
465
466   service = g_hash_table_lookup (self->priv->accounts, account_name);
467   if (service == NULL)
468     return FALSE;
469
470   DEBUG ("%s: %s, %s", G_STRFUNC, account_name, key);
471
472   account = ag_account_service_get_account (service);
473   s = ag_account_service_get_service (service);
474
475   /* NULL key means we want all settings */
476   if (key == NULL)
477     {
478       AgAccountSettingIter iter;
479       const gchar *k;
480       GVariant *v;
481
482       ag_account_service_settings_iter_init (service, &iter, KEY_PREFIX);
483       while (ag_account_settings_iter_get_next (&iter, &k, &v))
484         {
485           if (!g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
486             continue;
487
488           mcp_account_manager_set_value (am, account_name,
489               k, g_variant_get_string (v, NULL));
490         }
491     }
492
493   /* Some special keys that are not stored in setting */
494   if (key == NULL || !tp_strdiff (key, "Enabled"))
495     {
496       mcp_account_manager_set_value (am, account_name, "Enabled",
497           ag_account_service_get_enabled (service) ? "true" : "false");
498       handled = TRUE;
499     }
500
501   if (key == NULL || !tp_strdiff (key, "DisplayName"))
502     {
503       mcp_account_manager_set_value (am, account_name, "DisplayName",
504           ag_account_get_display_name (account));
505       handled = TRUE;
506     }
507
508   if (key == NULL || !tp_strdiff (key, "Service"))
509     {
510       mcp_account_manager_set_value (am, account_name, "Service",
511           provider_to_tp_service_name (ag_account_get_provider_name (account)));
512       handled = TRUE;
513     }
514
515   if (key == NULL || !tp_strdiff (key, "Icon"))
516     {
517       mcp_account_manager_set_value (am, account_name, "Icon",
518           ag_service_get_icon_name (s));
519       handled = TRUE;
520     }
521
522   /* If it was none of the above, then just lookup in service' settings */
523   if (!handled)
524     {
525       gchar *value = _service_dup_tp_value (service, key);
526
527       mcp_account_manager_set_value (am, account_name, key, value);
528       g_free (value);
529     }
530
531   return TRUE;
532 }
533
534 static gboolean
535 account_manager_uoa_set (const McpAccountStorage *storage,
536     const McpAccountManager *am,
537     const gchar *account_name,
538     const gchar *key,
539     const gchar *val)
540 {
541   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
542   AgAccountService *service;
543   AgAccount *account;
544
545   g_return_val_if_fail (self->priv->manager != NULL, FALSE);
546
547   service = g_hash_table_lookup (self->priv->accounts, account_name);
548   if (service == NULL)
549     return FALSE;
550
551   account = ag_account_service_get_account (service);
552
553   DEBUG ("%s: %s, %s, %s", G_STRFUNC, account_name, key, val);
554
555   if (!tp_strdiff (key, "Enabled"))
556     {
557       /* Enabled is a global setting on the account, not per-services,
558        * unfortunately */
559       ag_account_select_service (account, NULL);
560       ag_account_set_enabled (account, !tp_strdiff (val, "true"));
561     }
562   else if (!tp_strdiff (key, "DisplayName"))
563     {
564       ag_account_set_display_name (account, val);
565     }
566   else
567     {
568       _service_set_tp_value (service, key, val);
569     }
570
571   return TRUE;
572 }
573
574 static gchar *
575 account_manager_uoa_create (const McpAccountStorage *storage,
576     const McpAccountManager *am,
577     const gchar *cm_name,
578     const gchar *protocol_name,
579     GHashTable *params,
580     GError **error)
581 {
582   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
583   gchar *account_name;
584   AgAccount *account;
585   AgAccountService *service;
586   GList *l;
587
588   g_return_val_if_fail (self->priv->manager != NULL, NULL);
589
590   if (!self->priv->ready)
591     {
592       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
593           "Cannot create account before being ready");
594       return NULL;
595     }
596
597   DEBUG (G_STRFUNC);
598
599   /* Create a new AgAccountService and keep it internally. This won't save it
600    * into persistent storage until account_manager_uoa_commit() is called.
601    * We assume there is only one IM service */
602   account = ag_manager_create_account (self->priv->manager, protocol_name);
603   l = ag_account_list_services_by_type (account, SERVICE_TYPE);
604   if (l == NULL)
605     {
606       g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
607           "Cannot create a %s service for %s provider",
608           SERVICE_TYPE, protocol_name);
609       g_object_unref (account);
610       return NULL;
611     }
612   service = ag_account_service_new (account, l->data);
613   ag_service_list_free (l);
614   g_object_unref (account);
615
616   account_name = mcp_account_manager_get_unique_name (self->priv->am,
617       cm_name, protocol_name, params);
618   _service_set_tp_account_name (service, account_name);
619   g_assert (_add_service (self, service, account_name));
620
621   /* MC will set all params on the account and commit */
622
623   return account_name;
624 }
625
626 static gboolean
627 account_manager_uoa_delete (const McpAccountStorage *storage,
628     const McpAccountManager *am,
629     const gchar *account_name,
630     const gchar *key)
631 {
632   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
633   AgAccountService *service;
634   AgAccount *account;
635
636   g_return_val_if_fail (self->priv->manager != NULL, FALSE);
637
638   service = g_hash_table_lookup (self->priv->accounts, account_name);
639   if (service == NULL)
640     return FALSE;
641
642   account = ag_account_service_get_account (service);
643
644   DEBUG ("%s: %s, %s", G_STRFUNC, account_name, key);
645
646   if (key == NULL)
647     {
648       ag_account_delete (account);
649       g_hash_table_remove (self->priv->accounts, account_name);
650     }
651   else
652     {
653       _service_set_tp_value (service, key, NULL);
654     }
655
656   return TRUE;
657 }
658
659 static gboolean
660 account_manager_uoa_commit (const McpAccountStorage *storage,
661     const McpAccountManager *am)
662 {
663   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
664   GHashTableIter iter;
665   gpointer value;
666
667   DEBUG (G_STRFUNC);
668
669   g_return_val_if_fail (self->priv->manager != NULL, FALSE);
670
671   g_hash_table_iter_init (&iter, self->priv->accounts);
672   while (g_hash_table_iter_next (&iter, NULL, &value))
673     {
674       AgAccountService *service = value;
675       AgAccount *account = ag_account_service_get_account (service);
676
677       ag_account_store_async (account, NULL, _account_stored_cb, self);
678     }
679
680   return TRUE;
681 }
682
683 static void
684 failure_removed_cb (EmpathyWebcredentialsMonitor *monitor,
685     AgAccount *account,
686     McpAccountManagerUoa *self)
687 {
688   GList *l;
689
690   DEBUG ("Account '%u' is not failing any more", account->id);
691
692   l = ag_account_list_services_by_type (account, SERVICE_TYPE);
693   while (l != NULL)
694     {
695       AgAccountService *service = ag_account_service_new (account, l->data);
696       gchar *account_name = _service_dup_tp_account_name (service);
697
698       if (account_name != NULL)
699         {
700           DEBUG ("Reconnect account %s", account_name);
701
702           mcp_account_storage_emit_reconnect (MCP_ACCOUNT_STORAGE (self),
703               account_name);
704         }
705
706       g_free (account_name);
707       g_object_unref (service);
708       ag_service_unref (l->data);
709       l = g_list_delete_link (l, l);
710     }
711 }
712
713 static void
714 account_manager_uoa_ready (const McpAccountStorage *storage,
715     const McpAccountManager *am)
716 {
717   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
718   DelayedSignalData *data;
719
720   g_return_if_fail (self->priv->manager != NULL);
721
722   if (self->priv->ready)
723     return;
724
725   DEBUG (G_STRFUNC);
726
727   self->priv->ready = TRUE;
728   self->priv->am = g_object_ref (G_OBJECT (am));
729
730   while ((data = g_queue_pop_head (self->priv->pending_signals)) != NULL)
731     {
732       switch (data->signal)
733         {
734           case DELAYED_CREATE:
735             _account_created_cb (self->priv->manager, data->account_id, self);
736             break;
737           case DELAYED_DELETE:
738             _account_deleted_cb (self->priv->manager, data->account_id, self);
739             break;
740           default:
741             g_assert_not_reached ();
742         }
743
744       g_slice_free (DelayedSignalData, data);
745     }
746
747   g_queue_free (self->priv->pending_signals);
748   self->priv->pending_signals = NULL;
749
750   g_signal_connect (self->priv->monitor, "failure-removed",
751       G_CALLBACK (failure_removed_cb), self);
752 }
753
754 static void
755 account_manager_uoa_get_identifier (const McpAccountStorage *storage,
756     const gchar *account_name,
757     GValue *identifier)
758 {
759   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
760   AgAccountService *service;
761   AgAccount *account;
762
763   g_return_if_fail (self->priv->manager != NULL);
764
765   service = g_hash_table_lookup (self->priv->accounts, account_name);
766   if (service == NULL)
767     return;
768
769   account = ag_account_service_get_account (service);
770
771   g_value_init (identifier, G_TYPE_UINT);
772   g_value_set_uint (identifier, account->id);
773 }
774
775 static guint
776 account_manager_uoa_get_restrictions (const McpAccountStorage *storage,
777     const gchar *account_name)
778 {
779   McpAccountManagerUoa *self = (McpAccountManagerUoa *) storage;
780   AgAccountService *service;
781   guint restrictions = TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_SERVICE;
782   GVariant *value;
783
784   g_return_val_if_fail (self->priv->manager != NULL, 0);
785
786   /* If we don't know this account, we cannot do anything */
787   service = g_hash_table_lookup (self->priv->accounts, account_name);
788   if (service == NULL)
789     return G_MAXUINT;
790
791   value = ag_account_service_get_variant (service,
792       KEY_PREFIX KEY_READONLY_PARAMS, NULL);
793
794   if (value != NULL && g_variant_get_boolean (value))
795     restrictions |= TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PARAMETERS;
796
797   /* FIXME: We can't set Icon either, but there is no flag for that */
798   return restrictions;
799 }
800
801 static void
802 account_storage_iface_init (McpAccountStorageIface *iface)
803 {
804   mcp_account_storage_iface_set_name (iface, PLUGIN_NAME);
805   mcp_account_storage_iface_set_desc (iface, PLUGIN_DESCRIPTION);
806   mcp_account_storage_iface_set_priority (iface, PLUGIN_PRIORITY);
807   mcp_account_storage_iface_set_provider (iface, PLUGIN_PROVIDER);
808
809 #define IMPLEMENT(x) mcp_account_storage_iface_implement_##x(iface, \
810     account_manager_uoa_##x)
811   IMPLEMENT (get);
812   IMPLEMENT (list);
813   IMPLEMENT (set);
814   IMPLEMENT (create);
815   IMPLEMENT (delete);
816   IMPLEMENT (commit);
817   IMPLEMENT (ready);
818   IMPLEMENT (get_identifier);
819   IMPLEMENT (get_restrictions);
820 #undef IMPLEMENT
821 }
822
823 McpAccountManagerUoa *
824 mcp_account_manager_uoa_new (void)
825 {
826   return g_object_new (MCP_TYPE_ACCOUNT_MANAGER_UOA, NULL);
827 }