Blame src/daemon/goadaemon.c

Packit Service c6b9b0
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
Packit Service c6b9b0
/*
Packit Service c6b9b0
 * Copyright © 2011 – 2017 Red Hat, Inc.
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * This library is free software; you can redistribute it and/or
Packit Service c6b9b0
 * modify it under the terms of the GNU Lesser General Public
Packit Service c6b9b0
 * License as published by the Free Software Foundation; either
Packit Service c6b9b0
 * version 2 of the License, or (at your option) any later version.
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * This library is distributed in the hope that it will be useful,
Packit Service c6b9b0
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service c6b9b0
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service c6b9b0
 * Lesser General Public License for more details.
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * You should have received a copy of the GNU Lesser General
Packit Service c6b9b0
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit Service c6b9b0
 */
Packit Service c6b9b0
Packit Service c6b9b0
#include "config.h"
Packit Service c6b9b0
Packit Service c6b9b0
#include <errno.h>
Packit Service c6b9b0
#include <string.h>
Packit Service c6b9b0
Packit Service c6b9b0
#include <gio/gio.h>
Packit Service c6b9b0
#include <glib/gi18n.h>
Packit Service c6b9b0
#include <rest/rest-proxy.h>
Packit Service c6b9b0
#include <libsoup/soup.h>
Packit Service c6b9b0
Packit Service c6b9b0
#include "goadaemon.h"
Packit Service c6b9b0
#include "goa/goa.h"
Packit Service c6b9b0
#include "goabackend/goabackend.h"
Packit Service c6b9b0
#include "goabackend/goaprovider-priv.h"
Packit Service c6b9b0
#include "goabackend/goautils.h"
Packit Service c6b9b0
Packit Service c6b9b0
struct _GoaDaemon
Packit Service c6b9b0
{
Packit Service c6b9b0
  GObject parent_instance;
Packit Service c6b9b0
Packit Service c6b9b0
  GDBusConnection *connection;
Packit Service c6b9b0
Packit Service c6b9b0
  GFileMonitor *home_conf_file_monitor;
Packit Service c6b9b0
  GFileMonitor *template_file_monitor;
Packit Service c6b9b0
  gchar *home_conf_file_path;
Packit Service c6b9b0
Packit Service c6b9b0
  GNetworkMonitor *network_monitor;
Packit Service c6b9b0
Packit Service c6b9b0
  GDBusObjectManagerServer *object_manager;
Packit Service c6b9b0
Packit Service c6b9b0
  GoaManager *manager;
Packit Service c6b9b0
Packit Service c6b9b0
  GQueue *ensure_credentials_queue;
Packit Service c6b9b0
  gboolean ensure_credentials_running;
Packit Service c6b9b0
Packit Service c6b9b0
  guint config_timeout_id;
Packit Service c6b9b0
  guint credentials_timeout_id;
Packit Service c6b9b0
};
Packit Service c6b9b0
Packit Service c6b9b0
enum
Packit Service c6b9b0
{
Packit Service c6b9b0
  PROP_0,
Packit Service c6b9b0
  PROP_CONNECTION
Packit Service c6b9b0
};
Packit Service c6b9b0
Packit Service c6b9b0
static void on_file_monitor_changed (GFileMonitor     *monitor,
Packit Service c6b9b0
                                     GFile            *file,
Packit Service c6b9b0
                                     GFile            *other_file,
Packit Service c6b9b0
                                     GFileMonitorEvent event_type,
Packit Service c6b9b0
                                     gpointer          user_data);
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean on_manager_handle_add_account (GoaManager            *object,
Packit Service c6b9b0
                                               GDBusMethodInvocation *invocation,
Packit Service c6b9b0
                                               const gchar           *provider_type,
Packit Service c6b9b0
                                               const gchar           *identity,
Packit Service c6b9b0
                                               const gchar           *presentation_identity,
Packit Service c6b9b0
                                               GVariant              *credentials,
Packit Service c6b9b0
                                               GVariant              *details,
Packit Service c6b9b0
                                               gpointer               user_data);
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean on_account_handle_remove (GoaAccount            *account,
Packit Service c6b9b0
                                          GDBusMethodInvocation *invocation,
Packit Service c6b9b0
                                          gpointer               user_data);
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean on_account_handle_ensure_credentials (GoaAccount            *account,
Packit Service c6b9b0
                                                      GDBusMethodInvocation *invocation,
Packit Service c6b9b0
                                                      gpointer               user_data);
Packit Service c6b9b0
Packit Service c6b9b0
static void ensure_credentials_queue_check (GoaDaemon *self);
Packit Service c6b9b0
Packit Service c6b9b0
static void goa_daemon_check_credentials (GoaDaemon *self);
Packit Service c6b9b0
static void goa_daemon_reload_configuration (GoaDaemon *self);
Packit Service c6b9b0
Packit Service c6b9b0
G_DEFINE_TYPE (GoaDaemon, goa_daemon, G_TYPE_OBJECT);
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
typedef struct
Packit Service c6b9b0
{
Packit Service c6b9b0
  GError **error;
Packit Service c6b9b0
  GList **out_providers;
Packit Service c6b9b0
  GMainLoop *loop;
Packit Service c6b9b0
  gboolean op_res;
Packit Service c6b9b0
} GetAllSyncData;
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
get_all_providers_sync_cb (GObject       *source_object,
Packit Service c6b9b0
                           GAsyncResult  *res,
Packit Service c6b9b0
                           gpointer       user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GetAllSyncData *data = (GetAllSyncData *) user_data;
Packit Service c6b9b0
Packit Service c6b9b0
  data->op_res = goa_provider_get_all_finish (data->out_providers, res, data->error);
Packit Service c6b9b0
  g_main_loop_quit (data->loop);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
get_all_providers_sync (GCancellable  *cancellable,
Packit Service c6b9b0
                        GList        **out_providers,
Packit Service c6b9b0
                        GError       **error)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GetAllSyncData data;
Packit Service c6b9b0
Packit Service c6b9b0
  data.error = error;
Packit Service c6b9b0
  data.out_providers = out_providers;
Packit Service c6b9b0
Packit Service c6b9b0
  /* HACK: Since telepathy-glib doesn't use the thread-default
Packit Service c6b9b0
   * GMainContext for invoking the asynchronous callbacks, we can't
Packit Service c6b9b0
   * push a new GMainContext here.
Packit Service c6b9b0
   */
Packit Service c6b9b0
  data.loop = g_main_loop_new (NULL, FALSE);
Packit Service c6b9b0
Packit Service c6b9b0
  goa_provider_get_all (get_all_providers_sync_cb, &data);
Packit Service c6b9b0
  g_main_loop_run (data.loop);
Packit Service c6b9b0
  g_main_loop_unref (data.loop);
Packit Service c6b9b0
Packit Service c6b9b0
  return data.op_res;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_daemon_constructed (GObject *object)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (object);
Packit Service c6b9b0
Packit Service c6b9b0
  G_OBJECT_CLASS (goa_daemon_parent_class)->constructed (object);
Packit Service c6b9b0
Packit Service c6b9b0
  /* prime the list of accounts */
Packit Service c6b9b0
  goa_daemon_reload_configuration (self);
Packit Service c6b9b0
Packit Service c6b9b0
  /* Export objects */
Packit Service c6b9b0
  g_dbus_object_manager_server_set_connection (self->object_manager, self->connection);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_daemon_finalize (GObject *object)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (object);
Packit Service c6b9b0
Packit Service c6b9b0
  if (self->config_timeout_id != 0)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_source_remove (self->config_timeout_id);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (self->credentials_timeout_id != 0)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_source_remove (self->credentials_timeout_id);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (self->home_conf_file_monitor != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_signal_handlers_disconnect_by_func (self->home_conf_file_monitor, on_file_monitor_changed, self);
Packit Service c6b9b0
      g_object_unref (self->home_conf_file_monitor);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (self->template_file_monitor != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_signal_handlers_disconnect_by_func (self->template_file_monitor, on_file_monitor_changed, self);
Packit Service c6b9b0
      g_object_unref (self->template_file_monitor);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  g_free (self->home_conf_file_path);
Packit Service c6b9b0
  g_object_unref (self->manager);
Packit Service c6b9b0
  g_object_unref (self->object_manager);
Packit Service c6b9b0
  g_object_unref (self->connection);
Packit Service c6b9b0
  g_queue_free_full (self->ensure_credentials_queue, g_object_unref);
Packit Service c6b9b0
Packit Service c6b9b0
  G_OBJECT_CLASS (goa_daemon_parent_class)->finalize (object);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_daemon_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (object);
Packit Service c6b9b0
Packit Service c6b9b0
  switch (prop_id)
Packit Service c6b9b0
    {
Packit Service c6b9b0
    case PROP_CONNECTION:
Packit Service c6b9b0
      self->connection = G_DBUS_CONNECTION (g_value_dup_object (value));
Packit Service c6b9b0
      break;
Packit Service c6b9b0
Packit Service c6b9b0
    default:
Packit Service c6b9b0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service c6b9b0
      break;
Packit Service c6b9b0
    }
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static GFileMonitor *
Packit Service c6b9b0
create_monitor (const gchar *path, gboolean is_dir)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GFile *file;
Packit Service c6b9b0
  GFileMonitor *monitor;
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  file = g_file_new_for_path (path);
Packit Service c6b9b0
  if (is_dir)
Packit Service c6b9b0
    monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, &error);
Packit Service c6b9b0
  else
Packit Service c6b9b0
    monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error);
Packit Service c6b9b0
Packit Service c6b9b0
  if (monitor == NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("Error monitoring %s at %s: %s (%s, %d)",
Packit Service c6b9b0
                 is_dir ? "directory" : "file",
Packit Service c6b9b0
                 path,
Packit Service c6b9b0
                 error->message, g_quark_to_string (error->domain), error->code);
Packit Service c6b9b0
      g_error_free (error);
Packit Service c6b9b0
    }
Packit Service c6b9b0
  g_object_unref (file);
Packit Service c6b9b0
Packit Service c6b9b0
  return monitor;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
on_config_file_monitor_timeout (gpointer user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (user_data);
Packit Service c6b9b0
Packit Service c6b9b0
  self->config_timeout_id = 0;
Packit Service c6b9b0
  g_debug ("Reloading configuration files");
Packit Service c6b9b0
  goa_daemon_reload_configuration (self);
Packit Service c6b9b0
Packit Service c6b9b0
  return G_SOURCE_REMOVE;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
on_file_monitor_changed (GFileMonitor      *monitor,
Packit Service c6b9b0
                         GFile             *file,
Packit Service c6b9b0
                         GFile             *other_file,
Packit Service c6b9b0
                         GFileMonitorEvent  event_type,
Packit Service c6b9b0
                         gpointer           user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (user_data);
Packit Service c6b9b0
Packit Service c6b9b0
  if (self->config_timeout_id == 0)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      self->config_timeout_id = g_timeout_add (200, on_config_file_monitor_timeout, self);
Packit Service c6b9b0
    }
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
on_check_credentials_timeout (gpointer user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (user_data);
Packit Service c6b9b0
Packit Service c6b9b0
  self->credentials_timeout_id = 0;
Packit Service c6b9b0
  g_debug ("Calling EnsureCredentials due to network changes");
Packit Service c6b9b0
  goa_daemon_check_credentials (self);
Packit Service c6b9b0
Packit Service c6b9b0
  return G_SOURCE_REMOVE;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
queue_check_credentials (GoaDaemon *self)
Packit Service c6b9b0
{
Packit Service c6b9b0
  if (self->credentials_timeout_id != 0)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_source_remove (self->credentials_timeout_id);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  self->credentials_timeout_id = g_timeout_add_seconds (1, on_check_credentials_timeout, self);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
on_network_monitor_network_changed (GoaDaemon *self, gboolean available)
Packit Service c6b9b0
{
Packit Service c6b9b0
  queue_check_credentials (self);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_daemon_init (GoaDaemon *self)
Packit Service c6b9b0
{
Packit Service c6b9b0
  static volatile GQuark goa_error_domain = 0;
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
  GList *l;
Packit Service c6b9b0
  GList *providers = NULL;
Packit Service c6b9b0
  GoaObjectSkeleton *object;
Packit Service c6b9b0
  gchar *path;
Packit Service c6b9b0
Packit Service c6b9b0
  /* this will force associating errors in the GOA_ERROR error domain
Packit Service c6b9b0
   * with org.freedesktop.Goa.Error.* errors via g_dbus_error_register_error_domain().
Packit Service c6b9b0
   */
Packit Service c6b9b0
  goa_error_domain = GOA_ERROR;
Packit Service c6b9b0
  goa_error_domain; /* shut up -Wunused-but-set-variable */
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!get_all_providers_sync (NULL, &providers, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("Unable to get the list of providers: %s (%s, %d)",
Packit Service c6b9b0
                 error->message,
Packit Service c6b9b0
                 g_quark_to_string (error->domain),
Packit Service c6b9b0
                 error->code);
Packit Service c6b9b0
      g_error_free (error);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  for (l = providers; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      GoaProvider *provider = GOA_PROVIDER (l->data);
Packit Service c6b9b0
      goa_provider_initialize (provider);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  /* Create object manager */
Packit Service c6b9b0
  self->object_manager = g_dbus_object_manager_server_new ("/org/gnome/OnlineAccounts");
Packit Service c6b9b0
Packit Service c6b9b0
  /* Create and export Manager */
Packit Service c6b9b0
  self->manager = goa_manager_skeleton_new ();
Packit Service c6b9b0
  g_signal_connect (self->manager,
Packit Service c6b9b0
                    "handle-add-account",
Packit Service c6b9b0
                    G_CALLBACK (on_manager_handle_add_account),
Packit Service c6b9b0
                    self);
Packit Service c6b9b0
  object = goa_object_skeleton_new ("/org/gnome/OnlineAccounts/Manager");
Packit Service c6b9b0
  goa_object_skeleton_set_manager (object, self->manager);
Packit Service c6b9b0
  g_dbus_object_manager_server_export (self->object_manager, G_DBUS_OBJECT_SKELETON (object));
Packit Service c6b9b0
  g_object_unref (object);
Packit Service c6b9b0
Packit Service c6b9b0
  self->home_conf_file_path = g_strdup_printf ("%s/goa-1.0/accounts.conf", g_get_user_config_dir ());
Packit Service c6b9b0
Packit Service c6b9b0
  /* create ~/.config/goa-1.0 directory */
Packit Service c6b9b0
  path = g_path_get_dirname (self->home_conf_file_path);
Packit Service c6b9b0
  if (g_mkdir_with_parents (path, 0755) != 0)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("Error creating directory %s: %s", path, strerror (errno));
Packit Service c6b9b0
    }
Packit Service c6b9b0
  g_free (path);
Packit Service c6b9b0
Packit Service c6b9b0
  /* set up file monitoring */
Packit Service c6b9b0
  self->home_conf_file_monitor = create_monitor (self->home_conf_file_path, FALSE);
Packit Service c6b9b0
  if (self->home_conf_file_monitor != NULL)
Packit Service c6b9b0
    g_signal_connect (self->home_conf_file_monitor, "changed", G_CALLBACK (on_file_monitor_changed), self);
Packit Service c6b9b0
Packit Service c6b9b0
  if (GOA_TEMPLATE_FILE != NULL && GOA_TEMPLATE_FILE[0] != '\0')
Packit Service c6b9b0
    {
Packit Service c6b9b0
      self->template_file_monitor = create_monitor (GOA_TEMPLATE_FILE, FALSE);
Packit Service c6b9b0
      if (self->template_file_monitor != NULL)
Packit Service c6b9b0
        g_signal_connect (self->template_file_monitor, "changed", G_CALLBACK (on_file_monitor_changed), self);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  self->network_monitor = g_network_monitor_get_default ();
Packit Service c6b9b0
  g_signal_connect_object (self->network_monitor,
Packit Service c6b9b0
                           "network-changed",
Packit Service c6b9b0
                           G_CALLBACK (on_network_monitor_network_changed),
Packit Service c6b9b0
                           self,
Packit Service c6b9b0
                           G_CONNECT_SWAPPED);
Packit Service c6b9b0
Packit Service c6b9b0
  self->ensure_credentials_queue = g_queue_new ();
Packit Service c6b9b0
  queue_check_credentials (self);
Packit Service c6b9b0
Packit Service c6b9b0
  g_list_free_full (providers, g_object_unref);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_daemon_class_init (GoaDaemonClass *klass)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GObjectClass *gobject_class;
Packit Service c6b9b0
Packit Service c6b9b0
  gobject_class = G_OBJECT_CLASS (klass);
Packit Service c6b9b0
  gobject_class->constructed  = goa_daemon_constructed;
Packit Service c6b9b0
  gobject_class->finalize     = goa_daemon_finalize;
Packit Service c6b9b0
  gobject_class->set_property = goa_daemon_set_property;
Packit Service c6b9b0
Packit Service c6b9b0
  g_object_class_install_property (gobject_class,
Packit Service c6b9b0
                                   PROP_CONNECTION,
Packit Service c6b9b0
                                   g_param_spec_object ("connection",
Packit Service c6b9b0
                                                        "GDBusConnection object",
Packit Service c6b9b0
                                                        "A connection to a message bus",
Packit Service c6b9b0
                                                        G_TYPE_DBUS_CONNECTION,
Packit Service c6b9b0
                                                        G_PARAM_CONSTRUCT_ONLY |
Packit Service c6b9b0
                                                        G_PARAM_STATIC_STRINGS |
Packit Service c6b9b0
                                                        G_PARAM_WRITABLE));
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
GoaDaemon *
Packit Service c6b9b0
goa_daemon_new (GDBusConnection *connection)
Packit Service c6b9b0
{
Packit Service c6b9b0
  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
Packit Service c6b9b0
  return GOA_DAEMON (g_object_new (GOA_TYPE_DAEMON, "connection", connection, NULL));
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
diff_sorted_lists (GList *list1,
Packit Service c6b9b0
                   GList *list2,
Packit Service c6b9b0
                   GCompareFunc compare,
Packit Service c6b9b0
                   GList **out_added,
Packit Service c6b9b0
                   GList **out_removed,
Packit Service c6b9b0
                   GList **out_unchanged)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GList *added = NULL;
Packit Service c6b9b0
  GList *removed = NULL;
Packit Service c6b9b0
  GList *unchanged = NULL;
Packit Service c6b9b0
  gint order;
Packit Service c6b9b0
Packit Service c6b9b0
  while (list1 != NULL && list2 != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      order = (*compare) (list1->data, list2->data);
Packit Service c6b9b0
      if (order < 0)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          removed = g_list_prepend (removed, list1->data);
Packit Service c6b9b0
          list1 = list1->next;
Packit Service c6b9b0
        }
Packit Service c6b9b0
      else if (order > 0)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          added = g_list_prepend (added, list2->data);
Packit Service c6b9b0
          list2 = list2->next;
Packit Service c6b9b0
        }
Packit Service c6b9b0
      else
Packit Service c6b9b0
        { /* same item */
Packit Service c6b9b0
          unchanged = g_list_prepend (unchanged, list1->data);
Packit Service c6b9b0
          list1 = list1->next;
Packit Service c6b9b0
          list2 = list2->next;
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  while (list1 != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      removed = g_list_prepend (removed, list1->data);
Packit Service c6b9b0
      list1 = list1->next;
Packit Service c6b9b0
    }
Packit Service c6b9b0
  while (list2 != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      added = g_list_prepend (added, list2->data);
Packit Service c6b9b0
      list2 = list2->next;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (out_added != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      *out_added = added;
Packit Service c6b9b0
      added = NULL;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (out_removed != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      *out_removed = removed;
Packit Service c6b9b0
      removed = NULL;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (out_unchanged != NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      *out_unchanged = unchanged;
Packit Service c6b9b0
      unchanged = NULL;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  g_list_free (added);
Packit Service c6b9b0
  g_list_free (removed);
Packit Service c6b9b0
  g_list_free (unchanged);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
account_group_to_id (const gchar *group)
Packit Service c6b9b0
{
Packit Service c6b9b0
  g_return_val_if_fail (g_str_has_prefix (group, "Account "), NULL);
Packit Service c6b9b0
  return group + sizeof "Account " - 1;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gchar *
Packit Service c6b9b0
account_object_path_to_group (const gchar *object_path)
Packit Service c6b9b0
{
Packit Service c6b9b0
  g_return_val_if_fail (g_str_has_prefix (object_path, "/org/gnome/OnlineAccounts/Accounts/"), NULL);
Packit Service c6b9b0
  return g_strdup_printf ("Account %s", object_path + sizeof "/org/gnome/OnlineAccounts/Accounts/" - 1);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
template_group_to_id (const gchar *group)
Packit Service c6b9b0
{
Packit Service c6b9b0
  g_return_val_if_fail (g_str_has_prefix (group, "Template "), NULL);
Packit Service c6b9b0
  return group + sizeof "Template " - 1;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
typedef struct
Packit Service c6b9b0
{
Packit Service c6b9b0
  GKeyFile *key_file;
Packit Service c6b9b0
  gchar *path;
Packit Service c6b9b0
} KeyFileData;
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
key_file_data_free (KeyFileData *data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  g_key_file_unref (data->key_file);
Packit Service c6b9b0
  g_free (data->path);
Packit Service c6b9b0
  g_slice_free (KeyFileData, data);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static KeyFileData *
Packit Service c6b9b0
key_file_data_new (GKeyFile    *key_file,
Packit Service c6b9b0
                   const gchar *path)
Packit Service c6b9b0
{
Packit Service c6b9b0
  KeyFileData *data;
Packit Service c6b9b0
  data = g_slice_new (KeyFileData);
Packit Service c6b9b0
  data->key_file = g_key_file_ref (key_file);
Packit Service c6b9b0
  data->path = g_strdup (path);
Packit Service c6b9b0
  return data;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
add_config_file (GoaDaemon     *self,
Packit Service c6b9b0
                 const gchar   *path,
Packit Service c6b9b0
                 GHashTable    *group_name_to_key_file_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GKeyFile *key_file;
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
  gboolean needs_update = FALSE;
Packit Service c6b9b0
  gchar **groups;
Packit Service c6b9b0
  const char *guid;
Packit Service c6b9b0
  gsize num_groups;
Packit Service c6b9b0
  guint n;
Packit Service c6b9b0
Packit Service c6b9b0
  key_file = g_key_file_new ();
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!g_key_file_load_from_file (key_file,
Packit Service c6b9b0
                                  path,
Packit Service c6b9b0
                                  G_KEY_FILE_NONE,
Packit Service c6b9b0
                                  &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_warning ("Error loading %s: %s (%s, %d)",
Packit Service c6b9b0
                     path,
Packit Service c6b9b0
                     error->message, g_quark_to_string (error->domain), error->code);
Packit Service c6b9b0
        }
Packit Service c6b9b0
      g_error_free (error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  guid = g_dbus_connection_get_guid (self->connection);
Packit Service c6b9b0
  groups = g_key_file_get_groups (key_file, &num_groups);
Packit Service c6b9b0
  for (n = 0; n < num_groups; n++)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      if (g_str_has_prefix (groups[n], "Account "))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          gboolean is_temporary;
Packit Service c6b9b0
          char *session_id;
Packit Service c6b9b0
Packit Service c6b9b0
          is_temporary = g_key_file_get_boolean (key_file,
Packit Service c6b9b0
                                                 groups[n],
Packit Service c6b9b0
                                                 "IsTemporary",
Packit Service c6b9b0
                                                 NULL);
Packit Service c6b9b0
Packit Service c6b9b0
          if (is_temporary)
Packit Service c6b9b0
            {
Packit Service c6b9b0
              session_id = g_key_file_get_string (key_file,
Packit Service c6b9b0
                                                  groups[n],
Packit Service c6b9b0
                                                  "SessionId",
Packit Service c6b9b0
                                                  NULL);
Packit Service c6b9b0
Packit Service c6b9b0
              /* discard temporary accounts from older sessions */
Packit Service c6b9b0
              if (session_id != NULL &&
Packit Service c6b9b0
                  g_strcmp0 (session_id, guid) != 0)
Packit Service c6b9b0
                {
Packit Service c6b9b0
                  GoaProvider *provider = NULL;
Packit Service c6b9b0
                  const gchar *id;
Packit Service c6b9b0
                  gchar *provider_type = NULL;
Packit Service c6b9b0
Packit Service c6b9b0
                  g_debug ("ignoring account \"%s\" in file %s because it's stale",
Packit Service c6b9b0
                           groups[n], path);
Packit Service c6b9b0
Packit Service c6b9b0
                  id = account_group_to_id (groups[n]);
Packit Service c6b9b0
                  if (id == NULL)
Packit Service c6b9b0
                    {
Packit Service c6b9b0
                      g_warning ("Unable to get account ID from group: %s", groups[n]);
Packit Service c6b9b0
                      goto cleanup_and_continue;
Packit Service c6b9b0
                    }
Packit Service c6b9b0
Packit Service c6b9b0
                  provider_type = g_key_file_get_string (key_file, groups[n], "Provider", NULL);
Packit Service c6b9b0
                  if (provider_type != NULL)
Packit Service c6b9b0
                    provider = goa_provider_get_for_provider_type (provider_type);
Packit Service c6b9b0
Packit Service c6b9b0
                  if (provider == NULL)
Packit Service c6b9b0
                    {
Packit Service c6b9b0
                      g_warning ("Unsupported account type %s for ID %s (no provider)", provider_type, id);
Packit Service c6b9b0
                      goto cleanup_and_continue;
Packit Service c6b9b0
                    }
Packit Service c6b9b0
Packit Service c6b9b0
                  needs_update = g_key_file_remove_group (key_file, groups[n], NULL);
Packit Service c6b9b0
Packit Service c6b9b0
                  error = NULL;
Packit Service c6b9b0
                  if (!goa_utils_delete_credentials_for_id_sync (provider, id, NULL, &error))
Packit Service c6b9b0
                    {
Packit Service c6b9b0
                      g_warning ("Unable to clean-up stale keyring entries: %s", error->message);
Packit Service c6b9b0
                      g_error_free (error);
Packit Service c6b9b0
                      goto cleanup_and_continue;
Packit Service c6b9b0
                    }
Packit Service c6b9b0
Packit Service c6b9b0
                cleanup_and_continue:
Packit Service c6b9b0
                  g_clear_object (&provider);
Packit Service c6b9b0
                  g_free (groups[n]);
Packit Service c6b9b0
                  g_free (provider_type);
Packit Service c6b9b0
                  g_free (session_id);
Packit Service c6b9b0
                  continue;
Packit Service c6b9b0
                }
Packit Service c6b9b0
              g_free (session_id);
Packit Service c6b9b0
            }
Packit Service c6b9b0
          else
Packit Service c6b9b0
            {
Packit Service c6b9b0
              needs_update = g_key_file_remove_key (key_file, groups[n], "SessionId", NULL);
Packit Service c6b9b0
            }
Packit Service c6b9b0
Packit Service c6b9b0
          g_hash_table_insert (group_name_to_key_file_data,
Packit Service c6b9b0
                               groups[n], /* steals string */
Packit Service c6b9b0
                               key_file_data_new (key_file, path));
Packit Service c6b9b0
        }
Packit Service c6b9b0
      else if (g_str_has_prefix (groups[n], "Template "))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_hash_table_insert (group_name_to_key_file_data,
Packit Service c6b9b0
                               groups[n], /* steals string */
Packit Service c6b9b0
                               key_file_data_new (key_file, path));
Packit Service c6b9b0
        }
Packit Service c6b9b0
      else
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_warning ("Unexpected group \"%s\" in file %s", groups[n], path);
Packit Service c6b9b0
          g_free (groups[n]);
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
  g_free (groups);
Packit Service c6b9b0
Packit Service c6b9b0
  if (needs_update)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      error = NULL;
Packit Service c6b9b0
      if (!g_key_file_save_to_file (key_file, path, &error))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_prefix_error (&error, "Error writing key-value-file %s: ", path);
Packit Service c6b9b0
          g_warning ("%s (%s, %d)", error->message, g_quark_to_string (error->domain), error->code);
Packit Service c6b9b0
          g_error_free (error);
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_key_file_unref (key_file);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
/* returns FALSE if object is not (or no longer) valid */
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
update_account_object (GoaDaemon           *self,
Packit Service c6b9b0
                       GoaObjectSkeleton   *object,
Packit Service c6b9b0
                       const gchar         *path,
Packit Service c6b9b0
                       const gchar         *group,
Packit Service c6b9b0
                       GKeyFile            *key_file,
Packit Service c6b9b0
                       gboolean             just_added)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaAccount *account = NULL;
Packit Service c6b9b0
  GoaProvider *provider = NULL;
Packit Service c6b9b0
  gboolean is_locked;
Packit Service c6b9b0
  gboolean is_temporary;
Packit Service c6b9b0
  gboolean ret = FALSE;
Packit Service c6b9b0
  gchar *identity = NULL;
Packit Service c6b9b0
  gchar *presentation_identity;
Packit Service c6b9b0
  gchar *type = NULL;
Packit Service c6b9b0
  gchar *name = NULL;
Packit Service c6b9b0
  GIcon *icon = NULL;
Packit Service c6b9b0
  gchar *serialized_icon = NULL;
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
Packit Service c6b9b0
  g_return_val_if_fail (GOA_IS_DAEMON (self), FALSE);
Packit Service c6b9b0
  g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), FALSE);
Packit Service c6b9b0
  g_return_val_if_fail (group != NULL, FALSE);
Packit Service c6b9b0
  g_return_val_if_fail (key_file != NULL, FALSE);
Packit Service c6b9b0
Packit Service c6b9b0
  g_debug ("updating %s %d", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)), just_added);
Packit Service c6b9b0
Packit Service c6b9b0
  type = g_key_file_get_string (key_file, group, "Provider", NULL);
Packit Service c6b9b0
  identity = g_key_file_get_string (key_file, group, "Identity", NULL);
Packit Service c6b9b0
  presentation_identity = g_key_file_get_string (key_file, group, "PresentationIdentity", NULL);
Packit Service c6b9b0
  is_locked = g_key_file_get_boolean (key_file, group, "IsLocked", NULL);
Packit Service c6b9b0
  is_temporary = g_key_file_get_boolean (key_file, group, "IsTemporary", NULL);
Packit Service c6b9b0
  if (just_added)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      account = goa_account_skeleton_new ();
Packit Service c6b9b0
      goa_object_skeleton_set_account (object, account);
Packit Service c6b9b0
    }
Packit Service c6b9b0
  else
Packit Service c6b9b0
    {
Packit Service c6b9b0
      account = goa_object_get_account (GOA_OBJECT (object));
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  provider = goa_provider_get_for_provider_type (type);
Packit Service c6b9b0
  if (provider == NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("Unsupported account type %s for identity %s (no provider)", type, identity);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  goa_account_set_id (account, g_strrstr (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)), "/") + 1);
Packit Service c6b9b0
  goa_account_set_provider_type (account, type);
Packit Service c6b9b0
  goa_account_set_identity (account, identity);
Packit Service c6b9b0
  goa_account_set_presentation_identity (account, presentation_identity);
Packit Service c6b9b0
  goa_account_set_is_locked (account, is_locked);
Packit Service c6b9b0
  goa_account_set_is_temporary (account, is_temporary);
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!goa_provider_build_object (provider, object, key_file, group, self->connection, just_added, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("Error parsing account: %s (%s, %d)",
Packit Service c6b9b0
                 error->message, g_quark_to_string (error->domain), error->code);
Packit Service c6b9b0
      g_error_free (error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  name = goa_provider_get_provider_name (provider, GOA_OBJECT (object));
Packit Service c6b9b0
  goa_account_set_provider_name (account, name);
Packit Service c6b9b0
Packit Service c6b9b0
  icon = goa_provider_get_provider_icon (provider, GOA_OBJECT (object));
Packit Service c6b9b0
  serialized_icon = g_icon_to_string (icon);
Packit Service c6b9b0
  goa_account_set_provider_icon (account, serialized_icon);
Packit Service c6b9b0
Packit Service c6b9b0
  ret = TRUE;
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_free (serialized_icon);
Packit Service c6b9b0
  g_clear_object (&icon);
Packit Service c6b9b0
  g_free (name);
Packit Service c6b9b0
  g_clear_object (&provider);
Packit Service c6b9b0
  g_clear_object (&account);
Packit Service c6b9b0
  g_free (type);
Packit Service c6b9b0
  g_free (identity);
Packit Service c6b9b0
  g_free (presentation_identity);
Packit Service c6b9b0
  return ret;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
process_config_entries (GoaDaemon  *self,
Packit Service c6b9b0
                        GHashTable *group_name_to_key_file_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GHashTableIter iter;
Packit Service c6b9b0
  KeyFileData *key_file_data;
Packit Service c6b9b0
  GList *existing_object_paths = NULL;
Packit Service c6b9b0
  GList *config_object_paths = NULL;
Packit Service c6b9b0
  GList *added;
Packit Service c6b9b0
  GList *removed;
Packit Service c6b9b0
  GList *unchanged;
Packit Service c6b9b0
  GList *l;
Packit Service c6b9b0
Packit Service c6b9b0
  {
Packit Service c6b9b0
    GList *existing_objects;
Packit Service c6b9b0
    existing_objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager));
Packit Service c6b9b0
    for (l = existing_objects; l != NULL; l = l->next)
Packit Service c6b9b0
      {
Packit Service c6b9b0
        GoaObject *object = GOA_OBJECT (l->data);
Packit Service c6b9b0
        const gchar *object_path;
Packit Service c6b9b0
        object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
Packit Service c6b9b0
        if (g_str_has_prefix (object_path, "/org/gnome/OnlineAccounts/Accounts/"))
Packit Service c6b9b0
          existing_object_paths = g_list_prepend (existing_object_paths, g_strdup (object_path));
Packit Service c6b9b0
      }
Packit Service c6b9b0
    g_list_free_full (existing_objects, g_object_unref);
Packit Service c6b9b0
  }
Packit Service c6b9b0
Packit Service c6b9b0
  {
Packit Service c6b9b0
    const gchar *group;
Packit Service c6b9b0
Packit Service c6b9b0
    g_hash_table_iter_init (&iter, group_name_to_key_file_data);
Packit Service c6b9b0
    while (g_hash_table_iter_next (&iter, (gpointer*) &group, (gpointer*) &key_file_data))
Packit Service c6b9b0
      {
Packit Service c6b9b0
        const gchar *id;
Packit Service c6b9b0
        gchar *object_path;
Packit Service c6b9b0
Packit Service c6b9b0
        if (!g_str_has_prefix (group, "Account "))
Packit Service c6b9b0
          continue;
Packit Service c6b9b0
Packit Service c6b9b0
        id = account_group_to_id (group);
Packit Service c6b9b0
Packit Service c6b9b0
        /* create and validate object path */
Packit Service c6b9b0
        object_path = g_strdup_printf ("/org/gnome/OnlineAccounts/Accounts/%s", id);
Packit Service c6b9b0
        if (strstr (id, "/") != NULL || !g_variant_is_object_path (object_path))
Packit Service c6b9b0
          {
Packit Service c6b9b0
            g_warning ("`%s' is not a valid account identifier", group);
Packit Service c6b9b0
            g_free (object_path);
Packit Service c6b9b0
            continue;
Packit Service c6b9b0
          }
Packit Service c6b9b0
        /* steals object_path variable */
Packit Service c6b9b0
        config_object_paths = g_list_prepend (config_object_paths, object_path);
Packit Service c6b9b0
      }
Packit Service c6b9b0
  }
Packit Service c6b9b0
Packit Service c6b9b0
  existing_object_paths = g_list_sort (existing_object_paths, (GCompareFunc) g_strcmp0);
Packit Service c6b9b0
  config_object_paths = g_list_sort (config_object_paths, (GCompareFunc) g_strcmp0);
Packit Service c6b9b0
  diff_sorted_lists (existing_object_paths,
Packit Service c6b9b0
                     config_object_paths,
Packit Service c6b9b0
                     (GCompareFunc) g_strcmp0,
Packit Service c6b9b0
                     &added,
Packit Service c6b9b0
                     &removed,
Packit Service c6b9b0
                     &unchanged);
Packit Service c6b9b0
Packit Service c6b9b0
  for (l = removed; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      const gchar *object_path = l->data;
Packit Service c6b9b0
      GoaObject *object;
Packit Service c6b9b0
      object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->object_manager), object_path));
Packit Service c6b9b0
      g_warn_if_fail (object != NULL);
Packit Service c6b9b0
      g_signal_handlers_disconnect_by_func (goa_object_peek_account (object),
Packit Service c6b9b0
                                            G_CALLBACK (on_account_handle_remove),
Packit Service c6b9b0
                                            self);
Packit Service c6b9b0
      g_object_unref (object);
Packit Service c6b9b0
      g_debug ("removing %s", object_path);
Packit Service c6b9b0
      g_warn_if_fail (g_dbus_object_manager_server_unexport (self->object_manager, object_path));
Packit Service c6b9b0
    }
Packit Service c6b9b0
  for (l = added; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      const gchar *object_path = l->data;
Packit Service c6b9b0
      GoaObjectSkeleton *object;
Packit Service c6b9b0
      gchar *group;
Packit Service c6b9b0
Packit Service c6b9b0
      g_debug ("adding %s", object_path);
Packit Service c6b9b0
Packit Service c6b9b0
      group = account_object_path_to_group (object_path);
Packit Service c6b9b0
      key_file_data = g_hash_table_lookup (group_name_to_key_file_data, group);
Packit Service c6b9b0
      g_warn_if_fail (key_file_data != NULL);
Packit Service c6b9b0
Packit Service c6b9b0
      object = goa_object_skeleton_new (object_path);
Packit Service c6b9b0
      if (update_account_object (self,
Packit Service c6b9b0
                                 object,
Packit Service c6b9b0
                                 key_file_data->path,
Packit Service c6b9b0
                                 group,
Packit Service c6b9b0
                                 key_file_data->key_file,
Packit Service c6b9b0
                                 TRUE))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_dbus_object_manager_server_export (self->object_manager, G_DBUS_OBJECT_SKELETON (object));
Packit Service c6b9b0
          g_signal_connect (goa_object_peek_account (GOA_OBJECT (object)),
Packit Service c6b9b0
                            "handle-remove",
Packit Service c6b9b0
                            G_CALLBACK (on_account_handle_remove),
Packit Service c6b9b0
                            self);
Packit Service c6b9b0
          g_signal_connect (goa_object_peek_account (GOA_OBJECT (object)),
Packit Service c6b9b0
                            "handle-ensure-credentials",
Packit Service c6b9b0
                            G_CALLBACK (on_account_handle_ensure_credentials),
Packit Service c6b9b0
                            self);
Packit Service c6b9b0
        }
Packit Service c6b9b0
      g_object_unref (object);
Packit Service c6b9b0
      g_free (group);
Packit Service c6b9b0
    }
Packit Service c6b9b0
  for (l = unchanged; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      const gchar *object_path = l->data;
Packit Service c6b9b0
      GoaObject *object;
Packit Service c6b9b0
      gchar *group;
Packit Service c6b9b0
Packit Service c6b9b0
      g_debug ("unchanged %s", object_path);
Packit Service c6b9b0
Packit Service c6b9b0
      group = account_object_path_to_group (object_path);
Packit Service c6b9b0
      key_file_data = g_hash_table_lookup (group_name_to_key_file_data, group);
Packit Service c6b9b0
      g_warn_if_fail (key_file_data != NULL);
Packit Service c6b9b0
Packit Service c6b9b0
      object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (self->object_manager), object_path));
Packit Service c6b9b0
      g_warn_if_fail (object != NULL);
Packit Service c6b9b0
      if (!update_account_object (self,
Packit Service c6b9b0
                                  GOA_OBJECT_SKELETON (object),
Packit Service c6b9b0
                                  key_file_data->path,
Packit Service c6b9b0
                                  group,
Packit Service c6b9b0
                                  key_file_data->key_file,
Packit Service c6b9b0
                                  FALSE))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_signal_handlers_disconnect_by_func (goa_object_peek_account (object),
Packit Service c6b9b0
                                                G_CALLBACK (on_account_handle_remove),
Packit Service c6b9b0
                                                self);
Packit Service c6b9b0
          g_signal_handlers_disconnect_by_func (goa_object_peek_account (object),
Packit Service c6b9b0
                                                G_CALLBACK (on_account_handle_ensure_credentials),
Packit Service c6b9b0
                                                self);
Packit Service c6b9b0
          g_warn_if_fail (g_dbus_object_manager_server_unexport (self->object_manager, object_path));
Packit Service c6b9b0
        }
Packit Service c6b9b0
      g_object_unref (object);
Packit Service c6b9b0
      g_free (group);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  g_list_free (removed);
Packit Service c6b9b0
  g_list_free (added);
Packit Service c6b9b0
  g_list_free (unchanged);
Packit Service c6b9b0
  g_list_free_full (existing_object_paths, g_free);
Packit Service c6b9b0
  g_list_free_full (config_object_paths, g_free);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static gint
Packit Service c6b9b0
compare_account_and_template_groups (const gchar *account_group, const gchar *template_group)
Packit Service c6b9b0
{
Packit Service c6b9b0
  const gchar *account_id;
Packit Service c6b9b0
  const gchar *template_id;
Packit Service c6b9b0
Packit Service c6b9b0
  g_return_val_if_fail (g_str_has_prefix (account_group, "Account "), 0);
Packit Service c6b9b0
  g_return_val_if_fail (g_str_has_prefix (template_group, "Template "), 0);
Packit Service c6b9b0
Packit Service c6b9b0
  account_id = account_group + sizeof "Account " - 1;
Packit Service c6b9b0
  template_id = template_group + sizeof "Template " - 1;
Packit Service c6b9b0
Packit Service c6b9b0
  return g_strcmp0 (account_id, template_id);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
process_template_entries (GoaDaemon  *self,
Packit Service c6b9b0
                          GHashTable *group_name_to_key_file_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
  GHashTable *key_files_to_update = NULL;
Packit Service c6b9b0
  GHashTableIter iter;
Packit Service c6b9b0
  GKeyFile *home_conf_key_file = NULL;
Packit Service c6b9b0
  GKeyFile *key_file;
Packit Service c6b9b0
  KeyFileData *key_file_data;
Packit Service c6b9b0
  const gchar *group;
Packit Service c6b9b0
  const gchar *key_file_path;
Packit Service c6b9b0
  GList *config_object_groups = NULL;
Packit Service c6b9b0
  GList *config_template_groups = NULL;
Packit Service c6b9b0
  GList *added;
Packit Service c6b9b0
  GList *unchanged;
Packit Service c6b9b0
  GList *l;
Packit Service c6b9b0
Packit Service c6b9b0
  key_files_to_update = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_key_file_unref);
Packit Service c6b9b0
Packit Service c6b9b0
  g_hash_table_iter_init (&iter, group_name_to_key_file_data);
Packit Service c6b9b0
  while (g_hash_table_iter_next (&iter, (gpointer *) &group, (gpointer *) &key_file_data))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      if (home_conf_key_file == NULL && g_strcmp0 (key_file_data->path, self->home_conf_file_path) == 0)
Packit Service c6b9b0
        home_conf_key_file = g_key_file_ref (key_file_data->key_file);
Packit Service c6b9b0
Packit Service c6b9b0
      if (g_str_has_prefix (group, "Account "))
Packit Service c6b9b0
        config_object_groups = g_list_prepend (config_object_groups, g_strdup (group));
Packit Service c6b9b0
      else if (g_str_has_prefix (group, "Template "))
Packit Service c6b9b0
        config_template_groups = g_list_prepend (config_template_groups, g_strdup (group));
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (home_conf_key_file == NULL)
Packit Service c6b9b0
    home_conf_key_file = g_key_file_new ();
Packit Service c6b9b0
Packit Service c6b9b0
  config_object_groups = g_list_sort (config_object_groups, (GCompareFunc) g_strcmp0);
Packit Service c6b9b0
  config_template_groups = g_list_sort (config_template_groups, (GCompareFunc) g_strcmp0);
Packit Service c6b9b0
  diff_sorted_lists (config_object_groups,
Packit Service c6b9b0
                     config_template_groups,
Packit Service c6b9b0
                     (GCompareFunc) compare_account_and_template_groups,
Packit Service c6b9b0
                     &added,
Packit Service c6b9b0
                     NULL,
Packit Service c6b9b0
                     &unchanged);
Packit Service c6b9b0
Packit Service c6b9b0
  for (l = added; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      gboolean needs_update;
Packit Service c6b9b0
      const gchar *id;
Packit Service c6b9b0
      const gchar *template_group = l->data;
Packit Service c6b9b0
      gchar *object_group = NULL;
Packit Service c6b9b0
Packit Service c6b9b0
      key_file_data = g_hash_table_lookup (group_name_to_key_file_data, template_group);
Packit Service c6b9b0
      g_assert_nonnull (key_file_data);
Packit Service c6b9b0
Packit Service c6b9b0
      if (goa_utils_keyfile_get_boolean (key_file_data->key_file, template_group, "ForceRemove"))
Packit Service c6b9b0
        continue;
Packit Service c6b9b0
Packit Service c6b9b0
      g_debug ("Adding from template %s", template_group);
Packit Service c6b9b0
Packit Service c6b9b0
      id = template_group_to_id (template_group);
Packit Service c6b9b0
      object_group = g_strdup_printf ("Account %s", id);
Packit Service c6b9b0
      g_warn_if_fail (!g_key_file_has_group (home_conf_key_file, object_group));
Packit Service c6b9b0
Packit Service c6b9b0
      needs_update = goa_utils_keyfile_copy_group (key_file_data->key_file,
Packit Service c6b9b0
                                                   template_group,
Packit Service c6b9b0
                                                   home_conf_key_file,
Packit Service c6b9b0
                                                   object_group);
Packit Service c6b9b0
Packit Service c6b9b0
      if (needs_update)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_key_file_set_boolean (home_conf_key_file, object_group, "IsLocked", TRUE);
Packit Service c6b9b0
          g_hash_table_insert (key_files_to_update,
Packit Service c6b9b0
                               g_strdup (self->home_conf_file_path),
Packit Service c6b9b0
                               g_key_file_ref (home_conf_key_file));
Packit Service c6b9b0
        }
Packit Service c6b9b0
Packit Service c6b9b0
      g_free (object_group);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  for (l = unchanged; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      KeyFileData *object_key_file_data;
Packit Service c6b9b0
      KeyFileData *template_key_file_data;
Packit Service c6b9b0
      gboolean needs_update;
Packit Service c6b9b0
      const gchar *id;
Packit Service c6b9b0
      const gchar *object_group = l->data;
Packit Service c6b9b0
      gchar *template_group = NULL;
Packit Service c6b9b0
Packit Service c6b9b0
      object_key_file_data = g_hash_table_lookup (group_name_to_key_file_data, object_group);
Packit Service c6b9b0
      g_assert_nonnull (object_key_file_data);
Packit Service c6b9b0
Packit Service c6b9b0
      g_warn_if_fail (g_key_file_has_group (object_key_file_data->key_file, object_group));
Packit Service c6b9b0
Packit Service c6b9b0
      id = account_group_to_id (object_group);
Packit Service c6b9b0
      template_group = g_strdup_printf ("Template %s", id);
Packit Service c6b9b0
Packit Service c6b9b0
      template_key_file_data = g_hash_table_lookup (group_name_to_key_file_data, template_group);
Packit Service c6b9b0
      g_assert_nonnull (template_key_file_data);
Packit Service c6b9b0
      g_assert_true (g_key_file_has_group (template_key_file_data->key_file, template_group));
Packit Service c6b9b0
Packit Service c6b9b0
      if (goa_utils_keyfile_get_boolean (template_key_file_data->key_file, template_group, "ForceRemove"))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          gboolean removed;
Packit Service c6b9b0
Packit Service c6b9b0
          g_debug ("Template %s specifies ForceRemove, removing %s", template_group, object_group);
Packit Service c6b9b0
Packit Service c6b9b0
          error = NULL;
Packit Service c6b9b0
          needs_update = g_key_file_remove_group (object_key_file_data->key_file, object_group, &error);
Packit Service c6b9b0
          if (error != NULL)
Packit Service c6b9b0
            {
Packit Service c6b9b0
              g_warning ("Error removing group %s from %s: %s (%s, %d)",
Packit Service c6b9b0
                         object_group,
Packit Service c6b9b0
                         key_file_data->path,
Packit Service c6b9b0
                         error->message,
Packit Service c6b9b0
                         g_quark_to_string (error->domain),
Packit Service c6b9b0
                         error->code);
Packit Service c6b9b0
              g_error_free (error);
Packit Service c6b9b0
            }
Packit Service c6b9b0
Packit Service c6b9b0
          if (needs_update)
Packit Service c6b9b0
            {
Packit Service c6b9b0
              g_hash_table_insert (key_files_to_update,
Packit Service c6b9b0
                                   g_strdup (object_key_file_data->path),
Packit Service c6b9b0
                                   g_key_file_ref (object_key_file_data->key_file));
Packit Service c6b9b0
            }
Packit Service c6b9b0
Packit Service c6b9b0
          removed = g_hash_table_remove (group_name_to_key_file_data, object_group);
Packit Service c6b9b0
          g_warn_if_fail (removed);
Packit Service c6b9b0
        }
Packit Service c6b9b0
      else
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_debug ("Updating %s from template %s", object_group, template_group);
Packit Service c6b9b0
Packit Service c6b9b0
          needs_update = goa_utils_keyfile_copy_group (template_key_file_data->key_file,
Packit Service c6b9b0
                                                       template_group,
Packit Service c6b9b0
                                                       object_key_file_data->key_file,
Packit Service c6b9b0
                                                       object_group);
Packit Service c6b9b0
Packit Service c6b9b0
          if (needs_update)
Packit Service c6b9b0
            {
Packit Service c6b9b0
              g_key_file_set_boolean (home_conf_key_file, object_group, "IsLocked", TRUE);
Packit Service c6b9b0
              g_hash_table_insert (key_files_to_update,
Packit Service c6b9b0
                                   g_strdup (object_key_file_data->path),
Packit Service c6b9b0
                                   g_key_file_ref (object_key_file_data->key_file));
Packit Service c6b9b0
            }
Packit Service c6b9b0
        }
Packit Service c6b9b0
Packit Service c6b9b0
      g_free (template_group);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  g_hash_table_iter_init (&iter, key_files_to_update);
Packit Service c6b9b0
  while (g_hash_table_iter_next (&iter, (gpointer *) &key_file_path, (gpointer *) &key_file))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      error = NULL;
Packit Service c6b9b0
      if (!g_key_file_save_to_file (key_file, key_file_path, &error))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_prefix_error (&error, "Error writing key-value-file %s: ", key_file_path);
Packit Service c6b9b0
          g_warning ("%s (%s, %d)", error->message, g_quark_to_string (error->domain), error->code);
Packit Service c6b9b0
          g_error_free (error);
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  g_hash_table_unref (key_files_to_update);
Packit Service c6b9b0
  g_key_file_unref (home_conf_key_file);
Packit Service c6b9b0
  g_list_free (added);
Packit Service c6b9b0
  g_list_free (unchanged);
Packit Service c6b9b0
  g_list_free_full (config_object_groups, g_free);
Packit Service c6b9b0
  g_list_free_full (config_template_groups, g_free);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
/* <internal>
Packit Service c6b9b0
 * goa_daemon_reload_configuration:
Packit Service c6b9b0
 * @self: A #GoaDaemon
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * Updates the accounts_objects member from stored configuration -
Packit Service c6b9b0
 * typically called at startup or when a change on the configuration
Packit Service c6b9b0
 * files has been detected.
Packit Service c6b9b0
 */
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_daemon_reload_configuration (GoaDaemon *self)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GHashTable *group_name_to_key_file_data;
Packit Service c6b9b0
Packit Service c6b9b0
  group_name_to_key_file_data = g_hash_table_new_full (g_str_hash,
Packit Service c6b9b0
                                                       g_str_equal,
Packit Service c6b9b0
                                                       g_free,
Packit Service c6b9b0
                                                       (GDestroyNotify) key_file_data_free);
Packit Service c6b9b0
Packit Service c6b9b0
  /* Read the main user config file at $HOME/.config/goa-1.0/accounts.conf */
Packit Service c6b9b0
  add_config_file (self, self->home_conf_file_path, group_name_to_key_file_data);
Packit Service c6b9b0
Packit Service c6b9b0
  if (GOA_TEMPLATE_FILE != NULL && GOA_TEMPLATE_FILE[0] != '\0')
Packit Service c6b9b0
    add_config_file (self, GOA_TEMPLATE_FILE, group_name_to_key_file_data);
Packit Service c6b9b0
Packit Service c6b9b0
  process_template_entries (self, group_name_to_key_file_data);
Packit Service c6b9b0
Packit Service c6b9b0
  /* now process the group_name_to_key_file_data hash table */
Packit Service c6b9b0
  process_config_entries (self, group_name_to_key_file_data);
Packit Service c6b9b0
Packit Service c6b9b0
  g_hash_table_unref (group_name_to_key_file_data);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static gchar *
Packit Service c6b9b0
generate_new_id (GoaDaemon *self)
Packit Service c6b9b0
{
Packit Service c6b9b0
  static guint counter = 0;
Packit Service c6b9b0
  GDateTime *dt;
Packit Service c6b9b0
  gchar *ret;
Packit Service c6b9b0
Packit Service c6b9b0
  dt = g_date_time_new_now_local ();
Packit Service c6b9b0
  ret = g_strdup_printf ("account_%" G_GINT64_FORMAT "_%u",
Packit Service c6b9b0
                         g_date_time_to_unix (dt), /* seconds since Epoch */
Packit Service c6b9b0
                         counter); /* avoids collisions */
Packit Service c6b9b0
  g_date_time_unref (dt);
Packit Service c6b9b0
Packit Service c6b9b0
  counter++;
Packit Service c6b9b0
  return ret;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
typedef struct
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *daemon;
Packit Service c6b9b0
  GoaManager *manager;
Packit Service c6b9b0
  GDBusMethodInvocation *invocation;
Packit Service c6b9b0
  gchar *provider_type;
Packit Service c6b9b0
  gchar *identity;
Packit Service c6b9b0
  gchar *presentation_identity;
Packit Service c6b9b0
  GVariant *credentials;
Packit Service c6b9b0
  GVariant *details;
Packit Service c6b9b0
} AddAccountData;
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
get_all_providers_cb (GObject      *source,
Packit Service c6b9b0
                      GAsyncResult *res,
Packit Service c6b9b0
                      gpointer      user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  AddAccountData *data = user_data;
Packit Service c6b9b0
  GoaProvider *provider = NULL;
Packit Service c6b9b0
  GKeyFile *key_file = NULL;
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
  GList *providers = NULL;
Packit Service c6b9b0
  GList *l;
Packit Service c6b9b0
  gchar *id = NULL;
Packit Service c6b9b0
  gchar *group = NULL;
Packit Service c6b9b0
  gchar *key_file_data = NULL;
Packit Service c6b9b0
  gsize length;
Packit Service c6b9b0
  gsize n_credentials;
Packit Service c6b9b0
  gchar *object_path = NULL;
Packit Service c6b9b0
  GVariantIter iter;
Packit Service c6b9b0
  const gchar *key;
Packit Service c6b9b0
  const gchar *value;
Packit Service c6b9b0
Packit Service c6b9b0
  /* TODO: could check for @type */
Packit Service c6b9b0
Packit Service c6b9b0
  if (!goa_provider_get_all_finish (&providers, res, NULL))
Packit Service c6b9b0
    goto out;
Packit Service c6b9b0
Packit Service c6b9b0
  for (l = providers; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      GoaProvider *p;
Packit Service c6b9b0
      const gchar *type;
Packit Service c6b9b0
Packit Service c6b9b0
      p = GOA_PROVIDER (l->data);
Packit Service c6b9b0
      type = goa_provider_get_provider_type (p);
Packit Service c6b9b0
      if (g_strcmp0 (type, data->provider_type) == 0)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          provider = p;
Packit Service c6b9b0
          break;
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (provider == NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      error= NULL;
Packit Service c6b9b0
      g_set_error (&error,
Packit Service c6b9b0
                   GOA_ERROR,
Packit Service c6b9b0
                   GOA_ERROR_FAILED, /* TODO: more specific */
Packit Service c6b9b0
                   _("Failed to find a provider for: %s"),
Packit Service c6b9b0
                   data->provider_type);
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (data->invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  key_file = g_key_file_new ();
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!g_file_get_contents (data->daemon->home_conf_file_path,
Packit Service c6b9b0
                            &key_file_data,
Packit Service c6b9b0
                            &length,
Packit Service c6b9b0
                            &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      if (error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_error_free (error);
Packit Service c6b9b0
        }
Packit Service c6b9b0
      else
Packit Service c6b9b0
        {
Packit Service c6b9b0
          g_prefix_error (&error, "Error loading file %s: ", data->daemon->home_conf_file_path);
Packit Service c6b9b0
          g_dbus_method_invocation_take_error (data->invocation, error);
Packit Service c6b9b0
          goto out;
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
  else
Packit Service c6b9b0
    {
Packit Service c6b9b0
      if (length > 0)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          error = NULL;
Packit Service c6b9b0
          if (!g_key_file_load_from_data (key_file, key_file_data, length, G_KEY_FILE_KEEP_COMMENTS, &error))
Packit Service c6b9b0
            {
Packit Service c6b9b0
              g_prefix_error (&error, "Error parsing key-value-file %s: ", data->daemon->home_conf_file_path);
Packit Service c6b9b0
              g_dbus_method_invocation_take_error (data->invocation, error);
Packit Service c6b9b0
              goto out;
Packit Service c6b9b0
            }
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  if (!g_variant_lookup (data->details, "Id", "s", &id))
Packit Service c6b9b0
    id = generate_new_id (data->daemon);
Packit Service c6b9b0
Packit Service c6b9b0
  group = g_strdup_printf ("Account %s", id);
Packit Service c6b9b0
  g_key_file_set_string (key_file, group, "Provider", data->provider_type);
Packit Service c6b9b0
  g_key_file_set_string (key_file, group, "Identity", data->identity);
Packit Service c6b9b0
  g_key_file_set_string (key_file, group, "PresentationIdentity", data->presentation_identity);
Packit Service c6b9b0
Packit Service c6b9b0
  g_variant_iter_init (&iter, data->details);
Packit Service c6b9b0
  while (g_variant_iter_next (&iter, "{&s&s}", &key, &value))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      /* We treat IsTemporary special.  If it's true we add in
Packit Service c6b9b0
       * the current session guid, so it can be ignored after
Packit Service c6b9b0
       * the session is over.
Packit Service c6b9b0
       */
Packit Service c6b9b0
      if (g_strcmp0 (key, "IsTemporary") == 0)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          if (g_strcmp0 (value, "true") == 0)
Packit Service c6b9b0
            {
Packit Service c6b9b0
              const char *guid;
Packit Service c6b9b0
Packit Service c6b9b0
              guid = g_dbus_connection_get_guid (data->daemon->connection);
Packit Service c6b9b0
              g_key_file_set_string (key_file, group, "SessionId", guid);
Packit Service c6b9b0
            }
Packit Service c6b9b0
        }
Packit Service c6b9b0
Packit Service c6b9b0
      /* Skip Id since we already handled it above. */
Packit Service c6b9b0
      if (g_strcmp0 (key, "Id") == 0)
Packit Service c6b9b0
        continue;
Packit Service c6b9b0
Packit Service c6b9b0
      g_key_file_set_string (key_file, group, key, value);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!g_key_file_save_to_file (key_file, data->daemon->home_conf_file_path, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_prefix_error (&error, "Error writing key-value-file %s: ", data->daemon->home_conf_file_path);
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (data->invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  n_credentials = g_variant_n_children (data->credentials);
Packit Service c6b9b0
  if (n_credentials > 0)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      /* We don't want to fail AddAccount if we could not store the
Packit Service c6b9b0
       * credentials in the keyring.
Packit Service c6b9b0
       */
Packit Service c6b9b0
      goa_utils_store_credentials_for_id_sync (provider,
Packit Service c6b9b0
                                               id,
Packit Service c6b9b0
                                               data->credentials,
Packit Service c6b9b0
                                               NULL, /* GCancellable */
Packit Service c6b9b0
                                               NULL);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  goa_daemon_reload_configuration (data->daemon);
Packit Service c6b9b0
Packit Service c6b9b0
  object_path = g_strdup_printf ("/org/gnome/OnlineAccounts/Accounts/%s", id);
Packit Service c6b9b0
  goa_manager_complete_add_account (data->manager, data->invocation, object_path);
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_free (object_path);
Packit Service c6b9b0
  g_list_free_full (providers, g_object_unref);
Packit Service c6b9b0
  g_free (key_file_data);
Packit Service c6b9b0
  g_free (group);
Packit Service c6b9b0
  g_free (id);
Packit Service c6b9b0
  g_clear_pointer (&key_file, (GDestroyNotify) g_key_file_unref);
Packit Service c6b9b0
  g_object_unref (data->daemon);
Packit Service c6b9b0
  g_object_unref (data->manager);
Packit Service c6b9b0
  g_object_unref (data->invocation);
Packit Service c6b9b0
  g_free (data->provider_type);
Packit Service c6b9b0
  g_free (data->identity);
Packit Service c6b9b0
  g_free (data->presentation_identity);
Packit Service c6b9b0
  g_variant_unref (data->credentials);
Packit Service c6b9b0
  g_variant_unref (data->details);
Packit Service c6b9b0
  g_slice_free (AddAccountData, data);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
on_manager_handle_add_account (GoaManager             *manager,
Packit Service c6b9b0
                               GDBusMethodInvocation  *invocation,
Packit Service c6b9b0
                               const gchar            *provider_type,
Packit Service c6b9b0
                               const gchar            *identity,
Packit Service c6b9b0
                               const gchar            *presentation_identity,
Packit Service c6b9b0
                               GVariant               *credentials,
Packit Service c6b9b0
                               GVariant               *details,
Packit Service c6b9b0
                               gpointer                user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (user_data);
Packit Service c6b9b0
  AddAccountData *data;
Packit Service c6b9b0
Packit Service c6b9b0
  data = g_slice_new0 (AddAccountData);
Packit Service c6b9b0
  data->daemon = g_object_ref (self);
Packit Service c6b9b0
  data->manager = g_object_ref (manager);
Packit Service c6b9b0
  data->invocation = g_object_ref (invocation);
Packit Service c6b9b0
  data->provider_type = g_strdup (provider_type);
Packit Service c6b9b0
  data->identity = g_strdup (identity);
Packit Service c6b9b0
  data->presentation_identity = g_strdup (presentation_identity);
Packit Service c6b9b0
  data->credentials = g_variant_ref (credentials);
Packit Service c6b9b0
  data->details = g_variant_ref (details);
Packit Service c6b9b0
Packit Service c6b9b0
  goa_provider_get_all (get_all_providers_cb, data);
Packit Service c6b9b0
Packit Service c6b9b0
  return TRUE; /* invocation was handled */
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
typedef struct
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaObject *object;
Packit Service c6b9b0
  GList *invocations;
Packit Service c6b9b0
} ObjectInvocationData;
Packit Service c6b9b0
Packit Service c6b9b0
static ObjectInvocationData *
Packit Service c6b9b0
object_invocation_data_new (GoaObject             *object,
Packit Service c6b9b0
                 GDBusMethodInvocation *invocation)
Packit Service c6b9b0
{
Packit Service c6b9b0
  ObjectInvocationData *data;
Packit Service c6b9b0
  data = g_slice_new0 (ObjectInvocationData);
Packit Service c6b9b0
  data->object = g_object_ref (object);
Packit Service c6b9b0
  data->invocations = g_list_prepend (data->invocations, invocation);
Packit Service c6b9b0
  return data;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
object_invocation_data_unref (ObjectInvocationData *data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  g_list_free (data->invocations);
Packit Service c6b9b0
  g_object_unref (data->object);
Packit Service c6b9b0
  g_slice_free (ObjectInvocationData, data);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
remove_account_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GTask *task = G_TASK (user_data);
Packit Service c6b9b0
  GoaDaemon *self;
Packit Service c6b9b0
  GDBusMethodInvocation *invocation;
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
  GoaAccount *account;
Packit Service c6b9b0
  GoaProvider *provider = GOA_PROVIDER (source_object);
Packit Service c6b9b0
  ObjectInvocationData *data;
Packit Service c6b9b0
Packit Service c6b9b0
  self = GOA_DAEMON (g_task_get_source_object (task));
Packit Service c6b9b0
  data = g_task_get_task_data (task);
Packit Service c6b9b0
Packit Service c6b9b0
  error= NULL;
Packit Service c6b9b0
  if (!goa_provider_remove_account_finish (provider, res, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("goa_provider_remove_account() failed: %s (%s, %d)",
Packit Service c6b9b0
                 error->message,
Packit Service c6b9b0
                 g_quark_to_string (error->domain),
Packit Service c6b9b0
                 error->code);
Packit Service c6b9b0
      g_error_free (error);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  goa_daemon_reload_configuration (self);
Packit Service c6b9b0
Packit Service c6b9b0
  account = goa_object_peek_account (data->object);
Packit Service c6b9b0
  invocation = G_DBUS_METHOD_INVOCATION (data->invocations->data);
Packit Service c6b9b0
  goa_account_complete_remove (account, invocation);
Packit Service c6b9b0
Packit Service c6b9b0
  g_object_unref (task);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
on_account_handle_remove (GoaAccount            *account,
Packit Service c6b9b0
                          GDBusMethodInvocation *invocation,
Packit Service c6b9b0
                          gpointer               user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (user_data);
Packit Service c6b9b0
  GoaObject *object;
Packit Service c6b9b0
  GoaProvider *provider = NULL;
Packit Service c6b9b0
  GKeyFile *key_file = NULL;
Packit Service c6b9b0
  GTask *task = NULL;
Packit Service c6b9b0
  ObjectInvocationData *data;
Packit Service c6b9b0
  const gchar *provider_type = NULL;
Packit Service c6b9b0
  gchar *group = NULL;
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
Packit Service c6b9b0
  if (goa_account_get_is_locked (account))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      error = NULL;
Packit Service c6b9b0
      g_set_error_literal (&error,
Packit Service c6b9b0
                           GOA_ERROR,
Packit Service c6b9b0
                           GOA_ERROR_NOT_SUPPORTED,
Packit Service c6b9b0
                           _("IsLocked property is set for account"));
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  /* update key-file - right now we only support removing the account
Packit Service c6b9b0
   * if the entry is in ~/.config/goa-1.0/accounts.conf
Packit Service c6b9b0
   */
Packit Service c6b9b0
Packit Service c6b9b0
  key_file = g_key_file_new ();
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!g_key_file_load_from_file (key_file,
Packit Service c6b9b0
                                  self->home_conf_file_path,
Packit Service c6b9b0
                                  G_KEY_FILE_KEEP_COMMENTS,
Packit Service c6b9b0
                                  &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  group = g_strdup_printf ("Account %s", goa_account_get_id (account));
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!g_key_file_remove_group (key_file, group, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!g_key_file_save_to_file (key_file, self->home_conf_file_path, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_prefix_error (&error, "Error writing key-value-file %s: ", self->home_conf_file_path);
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  provider_type = goa_account_get_provider_type (account);
Packit Service c6b9b0
  if (provider_type == NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      error = NULL;
Packit Service c6b9b0
      g_set_error_literal (&error,
Packit Service c6b9b0
                           GOA_ERROR,
Packit Service c6b9b0
                           GOA_ERROR_FAILED, /* TODO: more specific */
Packit Service c6b9b0
                           _("ProviderType property is not set for account"));
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  provider = goa_provider_get_for_provider_type (provider_type);
Packit Service c6b9b0
  if (provider == NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      error = NULL;
Packit Service c6b9b0
      g_set_error (&error,
Packit Service c6b9b0
                   GOA_ERROR,
Packit Service c6b9b0
                   GOA_ERROR_FAILED, /* TODO: more specific */
Packit Service c6b9b0
                   _("Failed to find a provider for: %s"),
Packit Service c6b9b0
                   provider_type);
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  error = NULL;
Packit Service c6b9b0
  if (!goa_utils_delete_credentials_for_account_sync (provider, account, NULL, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_dbus_method_invocation_take_error (invocation, error);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (account)));
Packit Service c6b9b0
  data = object_invocation_data_new (object, invocation);
Packit Service c6b9b0
Packit Service c6b9b0
  task = g_task_new (self, NULL, NULL, NULL);
Packit Service c6b9b0
  g_task_set_task_data (task, data, (GDestroyNotify) object_invocation_data_unref);
Packit Service c6b9b0
Packit Service c6b9b0
  goa_provider_remove_account (provider, object, NULL, remove_account_cb, g_object_ref (task));
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_clear_object (&provider);
Packit Service c6b9b0
  g_clear_object (&task);
Packit Service c6b9b0
  g_clear_pointer (&key_file, (GDestroyNotify) g_key_file_unref);
Packit Service c6b9b0
  g_free (group);
Packit Service c6b9b0
  return TRUE; /* invocation was handled */
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
is_authorization_error (GError *error)
Packit Service c6b9b0
{
Packit Service c6b9b0
  gboolean ret;
Packit Service c6b9b0
Packit Service c6b9b0
  g_return_val_if_fail (error != NULL, FALSE);
Packit Service c6b9b0
Packit Service c6b9b0
  ret = FALSE;
Packit Service c6b9b0
  if (error->domain == REST_PROXY_ERROR || error->domain == SOUP_HTTP_ERROR)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      if (SOUP_STATUS_IS_CLIENT_ERROR (error->code))
Packit Service c6b9b0
        ret = TRUE;
Packit Service c6b9b0
    }
Packit Service c6b9b0
  else if (error->domain == GOA_ERROR)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      if (error->code == GOA_ERROR_NOT_AUTHORIZED)
Packit Service c6b9b0
        ret = TRUE;
Packit Service c6b9b0
    }
Packit Service c6b9b0
  return ret;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
ensure_credentials_queue_complete (GList *invocations, GoaAccount *account, gint expires_in, GError *error)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GList *l;
Packit Service c6b9b0
  const gchar *id;
Packit Service c6b9b0
  const gchar *provider_type;
Packit Service c6b9b0
  gint64 timestamp;
Packit Service c6b9b0
Packit Service c6b9b0
  for (l = invocations; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (l->data);
Packit Service c6b9b0
Packit Service c6b9b0
      if (invocation == NULL)
Packit Service c6b9b0
        continue;
Packit Service c6b9b0
Packit Service c6b9b0
      if (error == NULL)
Packit Service c6b9b0
        goa_account_complete_ensure_credentials (account, invocation, expires_in);
Packit Service c6b9b0
      else
Packit Service c6b9b0
        g_dbus_method_invocation_return_gerror (invocation, error);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  id = goa_account_get_id (account);
Packit Service c6b9b0
  provider_type = goa_account_get_provider_type (account);
Packit Service c6b9b0
  timestamp = g_get_monotonic_time ();
Packit Service c6b9b0
  g_debug ("%" G_GINT64_FORMAT ": Handled EnsureCredentials (%s, %s)", timestamp, provider_type, id);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
ensure_credentials_queue_collector (GObject *source_object, GAsyncResult *res, gpointer user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GTask *task = G_TASK (user_data);
Packit Service c6b9b0
  GTask *task_queued;
Packit Service c6b9b0
  GoaDaemon *self;
Packit Service c6b9b0
  GoaAccount *account;
Packit Service c6b9b0
  GoaProvider *provider = GOA_PROVIDER (source_object);
Packit Service c6b9b0
  GError *error;
Packit Service c6b9b0
  ObjectInvocationData *data;
Packit Service c6b9b0
  gint expires_in;
Packit Service c6b9b0
Packit Service c6b9b0
  self = GOA_DAEMON (g_task_get_source_object (task));
Packit Service c6b9b0
Packit Service c6b9b0
  task_queued = G_TASK (g_queue_pop_head (self->ensure_credentials_queue));
Packit Service c6b9b0
  g_assert (task == task_queued);
Packit Service c6b9b0
Packit Service c6b9b0
  data = g_task_get_task_data (task);
Packit Service c6b9b0
  account = goa_object_peek_account (data->object);
Packit Service c6b9b0
Packit Service c6b9b0
  error= NULL;
Packit Service c6b9b0
  if (!goa_provider_ensure_credentials_finish (provider, &expires_in, res, &error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      /* Set AttentionNeeded only if the error is an authorization error */
Packit Service c6b9b0
      if (is_authorization_error (error))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          if (!goa_account_get_attention_needed (account))
Packit Service c6b9b0
            {
Packit Service c6b9b0
              goa_account_set_attention_needed (account, TRUE);
Packit Service c6b9b0
              g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (account));
Packit Service c6b9b0
              g_message ("%s: Setting AttentionNeeded to TRUE because EnsureCredentials() failed with: %s (%s, %d)",
Packit Service c6b9b0
                         g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object)),
Packit Service c6b9b0
                         error->message, g_quark_to_string (error->domain), error->code);
Packit Service c6b9b0
            }
Packit Service c6b9b0
        }
Packit Service c6b9b0
Packit Service c6b9b0
      ensure_credentials_queue_complete (data->invocations, account, 0, error);
Packit Service c6b9b0
      g_error_free (error);
Packit Service c6b9b0
    }
Packit Service c6b9b0
  else
Packit Service c6b9b0
    {
Packit Service c6b9b0
      /* Clear AttentionNeeded flag if set */
Packit Service c6b9b0
      if (goa_account_get_attention_needed (account))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          goa_account_set_attention_needed (account, FALSE);
Packit Service c6b9b0
          g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (account));
Packit Service c6b9b0
          g_message ("%s: Setting AttentionNeeded to FALSE because EnsureCredentials() succeded\n",
Packit Service c6b9b0
                     g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object)));
Packit Service c6b9b0
        }
Packit Service c6b9b0
Packit Service c6b9b0
      ensure_credentials_queue_complete (data->invocations, account, expires_in, NULL);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  self->ensure_credentials_running = FALSE;
Packit Service c6b9b0
  ensure_credentials_queue_check (self);
Packit Service c6b9b0
  g_object_unref (task);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gint
Packit Service c6b9b0
ensure_credentials_queue_sort (gconstpointer a, gconstpointer b, gpointer user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GTask *task_a = G_TASK (a);
Packit Service c6b9b0
  GTask *task_b = G_TASK (b);
Packit Service c6b9b0
  gint priority_a;
Packit Service c6b9b0
  gint priority_b;
Packit Service c6b9b0
Packit Service c6b9b0
  priority_a = g_task_get_priority (task_a);
Packit Service c6b9b0
  priority_b = g_task_get_priority (task_b);
Packit Service c6b9b0
Packit Service c6b9b0
  return priority_a - priority_b;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
ensure_credentials_queue_check (GoaDaemon *self)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaAccount *account;
Packit Service c6b9b0
  GoaProvider *provider = NULL;
Packit Service c6b9b0
  GTask *task;
Packit Service c6b9b0
  ObjectInvocationData *data;
Packit Service c6b9b0
  const gchar *id;
Packit Service c6b9b0
  const gchar *provider_type;
Packit Service c6b9b0
  gint64 timestamp;
Packit Service c6b9b0
Packit Service c6b9b0
  if (self->ensure_credentials_running)
Packit Service c6b9b0
    goto out;
Packit Service c6b9b0
Packit Service c6b9b0
  if (self->ensure_credentials_queue->length == 0)
Packit Service c6b9b0
    goto out;
Packit Service c6b9b0
Packit Service c6b9b0
  g_queue_sort (self->ensure_credentials_queue, ensure_credentials_queue_sort, NULL);
Packit Service c6b9b0
Packit Service c6b9b0
  task = G_TASK (g_queue_peek_head (self->ensure_credentials_queue));
Packit Service c6b9b0
  self->ensure_credentials_running = TRUE;
Packit Service c6b9b0
Packit Service c6b9b0
  data = (ObjectInvocationData *) g_task_get_task_data (task);
Packit Service c6b9b0
  account = goa_object_peek_account (data->object);
Packit Service c6b9b0
Packit Service c6b9b0
  id = goa_account_get_id (account);
Packit Service c6b9b0
  provider_type = goa_account_get_provider_type (account);
Packit Service c6b9b0
  timestamp = g_get_monotonic_time ();
Packit Service c6b9b0
  g_debug ("%" G_GINT64_FORMAT ": Handling EnsureCredentials (%s, %s)", timestamp, provider_type, id);
Packit Service c6b9b0
Packit Service c6b9b0
  provider = goa_provider_get_for_provider_type (provider_type);
Packit Service c6b9b0
  g_assert_nonnull (provider);
Packit Service c6b9b0
Packit Service c6b9b0
  goa_provider_ensure_credentials (provider,
Packit Service c6b9b0
                                   data->object,
Packit Service c6b9b0
                                   NULL, /* GCancellable */
Packit Service c6b9b0
                                   ensure_credentials_queue_collector,
Packit Service c6b9b0
                                   task);
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_clear_object (&provider);
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
ensure_credentials_queue_coalesce (GoaDaemon *self, GoaObject *object, GDBusMethodInvocation *invocation)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GList *l;
Packit Service c6b9b0
  GoaAccount *account;
Packit Service c6b9b0
  const gchar *id;
Packit Service c6b9b0
  gboolean ret = FALSE;
Packit Service c6b9b0
  gint priority;
Packit Service c6b9b0
Packit Service c6b9b0
  account = goa_object_peek_account (object);
Packit Service c6b9b0
  id = goa_account_get_id (account);
Packit Service c6b9b0
Packit Service c6b9b0
  priority = (invocation == NULL) ? G_PRIORITY_LOW : G_PRIORITY_HIGH;
Packit Service c6b9b0
Packit Service c6b9b0
  for (l = self->ensure_credentials_queue->head; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      GoaAccount *account_queued;
Packit Service c6b9b0
      GTask *task = G_TASK (l->data);
Packit Service c6b9b0
      ObjectInvocationData *data;
Packit Service c6b9b0
      const gchar *id_queued;
Packit Service c6b9b0
Packit Service c6b9b0
      data = g_task_get_task_data (task);
Packit Service c6b9b0
      account_queued = goa_object_peek_account (data->object);
Packit Service c6b9b0
      id_queued = goa_account_get_id (account_queued);
Packit Service c6b9b0
      if (g_strcmp0 (id, id_queued) == 0)
Packit Service c6b9b0
        {
Packit Service c6b9b0
          gint priority_queued;
Packit Service c6b9b0
Packit Service c6b9b0
          priority_queued = g_task_get_priority (task);
Packit Service c6b9b0
          if (priority < priority_queued)
Packit Service c6b9b0
            g_task_set_priority (task, priority);
Packit Service c6b9b0
Packit Service c6b9b0
          data->invocations = g_list_prepend (data->invocations, invocation);
Packit Service c6b9b0
Packit Service c6b9b0
          ret = TRUE;
Packit Service c6b9b0
          break;
Packit Service c6b9b0
        }
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  return ret;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
on_account_handle_ensure_credentials (GoaAccount            *account,
Packit Service c6b9b0
                                      GDBusMethodInvocation *invocation,
Packit Service c6b9b0
                                      gpointer               user_data)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaDaemon *self = GOA_DAEMON (user_data);
Packit Service c6b9b0
  GoaObject *object;
Packit Service c6b9b0
  GoaProvider *provider = NULL;
Packit Service c6b9b0
  GTask *task = NULL;
Packit Service c6b9b0
  ObjectInvocationData *data;
Packit Service c6b9b0
  const gchar *id;
Packit Service c6b9b0
  const gchar *method_name;
Packit Service c6b9b0
  const gchar *provider_type;
Packit Service c6b9b0
  gint64 timestamp;
Packit Service c6b9b0
Packit Service c6b9b0
  id = goa_account_get_id (account);
Packit Service c6b9b0
  provider_type = goa_account_get_provider_type (account);
Packit Service c6b9b0
  method_name = g_dbus_method_invocation_get_method_name (invocation);
Packit Service c6b9b0
  timestamp = g_get_monotonic_time ();
Packit Service c6b9b0
  g_debug ("%" G_GINT64_FORMAT ": Received %s (%s, %s)", timestamp, method_name, provider_type, id);
Packit Service c6b9b0
Packit Service c6b9b0
  provider = goa_provider_get_for_provider_type (provider_type);
Packit Service c6b9b0
  if (provider == NULL)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_dbus_method_invocation_return_error (invocation,
Packit Service c6b9b0
                                             GOA_ERROR,
Packit Service c6b9b0
                                             GOA_ERROR_FAILED,
Packit Service c6b9b0
                                             "Unsupported account type %s for id %s (no provider)",
Packit Service c6b9b0
                                             provider_type,
Packit Service c6b9b0
                                             id);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (account)));
Packit Service c6b9b0
  if (ensure_credentials_queue_coalesce (self, object, invocation))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      timestamp = g_get_monotonic_time ();
Packit Service c6b9b0
      g_debug ("%" G_GINT64_FORMAT ": Coalesced %s (%s, %s)",
Packit Service c6b9b0
               timestamp,
Packit Service c6b9b0
               method_name,
Packit Service c6b9b0
               provider_type,
Packit Service c6b9b0
               id);
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  data = object_invocation_data_new (object, invocation);
Packit Service c6b9b0
Packit Service c6b9b0
  task = g_task_new (self, NULL, NULL, NULL);
Packit Service c6b9b0
  g_task_set_priority (task, G_PRIORITY_HIGH);
Packit Service c6b9b0
  g_task_set_task_data (task, data, (GDestroyNotify) object_invocation_data_unref);
Packit Service c6b9b0
  g_queue_push_tail (self->ensure_credentials_queue, g_object_ref (task));
Packit Service c6b9b0
Packit Service c6b9b0
  ensure_credentials_queue_check (self);
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_clear_object (&provider);
Packit Service c6b9b0
  g_clear_object (&task);
Packit Service c6b9b0
  return TRUE; /* invocation was handled */
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* <internal>
Packit Service c6b9b0
 * goa_daemon_check_credentials:
Packit Service c6b9b0
 * @self: A #GoaDaemon
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * Checks whether credentials are valid and tries to refresh them if
Packit Service c6b9b0
 * not. It also reports whether accounts are usable with the current
Packit Service c6b9b0
 * network.
Packit Service c6b9b0
 */
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_daemon_check_credentials (GoaDaemon *self)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GList *l;
Packit Service c6b9b0
  GList *objects;
Packit Service c6b9b0
Packit Service c6b9b0
  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager));
Packit Service c6b9b0
  for (l = objects; l != NULL; l = l->next)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      GoaAccount *account;
Packit Service c6b9b0
      GoaObject *object = GOA_OBJECT (l->data);
Packit Service c6b9b0
      GoaProvider *provider = NULL;
Packit Service c6b9b0
      GTask *task = NULL;
Packit Service c6b9b0
      ObjectInvocationData *data;
Packit Service c6b9b0
      const gchar *id;
Packit Service c6b9b0
      const gchar *provider_type;
Packit Service c6b9b0
      gint64 timestamp;
Packit Service c6b9b0
Packit Service c6b9b0
      account = goa_object_peek_account (object);
Packit Service c6b9b0
      if (account == NULL)
Packit Service c6b9b0
        goto cleanup_and_continue;
Packit Service c6b9b0
Packit Service c6b9b0
      provider_type = goa_account_get_provider_type (account);
Packit Service c6b9b0
      provider = goa_provider_get_for_provider_type (provider_type);
Packit Service c6b9b0
      if (provider == NULL)
Packit Service c6b9b0
        goto cleanup_and_continue;
Packit Service c6b9b0
Packit Service c6b9b0
      id = goa_account_get_id (account);
Packit Service c6b9b0
      provider_type = goa_account_get_provider_type (account);
Packit Service c6b9b0
      timestamp = g_get_monotonic_time ();
Packit Service c6b9b0
      g_debug ("%" G_GINT64_FORMAT ": Calling EnsureCredentials (%s, %s)",
Packit Service c6b9b0
               timestamp,
Packit Service c6b9b0
               provider_type,
Packit Service c6b9b0
               id);
Packit Service c6b9b0
Packit Service c6b9b0
      if (ensure_credentials_queue_coalesce (self, object, NULL))
Packit Service c6b9b0
        {
Packit Service c6b9b0
          timestamp = g_get_monotonic_time ();
Packit Service c6b9b0
          g_debug ("%" G_GINT64_FORMAT ": Coalesced EnsureCredentials (%s, %s)",
Packit Service c6b9b0
                   timestamp,
Packit Service c6b9b0
                   provider_type,
Packit Service c6b9b0
                   id);
Packit Service c6b9b0
          goto cleanup_and_continue;
Packit Service c6b9b0
        }
Packit Service c6b9b0
Packit Service c6b9b0
      data = object_invocation_data_new (object, NULL);
Packit Service c6b9b0
Packit Service c6b9b0
      task = g_task_new (self, NULL, NULL, NULL);
Packit Service c6b9b0
      g_task_set_priority (task, G_PRIORITY_LOW);
Packit Service c6b9b0
      g_task_set_task_data (task, data, (GDestroyNotify) object_invocation_data_unref);
Packit Service c6b9b0
      g_queue_push_tail (self->ensure_credentials_queue, g_object_ref (task));
Packit Service c6b9b0
Packit Service c6b9b0
    cleanup_and_continue:
Packit Service c6b9b0
      g_clear_object (&provider);
Packit Service c6b9b0
      g_clear_object (&task);
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  ensure_credentials_queue_check (self);
Packit Service c6b9b0
  g_list_free_full (objects, g_object_unref);
Packit Service c6b9b0
}