]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blobdiff - common/user-list.c
Load all users only when really needed
[sojka/lightdm.git] / common / user-list.c
index d64e615fb4448a32a4f08c1715f2014459ad9a78..d5d95e208e32ee7f904afcdfd590f74843a76a85 100644 (file)
 
 enum
 {
-    LIST_PROP_0,
-    LIST_PROP_NUM_USERS,
+    LIST_PROP_NUM_USERS = 1,
     LIST_PROP_USERS,
 };
 
 enum
 {
-    USER_PROP_0,
-    USER_PROP_NAME,
+    USER_PROP_NAME = 1,
     USER_PROP_REAL_NAME,
     USER_PROP_DISPLAY_NAME,
     USER_PROP_HOME_DIRECTORY,
@@ -61,6 +59,7 @@ static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
 enum
 {
     CHANGED,
+    GET_LOGGED_IN,
     LAST_USER_SIGNAL
 };
 static guint user_signals[LAST_USER_SIGNAL] = { 0 };
@@ -93,11 +92,11 @@ typedef struct
 
 typedef struct
 {
-    /* User list this user is part of */
-    CommonUserList *user_list;
+    /* TRUE if have loaded the DMRC file */
+    gboolean loaded_dmrc;
 
-    /* TRUE if have loaded user properties */
-    gboolean loaded_values;
+    /* Bus we are listening for accounts service on */
+    GDBusConnection *bus;
 
     /* Accounts service path */
     gchar *path;
@@ -183,6 +182,12 @@ common_user_list_get_instance (void)
     return singleton;
 }
 
+void
+common_user_list_cleanup (void)
+{
+    g_clear_object (&singleton);
+}
+
 static CommonUser *
 get_user_by_name (CommonUserList *user_list, const gchar *username)
 {
@@ -246,10 +251,34 @@ update_passwd_user (CommonUser *user, const gchar *real_name, const gchar *home_
     return TRUE;
 }
 
+static void load_sessions (CommonUserList *user_list);
+
+static gboolean
+get_logged_in_cb (CommonUser *user, CommonUserList *user_list)
+{
+    CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+    const gchar *username;
+    GList *link;
+
+    // Lazily decide to load/listen to sessions
+    if (priv->session_added_signal == 0)
+        load_sessions (user_list);
+
+    username = GET_USER_PRIVATE (user)->name;
+    for (link = priv->sessions; link; link = link->next)
+    {
+        CommonSession *session = link->data;
+        if (strcmp (session->username, username) == 0)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
 static void
-user_changed_cb (CommonUser *user)
+user_changed_cb (CommonUser *user, CommonUserList *user_list)
 {
-    g_signal_emit (GET_USER_PRIVATE (user)->user_list, list_signals[USER_CHANGED], 0, user);
+    g_signal_emit (user_list, list_signals[USER_CHANGED], 0, user);
 }
 
 static CommonUser *
@@ -260,6 +289,8 @@ make_passwd_user (CommonUserList *user_list, struct passwd *entry)
     char **tokens;
     gchar *real_name, *image;
 
+    g_signal_connect (user, "get-logged-in", G_CALLBACK (get_logged_in_cb), user_list);  
+
     tokens = g_strsplit (entry->pw_gecos, ",", -1);
     if (tokens[0] != NULL && tokens[0][0] != '\0')
         real_name = g_strdup (tokens[0]);
@@ -279,7 +310,6 @@ make_passwd_user (CommonUserList *user_list, struct passwd *entry)
         }
     }
 
-    priv->user_list = user_list;
     priv->name = g_strdup (entry->pw_name);
     priv->real_name = real_name;
     priv->home_directory = g_strdup (entry->pw_dir);
@@ -399,7 +429,7 @@ load_passwd_file (CommonUserList *user_list, gboolean emit_add_signal)
     {
         CommonUser *info = link->data;
         g_debug ("User %s added", common_user_get_name (info));
-        g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), NULL);
+        g_signal_connect (info, USER_SIGNAL_CHANGED, G_CALLBACK (user_changed_cb), user_list);
         if (emit_add_signal)
             g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
     }
@@ -455,9 +485,12 @@ accounts_user_changed_cb (GDBusConnection *connection,
                           gpointer data)
 {
     CommonUser *user = data;
-    CommonUserPrivate *priv = GET_USER_PRIVATE (user);  
+    /*CommonUserPrivate *priv = GET_USER_PRIVATE (user);*/
 
-    g_debug ("User %s changed", priv->path);
+    /* Log message disabled as AccountsService can have arbitrary plugins that
+     * might cause us to log when properties change we don't use. LP: #1376357
+     */
+    /*g_debug ("User %s changed", priv->path);*/
     if (load_accounts_user (user))
         g_signal_emit (user, user_signals[CHANGED], 0);
 }
@@ -474,7 +507,7 @@ load_accounts_user (CommonUser *user)
 
     /* Get the properties for this user */
     if (!priv->changed_signal)
-        priv->changed_signal = g_dbus_connection_signal_subscribe (GET_LIST_PRIVATE (priv->user_list)->bus,
+        priv->changed_signal = g_dbus_connection_signal_subscribe (priv->bus,
                                                                    "org.freedesktop.Accounts",
                                                                    "org.freedesktop.Accounts.User",
                                                                    "Changed",
@@ -484,7 +517,7 @@ load_accounts_user (CommonUser *user)
                                                                    accounts_user_changed_cb,
                                                                    user,
                                                                    NULL);
-    result = g_dbus_connection_call_sync (GET_LIST_PRIVATE (priv->user_list)->bus,
+    result = g_dbus_connection_call_sync (priv->bus,
                                           "org.freedesktop.Accounts",
                                           priv->path,
                                           "org.freedesktop.DBus.Properties",
@@ -577,8 +610,6 @@ load_accounts_user (CommonUser *user)
 
     g_variant_unref (result);
 
-    priv->loaded_values = TRUE;
-
     return !system_account;
 }
 
@@ -593,9 +624,10 @@ add_accounts_user (CommonUserList *user_list, const gchar *path, gboolean emit_s
     priv = GET_USER_PRIVATE (user);
 
     g_debug ("User %s added", path);
-    priv->user_list = user_list;
+    priv->bus = g_object_ref (list_priv->bus);
     priv->path = g_strdup (path);
-    g_signal_connect (user, "changed", G_CALLBACK (user_changed_cb), NULL);
+    g_signal_connect (user, USER_SIGNAL_CHANGED, G_CALLBACK (user_changed_cb), user_list);
+    g_signal_connect (user, "get-logged-in", G_CALLBACK (get_logged_in_cb), user_list);  
     if (load_accounts_user (user))
     {
         list_priv->users = g_list_insert_sorted (list_priv->users, user, compare_user);
@@ -770,7 +802,7 @@ session_removed_cb (GDBusConnection *connection,
             CommonUser *user;
 
             g_debug ("Session %s removed", path);
-            priv->sessions = g_list_remove_link (priv->sessions, link);
+            priv->sessions = g_list_delete_link (priv->sessions, link);
             user = get_user_by_name (user_list, session->username);
             if (user)
                 g_signal_emit (user, user_signals[CHANGED], 0);
@@ -913,8 +945,6 @@ load_users (CommonUserList *user_list)
         g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
         priv->user_removed_signal = 0;
 
-        load_passwd_file (user_list, FALSE);
-
         /* Watch for changes to user list */
 
         passwd_file = g_file_new_for_path (PASSWD_FILE);
@@ -976,6 +1006,7 @@ common_user_list_get_user_by_name (CommonUserList *user_list, const gchar *usern
     g_return_val_if_fail (COMMON_IS_USER_LIST (user_list), NULL);
     g_return_val_if_fail (username != NULL, NULL);
 
+    /* Load users from AccountsService, do nothing when it does not run */
     load_users (user_list);
 
     CommonUser *user = get_user_by_name (user_list, username);
@@ -1002,19 +1033,19 @@ common_user_list_init (CommonUserList *user_list)
 }
 
 static void
-common_user_list_set_property (GObject    *object,
-                                guint       prop_id,
-                                const GValue *value,
-                                GParamSpec *pspec)
+common_user_list_set_property (GObject      *object,
+                               guint         prop_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
 {
     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 }
 
 static void
 common_user_list_get_property (GObject    *object,
-                                guint       prop_id,
-                                GValue     *value,
-                                GParamSpec *pspec)
+                               guint       prop_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
 {
     CommonUserList *self;
 
@@ -1050,8 +1081,7 @@ common_user_list_finalize (GObject *object)
     if (priv->session_removed_signal)
         g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_removed_signal);
     g_object_unref (priv->bus);
-    if (priv->passwd_monitor)
-        g_object_unref (priv->passwd_monitor);
+    g_clear_object (&priv->passwd_monitor);
 
     G_OBJECT_CLASS (common_user_list_parent_class)->finalize (object);
 }
@@ -1082,7 +1112,7 @@ common_user_list_class_init (CommonUserListClass *klass)
      * The ::user-added signal gets emitted when a user account is created.
      **/
     list_signals[USER_ADDED] =
-        g_signal_new ("user-added",
+        g_signal_new (USER_LIST_SIGNAL_USER_ADDED,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (CommonUserListClass, user_added),
@@ -1098,7 +1128,7 @@ common_user_list_class_init (CommonUserListClass *klass)
      * The ::user-changed signal gets emitted when a user account is modified.
      **/
     list_signals[USER_CHANGED] =
-        g_signal_new ("user-changed",
+        g_signal_new (USER_LIST_SIGNAL_USER_CHANGED,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (CommonUserListClass, user_changed),
@@ -1114,7 +1144,7 @@ common_user_list_class_init (CommonUserListClass *klass)
      * The ::user-removed signal gets emitted when a user account is removed.
      **/
     list_signals[USER_REMOVED] =
-        g_signal_new ("user-removed",
+        g_signal_new (USER_LIST_SIGNAL_USER_REMOVED,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (CommonUserListClass, user_removed),
@@ -1129,12 +1159,11 @@ call_method (CommonUser *user, const gchar *method, GVariant *args,
 {
     GVariant *answer;
     GError *error = NULL;
-    CommonUserPrivate *user_priv = GET_USER_PRIVATE (user);
-    CommonUserListPrivate *list_priv = GET_LIST_PRIVATE (user_priv->user_list);
+    CommonUserPrivate *priv = GET_USER_PRIVATE (user);
 
-    answer = g_dbus_connection_call_sync (list_priv->bus,
+    answer = g_dbus_connection_call_sync (priv->bus,
                                           "org.freedesktop.Accounts",
-                                          user_priv->path,
+                                          priv->path,
                                           "org.freedesktop.Accounts.User",
                                           method,
                                           args,
@@ -1171,12 +1200,20 @@ save_string_to_dmrc (CommonUser *user, const gchar *group,
     g_key_file_free (dmrc);
 }
 
+/* Loads language/layout/session info for user */
 static void
 load_dmrc (CommonUser *user)
 {
     CommonUserPrivate *priv = GET_USER_PRIVATE (user);
     GKeyFile *dmrc;
 
+    /* We're using Accounts service instead */
+    if (priv->path)
+        return;
+
+    if (priv->loaded_dmrc)
+        return;
+    priv->loaded_dmrc = TRUE;
     dmrc = dmrc_load (user);
 
     // FIXME: Watch for changes
@@ -1199,20 +1236,6 @@ load_dmrc (CommonUser *user)
     g_key_file_free (dmrc);
 }
 
-/* Loads language/layout/session info for user */
-static void
-load_user_values (CommonUser *user)
-{
-    CommonUserPrivate *priv = GET_USER_PRIVATE (user);
-
-    if (priv->loaded_values)
-        return;
-    priv->loaded_values = TRUE;
-
-    if (!priv->path)
-        load_dmrc (user);
-}
-
 /**
  * common_user_get_name:
  * @user: A #CommonUser
@@ -1225,7 +1248,6 @@ const gchar *
 common_user_get_name (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->name;
 }
 
@@ -1241,7 +1263,6 @@ const gchar *
 common_user_get_real_name (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->real_name;
 }
 
@@ -1260,8 +1281,6 @@ common_user_get_display_name (CommonUser *user)
 
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
 
-    load_user_values (user);
-
     priv = GET_USER_PRIVATE (user);
     if (!priv->real_name || strcmp (priv->real_name, "") == 0)
         return priv->name;
@@ -1281,7 +1300,6 @@ const gchar *
 common_user_get_home_directory (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->home_directory;
 }
 
@@ -1297,7 +1315,6 @@ const gchar *
 common_user_get_shell (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->shell;
 }
 
@@ -1313,7 +1330,6 @@ const gchar *
 common_user_get_image (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->image;
 }
 
@@ -1329,7 +1345,6 @@ const gchar *
 common_user_get_background (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->background;
 }
 
@@ -1345,7 +1360,7 @@ const gchar *
 common_user_get_language (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
+    load_dmrc (user);
     const gchar *language = GET_USER_PRIVATE (user)->language;
     return (language && language[0] == 0) ? NULL : language; /* Treat "" as NULL */
 }
@@ -1380,7 +1395,7 @@ const gchar *
 common_user_get_layout (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
+    load_dmrc (user);
     return GET_USER_PRIVATE (user)->layouts[0];
 }
 
@@ -1396,7 +1411,7 @@ const gchar * const *
 common_user_get_layouts (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
+    load_dmrc (user);
     return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
 }
 
@@ -1412,7 +1427,7 @@ const gchar *
 common_user_get_session (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), NULL);
-    load_user_values (user);
+    load_dmrc (user);
     const gchar *session = GET_USER_PRIVATE (user)->session;
     return (session && session[0] == 0) ? NULL : session; /* Treat "" as NULL */
 }
@@ -1446,27 +1461,13 @@ common_user_set_session (CommonUser *user, const gchar *session)
 gboolean
 common_user_get_logged_in (CommonUser *user)
 {
-    CommonUserPrivate *priv;
-    CommonUserListPrivate *list_priv;
-    GList *link;
+    gboolean result;
 
     g_return_val_if_fail (COMMON_IS_USER (user), FALSE);
 
-    priv = GET_USER_PRIVATE (user);
-    list_priv = GET_LIST_PRIVATE (priv->user_list);
-
-    // Lazily decide to load/listen to sessions
-    if (list_priv->session_added_signal == 0)
-        load_sessions (priv->user_list);
-
-    for (link = list_priv->sessions; link; link = link->next)
-    {
-        CommonSession *session = link->data;
-        if (strcmp (session->username, priv->name) == 0)
-            return TRUE;
-    }
+    g_signal_emit (user, user_signals[GET_LOGGED_IN], 0, &result);
 
-    return FALSE;
+    return result;
 }
 
 /**
@@ -1481,7 +1482,6 @@ gboolean
 common_user_get_has_messages (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), FALSE);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->has_messages;
 }
 
@@ -1497,7 +1497,6 @@ uid_t
 common_user_get_uid (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), 0);
-    load_user_values (user);
     return GET_USER_PRIVATE (user)->uid;
 }
 
@@ -1513,7 +1512,6 @@ gid_t
 common_user_get_gid (CommonUser *user)
 {
     g_return_val_if_fail (COMMON_IS_USER (user), 0);
-    load_user_values (user);
     /* gid is not actually stored in AccountsService, so if our user is from
        AccountsService, we have to look up manually in passwd.  gid won't
        change, so just look up the first time we're asked and never again. */
@@ -1615,14 +1613,17 @@ common_user_finalize (GObject *object)
 
     g_free (priv->path);
     if (priv->changed_signal)
-        g_dbus_connection_signal_unsubscribe (GET_LIST_PRIVATE (priv->user_list)->bus, priv->changed_signal);
+        g_dbus_connection_signal_unsubscribe (priv->bus, priv->changed_signal);
+    g_clear_object (&priv->bus);
     g_free (priv->name);
     g_free (priv->real_name);
     g_free (priv->home_directory);
     g_free (priv->shell);
     g_free (priv->image);
     g_free (priv->background);
+    g_free (priv->language);
     g_strfreev (priv->layouts);
+    g_free (priv->session);
 }
 
 static void
@@ -1753,13 +1754,23 @@ common_user_class_init (CommonUserClass *klass)
      * The ::changed signal gets emitted this user account is modified.
      **/
     user_signals[CHANGED] =
-        g_signal_new ("changed",
+        g_signal_new (USER_SIGNAL_CHANGED,
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
                       G_STRUCT_OFFSET (CommonUserClass, changed),
                       NULL, NULL,
                       NULL,
                       G_TYPE_NONE, 0);
+
+    user_signals[GET_LOGGED_IN] =
+        g_signal_new ("get-logged-in",
+                      G_TYPE_FROM_CLASS (klass),
+                      G_SIGNAL_RUN_LAST,
+                      0,
+                      g_signal_accumulator_first_wins,
+                      NULL,
+                      NULL,
+                      G_TYPE_BOOLEAN, 0);
 }
 
 static void