1 /* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
3 * Copyright (C) 2010 Robert Ancell.
4 * Author: Robert Ancell <robert.ancell@canonical.com>
6 * This library is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by the Free
8 * Software Foundation; either version 2 or version 3 of the License.
9 * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
16 #include <sys/utsname.h>
20 #include "lightdm/user.h"
34 USER_PROP_DISPLAY_NAME,
35 USER_PROP_HOME_DIRECTORY,
43 USER_PROP_HAS_MESSAGES
53 static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
60 static guint user_signals[LAST_USER_SIGNAL] = { 0 };
64 /* Bus connection being communicated on */
67 /* D-Bus signals for accounts service events */
68 guint user_added_signal;
69 guint user_removed_signal;
71 /* D-Bus signals for display manager events */
72 guint session_added_signal;
73 guint session_removed_signal;
75 /* File monitor for password file */
76 GFileMonitor *passwd_monitor;
78 /* TRUE if have scanned users */
84 /* List of sessions */
86 } LightDMUserListPrivate;
90 /* User list this user is part of */
91 LightDMUserList *user_list;
93 /* TRUE if have loaded user properties */
94 gboolean loaded_values;
96 /* Accounts service path */
102 /* Update signal from accounts service */
103 guint changed_signal;
108 /* Descriptive name for user */
111 /* Home directory of user */
112 gchar *home_directory;
117 /* Background image for users */
120 /* TRUE if this user has messages available */
121 gboolean has_messages;
123 /* User chosen language */
126 /* User layout preferences */
129 /* User default session */
131 } LightDMUserPrivate;
135 GObject parent_instance;
142 GObjectClass parent_class;
145 G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
146 G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
147 #define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
148 GType session_get_type (void);
149 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
151 #define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
152 #define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
154 #define PASSWD_FILE "/etc/passwd"
155 #define USER_CONFIG_FILE "/etc/lightdm/users.conf"
157 static LightDMUserList *singleton = NULL;
160 * lightdm_user_list_get_instance:
164 * Return value: (transfer none): the #LightDMUserList
167 lightdm_user_list_get_instance (void)
170 singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
175 get_user_by_name (LightDMUserList *user_list, const gchar *username)
177 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
180 for (link = priv->users; link; link = link->next)
182 LightDMUser *user = link->data;
183 if (g_strcmp0 (lightdm_user_get_name (user), username) == 0)
191 get_user_by_path (LightDMUserList *user_list, const gchar *path)
193 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
196 for (link = priv->users; link; link = link->next)
198 LightDMUser *user = link->data;
199 if (g_strcmp0 (GET_USER_PRIVATE (user)->path, path) == 0)
207 compare_user (gconstpointer a, gconstpointer b)
209 LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
210 return g_strcmp0 (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
214 update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
216 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
218 /* Skip if already set to this */
219 if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
220 g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
221 g_strcmp0 (lightdm_user_get_image (user), image) == 0)
224 g_free (priv->real_name);
225 priv->real_name = g_strdup (real_name);
226 g_free (priv->home_directory);
227 priv->home_directory = g_strdup (home_directory);
228 g_free (priv->image);
229 priv->image = g_strdup (image);
235 user_changed_cb (LightDMUser *user)
237 g_signal_emit (GET_USER_PRIVATE (user)->user_list, list_signals[USER_CHANGED], 0, user);
241 load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
243 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
247 gchar **hidden_users, **hidden_shells;
248 GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
249 GError *error = NULL;
251 g_debug ("Loading user config from %s", USER_CONFIG_FILE);
253 config = g_key_file_new ();
254 g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error);
255 if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
256 g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info
257 g_clear_error (&error);
259 if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
260 minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
264 value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
266 value = g_strdup ("nobody nobody4 noaccess");
267 hidden_users = g_strsplit (value, " ", -1);
270 value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
272 value = g_strdup ("/bin/false /usr/sbin/nologin");
273 hidden_shells = g_strsplit (value, " ", -1);
276 g_key_file_free (config);
282 struct passwd *entry;
284 LightDMUserPrivate *user_priv;
286 gchar *real_name, *image;
294 /* Ignore system users */
295 if (entry->pw_uid < minimum_uid)
298 /* Ignore users disabled by shell */
301 for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
302 if (hidden_shells[i])
306 /* Ignore certain users */
307 for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
311 tokens = g_strsplit (entry->pw_gecos, ",", -1);
312 if (tokens[0] != NULL && tokens[0][0] != '\0')
313 real_name = g_strdup (tokens[0]);
315 real_name = g_strdup ("");
318 image = g_build_filename (entry->pw_dir, ".face", NULL);
319 if (!g_file_test (image, G_FILE_TEST_EXISTS))
322 image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
323 if (!g_file_test (image, G_FILE_TEST_EXISTS))
330 user = g_object_new (LIGHTDM_TYPE_USER, NULL);
331 user_priv = GET_USER_PRIVATE (user);
332 user_priv->user_list = user_list;
333 g_free (user_priv->name);
334 user_priv->name = g_strdup (entry->pw_name);
335 g_free (user_priv->real_name);
336 user_priv->real_name = real_name;
337 g_free (user_priv->home_directory);
338 user_priv->home_directory = g_strdup (entry->pw_dir);
339 g_free (user_priv->image);
340 user_priv->image = image;
342 /* Update existing users if have them */
343 for (link = priv->users; link; link = link->next)
345 LightDMUser *info = link->data;
346 if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
348 if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
349 changed_users = g_list_insert_sorted (changed_users, info, compare_user);
350 g_object_unref (user);
357 /* Only notify once we have loaded the user list */
358 if (priv->have_users)
359 new_users = g_list_insert_sorted (new_users, user, compare_user);
361 users = g_list_insert_sorted (users, user, compare_user);
363 g_strfreev (hidden_users);
364 g_strfreev (hidden_shells);
367 g_warning ("Failed to read password database: %s", strerror (errno));
371 /* Use new user list */
372 old_users = priv->users;
375 /* Notify of changes */
376 for (link = new_users; link; link = link->next)
378 LightDMUser *info = link->data;
379 g_debug ("User %s added", lightdm_user_get_name (info));
380 g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), NULL);
382 g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
384 g_list_free (new_users);
385 for (link = changed_users; link; link = link->next)
387 LightDMUser *info = link->data;
388 g_debug ("User %s changed", lightdm_user_get_name (info));
389 g_signal_emit (info, user_signals[CHANGED], 0);
391 g_list_free (changed_users);
392 for (link = old_users; link; link = link->next)
396 /* See if this user is in the current list */
397 for (new_link = priv->users; new_link; new_link = new_link->next)
399 if (new_link->data == link->data)
405 LightDMUser *info = link->data;
406 g_debug ("User %s removed", lightdm_user_get_name (info));
407 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
408 g_object_unref (info);
411 g_list_free (old_users);
415 passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
417 if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
419 g_debug ("%s changed, reloading user list", g_file_get_path (file));
420 load_passwd_file (user_list, TRUE);
424 static gboolean load_accounts_user (LightDMUser *user);
427 accounts_user_changed_cb (GDBusConnection *connection,
428 const gchar *sender_name,
429 const gchar *object_path,
430 const gchar *interface_name,
431 const gchar *signal_name,
432 GVariant *parameters,
435 LightDMUser *user = data;
436 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
438 g_debug ("User %s changed", priv->path);
439 if (load_accounts_user (user))
440 g_signal_emit (user, user_signals[CHANGED], 0);
444 load_accounts_user (LightDMUser *user)
446 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
447 GVariant *result, *value;
450 gboolean system_account = FALSE;
451 GError *error = NULL;
453 /* Get the properties for this user */
454 if (!priv->changed_signal)
455 priv->changed_signal = g_dbus_connection_signal_subscribe (GET_LIST_PRIVATE (priv->user_list)->bus,
456 "org.freedesktop.Accounts",
457 "org.freedesktop.Accounts.User",
461 G_DBUS_SIGNAL_FLAGS_NONE,
462 accounts_user_changed_cb,
465 result = g_dbus_connection_call_sync (GET_LIST_PRIVATE (priv->user_list)->bus,
466 "org.freedesktop.Accounts",
468 "org.freedesktop.DBus.Properties",
470 g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
471 G_VARIANT_TYPE ("(a{sv})"),
472 G_DBUS_CALL_FLAGS_NONE,
477 g_warning ("Error updating user %s: %s", priv->path, error->message);
478 g_clear_error (&error);
482 /* Store the properties we need */
483 g_variant_get (result, "(a{sv})", &iter);
484 while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
486 if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
489 priv->name = g_variant_dup_string (value, NULL);
491 else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
493 g_free (priv->real_name);
494 priv->real_name = g_variant_dup_string (value, NULL);
496 else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
498 g_free (priv->home_directory);
499 priv->home_directory = g_variant_dup_string (value, NULL);
501 else if (strcmp (name, "SystemAccount") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
502 system_account = g_variant_get_boolean (value);
503 else if (strcmp (name, "Language") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
506 g_free (priv->language);
507 priv->language = g_variant_dup_string (value, NULL);
509 else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
511 g_free (priv->image);
512 priv->image = g_variant_dup_string (value, NULL);
513 if (strcmp (priv->image, "") == 0)
515 g_free (priv->image);
519 else if (strcmp (name, "XSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
521 g_free (priv->session);
522 priv->session = g_variant_dup_string (value, NULL);
524 else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
526 g_free (priv->background);
527 priv->background = g_variant_dup_string (value, NULL);
528 if (strcmp (priv->background, "") == 0)
530 g_free (priv->background);
531 priv->background = NULL;
534 else if (strcmp (name, "XKeyboardLayouts") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY))
536 g_strfreev (priv->layouts);
537 priv->layouts = g_variant_dup_strv (value, NULL);
540 priv->layouts = g_malloc (sizeof (gchar *) * 1);
541 priv->layouts[0] = NULL;
544 else if (strcmp (name, "XHasMessages") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
545 priv->has_messages = g_variant_get_boolean (value);
547 g_variant_iter_free (iter);
549 g_variant_unref (result);
551 priv->loaded_values = TRUE;
553 return !system_account;
557 add_accounts_user (LightDMUserList *user_list, const gchar *path, gboolean emit_signal)
559 LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (user_list);
561 LightDMUserPrivate *priv;
563 user = g_object_new (LIGHTDM_TYPE_USER, NULL);
564 priv = GET_USER_PRIVATE (user);
566 g_debug ("User %s added", path);
567 priv->user_list = user_list;
568 priv->path = g_strdup (path);
569 g_signal_connect (user, "changed", G_CALLBACK (user_changed_cb), NULL);
570 if (load_accounts_user (user))
572 list_priv->users = g_list_insert_sorted (list_priv->users, user, compare_user);
574 g_signal_emit (user_list, list_signals[USER_ADDED], 0, user);
577 g_object_unref (user);
581 accounts_user_added_cb (GDBusConnection *connection,
582 const gchar *sender_name,
583 const gchar *object_path,
584 const gchar *interface_name,
585 const gchar *signal_name,
586 GVariant *parameters,
589 LightDMUserList *user_list = data;
593 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
595 g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
599 g_variant_get (parameters, "(&o)", &path);
601 /* Add user if we haven't got them */
602 user = get_user_by_path (user_list, path);
604 add_accounts_user (user_list, path, TRUE);
608 accounts_user_deleted_cb (GDBusConnection *connection,
609 const gchar *sender_name,
610 const gchar *object_path,
611 const gchar *interface_name,
612 const gchar *signal_name,
613 GVariant *parameters,
616 LightDMUserList *user_list = data;
617 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
621 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
623 g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
627 g_variant_get (parameters, "(&o)", &path);
629 /* Delete user if we know of them */
630 user = get_user_by_path (user_list, path);
633 g_debug ("User %s deleted", path);
634 priv->users = g_list_remove (priv->users, user);
636 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, user);
638 g_object_unref (user);
643 load_session (LightDMUserList *user_list, const gchar *path)
645 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
646 Session *session = NULL;
647 GVariant *result, *username;
648 GError *error = NULL;
650 result = g_dbus_connection_call_sync (priv->bus,
651 "org.freedesktop.DisplayManager",
653 "org.freedesktop.DBus.Properties",
655 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
656 G_VARIANT_TYPE ("(v)"),
657 G_DBUS_CALL_FLAGS_NONE,
662 g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
663 g_clear_error (&error);
667 g_variant_get (result, "(v)", &username);
668 if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
672 g_variant_get (username, "&s", &name);
674 g_debug ("Loaded session %s (%s)", path, name);
675 session = g_object_new (session_get_type (), NULL);
676 session->username = g_strdup (name);
677 session->path = g_strdup (path);
678 priv->sessions = g_list_append (priv->sessions, session);
680 g_variant_unref (username);
681 g_variant_unref (result);
687 session_added_cb (GDBusConnection *connection,
688 const gchar *sender_name,
689 const gchar *object_path,
690 const gchar *interface_name,
691 const gchar *signal_name,
692 GVariant *parameters,
695 LightDMUserList *user_list = data;
698 LightDMUser *user = NULL;
700 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
702 g_warning ("Got DisplayManager signal SessionAdded with unknown parameters %s", g_variant_get_type_string (parameters));
706 g_variant_get (parameters, "(&o)", &path);
707 session = load_session (user_list, path);
709 user = get_user_by_name (user_list, session->username);
711 g_signal_emit (user, user_signals[CHANGED], 0);
715 session_removed_cb (GDBusConnection *connection,
716 const gchar *sender_name,
717 const gchar *object_path,
718 const gchar *interface_name,
719 const gchar *signal_name,
720 GVariant *parameters,
723 LightDMUserList *user_list = data;
724 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
728 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
730 g_warning ("Got DisplayManager signal SessionRemoved with unknown parameters %s", g_variant_get_type_string (parameters));
734 g_variant_get (parameters, "(&o)", &path);
736 for (link = priv->sessions; link; link = link->next)
738 Session *session = link->data;
739 if (strcmp (session->path, path) == 0)
743 g_debug ("Session %s removed", path);
744 priv->sessions = g_list_remove_link (priv->sessions, link);
745 user = get_user_by_name (user_list, session->username);
747 g_signal_emit (user, user_signals[CHANGED], 0);
748 g_object_unref (session);
755 load_users (LightDMUserList *user_list)
757 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
759 GError *error = NULL;
761 if (priv->have_users)
763 priv->have_users = TRUE;
765 /* Get user list from accounts service and fall back to /etc/passwd if that fails */
766 priv->user_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
767 "org.freedesktop.Accounts",
768 "org.freedesktop.Accounts",
770 "/org/freedesktop/Accounts",
772 G_DBUS_SIGNAL_FLAGS_NONE,
773 accounts_user_added_cb,
776 priv->user_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
777 "org.freedesktop.Accounts",
778 "org.freedesktop.Accounts",
780 "/org/freedesktop/Accounts",
782 G_DBUS_SIGNAL_FLAGS_NONE,
783 accounts_user_deleted_cb,
786 result = g_dbus_connection_call_sync (priv->bus,
787 "org.freedesktop.Accounts",
788 "/org/freedesktop/Accounts",
789 "org.freedesktop.Accounts",
791 g_variant_new ("()"),
792 G_VARIANT_TYPE ("(ao)"),
793 G_DBUS_CALL_FLAGS_NONE,
798 g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
799 g_clear_error (&error);
805 g_debug ("Loading users from org.freedesktop.Accounts");
806 g_variant_get (result, "(ao)", &iter);
807 while (g_variant_iter_loop (iter, "&o", &path))
808 add_accounts_user (user_list, path, FALSE);
809 g_variant_iter_free (iter);
810 g_variant_unref (result);
816 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
817 priv->user_added_signal = 0;
818 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
819 priv->user_removed_signal = 0;
821 load_passwd_file (user_list, FALSE);
823 /* Watch for changes to user list */
825 passwd_file = g_file_new_for_path (PASSWD_FILE);
826 priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
827 g_object_unref (passwd_file);
829 g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
831 g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
832 g_clear_error (&error);
835 priv->session_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
836 "org.freedesktop.DisplayManager",
837 "org.freedesktop.DisplayManager",
839 "/org/freedesktop/DisplayManager",
841 G_DBUS_SIGNAL_FLAGS_NONE,
845 priv->session_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
846 "org.freedesktop.DisplayManager",
847 "org.freedesktop.DisplayManager",
849 "/org/freedesktop/DisplayManager",
851 G_DBUS_SIGNAL_FLAGS_NONE,
856 result = g_dbus_connection_call_sync (priv->bus,
857 "org.freedesktop.DisplayManager",
858 "/org/freedesktop/DisplayManager",
859 "org.freedesktop.DBus.Properties",
861 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
862 G_VARIANT_TYPE ("(v)"),
863 G_DBUS_CALL_FLAGS_NONE,
868 g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
869 g_clear_error (&error);
872 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
878 g_variant_get (result, "(v)", &value);
880 g_debug ("Loading sessions from org.freedesktop.DisplayManager");
881 g_variant_get (value, "ao", &iter);
882 while (g_variant_iter_loop (iter, "&o", &path))
883 load_session (user_list, path);
884 g_variant_iter_free (iter);
886 g_variant_unref (value);
889 g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
891 g_variant_unref (result);
896 * lightdm_user_list_get_length:
897 * @user_list: a #LightDMUserList
899 * Return value: The number of users able to log in
902 lightdm_user_list_get_length (LightDMUserList *user_list)
904 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
905 load_users (user_list);
906 return g_list_length (GET_LIST_PRIVATE (user_list)->users);
910 * lightdm_user_list_get_users:
911 * @user_list: A #LightDMUserList
913 * Get a list of users to present to the user. This list may be a subset of the
914 * available users and may be empty depending on the server configuration.
916 * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user.
919 lightdm_user_list_get_users (LightDMUserList *user_list)
921 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
922 load_users (user_list);
923 return GET_LIST_PRIVATE (user_list)->users;
927 * lightdm_user_list_get_user_by_name:
928 * @user_list: A #LightDMUserList
929 * @username: Name of user to get.
931 * Get infomation about a given user or #NULL if this user doesn't exist.
933 * Return value: (transfer none): A #LightDMUser entry for the given user.
936 lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
938 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
939 g_return_val_if_fail (username != NULL, NULL);
941 load_users (user_list);
943 return get_user_by_name (user_list, username);
947 lightdm_user_list_init (LightDMUserList *user_list)
949 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
951 priv->bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
955 lightdm_user_list_set_property (GObject *object,
960 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
964 lightdm_user_list_get_property (GObject *object,
969 LightDMUserList *self;
971 self = LIGHTDM_USER_LIST (object);
975 case LIST_PROP_NUM_USERS:
976 g_value_set_int (value, lightdm_user_list_get_length (self));
979 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
985 lightdm_user_list_finalize (GObject *object)
987 LightDMUserList *self = LIGHTDM_USER_LIST (object);
988 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
990 /* Remove children first, they might access us */
991 g_list_free_full (priv->users, g_object_unref);
992 g_list_free_full (priv->sessions, g_object_unref);
994 if (priv->user_added_signal)
995 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
996 if (priv->user_removed_signal)
997 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
998 if (priv->session_added_signal)
999 g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_added_signal);
1000 if (priv->session_removed_signal)
1001 g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_removed_signal);
1002 g_object_unref (priv->bus);
1003 if (priv->passwd_monitor)
1004 g_object_unref (priv->passwd_monitor);
1006 G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
1010 lightdm_user_list_class_init (LightDMUserListClass *klass)
1012 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1014 g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
1016 object_class->set_property = lightdm_user_list_set_property;
1017 object_class->get_property = lightdm_user_list_get_property;
1018 object_class->finalize = lightdm_user_list_finalize;
1020 g_object_class_install_property (object_class,
1021 LIST_PROP_NUM_USERS,
1022 g_param_spec_int ("num-users",
1024 "Number of login users",
1028 * LightDMUserList::user-added:
1029 * @user_list: A #LightDMUserList
1030 * @user: The #LightDM user that has been added.
1032 * The ::user-added signal gets emitted when a user account is created.
1034 list_signals[USER_ADDED] =
1035 g_signal_new ("user-added",
1036 G_TYPE_FROM_CLASS (klass),
1038 G_STRUCT_OFFSET (LightDMUserListClass, user_added),
1041 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1044 * LightDMUserList::user-changed:
1045 * @user_list: A #LightDMUserList
1046 * @user: The #LightDM user that has been changed.
1048 * The ::user-changed signal gets emitted when a user account is modified.
1050 list_signals[USER_CHANGED] =
1051 g_signal_new ("user-changed",
1052 G_TYPE_FROM_CLASS (klass),
1054 G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
1057 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1060 * LightDMUserList::user-removed:
1061 * @user_list: A #LightDMUserList
1062 * @user: The #LightDM user that has been removed.
1064 * The ::user-removed signal gets emitted when a user account is removed.
1066 list_signals[USER_REMOVED] =
1067 g_signal_new ("user-removed",
1068 G_TYPE_FROM_CLASS (klass),
1070 G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
1073 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1077 load_dmrc (LightDMUser *user)
1079 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1081 //gboolean have_dmrc;
1083 if (!priv->dmrc_file)
1084 priv->dmrc_file = g_key_file_new ();
1086 /* Load from the user directory */
1087 path = g_build_filename (priv->home_directory, ".dmrc", NULL);
1088 /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
1091 /* If no ~/.dmrc, then load from the cache */
1094 // FIXME: Watch for changes
1096 /* The Language field contains the locale */
1098 g_free (priv->language);
1099 priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
1101 if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
1103 g_strfreev (priv->layouts);
1104 priv->layouts = g_malloc (sizeof (gchar *) * 2);
1105 priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
1106 priv->layouts[1] = NULL;
1110 g_free (priv->session);
1111 priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
1114 /* Loads language/layout/session info for user */
1116 load_user_values (LightDMUser *user)
1118 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1120 if (priv->loaded_values)
1122 priv->loaded_values = TRUE;
1129 * lightdm_user_get_name:
1130 * @user: A #LightDMUser
1132 * Get the name of a user.
1134 * Return value: The name of the given user
1137 lightdm_user_get_name (LightDMUser *user)
1139 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1140 load_user_values (user);
1141 return GET_USER_PRIVATE (user)->name;
1145 * lightdm_user_get_real_name:
1146 * @user: A #LightDMUser
1148 * Get the real name of a user.
1150 * Return value: The real name of the given user
1153 lightdm_user_get_real_name (LightDMUser *user)
1155 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1156 load_user_values (user);
1157 return GET_USER_PRIVATE (user)->real_name;
1161 * lightdm_user_get_display_name:
1162 * @user: A #LightDMUser
1164 * Get the display name of a user.
1166 * Return value: The display name of the given user
1169 lightdm_user_get_display_name (LightDMUser *user)
1171 LightDMUserPrivate *priv;
1173 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1175 load_user_values (user);
1177 priv = GET_USER_PRIVATE (user);
1178 if (!priv->real_name || strcmp (priv->real_name, "") == 0)
1181 return priv->real_name;
1185 * lightdm_user_get_home_directory:
1186 * @user: A #LightDMUser
1188 * Get the home directory for a user.
1190 * Return value: The users home directory
1193 lightdm_user_get_home_directory (LightDMUser *user)
1195 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1196 load_user_values (user);
1197 return GET_USER_PRIVATE (user)->home_directory;
1201 * lightdm_user_get_image:
1202 * @user: A #LightDMUser
1204 * Get the image URI for a user.
1206 * Return value: The image URI for the given user or #NULL if no URI
1209 lightdm_user_get_image (LightDMUser *user)
1211 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1212 load_user_values (user);
1213 return GET_USER_PRIVATE (user)->image;
1217 * lightdm_user_get_background:
1218 * @user: A #LightDMUser
1220 * Get the background file path for a user.
1222 * Return value: The background file path for the given user or #NULL if no path
1225 lightdm_user_get_background (LightDMUser *user)
1227 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1228 load_user_values (user);
1229 return GET_USER_PRIVATE (user)->background;
1233 * lightdm_user_get_language:
1234 * @user: A #LightDMUser
1236 * Get the language for a user.
1238 * Return value: The language in the form of a local specification (e.g. "de_DE.UTF-8") for the given user or #NULL if using the system default locale.
1241 lightdm_user_get_language (LightDMUser *user)
1243 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1244 load_user_values (user);
1245 return GET_USER_PRIVATE (user)->language;
1249 * lightdm_user_get_layout:
1250 * @user: A #LightDMUser
1252 * Get the keyboard layout for a user.
1254 * Return value: The keyboard layout for the given user or #NULL if using system defaults. Copy the value if you want to use it long term.
1257 lightdm_user_get_layout (LightDMUser *user)
1259 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1260 load_user_values (user);
1261 return GET_USER_PRIVATE (user)->layouts[0];
1265 * lightdm_user_get_layouts:
1266 * @user: A #LightDMUser
1268 * Get the configured keyboard layouts for a user.
1270 * Return value: (transfer none): A NULL-terminated array of keyboard layouts for the given user. Copy the values if you want to use them long term.
1272 const gchar * const *
1273 lightdm_user_get_layouts (LightDMUser *user)
1275 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1276 load_user_values (user);
1277 return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
1281 * lightdm_user_get_session:
1282 * @user: A #LightDMUser
1284 * Get the session for a user.
1286 * Return value: The session for the given user or #NULL if using system defaults.
1289 lightdm_user_get_session (LightDMUser *user)
1291 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1292 load_user_values (user);
1293 return GET_USER_PRIVATE (user)->session;
1297 * lightdm_user_get_logged_in:
1298 * @user: A #LightDMUser
1300 * Check if a user is logged in.
1302 * Return value: #TRUE if the user is currently logged in.
1305 lightdm_user_get_logged_in (LightDMUser *user)
1307 LightDMUserPrivate *priv;
1308 LightDMUserListPrivate *list_priv;
1311 g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1313 priv = GET_USER_PRIVATE (user);
1314 list_priv = GET_LIST_PRIVATE (priv->user_list);
1316 for (link = list_priv->sessions; link; link = link->next)
1318 Session *session = link->data;
1319 if (strcmp (session->username, priv->name) == 0)
1327 * lightdm_user_get_has_messages:
1328 * @user: A #LightDMUser
1330 * Check if a user has waiting messages.
1332 * Return value: #TRUE if the user has waiting messages.
1335 lightdm_user_get_has_messages (LightDMUser *user)
1337 g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1338 load_user_values (user);
1339 return GET_USER_PRIVATE (user)->has_messages;
1343 lightdm_user_init (LightDMUser *user)
1345 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1346 priv->layouts = g_malloc (sizeof (gchar *) * 1);
1347 priv->layouts[0] = NULL;
1351 lightdm_user_set_property (GObject *object,
1353 const GValue *value,
1356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1360 lightdm_user_get_property (GObject *object,
1367 self = LIGHTDM_USER (object);
1371 case USER_PROP_NAME:
1372 g_value_set_string (value, lightdm_user_get_name (self));
1374 case USER_PROP_REAL_NAME:
1375 g_value_set_string (value, lightdm_user_get_real_name (self));
1377 case USER_PROP_DISPLAY_NAME:
1378 g_value_set_string (value, lightdm_user_get_display_name (self));
1380 case USER_PROP_HOME_DIRECTORY:
1381 g_value_set_string (value, lightdm_user_get_home_directory (self));
1383 case USER_PROP_IMAGE:
1384 g_value_set_string (value, lightdm_user_get_image (self));
1386 case USER_PROP_BACKGROUND:
1387 g_value_set_string (value, lightdm_user_get_background (self));
1389 case USER_PROP_LANGUAGE:
1390 g_value_set_string (value, lightdm_user_get_language (self));
1392 case USER_PROP_LAYOUT:
1393 g_value_set_string (value, lightdm_user_get_layout (self));
1395 case USER_PROP_LAYOUTS:
1396 g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self)));
1398 case USER_PROP_SESSION:
1399 g_value_set_string (value, lightdm_user_get_session (self));
1401 case USER_PROP_LOGGED_IN:
1402 g_value_set_boolean (value, lightdm_user_get_logged_in (self));
1404 case USER_PROP_HAS_MESSAGES:
1405 g_value_set_boolean (value, lightdm_user_get_has_messages (self));
1408 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1414 lightdm_user_finalize (GObject *object)
1416 LightDMUser *self = LIGHTDM_USER (object);
1417 LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
1419 g_free (priv->path);
1420 if (priv->changed_signal)
1421 g_dbus_connection_signal_unsubscribe (GET_LIST_PRIVATE (priv->user_list)->bus, priv->changed_signal);
1422 g_free (priv->name);
1423 g_free (priv->real_name);
1424 g_free (priv->home_directory);
1425 g_free (priv->image);
1426 g_free (priv->background);
1427 g_strfreev (priv->layouts);
1428 if (priv->dmrc_file)
1429 g_key_file_free (priv->dmrc_file);
1433 lightdm_user_class_init (LightDMUserClass *klass)
1435 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1437 g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
1439 object_class->set_property = lightdm_user_set_property;
1440 object_class->get_property = lightdm_user_get_property;
1441 object_class->finalize = lightdm_user_finalize;
1443 g_object_class_install_property (object_class,
1445 g_param_spec_string ("name",
1449 G_PARAM_READWRITE));
1450 g_object_class_install_property (object_class,
1451 USER_PROP_REAL_NAME,
1452 g_param_spec_string ("real-name",
1456 G_PARAM_READWRITE));
1457 g_object_class_install_property (object_class,
1458 USER_PROP_DISPLAY_NAME,
1459 g_param_spec_string ("display-name",
1461 "Users display name",
1464 g_object_class_install_property (object_class,
1465 USER_PROP_HOME_DIRECTORY,
1466 g_param_spec_string ("home-directory",
1470 G_PARAM_READWRITE));
1471 g_object_class_install_property (object_class,
1473 g_param_spec_string ("image",
1477 G_PARAM_READWRITE));
1478 g_object_class_install_property (object_class,
1479 USER_PROP_BACKGROUND,
1480 g_param_spec_string ("background",
1484 G_PARAM_READWRITE));
1485 g_object_class_install_property (object_class,
1487 g_param_spec_string ("language",
1489 "Language used by this user",
1492 g_object_class_install_property (object_class,
1494 g_param_spec_string ("layout",
1496 "Keyboard layout used by this user",
1499 g_object_class_install_property (object_class,
1501 g_param_spec_boxed ("layouts",
1503 "Keyboard layouts used by this user",
1506 g_object_class_install_property (object_class,
1508 g_param_spec_string ("session",
1510 "Session used by this user",
1513 g_object_class_install_property (object_class,
1514 USER_PROP_LOGGED_IN,
1515 g_param_spec_boolean ("logged-in",
1517 "TRUE if the user is currently in a session",
1519 G_PARAM_READWRITE));
1520 g_object_class_install_property (object_class,
1521 USER_PROP_LOGGED_IN,
1522 g_param_spec_boolean ("has-messages",
1524 "TRUE if the user is has waiting messages",
1526 G_PARAM_READWRITE));
1529 * LightDMUser::changed:
1530 * @user: A #LightDMUser
1532 * The ::changed signal gets emitted this user account is modified.
1534 user_signals[CHANGED] =
1535 g_signal_new ("changed",
1536 G_TYPE_FROM_CLASS (klass),
1538 G_STRUCT_OFFSET (LightDMUserClass, changed),
1545 session_init (Session *session)
1550 session_finalize (GObject *object)
1552 Session *self = SESSION (object);
1554 g_free (self->path);
1555 g_free (self->username);
1559 session_class_init (SessionClass *klass)
1561 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1562 object_class->finalize = session_finalize;