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;
92 /* User list this user is part of */
93 LightDMUserList *user_list;
95 /* TRUE if have loaded user properties */
96 gboolean loaded_values;
98 /* Accounts service path */
107 /* Descriptive name for user */
110 /* Home directory of user */
111 gchar *home_directory;
116 /* Background image for users */
119 /* TRUE if this user has messages available */
120 gboolean has_messages;
122 /* User chosen language */
125 /* User layout preferences */
128 /* User default session */
130 } LightDMUserPrivate;
134 GObject parent_instance;
141 GObjectClass parent_class;
144 G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
145 G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
146 #define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
147 GType session_get_type (void);
148 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
150 #define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
151 #define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
153 #define PASSWD_FILE "/etc/passwd"
154 #define USER_CONFIG_FILE "/etc/lightdm/users.conf"
156 static LightDMUserList *singleton = NULL;
159 * lightdm_user_list_get_instance:
163 * Return value: (transfer none): the #LightDMUserList
166 lightdm_user_list_get_instance (void)
169 singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
174 get_user_by_name (LightDMUserList *user_list, const gchar *username)
176 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
179 for (link = priv->users; link; link = link->next)
181 LightDMUser *user = link->data;
182 if (g_strcmp0 (lightdm_user_get_name (user), username) == 0)
190 get_user_by_path (LightDMUserList *user_list, const gchar *path)
192 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
195 for (link = priv->users; link; link = link->next)
197 LightDMUser *user = link->data;
198 if (g_strcmp0 (GET_USER_PRIVATE (user)->path, path) == 0)
206 compare_user (gconstpointer a, gconstpointer b)
208 LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
209 return g_strcmp0 (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
213 update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
215 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
217 /* Skip if already set to this */
218 if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
219 g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
220 g_strcmp0 (lightdm_user_get_image (user), image) == 0)
223 g_free (priv->real_name);
224 priv->real_name = g_strdup (real_name);
225 g_free (priv->home_directory);
226 priv->home_directory = g_strdup (home_directory);
227 g_free (priv->image);
228 priv->image = g_strdup (image);
234 user_changed_cb (LightDMUser *user)
236 g_signal_emit (GET_USER_PRIVATE (user)->user_list, list_signals[USER_CHANGED], 0, user);
240 load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
242 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
246 gchar **hidden_users, **hidden_shells;
247 GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
248 GError *error = NULL;
250 g_debug ("Loading user config from %s", USER_CONFIG_FILE);
252 config = g_key_file_new ();
253 g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error);
254 if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
255 g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info
256 g_clear_error (&error);
258 if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
259 minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
263 value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
265 value = g_strdup ("nobody nobody4 noaccess");
266 hidden_users = g_strsplit (value, " ", -1);
269 value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
271 value = g_strdup ("/bin/false /usr/sbin/nologin");
272 hidden_shells = g_strsplit (value, " ", -1);
275 g_key_file_free (config);
281 struct passwd *entry;
283 LightDMUserPrivate *user_priv;
285 gchar *real_name, *image;
293 /* Ignore system users */
294 if (entry->pw_uid < minimum_uid)
297 /* Ignore users disabled by shell */
300 for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
301 if (hidden_shells[i])
305 /* Ignore certain users */
306 for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
310 tokens = g_strsplit (entry->pw_gecos, ",", -1);
311 if (tokens[0] != NULL && tokens[0][0] != '\0')
312 real_name = g_strdup (tokens[0]);
314 real_name = g_strdup ("");
317 image = g_build_filename (entry->pw_dir, ".face", NULL);
318 if (!g_file_test (image, G_FILE_TEST_EXISTS))
321 image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
322 if (!g_file_test (image, G_FILE_TEST_EXISTS))
329 user = g_object_new (LIGHTDM_TYPE_USER, NULL);
330 user_priv = GET_USER_PRIVATE (user);
331 user_priv->user_list = user_list;
332 g_free (user_priv->name);
333 user_priv->name = g_strdup (entry->pw_name);
334 g_free (user_priv->real_name);
335 user_priv->real_name = real_name;
336 g_free (user_priv->home_directory);
337 user_priv->home_directory = g_strdup (entry->pw_dir);
338 g_free (user_priv->image);
339 user_priv->image = image;
341 /* Update existing users if have them */
342 for (link = priv->users; link; link = link->next)
344 LightDMUser *info = link->data;
345 if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
347 if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
348 changed_users = g_list_insert_sorted (changed_users, info, compare_user);
349 g_object_unref (user);
356 /* Only notify once we have loaded the user list */
357 if (priv->have_users)
358 new_users = g_list_insert_sorted (new_users, user, compare_user);
360 users = g_list_insert_sorted (users, user, compare_user);
362 g_strfreev (hidden_users);
363 g_strfreev (hidden_shells);
366 g_warning ("Failed to read password database: %s", strerror (errno));
370 /* Use new user list */
371 old_users = priv->users;
374 /* Notify of changes */
375 for (link = new_users; link; link = link->next)
377 LightDMUser *info = link->data;
378 g_debug ("User %s added", lightdm_user_get_name (info));
379 g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), NULL);
381 g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
383 g_list_free (new_users);
384 for (link = changed_users; link; link = link->next)
386 LightDMUser *info = link->data;
387 g_debug ("User %s changed", lightdm_user_get_name (info));
388 g_signal_emit (info, user_signals[CHANGED], 0);
390 g_list_free (changed_users);
391 for (link = old_users; link; link = link->next)
395 /* See if this user is in the current list */
396 for (new_link = priv->users; new_link; new_link = new_link->next)
398 if (new_link->data == link->data)
404 LightDMUser *info = link->data;
405 g_debug ("User %s removed", lightdm_user_get_name (info));
406 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
407 g_object_unref (info);
410 g_list_free (old_users);
414 passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
416 if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
418 g_debug ("%s changed, reloading user list", g_file_get_path (file));
419 load_passwd_file (user_list, TRUE);
424 load_accounts_user (LightDMUser *user)
426 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
427 GVariant *result, *value;
430 GError *error = NULL;
432 result = g_dbus_connection_call_sync (GET_LIST_PRIVATE (priv->user_list)->bus,
433 "org.freedesktop.Accounts",
435 "org.freedesktop.DBus.Properties",
437 g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
438 G_VARIANT_TYPE ("(a{sv})"),
439 G_DBUS_CALL_FLAGS_NONE,
444 g_warning ("Error updating user %s: %s", priv->path, error->message);
445 g_clear_error (&error);
449 /* Store the properties we need */
450 g_variant_get (result, "(a{sv})", &iter);
451 while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
453 if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
456 priv->name = g_variant_dup_string (value, NULL);
458 else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
460 g_free (priv->real_name);
461 priv->real_name = g_variant_dup_string (value, NULL);
463 else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
465 g_free (priv->home_directory);
466 priv->home_directory = g_variant_dup_string (value, NULL);
468 else if (strcmp (name, "Language") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
471 g_free (priv->language);
472 priv->language = g_variant_dup_string (value, NULL);
474 else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
476 g_free (priv->image);
477 priv->image = g_variant_dup_string (value, NULL);
478 if (strcmp (priv->image, "") == 0)
480 g_free (priv->image);
484 else if (strcmp (name, "XSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
486 g_free (priv->session);
487 priv->session = g_variant_dup_string (value, NULL);
489 else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
491 g_free (priv->background);
492 priv->background = g_variant_dup_string (value, NULL);
493 if (strcmp (priv->background, "") == 0)
495 g_free (priv->background);
496 priv->background = NULL;
499 else if (strcmp (name, "XKeyboardLayouts") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY))
501 g_strfreev (priv->layouts);
502 priv->layouts = g_variant_dup_strv (value, NULL);
505 priv->layouts = g_malloc (sizeof (gchar *) * 1);
506 priv->layouts[0] = NULL;
509 else if (strcmp (name, "XHasMessages") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
510 priv->has_messages = g_variant_get_boolean (value);
512 g_variant_iter_free (iter);
514 g_variant_unref (result);
520 user_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUser *user)
522 if (strcmp (signal_name, "Changed") == 0)
524 if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
526 g_debug ("User %s changed", GET_USER_PRIVATE (user)->path);
527 load_accounts_user (user);
528 g_signal_emit (user, user_signals[CHANGED], 0);
531 g_warning ("Got org.freedesktop.Accounts.User signal Changed with unknown parameters %s", g_variant_get_type_string (parameters));
536 add_accounts_user (LightDMUserList *user_list, const gchar *path, gboolean emit_signal)
538 LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (user_list);
540 LightDMUserPrivate *priv;
542 user = g_object_new (LIGHTDM_TYPE_USER, NULL);
543 priv = GET_USER_PRIVATE (user);
545 g_debug ("User %s added", path);
546 priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
547 G_DBUS_PROXY_FLAGS_NONE,
549 "org.freedesktop.Accounts",
551 "org.freedesktop.Accounts.User",
554 g_signal_connect (priv->proxy, "g-signal", G_CALLBACK (user_signal_cb), user);
555 priv->user_list = user_list;
556 priv->path = g_strdup (path);
557 list_priv->users = g_list_insert_sorted (list_priv->users, user, compare_user);
558 g_signal_connect (user, "changed", G_CALLBACK (user_changed_cb), NULL);
560 g_signal_emit (user_list, list_signals[USER_ADDED], 0, user);
564 accounts_user_added_cb (GDBusConnection *connection,
565 const gchar *sender_name,
566 const gchar *object_path,
567 const gchar *interface_name,
568 const gchar *signal_name,
569 GVariant *parameters,
572 LightDMUserList *user_list = data;
576 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
578 g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
582 g_variant_get (parameters, "(&o)", &path);
584 /* Add user if we haven't got them */
585 user = get_user_by_path (user_list, path);
587 add_accounts_user (user_list, path, TRUE);
591 accounts_user_deleted_cb (GDBusConnection *connection,
592 const gchar *sender_name,
593 const gchar *object_path,
594 const gchar *interface_name,
595 const gchar *signal_name,
596 GVariant *parameters,
599 LightDMUserList *user_list = data;
600 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
604 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
606 g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
610 g_variant_get (parameters, "(&o)", &path);
612 /* Delete user if we know of them */
613 user = get_user_by_path (user_list, path);
616 g_debug ("User %s deleted", path);
617 priv->users = g_list_remove (priv->users, user);
619 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, user);
621 g_object_unref (user);
626 load_session (LightDMUserList *user_list, const gchar *path)
628 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
629 Session *session = NULL;
630 GVariant *result, *username;
631 GError *error = NULL;
633 result = g_dbus_connection_call_sync (priv->bus,
634 "org.freedesktop.DisplayManager",
636 "org.freedesktop.DBus.Properties",
638 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
639 G_VARIANT_TYPE ("(v)"),
640 G_DBUS_CALL_FLAGS_NONE,
645 g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
646 g_clear_error (&error);
650 g_variant_get (result, "(v)", &username);
651 if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
655 g_variant_get (username, "&s", &name);
657 g_debug ("Loaded session %s (%s)", path, name);
658 session = g_object_new (session_get_type (), NULL);
659 session->username = g_strdup (name);
660 session->path = g_strdup (path);
661 priv->sessions = g_list_append (priv->sessions, session);
663 g_variant_unref (username);
664 g_variant_unref (result);
670 session_added_cb (GDBusConnection *connection,
671 const gchar *sender_name,
672 const gchar *object_path,
673 const gchar *interface_name,
674 const gchar *signal_name,
675 GVariant *parameters,
678 LightDMUserList *user_list = data;
681 LightDMUser *user = NULL;
683 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
685 g_warning ("Got DisplayManager signal SessionAdded with unknown parameters %s", g_variant_get_type_string (parameters));
689 g_variant_get (parameters, "(&o)", &path);
690 session = load_session (user_list, path);
692 user = get_user_by_name (user_list, session->username);
694 g_signal_emit (user, user_signals[CHANGED], 0);
698 session_removed_cb (GDBusConnection *connection,
699 const gchar *sender_name,
700 const gchar *object_path,
701 const gchar *interface_name,
702 const gchar *signal_name,
703 GVariant *parameters,
706 LightDMUserList *user_list = data;
707 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
711 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
713 g_warning ("Got DisplayManager signal SessionRemoved with unknown parameters %s", g_variant_get_type_string (parameters));
717 g_variant_get (parameters, "(&o)", &path);
719 for (link = priv->sessions; link; link = link->next)
721 Session *session = link->data;
722 if (strcmp (session->path, path) == 0)
726 g_debug ("Session %s removed", path);
727 priv->sessions = g_list_remove_link (priv->sessions, link);
728 user = get_user_by_name (user_list, session->username);
730 g_signal_emit (user, user_signals[CHANGED], 0);
731 g_object_unref (session);
738 load_users (LightDMUserList *user_list)
740 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
742 GError *error = NULL;
744 if (priv->have_users)
746 priv->have_users = TRUE;
748 /* Get user list from accounts service and fall back to /etc/passwd if that fails */
749 priv->user_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
750 "org.freedesktop.Accounts",
751 "org.freedesktop.Accounts",
753 "/org/freedesktop/Accounts",
755 G_DBUS_SIGNAL_FLAGS_NONE,
756 accounts_user_added_cb,
759 priv->user_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
760 "org.freedesktop.Accounts",
761 "org.freedesktop.Accounts",
763 "/org/freedesktop/Accounts",
765 G_DBUS_SIGNAL_FLAGS_NONE,
766 accounts_user_deleted_cb,
769 result = g_dbus_connection_call_sync (priv->bus,
770 "org.freedesktop.Accounts",
771 "/org/freedesktop/Accounts",
772 "org.freedesktop.Accounts",
774 g_variant_new ("()"),
775 G_VARIANT_TYPE ("(ao)"),
776 G_DBUS_CALL_FLAGS_NONE,
781 g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
782 g_clear_error (&error);
788 g_debug ("Loading users from org.freedesktop.Accounts");
789 g_variant_get (result, "(ao)", &iter);
790 while (g_variant_iter_loop (iter, "&o", &path))
791 add_accounts_user (user_list, path, FALSE);
792 g_variant_iter_free (iter);
793 g_variant_unref (result);
799 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
800 priv->user_added_signal = 0;
801 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
802 priv->user_removed_signal = 0;
804 load_passwd_file (user_list, FALSE);
806 /* Watch for changes to user list */
808 passwd_file = g_file_new_for_path (PASSWD_FILE);
809 priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
810 g_object_unref (passwd_file);
812 g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
814 g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
815 g_clear_error (&error);
818 priv->session_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
819 "org.freedesktop.DisplayManager",
820 "org.freedesktop.DisplayManager",
822 "/org/freedesktop/DisplayManager",
824 G_DBUS_SIGNAL_FLAGS_NONE,
828 priv->session_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
829 "org.freedesktop.DisplayManager",
830 "org.freedesktop.DisplayManager",
832 "/org/freedesktop/DisplayManager",
834 G_DBUS_SIGNAL_FLAGS_NONE,
839 result = g_dbus_connection_call_sync (priv->bus,
840 "org.freedesktop.DisplayManager",
841 "/org/freedesktop/DisplayManager",
842 "org.freedesktop.DBus.Properties",
844 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
845 G_VARIANT_TYPE ("(v)"),
846 G_DBUS_CALL_FLAGS_NONE,
851 g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
852 g_clear_error (&error);
855 if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
861 g_variant_get (result, "(v)", &value);
863 g_debug ("Loading sessions from org.freedesktop.DisplayManager");
864 g_variant_get (value, "ao", &iter);
865 while (g_variant_iter_loop (iter, "&o", &path))
866 load_session (user_list, path);
867 g_variant_iter_free (iter);
869 g_variant_unref (value);
872 g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
874 g_variant_unref (result);
879 * lightdm_user_list_get_length:
880 * @user_list: a #LightDMUserList
882 * Return value: The number of users able to log in
885 lightdm_user_list_get_length (LightDMUserList *user_list)
887 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
888 load_users (user_list);
889 return g_list_length (GET_LIST_PRIVATE (user_list)->users);
893 * lightdm_user_list_get_users:
894 * @user_list: A #LightDMUserList
896 * Get a list of users to present to the user. This list may be a subset of the
897 * available users and may be empty depending on the server configuration.
899 * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user.
902 lightdm_user_list_get_users (LightDMUserList *user_list)
904 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
905 load_users (user_list);
906 return GET_LIST_PRIVATE (user_list)->users;
910 * lightdm_user_list_get_user_by_name:
911 * @user_list: A #LightDMUserList
912 * @username: Name of user to get.
914 * Get infomation about a given user or #NULL if this user doesn't exist.
916 * Return value: (transfer none): A #LightDMUser entry for the given user.
919 lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
921 g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
922 g_return_val_if_fail (username != NULL, NULL);
924 load_users (user_list);
926 return get_user_by_name (user_list, username);
930 lightdm_user_list_init (LightDMUserList *user_list)
932 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
934 priv->bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
938 lightdm_user_list_set_property (GObject *object,
943 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
947 lightdm_user_list_get_property (GObject *object,
952 LightDMUserList *self;
954 self = LIGHTDM_USER_LIST (object);
958 case LIST_PROP_NUM_USERS:
959 g_value_set_int (value, lightdm_user_list_get_length (self));
962 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
968 lightdm_user_list_finalize (GObject *object)
970 LightDMUserList *self = LIGHTDM_USER_LIST (object);
971 LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
973 /* Remove children first, they might access us */
974 g_list_free_full (priv->users, g_object_unref);
975 g_list_free_full (priv->sessions, g_object_unref);
977 if (priv->user_added_signal)
978 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_added_signal);
979 if (priv->user_removed_signal)
980 g_dbus_connection_signal_unsubscribe (priv->bus, priv->user_removed_signal);
981 if (priv->session_added_signal)
982 g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_added_signal);
983 if (priv->session_removed_signal)
984 g_dbus_connection_signal_unsubscribe (priv->bus, priv->session_removed_signal);
985 g_object_unref (priv->bus);
986 if (priv->passwd_monitor)
987 g_object_unref (priv->passwd_monitor);
989 G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
993 lightdm_user_list_class_init (LightDMUserListClass *klass)
995 GObjectClass *object_class = G_OBJECT_CLASS (klass);
997 g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
999 object_class->set_property = lightdm_user_list_set_property;
1000 object_class->get_property = lightdm_user_list_get_property;
1001 object_class->finalize = lightdm_user_list_finalize;
1003 g_object_class_install_property (object_class,
1004 LIST_PROP_NUM_USERS,
1005 g_param_spec_int ("num-users",
1007 "Number of login users",
1011 * LightDMUserList::user-added:
1012 * @user_list: A #LightDMUserList
1013 * @user: The #LightDM user that has been added.
1015 * The ::user-added signal gets emitted when a user account is created.
1017 list_signals[USER_ADDED] =
1018 g_signal_new ("user-added",
1019 G_TYPE_FROM_CLASS (klass),
1021 G_STRUCT_OFFSET (LightDMUserListClass, user_added),
1024 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1027 * LightDMUserList::user-changed:
1028 * @user_list: A #LightDMUserList
1029 * @user: The #LightDM user that has been changed.
1031 * The ::user-changed signal gets emitted when a user account is modified.
1033 list_signals[USER_CHANGED] =
1034 g_signal_new ("user-changed",
1035 G_TYPE_FROM_CLASS (klass),
1037 G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
1040 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1043 * LightDMUserList::user-removed:
1044 * @user_list: A #LightDMUserList
1045 * @user: The #LightDM user that has been removed.
1047 * The ::user-removed signal gets emitted when a user account is removed.
1049 list_signals[USER_REMOVED] =
1050 g_signal_new ("user-removed",
1051 G_TYPE_FROM_CLASS (klass),
1053 G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
1056 G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1060 load_dmrc (LightDMUser *user)
1062 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1064 //gboolean have_dmrc;
1066 if (!priv->dmrc_file)
1067 priv->dmrc_file = g_key_file_new ();
1069 /* Load from the user directory */
1070 path = g_build_filename (priv->home_directory, ".dmrc", NULL);
1071 /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
1074 /* If no ~/.dmrc, then load from the cache */
1077 // FIXME: Watch for changes
1079 /* The Language field contains the locale */
1081 g_free (priv->language);
1082 priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
1084 if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
1086 g_strfreev (priv->layouts);
1087 priv->layouts = g_malloc (sizeof (gchar *) * 2);
1088 priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
1089 priv->layouts[1] = NULL;
1093 g_free (priv->session);
1094 priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
1097 /* Loads language/layout/session info for user */
1099 load_user_values (LightDMUser *user)
1101 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1103 if (priv->loaded_values)
1105 priv->loaded_values = TRUE;
1108 load_accounts_user (user); // overrides dmrc values
1112 * lightdm_user_get_name:
1113 * @user: A #LightDMUser
1115 * Get the name of a user.
1117 * Return value: The name of the given user
1120 lightdm_user_get_name (LightDMUser *user)
1122 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1123 load_user_values (user);
1124 return GET_USER_PRIVATE (user)->name;
1128 * lightdm_user_get_real_name:
1129 * @user: A #LightDMUser
1131 * Get the real name of a user.
1133 * Return value: The real name of the given user
1136 lightdm_user_get_real_name (LightDMUser *user)
1138 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1139 load_user_values (user);
1140 return GET_USER_PRIVATE (user)->real_name;
1144 * lightdm_user_get_display_name:
1145 * @user: A #LightDMUser
1147 * Get the display name of a user.
1149 * Return value: The display name of the given user
1152 lightdm_user_get_display_name (LightDMUser *user)
1154 LightDMUserPrivate *priv;
1156 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1158 load_user_values (user);
1160 priv = GET_USER_PRIVATE (user);
1161 if (!priv->real_name || strcmp (priv->real_name, ""))
1162 return priv->real_name;
1168 * lightdm_user_get_home_directory:
1169 * @user: A #LightDMUser
1171 * Get the home directory for a user.
1173 * Return value: The users home directory
1176 lightdm_user_get_home_directory (LightDMUser *user)
1178 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1179 load_user_values (user);
1180 return GET_USER_PRIVATE (user)->home_directory;
1184 * lightdm_user_get_image:
1185 * @user: A #LightDMUser
1187 * Get the image URI for a user.
1189 * Return value: The image URI for the given user or #NULL if no URI
1192 lightdm_user_get_image (LightDMUser *user)
1194 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1195 load_user_values (user);
1196 return GET_USER_PRIVATE (user)->image;
1200 * lightdm_user_get_background:
1201 * @user: A #LightDMUser
1203 * Get the background file path for a user.
1205 * Return value: The background file path for the given user or #NULL if no path
1208 lightdm_user_get_background (LightDMUser *user)
1210 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1211 load_user_values (user);
1212 return GET_USER_PRIVATE (user)->background;
1216 * lightdm_user_get_language:
1217 * @user: A #LightDMUser
1219 * Get the language for a user.
1221 * 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.
1224 lightdm_user_get_language (LightDMUser *user)
1226 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1227 load_user_values (user);
1228 return GET_USER_PRIVATE (user)->language;
1232 * lightdm_user_get_layout:
1233 * @user: A #LightDMUser
1235 * Get the keyboard layout for a user.
1237 * 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.
1240 lightdm_user_get_layout (LightDMUser *user)
1242 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1243 load_user_values (user);
1244 return GET_USER_PRIVATE (user)->layouts[0];
1248 * lightdm_user_get_layouts:
1249 * @user: A #LightDMUser
1251 * Get the configured keyboard layouts for a user.
1253 * 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.
1255 const gchar * const *
1256 lightdm_user_get_layouts (LightDMUser *user)
1258 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1259 load_user_values (user);
1260 return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
1264 * lightdm_user_get_session:
1265 * @user: A #LightDMUser
1267 * Get the session for a user.
1269 * Return value: The session for the given user or #NULL if using system defaults.
1272 lightdm_user_get_session (LightDMUser *user)
1274 g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1275 load_user_values (user);
1276 return GET_USER_PRIVATE (user)->session;
1280 * lightdm_user_get_logged_in:
1281 * @user: A #LightDMUser
1283 * Check if a user is logged in.
1285 * Return value: #TRUE if the user is currently logged in.
1288 lightdm_user_get_logged_in (LightDMUser *user)
1290 LightDMUserPrivate *priv;
1291 LightDMUserListPrivate *list_priv;
1294 g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1296 priv = GET_USER_PRIVATE (user);
1297 list_priv = GET_LIST_PRIVATE (priv->user_list);
1299 for (link = list_priv->sessions; link; link = link->next)
1301 Session *session = link->data;
1302 if (strcmp (session->username, priv->name) == 0)
1310 * lightdm_user_get_has_messages:
1311 * @user: A #LightDMUser
1313 * Check if a user has waiting messages.
1315 * Return value: #TRUE if the user has waiting messages.
1318 lightdm_user_get_has_messages (LightDMUser *user)
1320 g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1321 load_user_values (user);
1322 return GET_USER_PRIVATE (user)->has_messages;
1326 lightdm_user_init (LightDMUser *user)
1328 LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1329 priv->layouts = g_malloc (sizeof (gchar *) * 1);
1330 priv->layouts[0] = NULL;
1334 lightdm_user_set_property (GObject *object,
1336 const GValue *value,
1339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1343 lightdm_user_get_property (GObject *object,
1350 self = LIGHTDM_USER (object);
1354 case USER_PROP_NAME:
1355 g_value_set_string (value, lightdm_user_get_name (self));
1357 case USER_PROP_REAL_NAME:
1358 g_value_set_string (value, lightdm_user_get_real_name (self));
1360 case USER_PROP_DISPLAY_NAME:
1361 g_value_set_string (value, lightdm_user_get_display_name (self));
1363 case USER_PROP_HOME_DIRECTORY:
1364 g_value_set_string (value, lightdm_user_get_home_directory (self));
1366 case USER_PROP_IMAGE:
1367 g_value_set_string (value, lightdm_user_get_image (self));
1369 case USER_PROP_BACKGROUND:
1370 g_value_set_string (value, lightdm_user_get_background (self));
1372 case USER_PROP_LANGUAGE:
1373 g_value_set_string (value, lightdm_user_get_language (self));
1375 case USER_PROP_LAYOUT:
1376 g_value_set_string (value, lightdm_user_get_layout (self));
1378 case USER_PROP_LAYOUTS:
1379 g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self)));
1381 case USER_PROP_SESSION:
1382 g_value_set_string (value, lightdm_user_get_session (self));
1384 case USER_PROP_LOGGED_IN:
1385 g_value_set_boolean (value, lightdm_user_get_logged_in (self));
1387 case USER_PROP_HAS_MESSAGES:
1388 g_value_set_boolean (value, lightdm_user_get_has_messages (self));
1391 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1397 lightdm_user_finalize (GObject *object)
1399 LightDMUser *self = LIGHTDM_USER (object);
1400 LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
1403 g_object_unref (priv->proxy);
1404 g_free (priv->path);
1405 g_free (priv->name);
1406 g_free (priv->real_name);
1407 g_free (priv->home_directory);
1408 g_free (priv->image);
1409 g_free (priv->background);
1410 g_strfreev (priv->layouts);
1411 if (priv->dmrc_file)
1412 g_key_file_free (priv->dmrc_file);
1416 lightdm_user_class_init (LightDMUserClass *klass)
1418 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1420 g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
1422 object_class->set_property = lightdm_user_set_property;
1423 object_class->get_property = lightdm_user_get_property;
1424 object_class->finalize = lightdm_user_finalize;
1426 g_object_class_install_property (object_class,
1428 g_param_spec_string ("name",
1432 G_PARAM_READWRITE));
1433 g_object_class_install_property (object_class,
1434 USER_PROP_REAL_NAME,
1435 g_param_spec_string ("real-name",
1439 G_PARAM_READWRITE));
1440 g_object_class_install_property (object_class,
1441 USER_PROP_DISPLAY_NAME,
1442 g_param_spec_string ("display-name",
1444 "Users display name",
1447 g_object_class_install_property (object_class,
1448 USER_PROP_HOME_DIRECTORY,
1449 g_param_spec_string ("home-directory",
1453 G_PARAM_READWRITE));
1454 g_object_class_install_property (object_class,
1456 g_param_spec_string ("image",
1460 G_PARAM_READWRITE));
1461 g_object_class_install_property (object_class,
1462 USER_PROP_BACKGROUND,
1463 g_param_spec_string ("background",
1467 G_PARAM_READWRITE));
1468 g_object_class_install_property (object_class,
1470 g_param_spec_string ("language",
1472 "Language used by this user",
1475 g_object_class_install_property (object_class,
1477 g_param_spec_string ("layout",
1479 "Keyboard layout used by this user",
1482 g_object_class_install_property (object_class,
1484 g_param_spec_boxed ("layouts",
1486 "Keyboard layouts used by this user",
1489 g_object_class_install_property (object_class,
1491 g_param_spec_string ("session",
1493 "Session used by this user",
1496 g_object_class_install_property (object_class,
1497 USER_PROP_LOGGED_IN,
1498 g_param_spec_boolean ("logged-in",
1500 "TRUE if the user is currently in a session",
1502 G_PARAM_READWRITE));
1503 g_object_class_install_property (object_class,
1504 USER_PROP_LOGGED_IN,
1505 g_param_spec_boolean ("has-messages",
1507 "TRUE if the user is has waiting messages",
1509 G_PARAM_READWRITE));
1512 * LightDMUser::changed:
1513 * @user: A #LightDMUser
1515 * The ::changed signal gets emitted this user account is modified.
1517 user_signals[CHANGED] =
1518 g_signal_new ("changed",
1519 G_TYPE_FROM_CLASS (klass),
1521 G_STRUCT_OFFSET (LightDMUserClass, changed),
1528 session_init (Session *session)
1533 session_finalize (GObject *object)
1535 Session *self = SESSION (object);
1537 g_free (self->path);
1538 g_free (self->username);
1542 session_class_init (SessionClass *klass)
1544 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1545 object_class->finalize = session_finalize;