Blob Blame History Raw
From 1e2385077256bd5156d4269becc3a9e0a2d29c58 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 3 Oct 2017 13:48:52 -0400
Subject: [PATCH 11/13] lib: simplify code dramatically

ActUser is a wrapper over the accountsservice daemon's
managed user objects.  There's a nearly 1-to-1 correspondence
between properties on the proxy to the daemon and properties
on the ActUser object.

This commit dramatically reduces the code, by leveraging the
proxies properties directly, rather than duplicating the values
on the ActUser object.

At the same time, it drops manual GetAll() calls for synchronizing
the proxies properties, since it's completely redundant with the
work the proxy is doing under the hood anyway.
---
 src/libaccountsservice/act-user.c | 676 ++++++++------------------------------
 1 file changed, 143 insertions(+), 533 deletions(-)

diff --git a/src/libaccountsservice/act-user.c b/src/libaccountsservice/act-user.c
index 17acacb..94884a1 100644
--- a/src/libaccountsservice/act-user.c
+++ b/src/libaccountsservice/act-user.c
@@ -81,94 +81,66 @@ enum {
         PROP_PASSWORD_HINT,
         PROP_HOME_DIR,
         PROP_SHELL,
         PROP_EMAIL,
         PROP_LOCATION,
         PROP_LOCKED,
         PROP_AUTOMATIC_LOGIN,
         PROP_SYSTEM_ACCOUNT,
         PROP_NONEXISTENT,
         PROP_LOCAL_ACCOUNT,
         PROP_LOGIN_FREQUENCY,
         PROP_LOGIN_TIME,
         PROP_LOGIN_HISTORY,
         PROP_ICON_FILE,
         PROP_LANGUAGE,
         PROP_X_SESSION,
         PROP_IS_LOADED
 };
 
 enum {
         CHANGED,
         SESSIONS_CHANGED,
         LAST_SIGNAL
 };
 
 struct _ActUser {
         GObject         parent;
 
         GDBusConnection *connection;
         AccountsUser    *accounts_proxy;
-        GDBusProxy      *object_proxy;
-        GCancellable    *get_all_cancellable;
-        char            *object_path;
-
-        uid_t           uid;
-        char           *user_name;
-        char           *real_name;
-        char           *password_hint;
-        char           *home_dir;
-        char           *shell;
-        char           *email;
-        char           *location;
-        char           *icon_file;
-        char           *language;
-        char           *x_session;
+
         GList          *our_sessions;
         GList          *other_sessions;
-        int             login_frequency;
-        gint64          login_time;
-        GVariant       *login_history;
-
-        ActUserAccountType  account_type;
-        ActUserPasswordMode password_mode;
-
-        guint           uid_set : 1;
 
         guint           is_loaded : 1;
-        guint           locked : 1;
-        guint           automatic_login : 1;
-        guint           system_account : 1;
-        guint           local_account : 1;
         guint           nonexistent : 1;
-
-        guint           update_info_timeout_id;
 };
 
 struct _ActUserClass
 {
         GObjectClass parent_class;
 };
 
 static void act_user_finalize     (GObject      *object);
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (ActUser, act_user, G_TYPE_OBJECT)
 
 static int
 session_compare (const char *a,
                  const char *b)
 {
         if (a == NULL) {
                 return 1;
         } else if (b == NULL) {
                 return -1;
         }
 
         return strcmp (a, b);
 }
 
 void
 _act_user_add_session (ActUser    *user,
                        const char *ssid,
                        gboolean    is_ours)
@@ -238,128 +210,75 @@ act_user_get_num_sessions (ActUser    *user)
 /**
  * act_user_get_num_sessions_anywhere:
  * @user: a user
  *
  * Get the number of sessions for a user on any seat of any type.
  * See also act_user_get_num_sessions().
  *
  * (Currently, this function is only implemented for systemd-logind.
  * For ConsoleKit, it is equivalent to act_user_get_num_sessions.)
  *
  * Returns: the number of sessions
  */
 guint
 act_user_get_num_sessions_anywhere (ActUser    *user)
 {
         return (g_list_length (user->our_sessions)
                 + g_list_length (user->other_sessions));
 }
 
 static void
 act_user_get_property (GObject    *object,
                        guint       param_id,
                        GValue     *value,
                        GParamSpec *pspec)
 {
         ActUser *user;
 
         user = ACT_USER (object);
 
         switch (param_id) {
-        case PROP_UID:
-                g_value_set_int (value, user->uid);
-                break;
-        case PROP_USER_NAME:
-                g_value_set_string (value, user->user_name);
-                break;
-        case PROP_REAL_NAME:
-                g_value_set_string (value, user->real_name);
-                break;
-        case PROP_ACCOUNT_TYPE:
-                g_value_set_int (value, user->account_type);
-                break;
-        case PROP_PASSWORD_MODE:
-                g_value_set_int (value, user->password_mode);
-                break;
-        case PROP_PASSWORD_HINT:
-                g_value_set_string (value, user->password_hint);
-                break;
-        case PROP_HOME_DIR:
-                g_value_set_string (value, user->home_dir);
-                break;
-        case PROP_LOGIN_FREQUENCY:
-                g_value_set_int (value, user->login_frequency);
-                break;
-        case PROP_LOGIN_TIME:
-                g_value_set_int64 (value, user->login_time);
-                break;
-        case PROP_LOGIN_HISTORY:
-                g_value_set_variant (value, user->login_history);
-                break;
-        case PROP_SHELL:
-                g_value_set_string (value, user->shell);
-                break;
-        case PROP_EMAIL:
-                g_value_set_string (value, user->email);
-                break;
-        case PROP_LOCATION:
-                g_value_set_string (value, user->location);
-                break;
-        case PROP_ICON_FILE:
-                g_value_set_string (value, user->icon_file);
-                break;
-        case PROP_LANGUAGE:
-                g_value_set_string (value, user->language);
-                break;
-        case PROP_X_SESSION:
-                g_value_set_string (value, user->x_session);
-                break;
-        case PROP_LOCKED:
-                g_value_set_boolean (value, user->locked);
-                break;
-        case PROP_AUTOMATIC_LOGIN:
-                g_value_set_boolean (value, user->automatic_login);
-                break;
-        case PROP_SYSTEM_ACCOUNT:
-                g_value_set_boolean (value, user->system_account);
-                break;
-        case PROP_LOCAL_ACCOUNT:
-                g_value_set_boolean (value, user->local_account);
-                break;
         case PROP_NONEXISTENT:
                 g_value_set_boolean (value, user->nonexistent);
                 break;
         case PROP_IS_LOADED:
                 g_value_set_boolean (value, user->is_loaded);
                 break;
         default:
-                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+                if (user->accounts_proxy != NULL) {
+                        const char *property_name;
+
+                        property_name = g_param_spec_get_name (pspec);
+
+                        g_object_get_property (G_OBJECT (user->accounts_proxy), property_name, value);
+
+                }
                 break;
         }
 }
 
 
 static void
 act_user_class_init (ActUserClass *class)
 {
         GObjectClass *gobject_class;
 
         gobject_class = G_OBJECT_CLASS (class);
 
         gobject_class->finalize = act_user_finalize;
         gobject_class->get_property = act_user_get_property;
 
         g_object_class_install_property (gobject_class,
                                          PROP_REAL_NAME,
                                          g_param_spec_string ("real-name",
                                                               "Real Name",
                                                               "The real name to display for this user.",
                                                               NULL,
                                                               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
         g_object_class_install_property (gobject_class,
                                          PROP_ACCOUNT_TYPE,
                                          g_param_spec_int ("account-type",
                                                            "Account Type",
                                                            "The account type for this user.",
                                                            ACT_USER_ACCOUNT_TYPE_STANDARD,
                                                            ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR,
@@ -525,1082 +444,773 @@ act_user_class_init (ActUserClass *class)
          * Emitted when the user accounts changes in some way.
          */
         signals [CHANGED] =
                 g_signal_new ("changed",
                               G_TYPE_FROM_CLASS (class),
                               G_SIGNAL_RUN_LAST,
                               0,
                               NULL, NULL,
                               g_cclosure_marshal_VOID__VOID,
                               G_TYPE_NONE, 0);
         /**
          * ActUser::sessions-changed:
          *
          * Emitted when the list of sessions for this user changes.
          */
         signals [SESSIONS_CHANGED] =
                 g_signal_new ("sessions-changed",
                               G_TYPE_FROM_CLASS (class),
                               G_SIGNAL_RUN_LAST,
                               0,
                               NULL, NULL,
                               g_cclosure_marshal_VOID__VOID,
                               G_TYPE_NONE, 0);
 }
 
 static void
 act_user_init (ActUser *user)
 {
         GError *error = NULL;
 
-        user->local_account = TRUE;
-        user->user_name = NULL;
-        user->real_name = NULL;
         user->our_sessions = NULL;
         user->other_sessions = NULL;
-        user->login_history = NULL;
 
         user->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
         if (user->connection == NULL) {
                 g_warning ("Couldn't connect to system bus: %s", error->message);
                 g_error_free (error);
         }
 }
 
 static void
 act_user_finalize (GObject *object)
 {
         ActUser *user;
 
         user = ACT_USER (object);
 
-        g_free (user->user_name);
-        g_free (user->real_name);
-        g_free (user->icon_file);
-        g_free (user->language);
-        g_free (user->object_path);
-        g_free (user->password_hint);
-        g_free (user->home_dir);
-        g_free (user->shell);
-        g_free (user->email);
-        g_free (user->location);
-        if (user->login_history)
-          g_variant_unref (user->login_history);
-
         if (user->accounts_proxy != NULL) {
                 g_object_unref (user->accounts_proxy);
         }
 
-        if (user->object_proxy != NULL) {
-                g_object_unref (user->object_proxy);
-        }
-
-        if (user->get_all_cancellable != NULL) {
-                g_object_unref (user->get_all_cancellable);
-        }
-
         if (user->connection != NULL) {
                 g_object_unref (user->connection);
         }
 
-        if (user->update_info_timeout_id != 0) {
-                g_source_remove (user->update_info_timeout_id);
-        }
-
         if (G_OBJECT_CLASS (act_user_parent_class)->finalize)
                 (*G_OBJECT_CLASS (act_user_parent_class)->finalize) (object);
 }
 
 static void
 set_is_loaded (ActUser  *user,
                gboolean  is_loaded)
 {
         if (user->is_loaded != is_loaded) {
                 user->is_loaded = is_loaded;
                 g_object_notify (G_OBJECT (user), "is-loaded");
         }
 }
 
 /**
  * act_user_get_uid:
  * @user: the user object to examine.
  *
  * Retrieves the ID of @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 
 uid_t
 act_user_get_uid (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), -1);
 
-        return user->uid;
+        if (user->accounts_proxy == NULL)
+                return -1;
+
+        return accounts_user_get_uid (user->accounts_proxy);
 }
 
 /**
  * act_user_get_real_name:
  * @user: the user object to examine.
  *
  * Retrieves the display name of @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 const char *
 act_user_get_real_name (ActUser *user)
 {
+        const char *real_name = NULL;
+
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        if (user->real_name == NULL ||
-            user->real_name[0] == '\0') {
-                return user->user_name;
+        real_name = accounts_user_get_real_name (user->accounts_proxy);
+
+        if (real_name == NULL || real_name[0] == '\0') {
+                real_name = accounts_user_get_user_name (user->accounts_proxy);
         }
 
-        return user->real_name;
+        return real_name;
 }
 
 /**
  * act_user_get_account_type:
  * @user: the user object to examine.
  *
  * Retrieves the account type of @user.
  *
  * Returns: a #ActUserAccountType
  **/
 ActUserAccountType
 act_user_get_account_type (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), ACT_USER_ACCOUNT_TYPE_STANDARD);
 
-        return user->account_type;
+        if (user->accounts_proxy == NULL)
+                return ACT_USER_ACCOUNT_TYPE_STANDARD;
+
+        return accounts_user_get_account_type (user->accounts_proxy);
 }
 
 /**
  * act_user_get_password_mode:
  * @user: the user object to examine.
  *
  * Retrieves the password mode of @user.
  *
  * Returns: a #ActUserPasswordMode
  **/
 ActUserPasswordMode
 act_user_get_password_mode (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), ACT_USER_PASSWORD_MODE_REGULAR);
 
-        return user->password_mode;
+        if (user->accounts_proxy == NULL)
+                return ACT_USER_PASSWORD_MODE_REGULAR;
+
+        return accounts_user_get_password_mode (user->accounts_proxy);
 }
 
 /**
  * act_user_get_password_hint:
  * @user: the user object to examine.
  *
  * Retrieves the password hint set by @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 const char *
 act_user_get_password_hint (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->password_hint;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_password_hint (user->accounts_proxy);
 }
 
 /**
  * act_user_get_home_dir:
  * @user: the user object to examine.
  *
  * Retrieves the home directory for @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 const char *
 act_user_get_home_dir (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->home_dir;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_home_directory (user->accounts_proxy);
 }
 
 /**
  * act_user_get_shell:
  * @user: the user object to examine.
  *
  * Retrieves the shell assigned to @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 const char *
 act_user_get_shell (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->shell;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_shell (user->accounts_proxy);
 }
 
 /**
  * act_user_get_email:
  * @user: the user object to examine.
  *
  * Retrieves the email address set by @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 const char *
 act_user_get_email (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->email;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_email (user->accounts_proxy);
 }
 
 /**
  * act_user_get_location:
  * @user: the user object to examine.
  *
  * Retrieves the location set by @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 const char *
 act_user_get_location (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->location;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_location (user->accounts_proxy);
 }
 
 /**
  * act_user_get_user_name:
  * @user: the user object to examine.
  *
  * Retrieves the login name of @user.
  *
  * Returns: (transfer none): a pointer to an array of characters which must not be modified or
  *  freed, or %NULL.
  **/
 
 const char *
 act_user_get_user_name (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->user_name;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_user_name (user->accounts_proxy);
 }
 
 /**
  * act_user_get_login_frequency:
  * @user: a #ActUser
  *
  * Returns the number of times @user has logged in.
  *
  * Returns: the login frequency
  */
 int
 act_user_get_login_frequency (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), 0);
 
-        return user->login_frequency;
+        if (user->accounts_proxy == NULL)
+                return 0;
+
+        return accounts_user_get_login_frequency (user->accounts_proxy);
 }
 
 /**
  * act_user_get_login_time:
  * @user: a #ActUser
  *
  * Returns the last login time for @user.
  *
  * Returns: (transfer none): the login time
  */
 gint64
-act_user_get_login_time (ActUser *user) {
+act_user_get_login_time (ActUser *user)
+{
         g_return_val_if_fail (ACT_IS_USER (user), 0);
 
-        return user->login_time;
+        if (user->accounts_proxy == NULL)
+                return 0;
+
+        return accounts_user_get_login_time (user->accounts_proxy);
 }
 
 /**
  * act_user_get_login_history:
  * @user: a #ActUser
  *
  * Returns the login history for @user.
  *
  * Returns: (transfer none): a pointer to GVariant of type "a(xxa{sv})"
  * which must not be modified or freed, or %NULL.
  */
 const GVariant *
-act_user_get_login_history (ActUser *user) {
+act_user_get_login_history (ActUser *user)
+{
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->login_history;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_login_history (user->accounts_proxy);
 }
 
 /**
  * act_user_collate:
  * @user1: a user
  * @user2: a user
  *
  * Organize the user by login frequency and names.
  *
  * Returns: negative if @user1 is before @user2, zero if equal
  *    or positive if @user1 is after @user2
  */
 int
 act_user_collate (ActUser *user1,
                   ActUser *user2)
 {
         const char *str1;
         const char *str2;
         int         num1;
         int         num2;
         guint       len1;
         guint       len2;
 
         g_return_val_if_fail (ACT_IS_USER (user1), 0);
         g_return_val_if_fail (ACT_IS_USER (user2), 0);
 
-        num1 = user1->login_frequency;
-        num2 = user2->login_frequency;
+        num1 = act_user_get_login_frequency (user1);
+        num2 = act_user_get_login_frequency (user2);
 
         if (num1 > num2) {
                 return -1;
         }
 
         if (num1 < num2) {
                 return 1;
         }
 
 
         len1 = g_list_length (user1->our_sessions);
         len2 = g_list_length (user2->our_sessions);
 
         if (len1 > len2) {
                 return -1;
         }
 
         if (len1 < len2) {
                 return 1;
         }
 
         /* if login frequency is equal try names */
-        if (user1->real_name != NULL) {
-                str1 = user1->real_name;
-        } else {
-                str1 = user1->user_name;
-        }
-
-        if (user2->real_name != NULL) {
-                str2 = user2->real_name;
-        } else {
-                str2 = user2->user_name;
-        }
+        str1 = act_user_get_real_name (user1);
+        str2 = act_user_get_real_name (user2);
 
         if (str1 == NULL && str2 != NULL) {
                 return -1;
         }
 
         if (str1 != NULL && str2 == NULL) {
                 return 1;
         }
 
         if (str1 == NULL && str2 == NULL) {
                 return 0;
         }
 
         return g_utf8_collate (str1, str2);
 }
 
 /**
  * act_user_is_logged_in:
  * @user: a #ActUser
  *
  * Returns whether or not #ActUser is currently graphically logged in
  * on the same seat as the seat of the session of the calling process.
  *
  * Returns: %TRUE or %FALSE
  */
 gboolean
 act_user_is_logged_in (ActUser *user)
 {
         return user->our_sessions != NULL;
 }
 
 /**
  * act_user_is_logged_in_anywhere:
  * @user: a #ActUser
  *
  * Returns whether or not #ActUser is currently logged in in any way
  * whatsoever.  See also act_user_is_logged_in().
  *
  * (Currently, this function is only implemented for systemd-logind.
  * For ConsoleKit, it is equivalent to act_user_is_logged_in.)
  *
  * Returns: %TRUE or %FALSE
  */
 gboolean
 act_user_is_logged_in_anywhere (ActUser *user)
 {
         return user->our_sessions != NULL || user->other_sessions != NULL;
 }
 
 /**
  * act_user_get_locked:
  * @user: a #ActUser
  *
  * Returns whether or not the #ActUser account is locked.
  *
  * Returns: %TRUE or %FALSE
  */
 gboolean
 act_user_get_locked (ActUser *user)
 {
-        return user->locked;;
+        return accounts_user_get_locked (user->accounts_proxy);
 }
 
 /**
  * act_user_get_automatic_login:
  * @user: a #ActUser
  *
  * Returns whether or not #ActUser is automatically logged in at boot time.
  *
  * Returns: %TRUE or %FALSE
  */
 gboolean
 act_user_get_automatic_login (ActUser *user)
 {
-        return user->automatic_login;
+        g_return_val_if_fail (ACT_IS_USER (user), FALSE);
+
+        if (user->accounts_proxy == NULL)
+                return FALSE;
+
+       return accounts_user_get_automatic_login (user->accounts_proxy);
 }
 
 /**
  * act_user_is_system_account:
  * @user: a #ActUser
  *
  * Returns whether or not #ActUser represents a 'system account' like
  * 'root' or 'nobody'.
  *
  * Returns: %TRUE or %FALSE
  */
 gboolean
 act_user_is_system_account (ActUser *user)
 {
-        return user->system_account;
+        g_return_val_if_fail (ACT_IS_USER (user), TRUE);
+
+        if (user->accounts_proxy == NULL)
+                return TRUE;
+
+        return accounts_user_get_system_account (user->accounts_proxy);
 }
 
 /**
  * act_user_is_local_account:
  * @user: the user object to examine.
  *
  * Retrieves whether the user is a local account or not.
  *
  * Returns: (transfer none): %TRUE if the user is local
  **/
 gboolean
 act_user_is_local_account (ActUser   *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), FALSE);
 
-        return user->local_account;
+        if (user->accounts_proxy == NULL)
+                return FALSE;
+
+        return accounts_user_get_local_account (user->accounts_proxy);
 }
 
 /**
  * act_user_is_nonexistent:
  * @user: the user object to examine.
  *
  * Retrieves whether the user is nonexistent or not.
  *
  * Returns: (transfer none): %TRUE if the user is nonexistent
  **/
 gboolean
 act_user_is_nonexistent (ActUser   *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), FALSE);
 
         return user->nonexistent;
 }
 
 /**
  * act_user_get_icon_file:
  * @user: a #ActUser
  *
  * Returns the path to the account icon belonging to @user.
  *
  * Returns: (transfer none): a path to an icon
  */
 const char *
 act_user_get_icon_file (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->icon_file;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_icon_file (user->accounts_proxy);
 }
 
 /**
  * act_user_get_language:
  * @user: a #ActUser
  *
  * Returns the path to the configured locale of @user.
  *
  * Returns: (transfer none): a path to an icon
  */
 const char *
 act_user_get_language (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->language;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_language (user->accounts_proxy);
 }
 
 /**
  * act_user_get_x_session:
  * @user: a #ActUser
  *
  * Returns the path to the configured X session for @user.
  *
  * Returns: (transfer none): a path to an icon
  */
 const char *
 act_user_get_x_session (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->x_session;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return accounts_user_get_xsession (user->accounts_proxy);
 }
 
 /**
  * act_user_get_object_path:
  * @user: a #ActUser
  *
  * Returns the user accounts service object path of @user,
  * or %NULL if @user doesn't have an object path associated
  * with it.
  *
  * Returns: (transfer none): the object path of the user
  */
 const char *
 act_user_get_object_path (ActUser *user)
 {
         g_return_val_if_fail (ACT_IS_USER (user), NULL);
 
-        return user->object_path;
+        if (user->accounts_proxy == NULL)
+                return NULL;
+
+        return g_dbus_proxy_get_object_path (G_DBUS_PROXY (user->accounts_proxy));
 }
 
 /**
  * act_user_get_primary_session_id:
  * @user: a #ActUser
  *
  * Returns the id of the primary session of @user, or %NULL if @user
  * has no primary session.  The primary session will always be
  * graphical and will be chosen from the sessions on the same seat as
  * the seat of the session of the calling process.
  *
  * Returns: (transfer none): the id of the primary session of the user
  */
 const char *
 act_user_get_primary_session_id (ActUser *user)
 {
         if (user->our_sessions == NULL) {
                 g_debug ("User %s is not logged in here, so has no primary session",
                          act_user_get_user_name (user));
                 return NULL;
         }
 
         /* FIXME: better way to choose? */
         return user->our_sessions->data;
 }
 
-static void
-collect_props (const gchar *key,
-               GVariant    *value,
-               ActUser     *user)
-{
-        gboolean handled = TRUE;
-
-        if (strcmp (key, "Uid") == 0) {
-                guint64 new_uid;
-
-                new_uid = g_variant_get_uint64 (value);
-                if (!user->uid_set || (guint64) user->uid != new_uid) {
-                        user->uid = (uid_t) new_uid;
-                        user->uid_set = TRUE;
-                        g_object_notify (G_OBJECT (user), "uid");
-                }
-        } else if (strcmp (key, "UserName") == 0) {
-                const char *new_user_name;
-
-                new_user_name = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->user_name, new_user_name) != 0) {
-                        g_free (user->user_name);
-                        user->user_name = g_strdup (new_user_name);
-                        g_object_notify (G_OBJECT (user), "user-name");
-                }
-        } else if (strcmp (key, "RealName") == 0) {
-                const char *new_real_name;
-
-                new_real_name = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->real_name, new_real_name) != 0) {
-                        g_free (user->real_name);
-                        user->real_name = g_strdup (new_real_name);
-                        g_object_notify (G_OBJECT (user), "real-name");
-                }
-        } else if (strcmp (key, "AccountType") == 0) {
-                int new_account_type;
-
-                new_account_type = g_variant_get_int32 (value);
-                if ((int) user->account_type != new_account_type) {
-                        user->account_type = (ActUserAccountType) new_account_type;
-                        g_object_notify (G_OBJECT (user), "account-type");
-                }
-        } else if (strcmp (key, "PasswordMode") == 0) {
-                int new_password_mode;
-
-                new_password_mode = g_variant_get_int32 (value);
-                if ((int) user->password_mode != new_password_mode) {
-                        user->password_mode = (ActUserPasswordMode) new_password_mode;
-                        g_object_notify (G_OBJECT (user), "password-mode");
-                }
-        } else if (strcmp (key, "PasswordHint") == 0) {
-                const char *new_password_hint;
-
-                new_password_hint = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->password_hint, new_password_hint) != 0) {
-                        g_free (user->password_hint);
-                        user->password_hint = g_strdup (new_password_hint);
-                        g_object_notify (G_OBJECT (user), "password-hint");
-                }
-        } else if (strcmp (key, "HomeDirectory") == 0) {
-                const char *new_home_dir;
-
-                new_home_dir = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->home_dir, new_home_dir) != 0) {
-                        g_free (user->home_dir);
-                        user->home_dir = g_strdup (new_home_dir);
-                        g_object_notify (G_OBJECT (user), "home-directory");
-                }
-        } else if (strcmp (key, "Shell") == 0) {
-                const char *new_shell;
-
-                new_shell = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->shell, new_shell) != 0) {
-                        g_free (user->shell);
-                        user->shell = g_strdup (new_shell);
-                        g_object_notify (G_OBJECT (user), "shell");
-                }
-        } else if (strcmp (key, "Email") == 0) {
-                const char *new_email;
-
-                new_email = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->email, new_email) != 0) {
-                        g_free (user->email);
-                        user->email = g_strdup (new_email);
-                        g_object_notify (G_OBJECT (user), "email");
-                }
-        } else if (strcmp (key, "Location") == 0) {
-                const char *new_location;
-
-                new_location = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->location, new_location) != 0) {
-                        g_free (user->location);
-                        user->location = g_strdup (new_location);
-                        g_object_notify (G_OBJECT (user), "location");
-                }
-        } else if (strcmp (key, "Locked") == 0) {
-                gboolean new_locked_state;
-
-                new_locked_state = g_variant_get_boolean (value);
-                if (new_locked_state != user->locked) {
-                        user->locked = new_locked_state;
-                        g_object_notify (G_OBJECT (user), "locked");
-                }
-        } else if (strcmp (key, "AutomaticLogin") == 0) {
-                gboolean new_automatic_login_state;
-
-                new_automatic_login_state = g_variant_get_boolean (value);
-                if (new_automatic_login_state != user->automatic_login) {
-                        user->automatic_login = new_automatic_login_state;
-                        g_object_notify (G_OBJECT (user), "automatic-login");
-                }
-        } else if (strcmp (key, "SystemAccount") == 0) {
-                gboolean new_system_account_state;
-
-                new_system_account_state = g_variant_get_boolean (value);
-                if (new_system_account_state != user->system_account) {
-                        user->system_account = new_system_account_state;
-                        g_object_notify (G_OBJECT (user), "system-account");
-                }
-        } else if (strcmp (key, "LocalAccount") == 0) {
-                gboolean new_local;
-
-                new_local = g_variant_get_boolean (value);
-                if (user->local_account != new_local) {
-                        user->local_account = new_local;
-                        g_object_notify (G_OBJECT (user), "local-account");
-                }
-        } else if (strcmp (key, "LoginFrequency") == 0) {
-                int new_login_frequency;
-
-                new_login_frequency = (int) g_variant_get_uint64 (value);
-                if ((int) user->login_frequency != (int) new_login_frequency) {
-                        user->login_frequency = new_login_frequency;
-                        g_object_notify (G_OBJECT (user), "login-frequency");
-                }
-        } else if (strcmp (key, "LoginTime") == 0) {
-                gint64 new_login_time = g_variant_get_int64 (value);
-
-                if (user->login_time != new_login_time) {
-                        user->login_time = new_login_time;
-                        g_object_notify (G_OBJECT (user), "login-time");
-                }
-        } else if (strcmp (key, "LoginHistory") == 0) {
-                GVariant *new_login_history = value;
-
-                if (user->login_history == NULL ||
-                    !g_variant_equal (user->login_history, new_login_history)) {
-                        if (user->login_history)
-                          g_variant_unref (user->login_history);
-                        user->login_history = g_variant_ref (new_login_history);
-                        g_object_notify (G_OBJECT (user), "login-history");
-                }
-        } else if (strcmp (key, "IconFile") == 0) {
-                const char *new_icon_file;
-
-                new_icon_file = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->icon_file, new_icon_file) != 0) {
-                        g_free (user->icon_file);
-                        user->icon_file = g_strdup (new_icon_file);
-                        g_object_notify (G_OBJECT (user), "icon-file");
-                }
-        } else if (strcmp (key, "Language") == 0) {
-                const char *new_language;
-
-                new_language = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->language, new_language) != 0) {
-                        g_free (user->language);
-                        user->language = g_strdup (new_language);
-                        g_object_notify (G_OBJECT (user), "language");
-                }
-        } else if (strcmp (key, "XSession") == 0) {
-                const char *new_x_session;
-
-                new_x_session = g_variant_get_string (value, NULL);
-                if (g_strcmp0 (user->x_session, new_x_session) != 0) {
-                        g_free (user->x_session);
-                        user->x_session = g_strdup (new_x_session);
-                        g_object_notify (G_OBJECT (user), "x-session");
-                }
-        } else {
-                handled = FALSE;
-        }
-
-        if (!handled) {
-                g_debug ("unhandled property %s", key);
-        }
-}
-
-static void
-on_get_all_finished (GObject        *object,
-                     GAsyncResult   *result,
-                     gpointer data)
-{
-        GDBusProxy  *proxy = G_DBUS_PROXY (object);
-        ActUser     *user = data;
-        GError      *error;
-        GVariant    *res;
-        GVariantIter *iter;
-        gchar       *key;
-        GVariant    *value;
-
-        g_assert (G_IS_DBUS_PROXY (user->object_proxy));
-        g_assert (user->object_proxy == proxy);
-
-        error = NULL;
-        res = g_dbus_proxy_call_finish (proxy, result, &error);
-
-        g_clear_object (&user->get_all_cancellable);
-
-        if (! res) {
-                g_debug ("Error calling GetAll() when retrieving properties for %s: %s",
-                         user->object_path, error->message);
-                g_error_free (error);
-
-                if (!user->is_loaded) {
-                        set_is_loaded (user, TRUE);
-                }
-                return;
-        }
-
-        g_variant_get (res, "(a{sv})", &iter);
-        while (g_variant_iter_next (iter, "{sv}", &key, &value)) {
-                collect_props (key, value, user);
-                g_free (key);
-                g_variant_unref (value);
-        }
-        g_variant_iter_free (iter);
-        g_variant_unref (res);
-
-        if (!user->is_loaded) {
-                set_is_loaded (user, TRUE);
-        }
-
-        g_signal_emit (user, signals[CHANGED], 0);
-}
-
-static void
-update_info (ActUser *user)
-{
-        g_assert (G_IS_DBUS_PROXY (user->object_proxy));
-
-        if (user->get_all_cancellable != NULL) {
-                g_cancellable_cancel (user->get_all_cancellable);
-                g_clear_object (&user->get_all_cancellable);
-        }
-
-        user->get_all_cancellable = g_cancellable_new ();
-        g_dbus_proxy_call (user->object_proxy,
-                           "GetAll",
-                           g_variant_new ("(s)", ACCOUNTS_USER_INTERFACE),
-                           G_DBUS_CALL_FLAGS_NONE,
-                           -1,
-                           user->get_all_cancellable,
-                           on_get_all_finished,
-                           user);
-}
-
-static gboolean
-on_timeout_update_info (ActUser *user)
-{
-        update_info (user);
-        user->update_info_timeout_id = 0;
-
-        return G_SOURCE_REMOVE;
-}
-
-static void
-changed_handler (AccountsUser *object,
-                 gpointer   *data)
-{
-        ActUser *user = ACT_USER (data);
-
-        if (user->update_info_timeout_id != 0)
-                return;
-
-        user->update_info_timeout_id = g_timeout_add (250, (GSourceFunc) on_timeout_update_info, user);
-}
-
 /**
  * _act_user_update_as_nonexistent:
  * @user: the user object to update.
  *
  * Set's the 'non-existent' property of @user to #TRUE
  * Can only be called before the user is loaded.
  **/
 void
 _act_user_update_as_nonexistent (ActUser *user)
 {
         g_return_if_fail (ACT_IS_USER (user));
         g_return_if_fail (!act_user_is_loaded (user));
-        g_return_if_fail (user->object_path == NULL);
+        g_return_if_fail (act_user_get_object_path (user) == NULL);
 
         user->nonexistent = TRUE;
         g_object_notify (G_OBJECT (user), "nonexistent");
 
         set_is_loaded (user, TRUE);
 }
 
+static void
+on_accounts_proxy_changed (ActUser *user)
+{
+        g_signal_emit (user, signals[CHANGED], 0);
+}
+
 /**
  * _act_user_update_from_object_path:
  * @user: the user object to update.
  * @object_path: the object path of the user to use.
  *
  * Updates the properties of @user from the accounts service via
  * the object path in @object_path.
  **/
 void
 _act_user_update_from_object_path (ActUser    *user,
                                    const char *object_path)
 {
-        GError *error = NULL;
+        AccountsUser    *accounts_proxy;
+        GError          *error = NULL;
 
         g_return_if_fail (ACT_IS_USER (user));
         g_return_if_fail (object_path != NULL);
-        g_return_if_fail (user->object_path == NULL);
-
-        user->object_path = g_strdup (object_path);
-
-        user->accounts_proxy = accounts_user_proxy_new_sync (user->connection,
-                                                             G_DBUS_PROXY_FLAGS_NONE,
-                                                             ACCOUNTS_NAME,
-                                                             user->object_path,
-                                                             NULL,
-                                                             &error);
-        if (!user->accounts_proxy) {
+        g_return_if_fail (act_user_get_object_path (user) == NULL);
+
+        accounts_proxy = accounts_user_proxy_new_sync (user->connection,
+                                                       G_DBUS_PROXY_FLAGS_NONE,
+                                                       ACCOUNTS_NAME,
+                                                       object_path,
+                                                       NULL,
+                                                       &error);
+        if (!accounts_proxy) {
                 g_warning ("Couldn't create accounts proxy: %s", error->message);
                 g_error_free (error);
                 return;
         }
-        g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (user->accounts_proxy), INT_MAX);
 
-        g_signal_connect (user->accounts_proxy, "changed", G_CALLBACK (changed_handler), user);
+        user->accounts_proxy = accounts_proxy;
 
-        user->object_proxy = g_dbus_proxy_new_sync (user->connection,
-                                                    G_DBUS_PROXY_FLAGS_NONE,
-                                                    0,
-                                                    ACCOUNTS_NAME,
-                                                    user->object_path,
-                                                    "org.freedesktop.DBus.Properties",
-                                                    NULL,
-                                                    &error);
-        if (!user->object_proxy) {
-                g_warning ("Couldn't create accounts property proxy: %s", error->message);
-                g_error_free (error);
-                return;
-        }
+        g_signal_connect_object (user->accounts_proxy,
+                                 "changed",
+                                 G_CALLBACK (on_accounts_proxy_changed),
+                                 user,
+                                 G_CONNECT_SWAPPED);
 
-       update_info (user);
+        g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (user->accounts_proxy), INT_MAX);
+
+        set_is_loaded (user, TRUE);
 }
 
 void
 _act_user_update_login_frequency (ActUser    *user,
                                   int         login_frequency)
 {
-        if (user->login_frequency != login_frequency) {
-                user->login_frequency = login_frequency;
-                g_object_notify (G_OBJECT (user), "login-frequency");
+        if (act_user_get_login_frequency (user) == login_frequency) {
+                return;
         }
+
+        accounts_user_set_login_frequency (user->accounts_proxy,
+                                           login_frequency);
 }
 
 static void
 copy_sessions_lists (ActUser *user,
                      ActUser *user_to_copy)
 {
         GList *node;
 
         for (node = g_list_last (user_to_copy->our_sessions);
              node != NULL;
              node = node->prev) {
                 user->our_sessions = g_list_prepend (user->our_sessions, g_strdup (node->data));
         }
 
         for (node = g_list_last (user_to_copy->other_sessions);
              node != NULL;
              node = node->prev) {
                 user->other_sessions = g_list_prepend (user->other_sessions, g_strdup (node->data));
         }
 }
 
 void
 _act_user_load_from_user (ActUser    *user,
                           ActUser    *user_to_copy)
 {
         if (!user_to_copy->is_loaded) {
                 return;
         }
 
-        /* loading users may already have a uid, user name, or session list
-         * from creation, so only update them if necessary
-         */
-        if (!user->uid_set) {
-                user->uid = user_to_copy->uid;
-                g_object_notify (G_OBJECT (user), "uid");
-        }
+        user->accounts_proxy = g_object_ref (user_to_copy->accounts_proxy);
 
-        if (user->user_name == NULL) {
-                user->user_name = g_strdup (user_to_copy->user_name);
-                g_object_notify (G_OBJECT (user), "user-name");
-        }
+        g_signal_connect_object (user->accounts_proxy,
+                                 "changed",
+                                 G_CALLBACK (on_accounts_proxy_changed),
+                                 user,
+                                 G_CONNECT_SWAPPED);
 
         if (user->our_sessions == NULL && user->other_sessions == NULL) {
                 copy_sessions_lists (user, user_to_copy);
                 g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
         }
 
-        g_free (user->real_name);
-        user->real_name = g_strdup (user_to_copy->real_name);
-        g_object_notify (G_OBJECT (user), "real-name");
-
-        g_free (user->password_hint);
-        user->password_hint = g_strdup (user_to_copy->password_hint);
-        g_object_notify (G_OBJECT (user), "password-hint");
-
-        g_free (user->home_dir);
-        user->home_dir = g_strdup (user_to_copy->home_dir);
-        g_object_notify (G_OBJECT (user), "home-directory");
-
-        g_free (user->shell);
-        user->shell = g_strdup (user_to_copy->shell);
-        g_object_notify (G_OBJECT (user), "shell");
-
-        g_free (user->email);
-        user->email = g_strdup (user_to_copy->email);
-        g_object_notify (G_OBJECT (user), "email");
-
-        g_free (user->location);
-        user->location = g_strdup (user_to_copy->location);
-        g_object_notify (G_OBJECT (user), "location");
-
-        g_free (user->icon_file);
-        user->icon_file = g_strdup (user_to_copy->icon_file);
-        g_object_notify (G_OBJECT (user), "icon-file");
-
-        g_free (user->language);
-        user->language = g_strdup (user_to_copy->language);
-        g_object_notify (G_OBJECT (user), "language");
-
-        g_free (user->x_session);
-        user->x_session = g_strdup (user_to_copy->x_session);
-        g_object_notify (G_OBJECT (user), "x-session");
-
-        user->login_frequency = user_to_copy->login_frequency;
-        g_object_notify (G_OBJECT (user), "login-frequency");
-
-        user->login_time = user_to_copy->login_time;
-        g_object_notify (G_OBJECT (user), "login-time");
-
-        user->login_history = user_to_copy->login_history ? g_variant_ref (user_to_copy->login_history) : NULL;
-        g_object_notify (G_OBJECT (user), "login-history");
-
-        user->account_type = user_to_copy->account_type;
-        g_object_notify (G_OBJECT (user), "account-type");
-
-        user->password_mode = user_to_copy->password_mode;
-        g_object_notify (G_OBJECT (user), "password-mode");
-
-        user->nonexistent = user_to_copy->nonexistent;
-        g_object_notify (G_OBJECT (user), "nonexistent");
-
         set_is_loaded (user, TRUE);
 }
 
 /**
  * act_user_is_loaded:
  * @user: a #ActUser
  *
  * Determines whether or not the user object is loaded and ready to read from.
  * #ActUserManager:is-loaded property must be %TRUE before calling
  * act_user_manager_list_users()
  *
  * Returns: %TRUE or %FALSE
  */
 gboolean
 act_user_is_loaded (ActUser *user)
 {
         return user->is_loaded;
 }
 
 /**
  * act_user_get_login_history:
  * @user: the user object to query.
  * @expiration_time: time users passwor expires
  * @last_change_time,
  * @min_days_between_changes,
  * @max_days_between_changes,
  * @days_to_warn,
  * @days_after_expiration_until_lock)
  *
  * Assigns a new email to @user.
-- 
2.14.1