]> 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 636ac778238bd1b1c71ebaaebd78c6acdb641207..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,12 +92,12 @@ typedef struct
 
 typedef struct
 {
-    /* User list this user is part of */
-    CommonUserList *user_list;
-
     /* TRUE if have loaded the DMRC file */
     gboolean loaded_dmrc;
 
+    /* Bus we are listening for accounts service on */
+    GDBusConnection *bus;
+
     /* Accounts service path */
     gchar *path;
 
@@ -117,9 +116,6 @@ typedef struct
     /* Shell for user */
     gchar *shell;
 
-    /* TRUE if a system account */
-    gboolean system_account;
-
     /* Image for user */
     gchar *image;
 
@@ -189,9 +185,7 @@ common_user_list_get_instance (void)
 void
 common_user_list_cleanup (void)
 {
-    if (singleton)
-        g_object_unref (singleton);
-    singleton = NULL;
+    g_clear_object (&singleton);
 }
 
 static CommonUser *
@@ -257,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 *
@@ -271,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]);
@@ -290,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);
@@ -410,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, USER_SIGNAL_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);
     }
@@ -454,110 +473,7 @@ passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileM
     }
 }
 
-static gboolean
-update_user_property (CommonUser *user, const gchar *name, GVariant *value)
-{
-    CommonUserPrivate *priv = GET_USER_PRIVATE (user);
-
-    if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        g_free (priv->name);
-        priv->name = g_variant_dup_string (value, NULL);
-        return TRUE;
-    }
-
-    if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        g_free (priv->real_name);
-        priv->real_name = g_variant_dup_string (value, NULL);
-        return TRUE;
-    }
-
-    if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        g_free (priv->home_directory);
-        priv->home_directory = g_variant_dup_string (value, NULL);
-        return TRUE;
-    }
-
-    if (strcmp (name, "Shell") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        g_free (priv->shell);
-        priv->shell = g_variant_dup_string (value, NULL);
-        return TRUE;
-    }
-
-    if (strcmp (name, "SystemAccount") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
-    {
-        priv->system_account = g_variant_get_boolean (value);
-        return TRUE;
-    }
-
-    if (strcmp (name, "Language") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        if (priv->language)
-            g_free (priv->language);
-        priv->language = g_variant_dup_string (value, NULL);
-        return TRUE;
-    }
-
-    if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        g_free (priv->image);
-        priv->image = g_variant_dup_string (value, NULL);
-        if (strcmp (priv->image, "") == 0)
-        {
-            g_free (priv->image);
-            priv->image = NULL;
-        }
-        return TRUE;
-    }
-
-    if (strcmp (name, "XSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        g_free (priv->session);
-        priv->session = g_variant_dup_string (value, NULL);
-        return TRUE;
-    }
-
-    if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
-    {
-        g_free (priv->background);
-        priv->background = g_variant_dup_string (value, NULL);
-        if (strcmp (priv->background, "") == 0)
-        {
-            g_free (priv->background);
-            priv->background = NULL;
-        }
-        return TRUE;
-    }
-
-    if (strcmp (name, "XKeyboardLayouts") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY))
-    {
-        g_strfreev (priv->layouts);
-        priv->layouts = g_variant_dup_strv (value, NULL);
-        if (!priv->layouts)
-        {
-            priv->layouts = g_malloc (sizeof (gchar *) * 1);
-            priv->layouts[0] = NULL;
-        }
-        return TRUE;
-    }
-
-    if (strcmp (name, "XHasMessages") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
-    {
-        priv->has_messages = g_variant_get_boolean (value);
-        return TRUE;
-    }
-
-    if (strcmp (name, "Uid") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64))
-    {
-        priv->uid = g_variant_get_uint64 (value);
-        return TRUE;
-    }
-
-    return FALSE;
-}
+static gboolean load_accounts_user (CommonUser *user);
 
 static void
 accounts_user_changed_cb (GDBusConnection *connection,
@@ -569,57 +485,14 @@ accounts_user_changed_cb (GDBusConnection *connection,
                           gpointer data)
 {
     CommonUser *user = data;
-    CommonUserPrivate *priv = GET_USER_PRIVATE (user);
-    gboolean changed = FALSE;
-    GVariantIter *iter;
-    GVariantIter *invalidated_properties;
-    gchar *name;
-    GVariant *value;
-
-    g_variant_get (parameters, "(sa{sv}as)", NULL, &iter, &invalidated_properties);
-    while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
-    {
-        if (update_user_property (user, name, value))
-            changed = TRUE;
-    }
-    g_variant_iter_free (iter);
-    while (g_variant_iter_loop (invalidated_properties, "&s", &name))
-    {
-        GVariant *result;
-        GError *error = NULL;
-
-        result = g_dbus_connection_call_sync (connection,
-                                              "org.freedesktop.Accounts",
-                                              priv->path,
-                                              "org.freedesktop.DBus.Properties",
-                                              "Get",
-                                              g_variant_new ("(ss)", "org.freedesktop.Accounts.User", name),
-                                              G_VARIANT_TYPE ("(v)"),
-                                              G_DBUS_CALL_FLAGS_NONE,
-                                              -1,
-                                              NULL,
-                                              &error);
-        if (error)
-            g_warning ("Error updating user property %s: %s", name, error->message);
-        g_clear_error (&error);
-
-        if (result)
-        {
-            GVariant *value;
-
-            g_variant_get (result, "(v)", &value);
-            if (update_user_property (user, name, value))
-                changed = TRUE;
-            g_variant_unref (value);
-            g_variant_unref (result);          
-        }
-    }
+    /*CommonUserPrivate *priv = GET_USER_PRIVATE (user);*/
 
-    if (changed)
-    {
-        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);
-    }
 }
 
 static gboolean
@@ -629,21 +502,22 @@ load_accounts_user (CommonUser *user)
     GVariant *result, *value;
     GVariantIter *iter;
     gchar *name;
+    gboolean system_account = FALSE;
     GError *error = NULL;
 
     /* 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.DBus.Properties",
-                                                                   "PropertiesChanged",
-                                                                   priv->path,
                                                                    "org.freedesktop.Accounts.User",
+                                                                   "Changed",
+                                                                   priv->path,
+                                                                   NULL,
                                                                    G_DBUS_SIGNAL_FLAGS_NONE,
                                                                    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",
@@ -663,12 +537,80 @@ load_accounts_user (CommonUser *user)
     /* Store the properties we need */
     g_variant_get (result, "(a{sv})", &iter);
     while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
-        update_user_property (user, name, value);
+    {
+        if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            g_free (priv->name);
+            priv->name = g_variant_dup_string (value, NULL);
+        }
+        else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            g_free (priv->real_name);
+            priv->real_name = g_variant_dup_string (value, NULL);
+        }
+        else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            g_free (priv->home_directory);
+            priv->home_directory = g_variant_dup_string (value, NULL);
+        }
+        else if (strcmp (name, "Shell") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            g_free (priv->shell);
+            priv->shell = g_variant_dup_string (value, NULL);
+        }
+        else if (strcmp (name, "SystemAccount") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
+            system_account = g_variant_get_boolean (value);
+        else if (strcmp (name, "Language") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            if (priv->language)
+                g_free (priv->language);
+            priv->language = g_variant_dup_string (value, NULL);
+        }
+        else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            g_free (priv->image);
+            priv->image = g_variant_dup_string (value, NULL);
+            if (strcmp (priv->image, "") == 0)
+            {
+                g_free (priv->image);
+                priv->image = NULL;
+            }
+        }
+        else if (strcmp (name, "XSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            g_free (priv->session);
+            priv->session = g_variant_dup_string (value, NULL);
+        }
+        else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+        {
+            g_free (priv->background);
+            priv->background = g_variant_dup_string (value, NULL);
+            if (strcmp (priv->background, "") == 0)
+            {
+                g_free (priv->background);
+                priv->background = NULL;
+            }
+        }
+        else if (strcmp (name, "XKeyboardLayouts") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY))
+        {
+            g_strfreev (priv->layouts);
+            priv->layouts = g_variant_dup_strv (value, NULL);
+            if (!priv->layouts)
+            {
+                priv->layouts = g_malloc (sizeof (gchar *) * 1);
+                priv->layouts[0] = NULL;
+            }
+        }
+        else if (strcmp (name, "XHasMessages") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
+            priv->has_messages = g_variant_get_boolean (value);
+        else if (strcmp (name, "Uid") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64))
+            priv->uid = g_variant_get_uint64 (value);
+    }
     g_variant_iter_free (iter);
 
     g_variant_unref (result);
 
-    return !priv->system_account;
+    return !system_account;
 }
 
 static void
@@ -682,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, USER_SIGNAL_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);
@@ -1002,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);
@@ -1065,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);
@@ -1091,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;
 
@@ -1139,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);
 }
@@ -1218,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,
@@ -1521,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;
 }
 
 /**
@@ -1687,7 +1613,8 @@ 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);
@@ -1834,6 +1761,16 @@ common_user_class_init (CommonUserClass *klass)
                       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