Bug 27727 - account storage plugins can contain partial accounts
Summary: account storage plugins can contain partial accounts
Status: RESOLVED FIXED
Alias: None
Product: Telepathy
Classification: Unclassified
Component: mission-control (show other bugs)
Version: git master
Hardware: Other All
: medium normal
Assignee: Simon McVittie
QA Contact: Telepathy bugs list
URL: http://cgit.freedesktop.org/~smcv/tel...
Whiteboard: review?
Keywords: patch
Depends on: 74185
Blocks: 71093
  Show dependency treegraph
 
Reported: 2010-04-18 13:51 UTC by Tomeu Vizoso
Modified: 2014-01-30 12:37 UTC (History)
2 users (show)

See Also:
i915 platform:
i915 features:


Attachments
debug log (179.41 KB, text/plain)
2010-04-18 13:51 UTC, Tomeu Vizoso
Details
01/26] Remove all notion of secret parameter (16.27 KB, patch)
2013-11-14 18:11 UTC, Simon McVittie
Details | Splinter Review
02/26] McpAccountStorage: merge commit and commit_one into one function (11.71 KB, patch)
2013-11-14 18:11 UTC, Simon McVittie
Details | Splinter Review
03/26] Remove mcp_account_storage_set() (13.85 KB, patch)
2013-11-14 18:12 UTC, Simon McVittie
Details | Splinter Review
04/26] mcp_account_storage_emit_created: fix doc-comment (897 bytes, patch)
2013-11-14 18:12 UTC, Simon McVittie
Details | Splinter Review
05/26] McpAccountStorage: have a default implementation for every method (10.55 KB, patch)
2013-11-14 18:12 UTC, Simon McVittie
Details | Splinter Review
06/26] Remove unused code (10.97 KB, patch)
2013-11-14 18:13 UTC, Simon McVittie
Details | Splinter Review
07/26] mcp_account_manager_list_keys: remove (4.04 KB, patch)
2013-11-14 18:13 UTC, Simon McVittie
Details | Splinter Review
08/26] mcd_storage_dup_attributes: remove (2.14 KB, patch)
2013-11-14 18:13 UTC, Simon McVittie
Details | Splinter Review
09/26] mcd_account_delete: be primarily responsible for emitting Removed (2.04 KB, patch)
2013-11-14 18:13 UTC, Simon McVittie
Details | Splinter Review
10/26] mcd_account_delete: convert into mcd_account_delete_async (9.37 KB, patch)
2013-11-14 18:14 UTC, Simon McVittie
Details | Splinter Review
11/26] mc-debug-server: don't exit when disconnected from system bus (1.59 KB, patch)
2013-11-14 18:14 UTC, Simon McVittie
Details | Splinter Review
12/26] McdStorage: adjust IdentifyAccount error behaviour (2.20 KB, patch)
2013-11-14 18:14 UTC, Simon McVittie
Details | Splinter Review
13/26] Add some missing test coverage: IdentifyAccount failing hard (3.98 KB, patch)
2013-11-14 18:15 UTC, Simon McVittie
Details | Splinter Review
14/26] McdAccountManager: don't double-delete accounts from storage (1.33 KB, patch)
2013-11-14 18:15 UTC, Simon McVittie
Details | Splinter Review
15/26] Call set_attribute, set_parameter to delete them (10.03 KB, patch)
2013-11-14 18:15 UTC, Simon McVittie
Details | Splinter Review
16/26] Make account deletion async (sort of), and imply a selective commit (27.33 KB, patch)
2013-11-14 18:16 UTC, Simon McVittie
Details | Splinter Review
17/26] Make mcp_account_storage_create() mandatory (14.79 KB, patch)
2013-11-14 18:16 UTC, Simon McVittie
Details | Splinter Review
18/26] McdStorage: remove "owns" method (6.15 KB, patch)
2013-11-14 18:16 UTC, Simon McVittie
Details | Splinter Review
19/26] mcp_account_storage_set_*: return whether anything changed (21.39 KB, patch)
2013-11-14 18:17 UTC, Simon McVittie
Details | Splinter Review
20/26] Thread expected GVariant types through to mcd_storage_get_* (16.91 KB, patch)
2013-11-14 18:17 UTC, Simon McVittie
Details | Splinter Review
21/26] mcp_account_manager_unescape_variant_from_keyfile: add (4.52 KB, patch)
2013-11-14 18:17 UTC, Simon McVittie
Details | Splinter Review
22/26] dbus-account-plugin: update internal cache correctly (1.19 KB, patch)
2013-11-14 18:18 UTC, Simon McVittie
Details | Splinter Review
23/26] mcp_account_storage_get: replace with get_attribute, get_parameter (48.03 KB, patch)
2013-11-14 18:18 UTC, Simon McVittie
Details | Splinter Review
24/26] McdStorage: when acting on one account, only store it in its plugin (4.21 KB, patch)
2013-11-14 18:18 UTC, Simon McVittie
Details | Splinter Review
25/26] McdAccount: have a ref to the storage plugin from construct time onwards (18.55 KB, patch)
2013-11-14 18:18 UTC, Simon McVittie
Details | Splinter Review
[26/26] McdAccountManager: ignore altered-one, deleted, toggled from wrong plugin (3.31 KB, patch)
2013-11-14 18:19 UTC, Simon McVittie
Details | Splinter Review
diff between master-without-all-revert and Simon's branch (162.00 KB, patch)
2013-11-14 20:48 UTC, Xavier Claessens
Details | Splinter Review

Description Tomeu Vizoso 2010-04-18 13:51:20 UTC
Created attachment 35148 [details]
debug log

Don't even have an object path, so when we get the ValidAccounts or InvalidAccounts, we put NULL values there and libdbus crashes when marshalling.

Attaching debug logs
Comment 2 Simon McVittie 2010-04-30 07:19:46 UTC
Regarding keyring-suppress-incomplete-accounts, the virtual method should be called "has_account".

keyring-suppress-incomplete-accounts-B looks OK, although there's a lot of code churn so it's hard to see how much is original.

Sjoerd had some quite strong opinions about this, so I'll talk to him when he's next in the office about which branch to use...
Comment 3 Simon McVittie 2010-05-26 06:47:08 UTC
The symptom has been fixed independently of those branches (by having the keyfile and gnome-keyring plugins not be independent), so the remaining bug here is: although in practice accounts are no longer split between plugins by any existing plugin, the API doesn't guarantee that accounts won't get split in this way. Vivek will fix the API eventually.
Comment 4 Simon McVittie 2013-11-07 17:16:11 UTC
(In reply to comment #3)
> Vivek will fix the API eventually.

[citation needed]

Xavier might be doing this, though; we've just broken plugin ABI, so it seems a good time.
Comment 5 Simon McVittie 2013-11-14 18:11:35 UTC
Created attachment 89208 [details] [review]
01/26] Remove all notion of secret parameter

From: Xavier Claessens <xavier.claessens@collabora.co.uk>

We now depend on SASLAuthentication for handling secret, and MC
does not have gnome-keyring anymore.

[Adjusted to apply before other storage API changes -smcv]
Comment 6 Simon McVittie 2013-11-14 18:11:51 UTC
Created attachment 89209 [details] [review]
02/26] McpAccountStorage: merge commit and commit_one into one  function

Based on part of a patch by Xavier Claessens.
Comment 7 Simon McVittie 2013-11-14 18:12:16 UTC
Created attachment 89210 [details] [review]
03/26] Remove mcp_account_storage_set()

_set_attribute() and _set_parameter() are now mandatory for writable
storage plugins.

Note that most of the keyfile escaping code is still needed to help
plugins to read their old keyfile values.

[adjusted to apply earlier in the branch; left in the code that
detects whether mcd_storage_set_parameter() is a no-op for an
escaped parameter; took out mcp_account_storage_emit_created
documentation fix -smcv]
Comment 8 Simon McVittie 2013-11-14 18:12:32 UTC
Created attachment 89211 [details] [review]
04/26] mcp_account_storage_emit_created: fix doc-comment

Originally part of a commit by Xavier Claessens.
Comment 9 Simon McVittie 2013-11-14 18:12:49 UTC
Created attachment 89212 [details] [review]
05/26] McpAccountStorage: have a default implementation for  every method

Based on a patch by Xavier Claessens.
Comment 10 Simon McVittie 2013-11-14 18:13:04 UTC
Created attachment 89213 [details] [review]
06/26] Remove unused code

[adjusted to apply at a different position in the branch -smcv]
Comment 11 Simon McVittie 2013-11-14 18:13:21 UTC
Created attachment 89214 [details] [review]
07/26] mcp_account_manager_list_keys: remove

This is unused, and plugins don't have any good reason to call it.
Comment 12 Simon McVittie 2013-11-14 18:13:40 UTC
Created attachment 89215 [details] [review]
08/26] mcd_storage_dup_attributes: remove

Nothing calls it, and getting rid of it is a step towards having
McdStorage just be a "view".
Comment 13 Simon McVittie 2013-11-14 18:13:57 UTC
Created attachment 89216 [details] [review]
09/26] mcd_account_delete: be primarily responsible for  emitting Removed

We still don't get here if disposed early, though.
Comment 14 Simon McVittie 2013-11-14 18:14:20 UTC
Created attachment 89217 [details] [review]
10/26] mcd_account_delete: convert into  mcd_account_delete_async
Comment 15 Simon McVittie 2013-11-14 18:14:37 UTC
Created attachment 89218 [details] [review]
11/26] mc-debug-server: don't exit when disconnected from  system bus

The session bus is our fake system bus, too. We exit when libdbus tells
us we have disconnected, and ignore both the possible ways in which
GDBus can kill us, in order to get coverage stats.
Comment 16 Simon McVittie 2013-11-14 18:14:55 UTC
Created attachment 89219 [details] [review]
12/26] McdStorage: adjust IdentifyAccount error behaviour

We were ignoring failures if they were NotImplemented or ServiceUnknown,
but thinking about it more, we should probably ignore "most" errors
here: the only errors that should abort the account-creation attempt
are those that indicate that the intended parameters are unusable,
namely InvalidArgument and InvalidHandle (in its secondary role as
"invalid identifier-that-corresponds-to-a-handle").
Comment 17 Simon McVittie 2013-11-14 18:15:08 UTC
Created attachment 89220 [details] [review]
13/26] Add some missing test coverage: IdentifyAccount failing  hard
Comment 18 Simon McVittie 2013-11-14 18:15:26 UTC
Created attachment 89221 [details] [review]
14/26] McdAccountManager: don't double-delete accounts from  storage

McdAccount (via mcd_account_delete_async) is responsible for deleting
itself from storage if necessary. McdAccountManager shouldn't
second-guess it.
Comment 19 Simon McVittie 2013-11-14 18:15:54 UTC
Created attachment 89222 [details] [review]
15/26] Call set_attribute, set_parameter to delete them

It really doesn't make a great deal of sense to use the same callback
to delete individual keys, and to delete accounts.

McdAccountManagerDefault already dealt with that case, but
the two test plugins didn't.
Comment 20 Simon McVittie 2013-11-14 18:16:16 UTC
Created attachment 89223 [details] [review]
16/26] Make account deletion async (sort of), and imply a  selective commit

This means we don't need to commit separately after each deletion,
and means account plugins don't have to have the concept of flagging
an account for "delete this later" - much rejoicing.

It also has the incidental benefit that we no longer use the C++
reserved word 'delete' in a header file.
Comment 21 Simon McVittie 2013-11-14 18:16:33 UTC
Created attachment 89224 [details] [review]
17/26] Make mcp_account_storage_create() mandatory

This means we can (finally) track which plugin "owns" which account
in a reliable way.
Comment 22 Simon McVittie 2013-11-14 18:16:49 UTC
Created attachment 89225 [details] [review]
18/26] McdStorage: remove "owns" method

We now know whose account it is, without having to do this.
Comment 23 Simon McVittie 2013-11-14 18:17:07 UTC
Created attachment 89226 [details] [review]
19/26] mcp_account_storage_set_*: return whether anything  changed

The plugins are better-placed to do this than McdStorage: they know
their own storage format, after all.
Comment 24 Simon McVittie 2013-11-14 18:17:25 UTC
Created attachment 89227 [details] [review]
20/26] Thread expected GVariant types through to  mcd_storage_get_*

We're going to need this soon, in order to advise plugins how best
to unescape the value. The result is still a GValue, for now.
Comment 25 Simon McVittie 2013-11-14 18:17:40 UTC
Created attachment 89228 [details] [review]
21/26] mcp_account_manager_unescape_variant_from_keyfile: add

I want to push responsibility for unescaping into storage plugins.
Comment 26 Simon McVittie 2013-11-14 18:18:05 UTC
Created attachment 89229 [details] [review]
22/26] dbus-account-plugin: update internal cache correctly

The backend-makes-changes test replaces an typed parameter with an
untyped parameter. We correctly signalled the change to MC,
but didn't update the internal cache; the rather strange way in
which MC receives attributes/parameters masked this bug.
Comment 27 Simon McVittie 2013-11-14 18:18:23 UTC
Created attachment 89230 [details] [review]
23/26] mcp_account_storage_get: replace with get_attribute,  get_parameter

The old API in which plugins poked new values into the McdStorage
was non-obvious, and also fundamentally incompatible with the idea
that each account is owned by at most one plugin: if an account
in a high-priority plugin is masked by one in a low-priority plugin,
the McdStorage can't prevent the low-priority plugin from changing
its effective attribute and parameter values.
Comment 28 Simon McVittie 2013-11-14 18:18:38 UTC
Created attachment 89231 [details] [review]
24/26] McdStorage: when acting on one account, only store it  in its plugin
Comment 29 Simon McVittie 2013-11-14 18:18:55 UTC
Created attachment 89232 [details] [review]
25/26] McdAccount: have a ref to the storage plugin from  construct time onwards

This will make the account more self-contained.
Comment 30 Simon McVittie 2013-11-14 18:19:18 UTC
Created attachment 89233 [details] [review]
[26/26] McdAccountManager: ignore altered-one, deleted, toggled  from wrong plugin

Now that the account knows its own storage plugin, this is pretty easy.
Comment 31 Xavier Claessens 2013-11-14 19:11:59 UTC
(In reply to comment #9)
> Created attachment 89212 [details] [review] [review]
> 05/26] McpAccountStorage: have a default implementation for  every method
> 
> Based on a patch by Xavier Claessens.

I don't think we want default implementation for list() and get(), they are still needed for any useful storage, no?
Comment 32 Xavier Claessens 2013-11-14 19:20:30 UTC
(In reply to comment #14)
> Created attachment 89217 [details] [review] [review]
> 10/26] mcd_account_delete: convert into  mcd_account_delete_async

migrate_delete_account_cb() looks weird, why don't you put directly mcd_account_delete_debug_cb as callback and free the MigrateCtx before the async call?

While we are adding async API, why omitting the GCancellable? I think you can just have one and put it on your GTask, it will do the right thing for you.
Comment 33 Xavier Claessens 2013-11-14 19:23:41 UTC
(In reply to comment #15)
> Created attachment 89218 [details] [review] [review]
> 11/26] mc-debug-server: don't exit when disconnected from  system bus
> 
> The session bus is our fake system bus, too. We exit when libdbus tells
> us we have disconnected, and ignore both the possible ways in which
> GDBus can kill us, in order to get coverage stats.

Not sure to understand why MC would ever create a system bus, modules doing it behind our back? You can also just use g_assert_no_error() instead of more complex error handling, no?
Comment 34 Xavier Claessens 2013-11-14 19:46:57 UTC
(In reply to comment #20)
> Created attachment 89223 [details] [review] [review]
> 16/26] Make account deletion async (sort of), and imply a  selective commit
> 
> This means we don't need to commit separately after each deletion,
> and means account plugins don't have to have the concept of flagging
> an account for "delete this later" - much rejoicing.
> 
> It also has the incidental benefit that we no longer use the C++
> reserved word 'delete' in a header file.

mcp_account_storage_delete_finish()'s doc should tell about the default implementation. Do we recommend to override _finish() when _async is overriden, or can we state that if _async is implemented using GTask then the default _finish is good? I can guess your answer on this, but better to say it explicitly in the doc, no?
Comment 35 Xavier Claessens 2013-11-14 19:58:52 UTC
(In reply to comment #21)
> Created attachment 89224 [details] [review] [review]
> 17/26] Make mcp_account_storage_create() mandatory
> 
> This means we can (finally) track which plugin "owns" which account
> in a reliable way.

In mcd_storage_add_account_from_plugin() I would keep the comment my branch adds:
/* This will fill our parameters/attributes tables */ because it's nowhere close to obvious.
Comment 36 Xavier Claessens 2013-11-14 20:18:07 UTC
Comment on attachment 89226 [details] [review]
19/26] mcp_account_storage_set_*: return whether anything  changed

Review of attachment 89226 [details] [review]:
-----------------------------------------------------------------

::: src/mcd-account-manager-default.c
@@ +182,3 @@
>  
> +      if (sa == NULL)
> +        return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;

I would make it g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED); because we are no longer setting on all backends. So when MC tells a plugin to set a value, the storage must know about that account.

@@ +194,5 @@
> +  else
> +    {
> +      GVariant *old;
> +
> +      sa = ensure_stored_account (amd, account);

ensure_stored_account() should only be called from _create(), right? Same as above, I would g_return_val_if_fail().

@@ +203,5 @@
> +          /* it might still be in untyped_parameters? */
> +          const gchar *escaped = g_hash_table_lookup (sa->untyped_parameters,
> +              parameter);
> +          gchar *new = mcp_account_manager_escape_variant_for_keyfile (
> +              am, val);

If we have an untyped param, now is a good time to move to to sa->parameters and consider that to be a change.

@@ +243,5 @@
> +    {
> +      sa = lookup_stored_account (amd, account);
> +
> +      if (sa == NULL)
> +        return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;

same as above, g_return_val_if_fail()

@@ +255,2 @@
>  
> +      sa = ensure_stored_account (amd, account);

same as above: s/ensure/lookup/ and g_return_val_if_fail()
Comment 37 Xavier Claessens 2013-11-14 20:48:50 UTC
Created attachment 89237 [details] [review]
diff between master-without-all-revert and Simon's branch

Easier to review than having to re-review the changes I already did.
Comment 38 Xavier Claessens 2013-11-14 21:54:38 UTC
Comment on attachment 89237 [details] [review]
diff between master-without-all-revert and Simon's branch

Review of attachment 89237 [details] [review]:
-----------------------------------------------------------------

Here is my full review, it repeat what I did in patch-by-patch, but add a few stuff I think.

::: mission-control-plugins/account-storage.c
@@ +59,1 @@
>   *   iface->delete = foo_plugin_delete;

Needs to be updated for delete_async/finish

@@ +157,2 @@
>  {
> +  return NULL;

I don't think we want a default for list()

@@ +207,5 @@
> +    const GVariantType *type,
> +    McpParameterFlags *flags)
> +{
> +  return NULL;
> +}

I'm not sure if we want a default for get_attribute/parameter. Does it make sense for any storage to have no attribute and/or no param?

@@ +470,3 @@
>   *
> + * There is a default implementation, which just returns %NULL.
> + * All account storage plugins must override this method.

If all plugins must override, better not have a default then, so we get a warn in g_return_val_if_fail (iface->get_attribute != NULL, FALSE); below.

@@ +508,5 @@
> + *
> + * Retrieve a parameter.
> + *
> + * There is a default implementation, which just returns %NULL.
> + * All account storage plugins must override this method.

likewise.

@@ -603,4 @@
>  {
>    McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
>  
> -  SDEBUG (storage, "");

why removing this debug? All other methods still have it.

@@ +739,3 @@
>   */
>  gboolean
> +mcp_account_storage_delete_finish (McpAccountStorage *storage,

Doc should tell about default implementation? Probably saying that it should not reply on it if _async() has been overridden. Or tell it's to not override if _async() uses a GTask?

::: src/mcd-account-manager-default.c
@@ +186,5 @@
> +
> +      sa = lookup_stored_account (amd, account);
> +
> +      if (sa == NULL)
> +        return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;

I would g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED); because MC now guarantees that it calls _set_parameter() on the right storage only.

@@ +200,5 @@
> +  else
> +    {
> +      GVariant *old;
> +
> +      sa = ensure_stored_account (amd, account);

ensure_stored_account() should be called only from _create().

I would do:

sa = lookup_stored_account (amd, account);
g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);

if (val == NULL)
  {
    ...
  }
else
  {
    ...
  }

@@ +214,5 @@
> +
> +          if (!tp_strdiff (escaped, new))
> +            {
> +              g_free (new);
> +              return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;

Can't we move the untyped param to sa->parameters now, and return MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED?

@@ +251,3 @@
>  
> +      if (sa == NULL)
> +        return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;

same as above

@@ +258,5 @@
>    else
>      {
> +      GVariant *old;
> +
> +      sa = ensure_stored_account (amd, account);

same as above

@@ +290,1 @@
>    if (sa == NULL || sa->absent)

Not sure what is sa->absent, but sa==NULL should be a g_return_val_if_fail (sa != NULL, NULL)

@@ +290,2 @@
>    if (sa == NULL || sa->absent)
>      return FALSE;

s/FALSE/NULL/

@@ +313,3 @@
>  
> +  if (sa == NULL || sa->absent)
> +    return FALSE;

same as above

@@ +366,5 @@
>    if (sa == NULL || sa->absent)
>      {
>        /* Apparently we never had this account anyway. The plugin API
>         * considers this to be "success". */
> +      g_task_return_boolean (task, TRUE);

Not sure... that would be a sign that something is broken in MC's representation of accounts. I would add a g_warning() but still return success for the operation because there is no reason to fail the dbus call initiated from client side.

@@ +392,2 @@
>  
> +  for (iter = g_get_system_data_dirs ();

we have distro-installed accounts?

@@ +422,5 @@
>      }
>  
> +  /* clean up the mess */
> +  g_hash_table_remove (amd->accounts, account);
> +  mcp_account_storage_emit_deleted (self, account);

I'm not sure, but shouldn't this be under the finally: ?

::: src/mcd-account-manager.c
@@ +294,5 @@
> +    }
> +    else
> +    {
> +        WARNING ("%s", error->message);
> +        goto finish;

error is leaked

@@ +1233,5 @@
>      DEBUG ("Account %s migrated, removing it",
>             mcd_account_get_unique_name (ctx->account));
>  
> +    mcd_account_delete_async (ctx->account, MCD_DBUS_PROP_SET_FLAG_NONE,
> +                              migrate_delete_account_cb, ctx);

Free ctx from here and use mcd_account_delete_debug_cb

::: src/mcd-storage.c
@@ +505,1 @@
>    while (store != NULL)

Now that we have a normal loop, I think it would look even better with:
for (store = stores; store != NULL; store = store->next)

@@ +547,2 @@
>  {
> +  return g_hash_table_ref (self->accounts);

tbh the ref here is just asking for leaks. Either deep-copy or return internal pointer with (transfer none).

@@ +1274,4 @@
>      }
>    else
>      {
> +      g_assert_not_reached ();

isn't it easier to have g_return_val_if_fail(plugin != NULL, FALSE); to remove a big if block?

@@ +1782,5 @@
> +
> +  if (mcp_account_storage_delete_finish (MCP_ACCOUNT_STORAGE (source),
> +        res, &error))
> +    {
> +      DEBUG ("deleted account %s", (const gchar *) user_data);

I would add a gchar *account_name = user_data; declaration.

@@ +1956,5 @@
> +    const gchar *escaped,
> +    const GVariantType *type,
> +    GError **error)
> +{
> +  return mcd_keyfile_unescape_variant (escaped, type, error);

That function can be inlined here, it's the only user.
Comment 39 Simon McVittie 2013-11-15 12:34:38 UTC
(In reply to comment #31)
> > 05/26] McpAccountStorage: have a default implementation for  every method
> > 
> > Based on a patch by Xavier Claessens.
> 
> I don't think we want default implementation for list() and get(), they are
> still needed for any useful storage, no?

Fair point. I can delete the default implementations for things that any useful plugin must override, if you'd prefer.

I think that means:

* list
* owns (but I deleted that later in the branch anyway)
* get (but I deleted that later)
* get_attribute (must be able to get at least "manager" and "protocol")
* get_parameter (well I suppose in theory a CM might not need parameters but... no)

(In reply to comment #32)
> (In reply to comment #14)
> > 10/26] mcd_account_delete: convert into  mcd_account_delete_async
> 
> migrate_delete_account_cb() looks weird, why don't you put directly
> mcd_account_delete_debug_cb as callback and free the MigrateCtx before the
> async call?

Because migrate_ctx_free() isn't 100% a free-function: it also releases a "lock" that prevents MC from saying it's ready until all migrations have completed.

> While we are adding async API, why omitting the GCancellable? I think you
> can just have one and put it on your GTask, it will do the right thing for
> you.

Hmm. I'm not sure what our rule should be on this: you can't *actually* cancel deletion of an account, only the callback. Then again, g_dbus_connection_call() takes a cancellable, and "send a D-Bus message" is pretty much the archetype of things you can't cancel, so... yeah, OK, you're right.

(In reply to comment #33)
> Not sure to understand why MC would ever create a system bus, modules doing
> it behind our back?

GNetworkMonitor might use the system bus, and McdConnectivityMonitor certainly does (to (try to) talk to systemd-logind).

> You can also just use g_assert_no_error() instead of
> more complex error handling, no?

Yeah, I suppose so, since it's just for the tests.

(In reply to comment #34)
> mcp_account_storage_delete_finish()'s doc should tell about the default
> implementation.

Sure.

> Do we recommend to override _finish() when _async is
> overriden, or can we state that if _async is implemented using GTask then
> the default _finish is good? I can guess your answer on this, but better to
> say it explicitly in the doc, no?

I think we should say you have to override neither or both: in some older Telepathy APIs we had "the default uses a GSimpleAsyncResult", and now we're regretting that because of GTask :-)

(In reply to comment #35)
> > 17/26] Make mcp_account_storage_create() mandatory
> 
> In mcd_storage_add_account_from_plugin() I would keep the comment my branch
> adds:
> /* This will fill our parameters/attributes tables */ because it's nowhere
> close to obvious.

OK, but only if I'm rebasing these changes in - later in the branch, that strange setup disappears anyway.
Comment 40 Simon McVittie 2013-11-15 12:55:15 UTC
(In reply to comment #38)
> ::: mission-control-plugins/account-storage.c
> @@ +59,1 @@
> >   *   iface->delete = foo_plugin_delete;
> 
> Needs to be updated for delete_async/finish

Yeah.

> I don't think we want a default for list()
...
> I'm not sure if we want a default for get_attribute/parameter. Does it make
> sense for any storage to have no attribute and/or no param?

Already noted

> @@ -603,4 @@
> >  {
> >    McpAccountStorageIface *iface = MCP_ACCOUNT_STORAGE_GET_IFACE (storage);
> >  
> > -  SDEBUG (storage, "");
> 
> why removing this debug? All other methods still have it.

Your "simplify a bit plugin API" added it, so it was lost in the revert. I'll put it back.

> I would g_return_val_if_fail (sa != NULL,
> MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED); because MC now guarantees that it
> calls _set_parameter() on the right storage only.

Yeah, makes sense. Or I was wondering whether to change the signature of most McdStorage methods so they take the plugin as an argument, now that McdAccount always knows its own plugin; then we could get rid of McdStorage->accounts altogether.

> > +      GVariant *old;
> > +
> > +      sa = ensure_stored_account (amd, account);
> 
> ensure_stored_account() should be called only from _create().

Makes sense. I'll see whether the tests still pass...

> > +          if (!tp_strdiff (escaped, new))
> > +            {
> > +              g_free (new);
> > +              return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
> 
> Can't we move the untyped param to sa->parameters now, and return
> MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED?

One of the regression tests asserts that this won't be considered to be a write - but you're probably right, we should consider changing that test.

> >    if (sa == NULL || sa->absent)
> 
> Not sure what is sa->absent, but sa==NULL should be a g_return_val_if_fail
> (sa != NULL, NULL)

sa->absent means the account is an empty file in a "higher-priority" directory, created in order to "mask" an account in a "lower-priority" directory (because we can't/shouldn't write to lower-priority directories - see my answer to your query about g_get_system_data_dirs() below).

Yes, now that McdStorage tracks plugin "ownership" better, this sort of thing can turn into a g_return*if_fail. I'd prefer to append that to the branch rather than rebasing it into the middle, because we only got that guarantee a couple of commits from the end.

> @@ +290,2 @@
> >    if (sa == NULL || sa->absent)
> >      return FALSE;
> 
> s/FALSE/NULL/

Good point.

> @@ +366,5 @@
> >    if (sa == NULL || sa->absent)
> >      {
> >        /* Apparently we never had this account anyway. The plugin API
> >         * considers this to be "success". */
> > +      g_task_return_boolean (task, TRUE);
> 
> Not sure... that would be a sign that something is broken in MC's
> representation of accounts. I would add a g_warning() but still return
> success for the operation because there is no reason to fail the dbus call
> initiated from client side.

This does happen in the regression tests, now that delete_async is expected to emit ::deleted (which it naturally ought to, I think - I don't like signals that are emitted or not depending on the reason for a change). ::deleted ends up calling back into delete_async.

We might be able to get rid of that by obeying the "already in storage" flag better?

> @@ +392,2 @@
> >  
> > +  for (iter = g_get_system_data_dirs ();
> 
> we have distro-installed accounts?

I hope not, but that's not actually all that g_get_system_data_dirs() returns: it also returns anything the user has put in $XDG_DATA_DIRS. So for instance you could have:

    XDG_DATA_HOME=/home/me/.local/share
    XDG_DATA_DIRS=/nfs/home/me/.local/share:/usr/local/share:/usr/share

I realize that doesn't necessarily make a huge amount of sense for accounts either, but I think a lot of the value of the XDG base directories is that you can rely on them being the same everywhere, so I'd prefer to do this Right™.

> > +  /* clean up the mess */
> > +  g_hash_table_remove (amd->accounts, account);
> > +  mcp_account_storage_emit_deleted (self, account);
> 
> I'm not sure, but shouldn't this be under the finally: ?

No, I don't think it should. If we fail to unlink the file representing the account, and thus fail the async operation, I think we should continue to believe that the account exists. The McdAccount will continue to exist, too, and I don't think we want those getting out of sync.

> > +        WARNING ("%s", error->message);
> > +        goto finish;
> 
> error is leaked

Good catch, will fix.

> @@ +1233,5 @@
> >      DEBUG ("Account %s migrated, removing it",
> >             mcd_account_get_unique_name (ctx->account));
> >  
> > +    mcd_account_delete_async (ctx->account, MCD_DBUS_PROP_SET_FLAG_NONE,
> > +                              migrate_delete_account_cb, ctx);
> 
> Free ctx from here and use mcd_account_delete_debug_cb

As noted above: good guess, but no.

> ::: src/mcd-storage.c
> @@ +505,1 @@
> >    while (store != NULL)
> 
> Now that we have a normal loop, I think it would look even better with:
> for (store = stores; store != NULL; store = store->next)

Yes.

> > +  return g_hash_table_ref (self->accounts);
> 
> tbh the ref here is just asking for leaks. Either deep-copy or return
> internal pointer with (transfer none).

OK, if you say so.

> isn't it easier to have g_return_val_if_fail(plugin != NULL, FALSE); to
> remove a big if block?

I didn't want to re-indent too much, to avoid making review even harder than it was already going to be. I'll fix the coding style next.

> > +  if (mcp_account_storage_delete_finish (MCP_ACCOUNT_STORAGE (source),
> > +        res, &error))
> > +    {
> > +      DEBUG ("deleted account %s", (const gchar *) user_data);
> 
> I would add a gchar *account_name = user_data; declaration.

Reasonable.

> @@ +1956,5 @@
> > +    const gchar *escaped,
> > +    const GVariantType *type,
> > +    GError **error)
> > +{
> > +  return mcd_keyfile_unescape_variant (escaped, type, error);
> 
> That function can be inlined here, it's the only user.

It is? OK, fine. I think MC used it internally in some intermediate version of this branch.
Comment 41 Simon McVittie 2013-11-15 13:27:17 UTC
http://cgit.freedesktop.org/~smcv/telepathy-mission-control/log/?h=account-rework-27727-round2 fixes some of the simpler things you pointed out. Still looking into the more involved stuff.
Comment 42 Xavier Claessens 2013-11-15 14:57:56 UTC
round2 looks good so far.
Comment 43 Simon McVittie 2013-11-15 18:04:15 UTC
I think <http://cgit.freedesktop.org/~smcv/telepathy-mission-control/log/?h=account-rework-27727-round3> fixes all your review comments.
Comment 44 Simon McVittie 2013-11-15 18:13:33 UTC
Looks as though there are still a couple of things I missed.

(In reply to comment #32)
> migrate_delete_account_cb() looks weird, why don't you put directly
> mcd_account_delete_debug_cb as callback and free the MigrateCtx before the
> async call?

Not done, I explained why above.

> While we are adding async API, why omitting the GCancellable? I think you
> can just have one and put it on your GTask, it will do the right thing for
> you.

Done.

(In reply to comment #33)
> Not sure to understand why MC would ever create a system bus, modules doing
> it behind our back?

I explained why above.

> You can also just use g_assert_no_error() instead of
> more complex error handling, no?

Done.

(In reply to comment #34)
> mcp_account_storage_delete_finish()'s doc should tell about the default
> implementation.

I said in delete_async that if you override one, you need to override both. Is that sufficient?

(In reply to comment #35)
> In mcd_storage_add_account_from_plugin() I would keep the comment my branch
> adds:
> /* This will fill our parameters/attributes tables */ because it's nowhere
> close to obvious.

The relevant code went away, so, not needed.

(In reply to comment #36)
> I would make it g_return_val_if_fail (sa != NULL,
> MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED); because we are no longer setting on
> all backends.

Done.

> ensure_stored_account() should only be called from _create(), right? Same as
> above, I would g_return_val_if_fail().

Done; it's only called from create() and load() now.

> If we have an untyped param, now is a good time to move to to sa->parameters
> and consider that to be a change.

**** not done yet ****

> > +      if (sa == NULL)
> > +        return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
> 
> same as above, g_return_val_if_fail()

Done

> > +      sa = ensure_stored_account (amd, account);
> 
> same as above: s/ensure/lookup/ and g_return_val_if_fail()

Done

(In reply to comment #38)
> >   *   iface->delete = foo_plugin_delete;
> 
> Needs to be updated for delete_async/finish

Done

> I don't think we want a default for list()

Fixed

> I'm not sure if we want a default for get_attribute/parameter

Deleted

> If all plugins must override, better not have a default then

Fixed

> > + * All account storage plugins must override this method.
> 
> likewise.

Fixed

> why removing this debug? All other methods still have it.

Added (and improved)

> Doc should tell about default implementation? Probably saying that it should
> not reply on it if _async() has been overridden.

Done

> I would g_return_val_if_fail (sa != NULL,
> MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED); because MC now guarantees that it
> calls _set_parameter() on the right storage only.

Done

> ensure_stored_account() should be called only from _create().

Done (well, it's also called from load())

> sa = lookup_stored_account (amd, account);
> g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
> 
> if (val == NULL)
>   {
>     ...
>   }
> else
>   {
>     ...
>   }

**** not yet done ****

> Can't we move the untyped param to sa->parameters now, and return
> MCP_ACCOUNT_STORAGE_SET_RESULT_CHANGED?

**** not yet done ****

> > +      if (sa == NULL)
> > +        return MCP_ACCOUNT_STORAGE_SET_RESULT_UNCHANGED;
> 
> same as above

Done

> > +      sa = ensure_stored_account (amd, account);
> 
> same as above

Done

> >    if (sa == NULL || sa->absent)
> 
> Not sure what is sa->absent, but sa==NULL should be a g_return_val_if_fail
> (sa != NULL, NULL)

Done

> >    if (sa == NULL || sa->absent)
> >      return FALSE;
> 
> s/FALSE/NULL/

I think I fixed all these, let me know if there are more

> >        /* Apparently we never had this account anyway. The plugin API
> >         * considers this to be "success". */
> > +      g_task_return_boolean (task, TRUE);
> 
> Not sure... that would be a sign that something is broken in MC's
> representation of accounts

Fixed!

> @@ +392,2 @@
> >  
> > +  for (iter = g_get_system_data_dirs ();
> 
> we have distro-installed accounts?

Explained above, no action taken

> > +  /* clean up the mess */
> > +  g_hash_table_remove (amd->accounts, account);
> > +  mcp_account_storage_emit_deleted (self, account);
> 
> I'm not sure, but shouldn't this be under the finally

Explained above why not

> > +        WARNING ("%s", error->message);
> > +        goto finish;
> 
> error is leaked

Fixed

> > +    mcd_account_delete_async (ctx->account, MCD_DBUS_PROP_SET_FLAG_NONE,
> > +                              migrate_delete_account_cb, ctx);
> 
> Free ctx from here and use mcd_account_delete_debug_cb

Explained why not

> Now that we have a normal loop, I think it would look even better with:
> for (store = stores; store != NULL; store = store->next)

Done

> tbh the ref here is just asking for leaks. Either deep-copy or return
> internal pointer with (transfer none).

Done, (transfer none)

> isn't it easier to have g_return_val_if_fail(plugin != NULL, FALSE); to
> remove a big if block?

Re-indented

> > +      DEBUG ("deleted account %s", (const gchar *) user_data);
> 
> I would add a gchar *account_name = user_data; declaration.

Done

> > +  return mcd_keyfile_unescape_variant (escaped, type, error);
> 
> That function can be inlined here, it's the only user.

Done
Comment 45 Simon McVittie 2013-11-15 18:17:58 UTC
Missing things are:

> If we have an untyped param, now is a good time to move to to sa->parameters
> and consider that to be a change.

It breaks a regression test, which is trying to assert that if you have an account in a low-priority location, just starting MC isn't enough to get it copied into a higher-priority location. The same test verifies that keyfile-escaped parameters (UntypedParameters) are unescaped correctly.

For that test to check what it's meant to check, I need to split it into "the one that is in a low-priority location" and "the one that has old-style parameters".

and...

> sa = lookup_stored_account (amd, account);
> g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
> 
> if (val == NULL)
>   {
>     ...
>   }
> else
>   {
>     ...
>   }

Which plugin is this? If it's McdAccountManagerDefault, I think I might have actually fixed that while fixing your other review feedback.
Comment 46 Xavier Claessens 2013-11-15 18:56:13 UTC
(In reply to comment #45)
> > sa = lookup_stored_account (amd, account);
> > g_return_val_if_fail (sa != NULL, MCP_ACCOUNT_STORAGE_SET_RESULT_FAILED);
> > 
> > if (val == NULL)
> >   {
> >     ...
> >   }
> > else
> >   {
> >     ...
> >   }
> 
> Which plugin is this? If it's McdAccountManagerDefault, I think I might have
> actually fixed that while fixing your other review feedback.

You fixed it already ;-)

0e7da13f3d4a1607372420fedca1124046b8716c _mcd_account_manager_setup:
Nitpicking: you iterate on hash table values, but the key is already the unique_name, no? so you could just take the key instead of calling mcd_account_get_unique_name().

The rest looks good to me.
Comment 47 Xavier Claessens 2013-11-15 19:01:10 UTC
a231756bd832064d531195656df1110c63575717, commit msg says: "We should never have get_something(), commit() with a non-NULL account"
s/non-// or s/never/always/ if I understand correctly, right?
Comment 48 Xavier Claessens 2013-11-20 21:09:32 UTC
Added 2 trivial patches on top of you -round3 branch:
http://cgit.collabora.com/git/user/xclaesse/telepathy-mission-control.git/log/?h=account-rework-27727-round3
Comment 49 Simon McVittie 2014-01-07 17:28:34 UTC
(In reply to comment #48)
> Added 2 trivial patches on top of you -round3 branch:
> http://cgit.collabora.com/git/user/xclaesse/telepathy-mission-control.git/
> log/?h=account-rework-27727-round3

They look fine.

Still to be done for this branch, then:

(In reply to comment #45)
> > If we have an untyped param, now is a good time to move to to sa->parameters
> > and consider that to be a change.
> 
> It breaks a regression test, which is trying to assert that if you have an
> account in a low-priority location, just starting MC isn't enough to get it
> copied into a higher-priority location. The same test verifies that
> keyfile-escaped parameters (UntypedParameters) are unescaped correctly.
> 
> For that test to check what it's meant to check, I need to split it into
> "the one that is in a low-priority location" and "the one that has old-style
> parameters".

Still to do

(In reply to comment #46)
> 0e7da13f3d4a1607372420fedca1124046b8716c _mcd_account_manager_setup:
> Nitpicking: you iterate on hash table values, but the key is already the
> unique_name, no? so you could just take the key instead of calling
> mcd_account_get_unique_name().

Yes, I think so. Still to do.

(In reply to comment #47)
> a231756bd832064d531195656df1110c63575717, commit msg says: "We should never
> have get_something(), commit() with a non-NULL account"
> s/non-// or s/never/always/ if I understand correctly, right?

No, I think I was right in the commit message. Read it as:

we should never have [any of]
  * get_something()
  * commit with a non-NULL account, or
  * set_something()
called on us while [either of]
  * inactive, or
  * with a nonexistent account

Here is (maybe) a better phrasing:

Methods that act on a single account should always be called with an account that actually exists - if it didn't, where did you get its name from? - so treat it as an error if they are called with a nonexistent account.

commit() has a dual role here: the method that takes a non-NULL account (which acts on a single account, as described) and the method that takes NULL for the account name (which is OK to call at any time, to commit all of our 0-or-more accounts).

While we are not active, we don't claim to have any accounts at all, so treat it as an error if any such method is called while inactive.

One exception (for now) is that it's less bad if delete_async() is called for an account that doesn't exist, because in that case, the desired state "that account doesn't exist" has already been reached. A later commit changes this to be an error.
Comment 50 Simon McVittie 2014-01-27 21:08:10 UTC
(In reply to comment #49)
> > For that test to check what it's meant to check, I need to split it into
> > "the one that is in a low-priority location" and "the one that has old-style
> > parameters".

Some progress on chopping up the tests:

http://cgit.freedesktop.org/~smcv/telepathy-mission-control/log/?h=account-rework-27727-round4

(rebased, commits since yours are new)

I haven't implemented automatic migration from untyped to typed parameters yet; that's next.

I also have a sketch of an Empathy GOA plugin that should be compilable against either 5.16 or "5.18" (this), although I haven't actually tried compiling it yet, much less using it!

> > Nitpicking: you iterate on hash table values, but the key is already the
> > unique_name, no? so you could just take the key instead of calling
> > mcd_account_get_unique_name().

Done, http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=4690efe7ecc874b1149f79118b4e9aa735d71b4e

> (In reply to comment #47)
> > a231756bd832064d531195656df1110c63575717, commit msg says: "We should never
> > have get_something(), commit() with a non-NULL account"
> > s/non-// or s/never/always/ if I understand correctly, right?

Rewrote the commit message to be clearer, I hope it's OK now?

http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=a240b95d030be02c9df1be3d7eb678e966ea60ac
Comment 51 Simon McVittie 2014-01-28 15:15:55 UTC
Added a commit to that MC branch, http://cgit.freedesktop.org/~smcv/telepathy-mission-control/log/?h=c9c370d972e8ee127e1a0bfd7e94a3f2244e4efa

I also have a proof-of-concept branch for Empathy's GOA backend, which I think demonstrates that for something that simple, it's entirely feasible to support both 5.16 and 5.18:

ssh://people.freedesktop.org/~smcv/empathy.git 38-mc-517
http://cgit.freedesktop.org/~smcv/empathy/log?h=38-mc-517 (when it updates)

so I don't think merging this needs to be blocked by implementations in Empathy or telepathy-ring.

For the more complex case of the UOA backend (also in Empathy), Xavier mentioned that he had an implementation.
Comment 52 Simon McVittie 2014-01-29 14:30:08 UTC
I think this is ready for review again:

http://cgit.freedesktop.org/~smcv/telepathy-mission-control/log/?h=d7b6b895f65

I'd also like to add more mandatory API to account storage plugins ("list keys", basically) but I'll do that on another bug.
Comment 53 Simon McVittie 2014-01-29 14:30:35 UTC
(In reply to comment #52)
> I think this is ready for review again:
> 
> http://cgit.freedesktop.org/~smcv/telepathy-mission-control/log/
> ?h=d7b6b895f65

The unreviewed commits are those since Xavier's last commit.
Comment 54 Simon McVittie 2014-01-29 19:45:14 UTC
Re-re-rebased this... tests pass after each commit now (assuming "fixup!" commits are squashed).

http://cgit.freedesktop.org/~smcv/telepathy-mission-control/log/?h=account-rework-27727-round4

Commits that have not been reviewed are:

* http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=a3521e21d9534bb169c4d5361537656af3b06376 fixes a compiler warning and is to be squashed into the previous

* http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=5633f3ae27a762444bb7a487abfd1f4b2aeacbaf fixes a compiler warning and is to be squashed into the previous

* http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=026cbb87190680f53a9a3382ed65f6e31cd9a4e5 fixes a compiler error and is to be squashed into the previous

* http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=8e5e39aa29a833be16598b2392539af07808a85d needed to be amended while rebasing

* so did http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=e7ba5a86df4e90ec334a4c8ff9a11f9305458e00

* commits since Xavier's "Be consistent in the constness of arguments" are new

The first two of those were fixed in one of Xavier's extra commits, but I moved them earlier in the branch.

It would be good if Xavier could look at <http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=eb7dc4a25c602de15f87fc63f56610ba5a7a05f8> and opine whether that rewritten commit message is enough to satisfy Comment #47. (No logic change, as described in Comment #49.)

My next thing on this topic is hopefully going to be Bug #71093.
Comment 55 Xavier Claessens 2014-01-30 02:51:26 UTC
It looks fine to me, nice work.

I'm not a big fan of the FIXME in http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/?h=account-rework-27727-round4&id=8e5e39aa29a833be16598b2392539af07808a85d, if we don't find the reason now we'll never do. otoh, it doesn't hurt to commit when in doubt. I'm not considering this as merge blocker.
Comment 56 Simon McVittie 2014-01-30 12:37:34 UTC
Ugh, accidentally pushed this without squashing the fixup commits. Never mind, too late now...

Fixed in git for 5.17.0.

(In reply to comment #55)
> I'm not a big fan of the FIXME in
> http://cgit.freedesktop.org/~smcv/telepathy-mission-control/commit/
> ?h=account-rework-27727-round4&id=8e5e39aa29a833be16598b2392539af07808a85d,
> if we don't find the reason now we'll never do.

I'll ask Vivek whether he can remember.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.