1 /* Mission Control plugin API - Account Storage plugins.
2  *
3  * Copyright © 2010 Nokia Corporation
4  * Copyright © 2010 Collabora Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 /**
22  * SECTION:account-storage
23  * @title: McpAccountStorage
24  * @short_description: Account Storage object, implemented by plugins
25  * @see_also:
26  * @include: mission-control-plugins/mission-control-plugins.h
27  *
28  * Plugins may implement #McpAccountStorage in order to provide account
29  * parameter storage backends to the AccountManager object.
30  *
31  * To do so, the plugin must implement a #GObject subclass that implements
32  * #McpAccountStorage, then return an instance of that subclass from
33  * mcp_plugin_ref_nth_object().
34  *
35  * Many methods take "the unique name of an account" as an argument.
36  * In this plugin, that means the unique "tail" of the account's
37  * object path, for instance "gabble/jabber/chris_40example_2ecom".
38  * The account's full object path is obtained by prepending
39  * %TP_ACCOUNT_OBJECT_PATH_BASE.
40  *
41  * A complete implementation of this interface with all methods would
42  * look something like this:
43  *
44  * <example><programlisting>
45  * G_DEFINE_TYPE_WITH_CODE (FooPlugin, foo_plugin,
46  *    G_TYPE_OBJECT,
47  *    G_IMPLEMENT_INTERFACE (...);
48  *    G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_STORAGE,
49  *      account_storage_iface_init));
50  * /<!-- -->* ... *<!-- -->/
51  * static void
52  * account_storage_iface_init (McpAccountStorageIface *iface)
53  * {
54  *   iface->priority = 0;
55  *   iface->name = "foo";
56  *   iface->desc = "The FOO storage backend";
57  *   iface->provider = "org.freedesktop.Telepathy.MissionControl5.FooStorage";
58  *
59  *   iface->get = foo_plugin_get;
60  *   iface->set = foo_plugin_get;
61  *   iface->delete = foo_plugin_delete;
62  *   iface->commit = foo_plugin_commit;
63  *   iface->commit_one = foo_plugin_commit_one;
64  *   iface->list = foo_plugin_list;
65  *   iface->ready = foo_plugin_ready;
66  *   iface->get_identifier = foo_plugin_get_identifier;
67  *   iface->get_additional_info = foo_plugin_get_additional_info;
68  *   iface->get_restrictions = foo_plugin_get_restrictions;
69  *   iface->create = foo_plugin_create;
70  *   iface->owns = foo_plugin_owns;
71  *   iface->set_attribute = foo_plugin_set_attribute;
72  *   iface->set_parameter = foo_plugin_set_parameter;
73  * }
74  * </programlisting></example>
75  *
76  * A single object can implement more than one interface; It is currently
77  * unlikely that you would find it useful to implement anything other than
78  * an account storage plugin in an account storage object, though.
79  */
80 
81 #include "config.h"
82 
83 #include <mission-control-plugins/mission-control-plugins.h>
84 #include <mission-control-plugins/mcp-signals-marshal.h>
85 #include <mission-control-plugins/implementation.h>
86 #include <mission-control-plugins/debug-internal.h>
87 #include <glib.h>
88 
89 #define MCP_DEBUG_TYPE  MCP_DEBUG_ACCOUNT_STORAGE
90 
91 #ifdef ENABLE_DEBUG
92 
93 #define SDEBUG(_p, _format, ...) \
94   DEBUG("%s: " _format, \
95         (_p != NULL) ? mcp_account_storage_name (_p) : "NULL", ##__VA_ARGS__)
96 
97 #else  /* ENABLE_DEBUG */
98 
99 #define SDEBUG(_p, _format, ...) do {} while (0);
100 
101 #endif /* ENABLE_DEBUG */
102 
103 enum
104 {
105   CREATED,
106   ALTERED,
107   TOGGLED,
108   DELETED,
109   ALTERED_ONE,
110   RECONNECT,
111   NO_SIGNAL
112 };
113 
114 static guint signals[NO_SIGNAL] = { 0 };
115 
116 static gboolean
default_set(const McpAccountStorage * storage,const McpAccountManager * am,const gchar * account,const gchar * key,const gchar * val)117 default_set (const McpAccountStorage *storage,
118     const McpAccountManager *am,
119     const gchar *account,
120     const gchar *key,
121     const gchar *val)
122 {
123   return FALSE;
124 }
125 
126 static gboolean
default_set_attribute(McpAccountStorage * storage,McpAccountManager * am,const gchar * account,const gchar * attribute,GVariant * value,McpAttributeFlags flags)127 default_set_attribute (McpAccountStorage *storage,
128     McpAccountManager *am,
129     const gchar *account,
130     const gchar *attribute,
131     GVariant *value,
132     McpAttributeFlags flags)
133 {
134   return FALSE;
135 }
136 
137 static gboolean
default_set_parameter(McpAccountStorage * storage,McpAccountManager * am,const gchar * account,const gchar * parameter,GVariant * value,McpParameterFlags flags)138 default_set_parameter (McpAccountStorage *storage,
139     McpAccountManager *am,
140     const gchar *account,
141     const gchar *parameter,
142     GVariant *value,
143     McpParameterFlags flags)
144 {
145   return FALSE;
146 }
147 
148 static gboolean
default_owns(McpAccountStorage * storage,McpAccountManager * am,const gchar * account)149 default_owns (McpAccountStorage *storage,
150     McpAccountManager *am,
151     const gchar *account)
152 {
153   /* This has the side-effect of pushing the "manager" key back into @am,
154    * but that should be a no-op in practice: we always call this
155    * method in priority order and stop at the first one that says "yes",
156    * and @am's idea of what "manager" is should have come from that same
157    * plugin anyway. */
158   return mcp_account_storage_get (storage, am, account, "manager");
159 }
160 
161 static void
class_init(gpointer klass,gpointer data)162 class_init (gpointer klass,
163     gpointer data)
164 {
165   GType type = G_TYPE_FROM_CLASS (klass);
166   McpAccountStorageIface *iface = klass;
167 
168   iface->owns = default_owns;
169   iface->set = default_set;
170   iface->set_attribute = default_set_attribute;
171   iface->set_parameter = default_set_parameter;
172 
173   if (signals[CREATED] != 0)
174     {
175       DEBUG ("already registered signals");
176       return;
177     }
178 
179   /**
180    * McpAccountStorage::created
181    * @account: the unique name of the created account
182    *
183    * Emitted if an external entity creates an account
184    * in the backend the emitting plugin handles.
185    *
186    * Should not be fired until mcp_account_storage_ready() has been called
187    *
188    */
189   signals[CREATED] = g_signal_new ("created",
190       type, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
191       g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
192       1, G_TYPE_STRING);
193 
194   /**
195    * McpAccountStorage::altered
196    * @account: the unique name of the altered account
197    *
198    * This signal does not appear to be fully implemented
199    * (see <ulink href="https://bugs.freedesktop.org/show_bug.cgi?id=28288"
200    *  >freedesktop.org bug 28288</ulink>).
201    * Emit #McpAccountStorage::altered-one instead.
202    *
203    * Should not be fired until mcp_account_storage_ready() has been called
204    *
205    */
206   signals[ALTERED] = g_signal_new ("altered",
207       type, G_SIGNAL_RUN_LAST | G_SIGNAL_DEPRECATED, 0, NULL, NULL,
208       g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
209       1, G_TYPE_STRING);
210 
211   /**
212    * McpAccountStorage::altered-one
213    * @account: the unique name of the altered account
214    * @name: the name of the altered property (its key)
215    *
216    * Emitted if an external entity alters an account
217    * in the backend that the emitting plugin handles.
218    *
219    * Before emitting this signal, the plugin must call
220    * either mcp_account_manager_set_attribute(),
221    * either mcp_account_manager_set_parameter() or
222    * mcp_account_manager_set_value() to push the new value
223    * into the account manager.
224    *
225    * Note that mcp_account_manager_set_parameter() does not use the
226    * "param-" prefix, but this signal and mcp_account_manager_set_value()
227    * both do.
228    *
229    * Should not be fired until mcp_account_storage_ready() has been called
230    */
231   signals[ALTERED_ONE] = g_signal_new ("altered-one",
232       type, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
233       _mcp_marshal_VOID__STRING_STRING, G_TYPE_NONE,
234       2, G_TYPE_STRING, G_TYPE_STRING);
235 
236 
237   /**
238    * McpAccountStorage::deleted
239    * @account: the unique name of the deleted account
240    *
241    * Emitted if an external entity deletes an account
242    * in the backend the emitting plugin handles.
243    *
244    * Should not be fired until mcp_account_storage_ready() has been called
245    *
246    */
247   signals[DELETED] = g_signal_new ("deleted",
248       type, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
249       g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
250       1, G_TYPE_STRING);
251 
252   /**
253    * McpAccountStorage::toggled
254    * @account: the unique name of the toggled account
255    * @enabled: #gboolean indicating whether the account is enabled
256    *
257    * Emitted if an external entity enables/disables an account
258    * in the backend the emitting plugin handles. This is similar to
259    * emitting #McpAccountStorage::altered-one for the attribute
260    * "Enabled", except that the plugin is not required to call
261    * a function like mcp_account_manager_set_value() first.
262    *
263    * Should not be fired until mcp_account_storage_ready() has been called
264    *
265    */
266   signals[TOGGLED] = g_signal_new ("toggled",
267       type, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
268       _mcp_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE,
269       2, G_TYPE_STRING, G_TYPE_BOOLEAN);
270 
271   /**
272    * McpAccountStorage::reconnect
273    * @account: the unique name of the account to reconnect
274    *
275    * emitted if an external entity modified important parameters of the
276    * account and a reconnection is required in order to apply them.
277    *
278    * Should not be fired until mcp_account_storage_ready() has been called
279    **/
280   signals[RECONNECT] = g_signal_new ("reconnect",
281       type, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
282       g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
283       1, G_TYPE_STRING);
284 }
285 
286 GType
mcp_account_storage_get_type(void)287 mcp_account_storage_get_type (void)
288 {
289   static gsize once = 0;
290   static GType type = 0;
291 
292   if (g_once_init_enter (&once))
293     {
294       static const GTypeInfo info =
295         {
296           sizeof (McpAccountStorageIface),
297           NULL, /* base_init      */
298           NULL, /* base_finalize  */
299           class_init, /* class_init     */
300           NULL, /* class_finalize */
301           NULL, /* class_data     */
302           0,    /* instance_size  */
303           0,    /* n_preallocs    */
304           NULL, /* instance_init  */
305           NULL  /* value_table    */
306         };
307 
308       type = g_type_register_static (G_TYPE_INTERFACE,
309           "McpAccountStorage", &info, 0);
310       g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
311 
312       g_once_init_leave (&once, 1);
313     }
314 
315   return type;
316 }
317 
318 /**
319  * McpAccountStorage:
320  *
321  * An object implementing the account storage plugin interface.
322  */
323 
324 /**
325  * McpAccountStorageIface:
326  * @parent: the standard fields for an interface
327  * @priority: returned by mcp_account_storage_priority()
328  * @name: returned by mcp_account_storage_name()
329  * @desc: returned by mcp_account_storage_description()
330  * @provider: returned by mcp_account_storage_provider()
331  * @set: implementation of mcp_account_storage_set()
332  * @get: implementation of mcp_account_storage_get()
333  * @delete: implementation of mcp_account_storage_delete()
334  * @commit: implementation of mcp_account_storage_commit()
335  * @list: implementation of mcp_account_storage_list()
336  * @ready: implementation of mcp_account_storage_ready()
337  * @commit_one: implementation of mcp_account_storage_commit_one()
338  * @get_identifier: implementation of mcp_account_storage_get_identifier()
339  * @get_additional_info: implementation of
340  *  mcp_account_storage_get_additional_info()
341  * @get_restrictions: implementation of mcp_account_storage_get_restrictions()
342  * @create: implementation of mcp_account_storage_create()
343  *
344  * The interface vtable for an account storage plugin.
345  */
346 
347 void
mcp_account_storage_iface_set_priority(McpAccountStorageIface * iface,guint prio)348 mcp_account_storage_iface_set_priority (McpAccountStorageIface *iface,
349     guint prio)
350 {
351   iface->priority = prio;
352 }
353 
354 void
mcp_account_storage_iface_set_name(McpAccountStorageIface * iface,const gchar * name)355 mcp_account_storage_iface_set_name (McpAccountStorageIface *iface,
356     const gchar *name)
357 {
358   iface->name = name;
359 }
360 
361 void
mcp_account_storage_iface_set_desc(McpAccountStorageIface * iface,const gchar * desc)362 mcp_account_storage_iface_set_desc (McpAccountStorageIface *iface,
363     const gchar *desc)
364 {
365   iface->desc = desc;
366 }
367 
368 void
mcp_account_storage_iface_set_provider(McpAccountStorageIface * iface,const gchar * provider)369 mcp_account_storage_iface_set_provider (McpAccountStorageIface *iface,
370     const gchar *provider)
371 {
372   iface->provider = provider;
373 }
374 
375 void
mcp_account_storage_iface_implement_get(McpAccountStorageIface * iface,McpAccountStorageGetFunc method)376 mcp_account_storage_iface_implement_get (McpAccountStorageIface *iface,
377     McpAccountStorageGetFunc method)
378 {
379   iface->get = method;
380 }
381 
382 void
mcp_account_storage_iface_implement_set(McpAccountStorageIface * iface,McpAccountStorageSetFunc method)383 mcp_account_storage_iface_implement_set (McpAccountStorageIface *iface,
384     McpAccountStorageSetFunc method)
385 {
386   iface->set = method;
387 }
388 
389 void
mcp_account_storage_iface_implement_delete(McpAccountStorageIface * iface,McpAccountStorageDeleteFunc method)390 mcp_account_storage_iface_implement_delete (McpAccountStorageIface *iface,
391     McpAccountStorageDeleteFunc method)
392 {
393   iface->delete = method;
394 }
395 
396 void
mcp_account_storage_iface_implement_commit(McpAccountStorageIface * iface,McpAccountStorageCommitFunc method)397 mcp_account_storage_iface_implement_commit (McpAccountStorageIface *iface,
398     McpAccountStorageCommitFunc method)
399 {
400   iface->commit = method;
401 }
402 
403 void
mcp_account_storage_iface_implement_commit_one(McpAccountStorageIface * iface,McpAccountStorageCommitOneFunc method)404 mcp_account_storage_iface_implement_commit_one (McpAccountStorageIface *iface,
405     McpAccountStorageCommitOneFunc method)
406 {
407   iface->commit_one = method;
408 }
409 
410 void
mcp_account_storage_iface_implement_list(McpAccountStorageIface * iface,McpAccountStorageListFunc method)411 mcp_account_storage_iface_implement_list (McpAccountStorageIface *iface,
412     McpAccountStorageListFunc method)
413 {
414   iface->list = method;
415 }
416 
417 void
mcp_account_storage_iface_implement_ready(McpAccountStorageIface * iface,McpAccountStorageReadyFunc method)418 mcp_account_storage_iface_implement_ready (McpAccountStorageIface *iface,
419     McpAccountStorageReadyFunc method)
420 {
421   iface->ready = method;
422 }
423 
424 void
mcp_account_storage_iface_implement_get_identifier(McpAccountStorageIface * iface,McpAccountStorageGetIdentifierFunc method)425 mcp_account_storage_iface_implement_get_identifier (
426     McpAccountStorageIface *iface,
427     McpAccountStorageGetIdentifierFunc method)
428 {
429   iface->get_identifier = method;
430 }
431 
432 void
mcp_account_storage_iface_implement_get_additional_info(McpAccountStorageIface * iface,McpAccountStorageGetAdditionalInfoFunc method)433 mcp_account_storage_iface_implement_get_additional_info (
434     McpAccountStorageIface *iface,
435     McpAccountStorageGetAdditionalInfoFunc method)
436 {
437   iface->get_additional_info = method;
438 }
439 
440 void
mcp_account_storage_iface_implement_get_restrictions(McpAccountStorageIface * iface,McpAccountStorageGetRestrictionsFunc method)441 mcp_account_storage_iface_implement_get_restrictions (
442     McpAccountStorageIface *iface,
443     McpAccountStorageGetRestrictionsFunc method)
444 {
445   iface->get_restrictions = method;
446 }
447 
448 void
mcp_account_storage_iface_implement_create(McpAccountStorageIface * iface,McpAccountStorageCreate method)449 mcp_account_storage_iface_implement_create (
450     McpAccountStorageIface *iface,
451     McpAccountStorageCreate method)
452 {
453   iface->create = method;
454 }
455 
456 /**
457  * mcp_account_storage_priority:
458  * @storage: an #McpAccountStorage instance
459  *
460  * Gets the priority for this plugin.
461  *
462  * Priorities currently run from MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_DEFAULT
463  * (the default storage plugin priority) upwards. More-positive numbers
464  * are higher priority.
465  *
466  * Plugins at a higher priority then MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_KEYRING
467  * used to have the opportunity to "steal" passwords from the gnome keyring.
468  * It is no longer significant.
469  *
470  * Plugins at a lower priority than the default plugin will never be asked to
471  * store any details, although they may still be asked to list them at startup
472  * time, and may asynchronously notify MC of accounts via the signals above.
473  *
474  * When loading accounts at startup, plugins are consulted in order from
475  * lowest to highest, so that higher priority plugins may overrule settings
476  * from lower priority plugins.
477  *
478  * Loading all the accounts is only done at startup, before the dbus name
479  * is claimed, and is therefore the only time plugins are allowed to indulge
480  * in blocking calls (indeed, they are expected to carry out this operation,
481  * and ONLY this operation, synchronously).
482  *
483  * When values are being set, the plugins are invoked from highest priority
484  * to lowest, with the first plugin that claims a setting being assigned
485  * ownership, and all lower priority plugins being asked to delete the
486  * setting in question.
487  *
488  * Returns: the priority of this plugin
489  **/
490 gint
mcp_account_storage_priority(const McpAccountStorage * storage)491 mcp_account_storage_priority (const McpAccountStorage *storage)
492 {
493   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
494 
495   g_return_val_if_fail (iface != NULL, -1);
496 
497   return iface->priority;
498 }
499 
500 /**
501  * McpAccountStorageGetFunc:
502  * @storage: the account storage plugin
503  * @am: object used to call back into the account manager
504  * @account: the unique name of the account
505  * @key: the setting whose value we wish to fetch: either an attribute
506  *  like "DisplayName", or "param-" plus a parameter like "account"
507  *
508  * An implementation of mcp_account_storage_get().
509  *
510  * Returns: %TRUE if @storage is responsible for @account
511  */
512 
513 /**
514  * mcp_account_storage_get:
515  * @storage: an #McpAccountStorage instance
516  * @am: an #McpAccountManager instance
517  * @account: the unique name of the account
518  * @key: the setting whose value we wish to fetch: either an attribute
519  *  like "DisplayName", or "param-" plus a parameter like "account"
520  *
521  * Get a value from the plugin's in-memory cache.
522  * Before emitting this signal, the plugin must call
523  * either mcp_account_manager_set_attribute(),
524  * mcp_account_manager_set_parameter(),
525  * or mcp_account_manager_set_value() and (if appropriate)
526  * mcp_account_manager_parameter_make_secret()
527  * before returning from this method call.
528  *
529  * Note that mcp_account_manager_set_parameter() does not use the
530  * "param-" prefix, even if called from this function.
531  *
532  * If @key is %NULL the plugin should iterate through all attributes and
533  * parameters, and push each of them into @am, as if this method had
534  * been called once for each attribute or parameter. It must then return
535  * %TRUE if any attributes or parameters were found, or %FALSE if it
536  * was not responsible for @account.
537  *
538  * Returns: %TRUE if @storage is responsible for @account
539  */
540 gboolean
mcp_account_storage_get(const McpAccountStorage * storage,McpAccountManager * am,const gchar * account,const gchar * key)541 mcp_account_storage_get (const McpAccountStorage *storage,
542     McpAccountManager *am,
543     const gchar *account,
544     const gchar *key)
545 {
546   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
547 
548   SDEBUG (storage, "");
549   g_return_val_if_fail (iface != NULL, FALSE);
550   g_return_val_if_fail (iface->get != NULL, FALSE);
551 
552   return iface->get (storage, am, account, key);
553 }
554 
555 /**
556  * McpAccountStorageSetFunc:
557  * @storage: an #McpAccountStorage instance
558  * @am: an #McpAccountManager instance
559  * @account: the unique name of the account
560  * @key: the setting whose value we wish to store: either an attribute
561  *  like "DisplayName", or "param-" plus a parameter like "account"
562  * @val: a non-%NULL value for @key
563  *
564  * An implementation of mcp_account_storage_set().
565  *
566  * Returns: %TRUE if @storage is responsible for @account
567  */
568 
569 /**
570  * mcp_account_storage_set:
571  * @storage: an #McpAccountStorage instance
572  * @am: an #McpAccountManager instance
573  * @account: the unique name of the account
574  * @key: the non-%NULL setting whose value we wish to store: either an
575  *  attribute like "DisplayName", or "param-" plus a parameter like "account"
576  * @value: a value to associate with @key, escaped as if for a #GKeyFile
577  *
578  * The plugin is expected to either quickly and synchronously
579  * update its internal cache of values with @value, or to
580  * decline to store the setting.
581  *
582  * The plugin is not expected to write to its long term storage
583  * at this point. It can expect Mission Control to call either
584  * mcp_account_storage_commit() or mcp_account_storage_commit_one()
585  * after a short delay.
586  *
587  * Plugins that implement mcp_storage_set_attribute() and
588  * mcp_account_storage_set_parameter() can just return %FALSE here.
589  * There is a default implementation, which just returns %FALSE.
590  *
591  * Returns: %TRUE if the attribute was claimed, %FALSE otherwise
592  */
593 gboolean
mcp_account_storage_set(const McpAccountStorage * storage,const McpAccountManager * am,const gchar * account,const gchar * key,const gchar * value)594 mcp_account_storage_set (const McpAccountStorage *storage,
595     const McpAccountManager *am,
596     const gchar *account,
597     const gchar *key,
598     const gchar *value)
599 {
600   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
601 
602   SDEBUG (storage, "");
603   g_return_val_if_fail (iface != NULL, FALSE);
604 
605   return iface->set (storage, am, account, key, value);
606 }
607 
608 /**
609  * mcp_account_storage_set_attribute:
610  * @storage: an #McpAccountStorage instance
611  * @am: an #McpAccountManager instance
612  * @account: the unique name of the account
613  * @attribute: the name of an attribute, e.g. "DisplayName"
614  * @value: a value to associate with @attribute
615  * @flags: flags influencing how the attribute is to be stored
616  *
617  * Store an attribute.
618  *
619  * The plugin is expected to either quickly and synchronously
620  * update its internal cache of values with @value, or to
621  * decline to store the attribute.
622  *
623  * The plugin is not expected to write to its long term storage
624  * at this point.
625  *
626  * There is a default implementation, which just returns %FALSE.
627  * Mission Control will call mcp_account_storage_set() instead,
628  * using a keyfile-escaped version of @value.
629  *
630  * Returns: %TRUE if the attribute was claimed, %FALSE otherwise
631  *
632  * Since: 5.15.0
633  */
634 gboolean
mcp_account_storage_set_attribute(McpAccountStorage * storage,McpAccountManager * am,const gchar * account,const gchar * attribute,GVariant * value,McpAttributeFlags flags)635 mcp_account_storage_set_attribute (McpAccountStorage *storage,
636     McpAccountManager *am,
637     const gchar *account,
638     const gchar *attribute,
639     GVariant *value,
640     McpAttributeFlags flags)
641 {
642   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
643 
644   SDEBUG (storage, "");
645   g_return_val_if_fail (iface != NULL, FALSE);
646   g_return_val_if_fail (iface->set_attribute != NULL, FALSE);
647 
648   return iface->set_attribute (storage, am, account, attribute, value, flags);
649 }
650 
651 /**
652  * mcp_account_storage_set_parameter:
653  * @storage: an #McpAccountStorage instance
654  * @am: an #McpAccountManager instance
655  * @account: the unique name of the account
656  * @parameter: the name of a parameter, e.g. "account" (note that there
657  *  is no "param-" prefix here)
658  * @value: a value to associate with @parameter
659  * @flags: flags influencing how the parameter is to be stored
660  *
661  * Store a parameter.
662  *
663  * The plugin is expected to either quickly and synchronously
664  * update its internal cache of values with @value, or to
665  * decline to store the parameter.
666  *
667  * The plugin is not expected to write to its long term storage
668  * at this point.
669  *
670  * There is a default implementation, which just returns %FALSE.
671  * Mission Control will call mcp_account_storage_set() instead,
672  * using "param-" + @parameter as key and a keyfile-escaped version
673  * of @value as value.
674  *
675  * Returns: %TRUE if the parameter was claimed, %FALSE otherwise
676  *
677  * Since: 5.15.0
678  */
679 gboolean
mcp_account_storage_set_parameter(McpAccountStorage * storage,McpAccountManager * am,const gchar * account,const gchar * parameter,GVariant * value,McpParameterFlags flags)680 mcp_account_storage_set_parameter (McpAccountStorage *storage,
681     McpAccountManager *am,
682     const gchar *account,
683     const gchar *parameter,
684     GVariant *value,
685     McpParameterFlags flags)
686 {
687   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
688 
689   SDEBUG (storage, "");
690   g_return_val_if_fail (iface != NULL, FALSE);
691   g_return_val_if_fail (iface->set_parameter != NULL, FALSE);
692 
693   return iface->set_parameter (storage, am, account, parameter, value, flags);
694 }
695 
696 /**
697  * McpAccountStorageCreate:
698  * @storage: an #McpAccountStorage instance
699  * @am: an object which can be used to call back into the account manager
700  * @manager: the name of the manager
701  * @protocol: the name of the protocol
702  * @params: A gchar * / GValue * hash table of account parameters
703  * @error: a GError to fill
704  *
705  * An implementation of mcp_account_storage_create()
706  *
707  * Returns: (transfer full): the account name or %NULL
708  */
709 
710 /**
711  * mcp_account_storage_create:
712  * @storage: an #McpAccountStorage instance
713  * @am: an object which can be used to call back into the account manager
714  * @manager: the name of the manager
715  * @protocol: the name of the protocol
716  * @params: A gchar * / GValue * hash table of account parameters
717  * @error: a GError to fill
718  *
719  * Inform the plugin that a new account is being created. @manager, @protocol
720  * and @params are given to help determining the account's unique name, but does
721  * not need to be stored on the account yet, mcp_account_storage_set() and
722  * mcp_account_storage_commit() will be called later.
723  *
724  * It is recommended to use mcp_account_manager_get_unique_name() to create the
725  * unique name, but it's not mandatory. One could base the unique name on an
726  * internal storage identifier, prefixed with the provider's name
727  * (e.g. goa__1234).
728  *
729  * #McpAccountStorage::created signal should not be emitted for this account,
730  * not even when mcp_account_storage_commit() will be called.
731  *
732  * Returns: (transfer full): the newly allocated account name, which should
733  *  be freed once the caller is done with it, or %NULL if that couldn't
734  *  be done.
735  */
736 gchar *
mcp_account_storage_create(const McpAccountStorage * storage,const McpAccountManager * am,const gchar * manager,const gchar * protocol,GHashTable * params,GError ** error)737 mcp_account_storage_create (const McpAccountStorage *storage,
738     const McpAccountManager *am,
739     const gchar *manager,
740     const gchar *protocol,
741     GHashTable *params,
742     GError **error)
743 {
744   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
745 
746   g_return_val_if_fail (iface != NULL, NULL);
747 
748   if (iface->create == NULL)
749     {
750       g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
751           "This storage does not implement create function");
752       return NULL;
753     }
754 
755   return iface->create (storage, am, manager, protocol, params, error);
756 }
757 
758 /**
759  * McpAccountStorageDeleteFunc:
760  * @storage: an #McpAccountStorage instance
761  * @am: an #McpAccountManager instance
762  * @account: the unique name of the account
763  * @key: (allow-none): the setting whose value we wish to store - either an
764  *  attribute like "DisplayName", or "param-" plus a parameter like
765  *  "account" - or %NULL to delete the entire account
766  *
767  * An implementation of mcp_account_storage_delete().
768  *
769  * Returns: %TRUE if the setting or settings are not
770  * the plugin's cache after this operation, %FALSE otherwise.
771  */
772 
773 /**
774  * mcp_account_storage_delete:
775  * @storage: an #McpAccountStorage instance
776  * @am: an #McpAccountManager instance
777  * @account: the unique name of the account
778  * @key: (allow-none): the setting whose value we wish to store - either an
779  *  attribute like "DisplayName", or "param-" plus a parameter like
780  *  "account" - or %NULL to delete the entire account
781  *
782  * The plugin is expected to remove the setting for @key from its
783  * internal cache and to remember that its state has changed, so
784  * that it can delete said setting from its long term storage if
785  * its long term storage method makes this necessary.
786  *
787  * If @key is %NULL, the plugin should forget all its settings for
788  * @account,and remember to delete the entire account from its storage later.
789  *
790  * The plugin is not expected to update its long term storage at
791  * this point.
792  *
793  * Returns: %TRUE if the setting or settings are not
794  * the plugin's cache after this operation, %FALSE otherwise.
795  * This is very unlikely to ever be %FALSE, as a plugin is always
796  * expected to be able to manipulate its own cache.
797  */
798 gboolean
mcp_account_storage_delete(const McpAccountStorage * storage,const McpAccountManager * am,const gchar * account,const gchar * key)799 mcp_account_storage_delete (const McpAccountStorage *storage,
800     const McpAccountManager *am,
801     const gchar *account,
802     const gchar *key)
803 {
804   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
805 
806   SDEBUG (storage, "");
807   g_return_val_if_fail (iface != NULL, FALSE);
808 
809   return iface->delete (storage, am, account, key);
810 }
811 
812 /**
813  * McpAccountStorageCommitFunc:
814  * @storage: an #McpAccountStorage instance
815  * @am: an #McpAccountManager instance
816  *
817  * An implementation of mcp_account_storage_commit().
818  *
819  * Returns: %TRUE if the commit process was started successfully
820  */
821 
822 /**
823  * mcp_account_storage_commit:
824  * @storage: an #McpAccountStorage instance
825  * @am: an #McpAccountManager instance
826  *
827  * The plugin is expected to write its cache to long term storage,
828  * deleting, adding or updating entries in said storage as needed.
829  *
830  * This call is expected to return promptly, but the plugin is
831  * not required to have finished its commit operation when it returns,
832  * merely to have started the operation.
833  *
834  * If the @commit_one method is implemented, it will be called preferentially
835  * if only one account is to be committed. If the @commit_one method is
836  * implemented but @commit is not, @commit_one will be called with
837  * @account_name = %NULL to commit all accounts.
838  *
839  * Returns: %TRUE if the commit process was started (but not necessarily
840  * completed) successfully; %FALSE if there was a problem that was immediately
841  * obvious.
842  */
843 gboolean
mcp_account_storage_commit(const McpAccountStorage * storage,const McpAccountManager * am)844 mcp_account_storage_commit (const McpAccountStorage *storage,
845     const McpAccountManager *am)
846 {
847   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
848 
849   SDEBUG (storage, "committing all accounts");
850   g_return_val_if_fail (iface != NULL, FALSE);
851 
852   if (iface->commit != NULL)
853     {
854       return iface->commit (storage, am);
855     }
856   else if (iface->commit_one != NULL)
857     {
858       return iface->commit_one (storage, am, NULL);
859     }
860   else
861     {
862       SDEBUG (storage,
863           "neither commit nor commit_one is implemented; cannot save accounts");
864       return FALSE;
865     }
866 }
867 
868 /**
869  * McpAccountStorageCommitOneFunc:
870  * @storage: an #McpAccountStorage instance
871  * @am: an #McpAccountManager instance
872  * @account: (allow-none): the unique suffix of an account's object path,
873  *  or %NULL
874  *
875  * An implementation of mcp_account_storage_commit_one().
876  *
877  * Returns: %TRUE if the commit process was started successfully
878  */
879 
880 /**
881  * mcp_account_storage_commit_one:
882  * @storage: an #McpAccountStorage instance
883  * @am: an #McpAccountManager instance
884  * @account: (allow-none): the unique suffix of an account's object path,
885  *  or %NULL if all accounts are to be committed and
886  *  mcp_account_storage_commit() is unimplemented
887  *
888  * The same as mcp_account_storage_commit(), but only commit the given
889  * account. This is optional to implement; the default implementation
890  * is to call @commit.
891  *
892  * If both mcp_account_storage_commit_one() and mcp_account_storage_commit()
893  * are implemented, Mission Control will never pass @account = %NULL to
894  * this method.
895  *
896  * Returns: %TRUE if the commit process was started (but not necessarily
897  * completed) successfully; %FALSE if there was a problem that was immediately
898  * obvious.
899  */
900 gboolean
mcp_account_storage_commit_one(const McpAccountStorage * storage,const McpAccountManager * am,const gchar * account)901 mcp_account_storage_commit_one (const McpAccountStorage *storage,
902     const McpAccountManager *am,
903     const gchar *account)
904 {
905   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
906 
907   SDEBUG (storage, "called for %s", account ? account : "<all accounts>");
908   g_return_val_if_fail (iface != NULL, FALSE);
909 
910   if (iface->commit_one != NULL)
911     return iface->commit_one (storage, am, account);
912   else
913     /* Fall back to plain ->commit() */
914     return mcp_account_storage_commit (storage, am);
915 }
916 
917 /**
918  * McpAccountStorageListFunc:
919  * @storage: an #McpAccountStorage instance
920  * @am: an #McpAccountManager instance
921  *
922  * An implementation of mcp_account_storage_list().
923  *
924  * Returns: (transfer full): a list of account names
925  */
926 
927 /**
928  * mcp_account_storage_list:
929  * @storage: an #McpAccountStorage instance
930  * @am: an #McpAccountManager instance
931  *
932  * Load details of every account stored by this plugin into an in-memory cache
933  * so that it can respond to requests promptly.
934  *
935  * This method is called only at initialisation time, before the dbus name
936  * has been claimed, and is the only one permitted to block.
937  *
938  * Returns: (element-type utf8) (transfer full): a list of account names that
939  * the plugin has settings for. The account names should be freed with
940  * g_free(), and the list with g_list_free(), when the caller is done with
941  * them.
942  */
943 GList *
mcp_account_storage_list(const McpAccountStorage * storage,const McpAccountManager * am)944 mcp_account_storage_list (const McpAccountStorage *storage,
945     const McpAccountManager *am)
946 {
947   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
948 
949   SDEBUG (storage, "");
950   g_return_val_if_fail (iface != NULL, NULL);
951 
952   return iface->list (storage, am);
953 }
954 
955 /**
956  * McpAccountStorageReadyFunc:
957  * @storage: an #McpAccountStorage instance
958  * @am: an #McpAccountManager instance
959  *
960  * An implementation of mcp_account_storage_ready().
961  */
962 
963 /**
964  * mcp_account_storage_ready:
965  * @storage: an #McpAccountStorage instance
966  * @am: an #McpAccountManager instance
967  *
968  * Informs the plugin that it is now permitted to create new accounts,
969  * ie it can now fire its "created", "altered", "toggled" and "deleted"
970  * signals.
971  */
972 void
mcp_account_storage_ready(const McpAccountStorage * storage,const McpAccountManager * am)973 mcp_account_storage_ready (const McpAccountStorage *storage,
974     const McpAccountManager *am)
975 {
976   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
977 
978   g_return_if_fail (iface != NULL);
979 
980   /* plugins that can't create accounts from external sources don't  *
981    * need to implement this method, as they can never fire the async *
982    * account change signals:                                         */
983   if (iface->ready != NULL)
984     iface->ready (storage, am);
985 }
986 
987 /**
988  * McpAccountStorageGetIdentifierFunc:
989  * @storage: an #McpAccountStorage instance
990  * @account: the unique name of the account
991  * @identifier: (out caller-allocates): a zero-filled #GValue whose type
992  *  can be sent over D-Bus by dbus-glib, to hold the identifier.
993  *
994  * An implementation of mcp_account_storage_get_identifier().
995  */
996 
997 /**
998  * mcp_account_storage_get_identifier:
999  * @storage: an #McpAccountStorage instance
1000  * @account: the unique name of the account
1001  * @identifier: (out caller-allocates): a zero-filled #GValue whose type
1002  *  can be sent over D-Bus by dbus-glib, to hold the identifier.
1003  *
1004  * Get the storage-specific identifier for this account. The type is variant,
1005  * hence the GValue.
1006  *
1007  * This method will only be called for the storage plugin that "owns"
1008  * the account.
1009  */
1010 void
mcp_account_storage_get_identifier(const McpAccountStorage * storage,const gchar * account,GValue * identifier)1011 mcp_account_storage_get_identifier (const McpAccountStorage *storage,
1012     const gchar *account,
1013     GValue *identifier)
1014 {
1015   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
1016 
1017   SDEBUG (storage, "");
1018   g_return_if_fail (iface != NULL);
1019   g_return_if_fail (identifier != NULL);
1020   g_return_if_fail (!G_IS_VALUE (identifier));
1021 
1022   if (iface->get_identifier == NULL)
1023     {
1024       g_value_init (identifier, G_TYPE_STRING);
1025       g_value_set_string (identifier, account);
1026     }
1027   else
1028     {
1029       iface->get_identifier (storage, account, identifier);
1030     }
1031 }
1032 
1033 /**
1034  * McpAccountStorageGetAdditionalInfoFunc
1035  * @storage: an #McpAccountStorage instance
1036  * @account: the unique name of the account
1037  *
1038  * An implementation of mcp_account_storage_get_identifier().
1039  *
1040  * Returns: (transfer container) (element-type utf8 GObject.Value): additional
1041  *  storage-specific information
1042  */
1043 
1044 /**
1045  * mcp_account_storage_get_additional_info:
1046  * @storage: an #McpAccountStorage instance
1047  * @account: the unique name of the account
1048  *
1049  * Return additional storage-specific information about this account, which is
1050  * made available on D-Bus but not otherwise interpreted by Mission Control.
1051  *
1052  * This method will only be called for the storage plugin that "owns"
1053  * the account.
1054  *
1055  * Returns: (transfer container) (element-type utf8 GObject.Value): additional
1056  *  storage-specific information
1057  */
1058 GHashTable *
mcp_account_storage_get_additional_info(const McpAccountStorage * storage,const gchar * account)1059 mcp_account_storage_get_additional_info (const McpAccountStorage *storage,
1060     const gchar *account)
1061 {
1062   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
1063   GHashTable *ret = NULL;
1064 
1065   SDEBUG (storage, "");
1066   g_return_val_if_fail (iface != NULL, FALSE);
1067 
1068   if (iface->get_additional_info != NULL)
1069     ret = iface->get_additional_info (storage, account);
1070 
1071   if (ret == NULL)
1072     ret = g_hash_table_new (g_str_hash, g_str_equal);
1073 
1074   return ret;
1075 }
1076 
1077 /**
1078  * McpAccountStorageGetRestrictionsFunc
1079  * @storage: an #McpAccountStorage instance
1080  * @account: the unique name of the account
1081  *
1082  * An implementation of mcp_account_storage_get_restrictions().
1083  *
1084  * Returns: any restrictions that apply to this account.
1085  */
1086 
1087 /**
1088  * mcp_account_storage_get_restrictions:
1089  * @storage: an #McpAccountStorage instance
1090  * @account: the unique name of the account
1091  *
1092  * This method will only be called for the storage plugin that "owns"
1093  * the account.
1094  *
1095  * Returns: a bitmask of %TpStorageRestrictionFlags with the restrictions to
1096  *  account storage.
1097  */
1098 /* FIXME: when breaking API, make this return TpStorageRestrictionFlags */
1099 guint
mcp_account_storage_get_restrictions(const McpAccountStorage * storage,const gchar * account)1100 mcp_account_storage_get_restrictions (const McpAccountStorage *storage,
1101     const gchar *account)
1102 {
1103   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
1104 
1105   g_return_val_if_fail (iface != NULL, 0);
1106 
1107   if (iface->get_restrictions == NULL)
1108     return 0;
1109   else
1110     return iface->get_restrictions (storage, account);
1111 }
1112 
1113 /**
1114  * mcp_account_storage_name:
1115  * @storage: an #McpAccountStorage instance
1116  *
1117  * <!-- nothing else to say -->
1118  *
1119  * Returns: the plugin's name (for logging etc)
1120  */
1121 const gchar *
mcp_account_storage_name(const McpAccountStorage * storage)1122 mcp_account_storage_name (const McpAccountStorage *storage)
1123 {
1124   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
1125 
1126   g_return_val_if_fail (iface != NULL, NULL);
1127 
1128   return iface->name;
1129 }
1130 
1131 /**
1132  * mcp_account_storage_description:
1133  * @storage: an #McpAccountStorage instance
1134  *
1135  * <!-- nothing else to say -->
1136  *
1137  * Returns: the plugin's description (for logging etc)
1138  */
1139 const gchar *
mcp_account_storage_description(const McpAccountStorage * storage)1140 mcp_account_storage_description (const McpAccountStorage *storage)
1141 {
1142   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
1143 
1144   g_return_val_if_fail (iface != NULL, NULL);
1145 
1146   return iface->desc;
1147 }
1148 
1149 /**
1150  * mcp_account_storage_provider:
1151  * @storage: an #McpAccountStorage instance
1152  *
1153  * <!-- nothing else to say -->
1154  *
1155  * Returns: a D-Bus namespaced name for this plugin, or "" if none
1156  *  was provided in #McpAccountStorageIface.provider.
1157  */
1158 const gchar *
mcp_account_storage_provider(const McpAccountStorage * storage)1159 mcp_account_storage_provider (const McpAccountStorage *storage)
1160 {
1161   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
1162 
1163   g_return_val_if_fail (iface != NULL, NULL);
1164 
1165   return iface->provider != NULL ? iface->provider : "";
1166 }
1167 
1168 /**
1169  * mcp_account_storage_emit_create:
1170  * @storage: an #McpAccountStorage instance
1171  * @account: the unique name of the created account
1172  *
1173  * Emits the #McpAccountStorage::created signal.
1174  */
1175 void
mcp_account_storage_emit_created(McpAccountStorage * storage,const gchar * account)1176 mcp_account_storage_emit_created (McpAccountStorage *storage,
1177     const gchar *account)
1178 {
1179   g_signal_emit (storage, signals[CREATED], 0, account);
1180 }
1181 
1182 /**
1183  * mcp_account_storage_emit_altered:
1184  * @storage: an #McpAccountStorage instance
1185  * @account: the unique name of the altered account
1186  *
1187  * Emits the #McpAccountStorage::altered signal
1188  */
1189 void
mcp_account_storage_emit_altered(McpAccountStorage * storage,const gchar * account)1190 mcp_account_storage_emit_altered (McpAccountStorage *storage,
1191     const gchar *account)
1192 {
1193   g_signal_emit (storage, signals[ALTERED], 0, account);
1194 }
1195 
1196 /**
1197  * mcp_account_storage_emit_altered_one:
1198  * @storage: an #McpAccountStorage instance
1199  * @account: the unique name of the altered account
1200  * @key: the key of the altered property: either an attribute name
1201  *  like "DisplayName", or "param-" plus a parameter name like "account"
1202  *
1203  * Emits the #McpAccountStorage::altered-one signal
1204  */
1205 void
mcp_account_storage_emit_altered_one(McpAccountStorage * storage,const gchar * account,const gchar * key)1206 mcp_account_storage_emit_altered_one (McpAccountStorage *storage,
1207     const gchar *account,
1208     const gchar *key)
1209 {
1210   g_signal_emit (storage, signals[ALTERED_ONE], 0, account, key);
1211 }
1212 
1213 /**
1214  * mcp_account_storage_emit_deleted:
1215  * @storage: an #McpAccountStorage instance
1216  * @account: the unique name of the deleted account
1217  *
1218  * Emits the #McpAccountStorage::deleted signal
1219  */
1220 void
mcp_account_storage_emit_deleted(McpAccountStorage * storage,const gchar * account)1221 mcp_account_storage_emit_deleted (McpAccountStorage *storage,
1222     const gchar *account)
1223 {
1224   g_signal_emit (storage, signals[DELETED], 0, account);
1225 }
1226 
1227 /**
1228  * mcp_account_storage_emit_toggled:
1229  * @storage: an #McpAccountStorage instance
1230  * @account: the unique name of the account
1231  * @enabled: %TRUE if the account is now enabled
1232  *
1233  * Emits ::toggled signal
1234  */
1235 void
mcp_account_storage_emit_toggled(McpAccountStorage * storage,const gchar * account,gboolean enabled)1236 mcp_account_storage_emit_toggled (McpAccountStorage *storage,
1237     const gchar *account,
1238     gboolean enabled)
1239 {
1240   g_signal_emit (storage, signals[TOGGLED], 0, account, enabled);
1241 }
1242 
1243 /**
1244  * mcp_account_storage_emit_reconnect:
1245  * @storage: an #McpAccountStorage instance
1246  * @account: the unique name of the account to reconnect
1247  *
1248  * Emits ::reconnect signal
1249  */
1250 void
mcp_account_storage_emit_reconnect(McpAccountStorage * storage,const gchar * account)1251 mcp_account_storage_emit_reconnect (McpAccountStorage *storage,
1252     const gchar *account)
1253 {
1254   g_signal_emit (storage, signals[RECONNECT], 0, account);
1255 }
1256 
1257 /**
1258  * mcp_account_storage_owns:
1259  * @storage: an #McpAccountStorage instance
1260  * @am: an #McpAccountManager instance
1261  * @account: the unique name (object-path tail) of an account
1262  *
1263  * Check whether @account is stored in @storage. The highest-priority
1264  * plugin for which this function returns %TRUE is considered to be
1265  * responsible for @account.
1266  *
1267  * There is a default implementation, which calls mcp_account_storage_get()
1268  * for the well-known key "manager".
1269  *
1270  * Returns: %TRUE if @account is stored in @storage
1271  *
1272  * Since: 5.15.0
1273  */
1274 gboolean
mcp_account_storage_owns(McpAccountStorage * storage,McpAccountManager * am,const gchar * account)1275 mcp_account_storage_owns (McpAccountStorage *storage,
1276     McpAccountManager *am,
1277     const gchar *account)
1278 {
1279   McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
1280 
1281   g_return_val_if_fail (iface != NULL, FALSE);
1282   g_return_val_if_fail (iface->owns != NULL, FALSE);
1283 
1284   return iface->owns (storage, am, account);
1285 }
1286