Back to index

lightdm  1.3.2
user.c
Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
00002  *
00003  * Copyright (C) 2010 Robert Ancell.
00004  * Author: Robert Ancell <robert.ancell@canonical.com>
00005  * 
00006  * This library is free software; you can redistribute it and/or modify it under
00007  * the terms of the GNU Lesser General Public License as published by the Free
00008  * Software Foundation; either version 3 of the License, or (at your option) any
00009  * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
00010  * license.
00011  */
00012 
00013 #include <config.h>
00014 
00015 #include <errno.h>
00016 #include <string.h>
00017 #include <sys/utsname.h>
00018 #include <pwd.h>
00019 #include <gio/gio.h>
00020 
00021 #include "lightdm/user.h"
00022 
00023 enum
00024 {
00025     LIST_PROP_0,
00026     LIST_PROP_NUM_USERS,
00027     LIST_PROP_USERS,
00028 };
00029 
00030 enum
00031 {
00032     USER_PROP_0,
00033     USER_PROP_NAME,
00034     USER_PROP_REAL_NAME,
00035     USER_PROP_DISPLAY_NAME,
00036     USER_PROP_HOME_DIRECTORY,
00037     USER_PROP_IMAGE,
00038     USER_PROP_BACKGROUND,
00039     USER_PROP_LANGUAGE,
00040     USER_PROP_LAYOUT,
00041     USER_PROP_LAYOUTS,
00042     USER_PROP_SESSION,
00043     USER_PROP_LOGGED_IN,
00044     USER_PROP_HAS_MESSAGES
00045 };
00046 
00047 enum
00048 {
00049     USER_ADDED,
00050     USER_CHANGED,
00051     USER_REMOVED,
00052     LAST_LIST_SIGNAL
00053 };
00054 static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
00055 
00056 enum
00057 {
00058     CHANGED,
00059     LAST_USER_SIGNAL
00060 };
00061 static guint user_signals[LAST_USER_SIGNAL] = { 0 };
00062 
00063 typedef struct
00064 {
00065     /* Connection to AccountsService */
00066     GDBusProxy *accounts_service_proxy;
00067     GList *user_account_objects;
00068 
00069     /* Connection to DisplayManager */
00070     GDBusProxy *display_manager_proxy;
00071 
00072     /* File monitor for password file */
00073     GFileMonitor *passwd_monitor;
00074   
00075     /* TRUE if have scanned users */
00076     gboolean have_users;
00077 
00078     /* List of users */
00079     GList *users;
00080 
00081     /* List of sessions */
00082     GList *sessions;
00083 } LightDMUserListPrivate;
00084 
00085 typedef struct
00086 {
00087     GDBusProxy *proxy;
00088     LightDMUser *user;
00089 } UserAccountObject;
00090 
00091 typedef struct
00092 {
00093     LightDMUserList *user_list;
00094 
00095     gchar *name;
00096     gchar *real_name;
00097     gchar *home_directory;
00098     gchar *image;
00099     gchar *background;
00100     gboolean has_messages;
00101 
00102     GKeyFile *dmrc_file;
00103     gchar *language;
00104     gchar **layouts;
00105     gchar *session;
00106 } LightDMUserPrivate;
00107 
00108 typedef struct
00109 {
00110     GObject parent_instance;
00111     gchar *path;
00112     gchar *username;
00113 } Session;
00114 
00115 typedef struct
00116 {
00117     GObjectClass parent_class;
00118 } SessionClass;
00119 
00120 G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
00121 G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
00122 #define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
00123 GType session_get_type (void);
00124 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
00125 
00126 #define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
00127 #define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
00128 
00129 #define PASSWD_FILE      "/etc/passwd"
00130 #define USER_CONFIG_FILE "/etc/lightdm/users.conf"
00131 
00132 static LightDMUserList *singleton = NULL;
00133 
00141 LightDMUserList *
00142 lightdm_user_list_get_instance (void)
00143 {
00144     if (!singleton)
00145         singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
00146     return singleton;
00147 }
00148 
00149 static LightDMUser *
00150 get_user_by_name (LightDMUserList *user_list, const gchar *username)
00151 {
00152     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
00153     GList *link;
00154   
00155     for (link = priv->users; link; link = link->next)
00156     {
00157         LightDMUser *user = link->data;
00158         if (strcmp (lightdm_user_get_name (user), username) == 0)
00159             return user;
00160     }
00161 
00162     return NULL;
00163 }
00164   
00165 static gint
00166 compare_user (gconstpointer a, gconstpointer b)
00167 {
00168     LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
00169     return strcmp (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
00170 }
00171 
00172 static gboolean
00173 update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
00174 {
00175     LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
00176 
00177     if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
00178         g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
00179         g_strcmp0 (lightdm_user_get_image (user), image) == 0)
00180         return FALSE;
00181 
00182     g_free (priv->real_name);
00183     priv->real_name = g_strdup (real_name);
00184     g_free (priv->home_directory);
00185     priv->home_directory = g_strdup (home_directory);
00186     g_free (priv->image);
00187     priv->image = g_strdup (image);
00188 
00189     return TRUE;
00190 }
00191 
00192 static void
00193 user_changed_cb (LightDMUser *user, LightDMUserList *user_list)
00194 {
00195     g_signal_emit (user_list, list_signals[USER_CHANGED], 0, user);
00196 }
00197 
00198 static void
00199 load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
00200 {
00201     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
00202     GKeyFile *config;
00203     gchar *value;
00204     gint minimum_uid;
00205     gchar **hidden_users, **hidden_shells;
00206     GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
00207     GError *error = NULL;
00208 
00209     g_debug ("Loading user config from %s", USER_CONFIG_FILE);
00210 
00211     config = g_key_file_new ();
00212     g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error);
00213     if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
00214         g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info
00215     g_clear_error (&error);
00216 
00217     if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
00218         minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
00219     else
00220         minimum_uid = 500;
00221 
00222     value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
00223     if (!value)
00224         value = g_strdup ("nobody nobody4 noaccess");
00225     hidden_users = g_strsplit (value, " ", -1);
00226     g_free (value);
00227 
00228     value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
00229     if (!value)
00230         value = g_strdup ("/bin/false /usr/sbin/nologin");
00231     hidden_shells = g_strsplit (value, " ", -1);
00232     g_free (value);
00233 
00234     g_key_file_free (config);
00235 
00236     setpwent ();
00237 
00238     while (TRUE)
00239     {
00240         struct passwd *entry;
00241         LightDMUser *user;
00242         LightDMUserPrivate *user_priv;
00243         char **tokens;
00244         gchar *real_name, *image;
00245         int i;
00246 
00247         errno = 0;
00248         entry = getpwent ();
00249         if (!entry)
00250             break;
00251 
00252         /* Ignore system users */
00253         if (entry->pw_uid < minimum_uid)
00254             continue;
00255 
00256         /* Ignore users disabled by shell */
00257         if (entry->pw_shell)
00258         {
00259             for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
00260             if (hidden_shells[i])
00261                 continue;
00262         }
00263 
00264         /* Ignore certain users */
00265         for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
00266         if (hidden_users[i])
00267             continue;
00268 
00269         tokens = g_strsplit (entry->pw_gecos, ",", -1);
00270         if (tokens[0] != NULL && tokens[0][0] != '\0')
00271             real_name = g_strdup (tokens[0]);
00272         else
00273             real_name = g_strdup ("");
00274         g_strfreev (tokens);
00275 
00276         image = g_build_filename (entry->pw_dir, ".face", NULL);
00277         if (!g_file_test (image, G_FILE_TEST_EXISTS))
00278         {
00279             g_free (image);
00280             image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
00281             if (!g_file_test (image, G_FILE_TEST_EXISTS))
00282             {
00283                 g_free (image);
00284                 image = NULL;
00285             }
00286         }
00287 
00288         user = g_object_new (LIGHTDM_TYPE_USER, NULL);
00289         user_priv = GET_USER_PRIVATE (user);
00290         user_priv->user_list = user_list;
00291         g_free (user_priv->name);
00292         user_priv->name = g_strdup (entry->pw_name);
00293         g_free (user_priv->real_name);
00294         user_priv->real_name = real_name;
00295         g_free (user_priv->home_directory);
00296         user_priv->home_directory = g_strdup (entry->pw_dir);
00297         g_free (user_priv->image);
00298         user_priv->image = image;
00299 
00300         /* Update existing users if have them */
00301         for (link = priv->users; link; link = link->next)
00302         {
00303             LightDMUser *info = link->data;
00304             if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
00305             {
00306                 if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
00307                     changed_users = g_list_insert_sorted (changed_users, info, compare_user);
00308                 g_object_unref (user);
00309                 user = info;
00310                 break;
00311             }
00312         }
00313         if (!link)
00314         {
00315             /* Only notify once we have loaded the user list */
00316             if (priv->have_users)
00317                 new_users = g_list_insert_sorted (new_users, user, compare_user);
00318         }
00319         users = g_list_insert_sorted (users, user, compare_user);
00320     }
00321     g_strfreev (hidden_users);
00322     g_strfreev (hidden_shells);
00323 
00324     if (errno != 0)
00325         g_warning ("Failed to read password database: %s", strerror (errno));
00326 
00327     endpwent ();
00328 
00329     /* Use new user list */
00330     old_users = priv->users;
00331     priv->users = users;
00332   
00333     /* Notify of changes */
00334     for (link = new_users; link; link = link->next)
00335     {
00336         LightDMUser *info = link->data;
00337         g_debug ("User %s added", lightdm_user_get_name (info));
00338         g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), user_list);
00339         if (emit_add_signal)
00340             g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
00341     }
00342     g_list_free (new_users);
00343     for (link = changed_users; link; link = link->next)
00344     {
00345         LightDMUser *info = link->data;
00346         g_debug ("User %s changed", lightdm_user_get_name (info));
00347         g_signal_emit (info, user_signals[CHANGED], 0);
00348     }
00349     g_list_free (changed_users);
00350     for (link = old_users; link; link = link->next)
00351     {
00352         GList *new_link;
00353 
00354         /* See if this user is in the current list */
00355         for (new_link = priv->users; new_link; new_link = new_link->next)
00356         {
00357             if (new_link->data == link->data)
00358                 break;
00359         }
00360 
00361         if (!new_link)
00362         {
00363             LightDMUser *info = link->data;
00364             g_debug ("User %s removed", lightdm_user_get_name (info));
00365             g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
00366             g_object_unref (info);
00367         }
00368     }
00369     g_list_free (old_users);
00370 }
00371 
00372 static void
00373 passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
00374 {
00375     if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
00376     {
00377         g_debug ("%s changed, reloading user list", g_file_get_path (file));
00378         load_passwd_file (user_list, TRUE);
00379     }
00380 }
00381 
00382 static gboolean
00383 update_user (UserAccountObject *object)
00384 {
00385     LightDMUserPrivate *priv = GET_USER_PRIVATE (object->user);
00386     GVariant *result, *value;
00387     GVariantIter *iter;
00388     gchar *name;
00389     GError *error = NULL;
00390 
00391     result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (object->proxy),
00392                                           "org.freedesktop.Accounts",
00393                                           g_dbus_proxy_get_object_path (object->proxy),
00394                                           "org.freedesktop.DBus.Properties",
00395                                           "GetAll",
00396                                           g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
00397                                           G_VARIANT_TYPE ("(a{sv})"),
00398                                           G_DBUS_CALL_FLAGS_NONE,
00399                                           -1,
00400                                           NULL,
00401                                           &error);
00402     if (error)
00403         g_warning ("Error updating user %s: %s", g_dbus_proxy_get_object_path (object->proxy), error->message);
00404     g_clear_error (&error);
00405     if (!result)
00406         return FALSE;
00407 
00408     g_variant_get (result, "(a{sv})", &iter);
00409     while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
00410     {
00411         if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
00412         {
00413             gchar *user_name;
00414             g_variant_get (value, "&s", &user_name);
00415             g_free (priv->name);
00416             priv->name = g_strdup (user_name);
00417         }
00418         else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
00419         {
00420             gchar *real_name;
00421             g_variant_get (value, "&s", &real_name);
00422             g_free (priv->real_name);
00423             priv->real_name = g_strdup (real_name);
00424         }
00425         else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
00426         {
00427             gchar *home_directory;
00428             g_variant_get (value, "&s", &home_directory);
00429             g_free (priv->home_directory);
00430             priv->home_directory = g_strdup (home_directory);
00431         }
00432         else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
00433         {
00434             gchar *icon_file;
00435             g_variant_get (value, "&s", &icon_file);
00436             g_free (priv->image);
00437             if (strcmp (icon_file, "") == 0)
00438                 priv->image = NULL;
00439             else
00440                 priv->image = g_strdup (icon_file);
00441         }
00442         else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
00443         {
00444             gchar *background_file;
00445             g_variant_get (value, "&s", &background_file);
00446             g_free (priv->background);
00447             if (strcmp (background_file, "") == 0)
00448                 priv->background = NULL;
00449             else
00450                 priv->background = g_strdup (background_file);
00451         }
00452     }
00453     g_variant_iter_free (iter);
00454 
00455     g_variant_unref (result);
00456 
00457     return TRUE;
00458 }
00459 
00460 static void
00461 user_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, UserAccountObject *object)
00462 {
00463     if (strcmp (signal_name, "Changed") == 0)
00464     {
00465         if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
00466         {
00467             g_debug ("User %s changed", g_dbus_proxy_get_object_path (object->proxy));
00468             update_user (object);
00469             g_signal_emit (object->user, user_signals[CHANGED], 0);
00470         }
00471         else
00472             g_warning ("Got org.freedesktop.Accounts.User signal Changed with unknown parameters %s", g_variant_get_type_string (parameters));
00473     }
00474 }
00475 
00476 static UserAccountObject *
00477 user_account_object_new (LightDMUserList *user_list, const gchar *path)
00478 {
00479     GDBusProxy *proxy;
00480     UserAccountObject *object;
00481     GError *error = NULL;
00482 
00483     proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
00484                                            G_DBUS_PROXY_FLAGS_NONE,
00485                                            NULL,
00486                                            "org.freedesktop.Accounts",
00487                                            path,
00488                                            "org.freedesktop.Accounts.User",
00489                                            NULL,
00490                                            &error);
00491     if (error)
00492         g_warning ("Error getting user %s: %s", path, error->message);
00493     g_clear_error (&error);
00494     if (!proxy)
00495         return NULL;
00496 
00497     object = g_malloc0 (sizeof (UserAccountObject));  
00498     object->user = g_object_new (LIGHTDM_TYPE_USER, NULL);
00499     GET_USER_PRIVATE (object->user)->user_list = user_list;
00500     object->proxy = proxy;
00501     g_signal_connect (proxy, "g-signal", G_CALLBACK (user_signal_cb), object);
00502   
00503     return object;
00504 }
00505 
00506 static void
00507 user_account_object_free (UserAccountObject *object)
00508 {
00509     if (!object)
00510         return;
00511     g_object_unref (object->user);
00512     g_object_unref (object->proxy);
00513     g_free (object);
00514 }
00515 
00516 static UserAccountObject *
00517 find_user_account_object (LightDMUserList *user_list, const gchar *path)
00518 {
00519     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
00520     GList *link;
00521 
00522     for (link = priv->user_account_objects; link; link = link->next)
00523     {
00524         UserAccountObject *object = link->data;
00525         if (strcmp (g_dbus_proxy_get_object_path (object->proxy), path) == 0)
00526             return object;
00527     }
00528 
00529     return NULL;
00530 }
00531 
00532 static void
00533 user_accounts_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
00534 {
00535     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
00536   
00537     if (strcmp (signal_name, "UserAdded") == 0)
00538     {
00539         if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
00540         {
00541             gchar *path;
00542             UserAccountObject *object;
00543 
00544             g_variant_get (parameters, "(&o)", &path);
00545 
00546             /* Ignore duplicate requests */
00547             object = find_user_account_object (user_list, path);
00548             if (object)
00549                 return;
00550 
00551             object = user_account_object_new (user_list, path);
00552             if (object && update_user (object))
00553             {
00554                 g_debug ("User %s added", path);
00555                 priv->user_account_objects = g_list_append (priv->user_account_objects, object);
00556                 priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
00557                 g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
00558                 g_signal_emit (user_list, list_signals[USER_ADDED], 0, object->user);
00559             }
00560             else
00561                 user_account_object_free (object);
00562         }
00563         else
00564             g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
00565     }
00566     else if (strcmp (signal_name, "UserDeleted") == 0)
00567     {
00568         if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
00569         {
00570             gchar *path;
00571             UserAccountObject *object;
00572 
00573             g_variant_get (parameters, "(&o)", &path);
00574 
00575             object = find_user_account_object (user_list, path);
00576             if (!object)
00577                 return;
00578 
00579             g_debug ("User %s deleted", path);
00580             priv->users = g_list_remove (priv->users, object->user);
00581             g_object_unref (object->user);
00582 
00583             g_signal_emit (user_list, list_signals[USER_REMOVED], 0, object->user);
00584 
00585             priv->user_account_objects = g_list_remove (priv->user_account_objects, object);
00586             user_account_object_free (object);
00587         }
00588         else
00589             g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
00590     }
00591 }
00592 
00593 static Session *
00594 load_session (LightDMUserList *user_list, const gchar *path)
00595 {
00596     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
00597     Session *session = NULL;
00598     GVariant *result, *username;
00599     GError *error = NULL;
00600 
00601     result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
00602                                           "org.freedesktop.DisplayManager",
00603                                           path,
00604                                           "org.freedesktop.DBus.Properties",
00605                                           "Get",
00606                                           g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
00607                                           G_VARIANT_TYPE ("(v)"),
00608                                           G_DBUS_CALL_FLAGS_NONE,
00609                                           -1,
00610                                           NULL,
00611                                           &error);
00612     if (error)
00613         g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
00614     g_clear_error (&error);
00615     if (!result)
00616         return NULL;
00617 
00618     g_variant_get (result, "(v)", &username);
00619     if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
00620     {
00621         gchar *name;
00622 
00623         g_variant_get (username, "&s", &name);
00624 
00625         g_debug ("Loaded session %s (%s)", path, name);
00626         session = g_object_new (session_get_type (), NULL);
00627         session->username = g_strdup (name);
00628         session->path = g_strdup (path);
00629         priv->sessions = g_list_append (priv->sessions, session);
00630     }
00631     g_variant_unref (username);
00632     g_variant_unref (result);
00633 
00634     return session;
00635 }
00636 
00637 static void
00638 display_manager_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
00639 {
00640     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
00641 
00642     if (strcmp (signal_name, "SessionAdded") == 0)
00643     {
00644         if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
00645         {
00646             gchar *path;
00647             Session *session;
00648             LightDMUser *user = NULL;
00649 
00650             g_variant_get (parameters, "(&o)", &path);
00651             session = load_session (user_list, path);
00652             if (session)
00653                 user = get_user_by_name (user_list, session->username);
00654             if (user)
00655                 g_signal_emit (user, user_signals[CHANGED], 0);
00656         }
00657     }
00658     else if (strcmp (signal_name, "SessionRemoved") == 0)
00659     {
00660         if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
00661         {
00662             gchar *path;
00663             GList *link;
00664 
00665             g_variant_get (parameters, "(&o)", &path);
00666 
00667             for (link = priv->sessions; link; link = link->next)
00668             {
00669                 Session *session = link->data;
00670                 if (strcmp (session->path, path) == 0)
00671                 {
00672                     LightDMUser *user;
00673 
00674                     g_debug ("Session %s removed", path);
00675                     priv->sessions = g_list_remove_link (priv->sessions, link);
00676                     user = get_user_by_name (user_list, session->username);
00677                     if (user)
00678                         g_signal_emit (user, user_signals[CHANGED], 0);
00679                     g_object_unref (session);
00680                     break;
00681                 }
00682             }
00683         }
00684     }
00685 }
00686 
00687 static void
00688 update_users (LightDMUserList *user_list)
00689 {
00690     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
00691     GError *error = NULL;
00692 
00693     if (priv->have_users)
00694         return;
00695     priv->have_users = TRUE;
00696 
00697     priv->accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
00698                                                                   G_DBUS_PROXY_FLAGS_NONE,
00699                                                                   NULL,
00700                                                                   "org.freedesktop.Accounts",
00701                                                                   "/org/freedesktop/Accounts",
00702                                                                   "org.freedesktop.Accounts",
00703                                                                   NULL,
00704                                                                   &error);
00705     if (error)
00706         g_warning ("Error contacting org.freedesktop.Accounts: %s", error->message);
00707     g_clear_error (&error);
00708 
00709     /* Check if the service exists */
00710     if (priv->accounts_service_proxy)
00711     {
00712         gchar *name;
00713 
00714         name = g_dbus_proxy_get_name_owner (priv->accounts_service_proxy);
00715         if (!name)
00716         {
00717             g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file");
00718             g_object_unref (priv->accounts_service_proxy);
00719             priv->accounts_service_proxy = NULL;
00720         }
00721         g_free (name);
00722     }
00723 
00724     if (priv->accounts_service_proxy)
00725     {
00726         GVariant *result;
00727 
00728         g_signal_connect (priv->accounts_service_proxy, "g-signal", G_CALLBACK (user_accounts_signal_cb), user_list);
00729 
00730         result = g_dbus_proxy_call_sync (priv->accounts_service_proxy,
00731                                          "ListCachedUsers",
00732                                          g_variant_new ("()"),
00733                                          G_DBUS_CALL_FLAGS_NONE,
00734                                          -1,
00735                                          NULL,
00736                                          &error);
00737         if (error)
00738             g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
00739         g_clear_error (&error);
00740         if (!result)
00741             return;
00742 
00743         if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(ao)")))
00744         {
00745             GVariantIter *iter;
00746             const gchar *path;
00747 
00748             g_debug ("Loading users from org.freedesktop.Accounts");
00749             g_variant_get (result, "(ao)", &iter);
00750             while (g_variant_iter_loop (iter, "&o", &path))
00751             {
00752                 UserAccountObject *object;
00753 
00754                 g_debug ("Loading user %s", path);
00755 
00756                 object = user_account_object_new (user_list, path);
00757                 if (object && update_user (object))
00758                 {
00759                     priv->user_account_objects = g_list_append (priv->user_account_objects, object);
00760                     priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
00761                     g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
00762                 }
00763                 else
00764                     user_account_object_free (object);
00765             }
00766             g_variant_iter_free (iter);
00767         }
00768         else
00769             g_warning ("Unexpected type from ListCachedUsers: %s", g_variant_get_type_string (result));
00770 
00771         g_variant_unref (result);
00772     }
00773     else
00774     {
00775         GFile *passwd_file;
00776 
00777         load_passwd_file (user_list, FALSE);
00778 
00779         /* Watch for changes to user list */
00780 
00781         passwd_file = g_file_new_for_path (PASSWD_FILE);
00782         priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
00783         g_object_unref (passwd_file);
00784         if (error)
00785             g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
00786         else
00787             g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
00788         g_clear_error (&error);
00789     }
00790 
00791     priv->display_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
00792                                                                  G_DBUS_PROXY_FLAGS_NONE,
00793                                                                  NULL,
00794                                                                  "org.freedesktop.DisplayManager",
00795                                                                  "/org/freedesktop/DisplayManager",
00796                                                                  "org.freedesktop.DisplayManager",
00797                                                                  NULL,
00798                                                                  &error);
00799     if (error)
00800         g_warning ("Error contacting org.freedesktop.DisplayManager: %s", error->message);
00801     g_clear_error (&error);
00802 
00803     if (priv->display_manager_proxy)
00804     {
00805         GVariant *result;
00806 
00807         g_signal_connect (priv->display_manager_proxy, "g-signal", G_CALLBACK (display_manager_signal_cb), user_list);
00808 
00809         result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
00810                                               "org.freedesktop.DisplayManager",
00811                                               "/org/freedesktop/DisplayManager",
00812                                               "org.freedesktop.DBus.Properties",
00813                                               "Get",
00814                                               g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
00815                                               G_VARIANT_TYPE ("(v)"),
00816                                               G_DBUS_CALL_FLAGS_NONE,
00817                                               -1,
00818                                               NULL,
00819                                               &error);
00820         if (error)
00821             g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
00822         g_clear_error (&error);
00823         if (!result)
00824             return;
00825 
00826         if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
00827         {
00828             GVariant *value;
00829             GVariantIter *iter;
00830             const gchar *path;
00831 
00832             g_variant_get (result, "(v)", &value);
00833 
00834             g_debug ("Loading sessions from org.freedesktop.DisplayManager");
00835             g_variant_get (value, "ao", &iter);
00836             while (g_variant_iter_loop (iter, "&o", &path))
00837                 load_session (user_list, path);
00838             g_variant_iter_free (iter);
00839 
00840             g_variant_unref (value);
00841         }
00842         else
00843             g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
00844 
00845         g_variant_unref (result);
00846     }
00847 }
00848 
00855 gint
00856 lightdm_user_list_get_length (LightDMUserList *user_list)
00857 {
00858     g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
00859     update_users (user_list);
00860     return g_list_length (GET_LIST_PRIVATE (user_list)->users);
00861 }
00862 
00872 GList *
00873 lightdm_user_list_get_users (LightDMUserList *user_list)
00874 {
00875     g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
00876     update_users (user_list);
00877     return GET_LIST_PRIVATE (user_list)->users;
00878 }
00879 
00889 LightDMUser *
00890 lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
00891 {
00892     g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
00893     g_return_val_if_fail (username != NULL, NULL);
00894 
00895     update_users (user_list);
00896 
00897     return get_user_by_name (user_list, username);
00898 }
00899 
00900 static void
00901 lightdm_user_list_init (LightDMUserList *user_list)
00902 {
00903 }
00904 
00905 static void
00906 lightdm_user_list_set_property (GObject    *object,
00907                                 guint       prop_id,
00908                                 const GValue *value,
00909                                 GParamSpec *pspec)
00910 {
00911     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00912 }
00913 
00914 static void
00915 lightdm_user_list_get_property (GObject    *object,
00916                                 guint       prop_id,
00917                                 GValue     *value,
00918                                 GParamSpec *pspec)
00919 {
00920     LightDMUserList *self;
00921 
00922     self = LIGHTDM_USER_LIST (object);
00923 
00924     switch (prop_id)
00925     {
00926     case LIST_PROP_NUM_USERS:
00927         g_value_set_int (value, lightdm_user_list_get_length (self));
00928         break;
00929     default:
00930         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00931         break;
00932     }
00933 }
00934 
00935 static void
00936 lightdm_user_list_finalize (GObject *object)
00937 {
00938     LightDMUserList *self = LIGHTDM_USER_LIST (object);
00939     LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
00940 
00941     if (priv->accounts_service_proxy)
00942         g_object_unref (priv->accounts_service_proxy);
00943     g_list_free_full (priv->user_account_objects, (GDestroyNotify) user_account_object_free);
00944     if (priv->passwd_monitor)
00945         g_object_unref (priv->passwd_monitor);
00946     g_list_free_full (priv->users, g_object_unref);
00947     g_list_free_full (priv->sessions, g_object_unref);
00948 
00949     G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
00950 }
00951 
00952 static void
00953 lightdm_user_list_class_init (LightDMUserListClass *klass)
00954 {
00955     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00956 
00957     g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
00958 
00959     object_class->set_property = lightdm_user_list_set_property;
00960     object_class->get_property = lightdm_user_list_get_property;
00961     object_class->finalize = lightdm_user_list_finalize;
00962 
00963     g_object_class_install_property (object_class,
00964                                      LIST_PROP_NUM_USERS,
00965                                      g_param_spec_int ("num-users",
00966                                                        "num-users",
00967                                                        "Number of login users",
00968                                                        0, G_MAXINT, 0,
00969                                                        G_PARAM_READABLE));
00977     list_signals[USER_ADDED] =
00978         g_signal_new ("user-added",
00979                       G_TYPE_FROM_CLASS (klass),
00980                       G_SIGNAL_RUN_LAST,
00981                       G_STRUCT_OFFSET (LightDMUserListClass, user_added),
00982                       NULL, NULL,
00983                       g_cclosure_marshal_VOID__OBJECT,
00984                       G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
00985 
00993     list_signals[USER_CHANGED] =
00994         g_signal_new ("user-changed",
00995                       G_TYPE_FROM_CLASS (klass),
00996                       G_SIGNAL_RUN_LAST,
00997                       G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
00998                       NULL, NULL,
00999                       g_cclosure_marshal_VOID__OBJECT,
01000                       G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
01001 
01009     list_signals[USER_REMOVED] =
01010         g_signal_new ("user-removed",
01011                       G_TYPE_FROM_CLASS (klass),
01012                       G_SIGNAL_RUN_LAST,
01013                       G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
01014                       NULL, NULL,
01015                       g_cclosure_marshal_VOID__OBJECT,
01016                       G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
01017 }
01018 
01027 const gchar *
01028 lightdm_user_get_name (LightDMUser *user)
01029 {
01030     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01031     return GET_USER_PRIVATE (user)->name;
01032 }
01033 
01042 const gchar *
01043 lightdm_user_get_real_name (LightDMUser *user)
01044 {
01045     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01046     return GET_USER_PRIVATE (user)->real_name;
01047 }
01048 
01057 const gchar *
01058 lightdm_user_get_display_name (LightDMUser *user)
01059 {
01060     LightDMUserPrivate *priv;
01061 
01062     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01063 
01064     priv = GET_USER_PRIVATE (user);
01065     if (strcmp (priv->real_name, ""))
01066         return priv->real_name;
01067     else
01068         return priv->name;
01069 }
01070 
01079 const gchar *
01080 lightdm_user_get_home_directory (LightDMUser *user)
01081 {
01082     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01083     return GET_USER_PRIVATE (user)->home_directory;
01084 }
01085 
01094 const gchar *
01095 lightdm_user_get_image (LightDMUser *user)
01096 {
01097     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01098     return GET_USER_PRIVATE (user)->image;
01099 }
01100 
01109 const gchar *
01110 lightdm_user_get_background (LightDMUser *user)
01111 {
01112     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01113     return GET_USER_PRIVATE (user)->background;
01114 }
01115 
01116 static void
01117 load_dmrc (LightDMUser *user)
01118 {
01119     LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
01120     gchar *path;
01121     //gboolean have_dmrc;
01122 
01123     if (!priv->dmrc_file)
01124         priv->dmrc_file = g_key_file_new ();
01125 
01126     /* Load from the user directory */  
01127     path = g_build_filename (priv->home_directory, ".dmrc", NULL);
01128     /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
01129     g_free (path);
01130 
01131     /* If no ~/.dmrc, then load from the cache */
01132     // FIXME
01133 
01134     // FIXME: Watch for changes
01135 
01136     /* The Language field is actually a locale, strip the codeset off it to get the language */
01137     if (priv->language)
01138         g_free (priv->language);
01139     priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
01140     if (priv->language)
01141     {
01142         gchar *codeset = strchr (priv->language, '.');
01143         if (codeset)
01144             *codeset = '\0';
01145     }
01146 
01147     if (priv->layouts)
01148     {
01149         g_strfreev (priv->layouts);
01150         priv->layouts = NULL;
01151     }
01152     if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
01153     {
01154         priv->layouts = g_malloc (sizeof (gchar *) * 2);
01155         priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
01156         priv->layouts[1] = NULL;
01157     }
01158 
01159     if (priv->session)
01160         g_free (priv->session);
01161     priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
01162 }
01163 
01164 static GVariant *
01165 get_property (GDBusProxy *proxy, const gchar *property)
01166 {
01167     GVariant *answer;
01168 
01169     if (!proxy)
01170         return NULL;
01171 
01172     answer = g_dbus_proxy_get_cached_property (proxy, property);
01173 
01174     if (!answer)
01175     {
01176         g_warning ("Could not get accounts property %s", property);
01177         return NULL;
01178     }
01179 
01180     return answer;
01181 }
01182 
01183 static gboolean
01184 get_boolean_property (GDBusProxy *proxy, const gchar *property)
01185 {
01186     GVariant *answer;
01187     gboolean rv;
01188 
01189     answer = get_property (proxy, property);
01190     if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_BOOLEAN))
01191     {
01192         g_warning ("Unexpected accounts property type for %s: %s",
01193                    property, g_variant_get_type_string (answer));
01194         g_variant_unref (answer);
01195         return FALSE;
01196     }
01197 
01198     rv = g_variant_get_boolean (answer);
01199     g_variant_unref (answer);
01200 
01201     return rv;
01202 }
01203 
01204 static gchar *
01205 get_string_property (GDBusProxy *proxy, const gchar *property)
01206 {
01207     GVariant *answer;
01208     gchar *rv;
01209   
01210     answer = get_property (proxy, property);
01211     if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_STRING))
01212     {
01213         g_warning ("Unexpected accounts property type for %s: %s",
01214                    property, g_variant_get_type_string (answer));
01215         g_variant_unref (answer);
01216         return NULL;
01217     }
01218 
01219     rv = g_strdup (g_variant_get_string (answer, NULL));
01220     if (strcmp (rv, "") == 0)
01221     {
01222         g_free (rv);
01223         rv = NULL;
01224     }
01225     g_variant_unref (answer);
01226 
01227     return rv;
01228 }
01229 
01230 static gchar **
01231 get_string_array_property (GDBusProxy *proxy, const gchar *property)
01232 {
01233     GVariant *answer;
01234     gchar **rv;
01235 
01236     if (!proxy)
01237         return NULL;
01238 
01239     answer = g_dbus_proxy_get_cached_property (proxy, property);
01240 
01241     if (!answer)
01242     {
01243         g_warning ("Could not get accounts property %s", property);
01244         return NULL;
01245     }
01246 
01247     if (!g_variant_is_of_type (answer, G_VARIANT_TYPE ("as")))
01248     {
01249         g_warning ("Unexpected accounts property type for %s: %s",
01250                    property, g_variant_get_type_string (answer));
01251         g_variant_unref (answer);
01252         return NULL;
01253     }
01254 
01255     rv = g_variant_dup_strv (answer, NULL);
01256 
01257     g_variant_unref (answer);
01258     return rv;
01259 }
01260 
01261 static gboolean
01262 load_accounts_service (LightDMUser *user)
01263 {
01264     LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
01265     LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
01266     UserAccountObject *account = NULL;
01267     GList *iter;
01268     gchar **value;
01269 
01270     /* First, find AccountObject proxy */
01271     for (iter = list_priv->user_account_objects; iter; iter = iter->next)
01272     {
01273         UserAccountObject *a = iter->data;
01274         if (a->user == user)
01275         {
01276             account = a;
01277             break;
01278         }
01279     }
01280     if (!account)
01281         return FALSE;
01282 
01283     /* We have proxy, let's grab some properties */
01284     if (priv->language)
01285         g_free (priv->language);
01286     priv->language = get_string_property (account->proxy, "Language");
01287     if (priv->session)
01288         g_free (priv->session);
01289     priv->session = get_string_property (account->proxy, "XSession");
01290 
01291     value = get_string_array_property (account->proxy, "XKeyboardLayouts");
01292     if (value)
01293     {
01294         if (value[0])
01295         {
01296             g_strfreev (priv->layouts);
01297             priv->layouts = value;
01298         }
01299         else
01300             g_strfreev (value);
01301     }
01302 
01303     priv->has_messages = get_boolean_property (account->proxy, "XHasMessages");
01304 
01305     return TRUE;
01306 }
01307 
01308 /* Loads language/layout/session info for user */
01309 static void
01310 load_user_values (LightDMUser *user)
01311 {
01312     LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
01313 
01314     load_dmrc (user);
01315     load_accounts_service (user); // overrides dmrc values
01316 
01317     /* Ensure a few guarantees */
01318     if (priv->layouts == NULL)
01319     {
01320         priv->layouts = g_malloc (sizeof (gchar *) * 1);
01321         priv->layouts[0] = NULL;
01322     }
01323 }
01324 
01333 const gchar *
01334 lightdm_user_get_language (LightDMUser *user)
01335 {
01336     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01337     load_user_values (user);
01338     return GET_USER_PRIVATE (user)->language;
01339 }
01340 
01349 const gchar *
01350 lightdm_user_get_layout (LightDMUser *user)
01351 {
01352     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01353     load_user_values (user);
01354     return GET_USER_PRIVATE (user)->layouts[0];
01355 }
01356 
01365 const gchar * const *
01366 lightdm_user_get_layouts (LightDMUser *user)
01367 {
01368     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01369     load_user_values (user);
01370     return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
01371 }
01372 
01381 const gchar *
01382 lightdm_user_get_session (LightDMUser *user)
01383 {
01384     g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
01385     load_user_values (user);
01386     return GET_USER_PRIVATE (user)->session; 
01387 }
01388 
01397 gboolean
01398 lightdm_user_get_logged_in (LightDMUser *user)
01399 {
01400     LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
01401     LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
01402     GList *link;
01403 
01404     g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
01405 
01406     for (link = list_priv->sessions; link; link = link->next)
01407     {
01408         Session *session = link->data;
01409         if (strcmp (session->username, priv->name) == 0)
01410             return TRUE;
01411     }
01412 
01413     return FALSE;
01414 }
01415 
01424 gboolean
01425 lightdm_user_get_has_messages (LightDMUser *user)
01426 {
01427     g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
01428     load_user_values (user);
01429     return GET_USER_PRIVATE (user)->has_messages;
01430 }
01431 
01432 static void
01433 lightdm_user_init (LightDMUser *user)
01434 {
01435 }
01436 
01437 static void
01438 lightdm_user_set_property (GObject    *object,
01439                            guint       prop_id,
01440                            const GValue *value,
01441                            GParamSpec *pspec)
01442 {
01443     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01444 }
01445 
01446 static void
01447 lightdm_user_get_property (GObject    *object,
01448                            guint       prop_id,
01449                            GValue     *value,
01450                            GParamSpec *pspec)
01451 {
01452     LightDMUser *self;
01453 
01454     self = LIGHTDM_USER (object);
01455 
01456     switch (prop_id)
01457     {
01458     case USER_PROP_NAME:
01459         g_value_set_string (value, lightdm_user_get_name (self));
01460         break;
01461     case USER_PROP_REAL_NAME:
01462         g_value_set_string (value, lightdm_user_get_real_name (self));
01463         break;
01464     case USER_PROP_DISPLAY_NAME:
01465         g_value_set_string (value, lightdm_user_get_display_name (self));
01466         break;
01467     case USER_PROP_HOME_DIRECTORY:
01468         g_value_set_string (value, lightdm_user_get_home_directory (self));
01469         break;
01470     case USER_PROP_IMAGE:
01471         g_value_set_string (value, lightdm_user_get_image (self));
01472         break;
01473     case USER_PROP_BACKGROUND:
01474         g_value_set_string (value, lightdm_user_get_background (self));
01475         break;
01476     case USER_PROP_LANGUAGE:
01477         g_value_set_string (value, lightdm_user_get_language (self));
01478         break;
01479     case USER_PROP_LAYOUT:
01480         g_value_set_string (value, lightdm_user_get_layout (self));
01481         break;
01482     case USER_PROP_LAYOUTS:
01483         g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self)));
01484         break;
01485     case USER_PROP_SESSION:
01486         g_value_set_string (value, lightdm_user_get_session (self));
01487         break;
01488     case USER_PROP_LOGGED_IN:
01489         g_value_set_boolean (value, lightdm_user_get_logged_in (self));
01490         break;
01491     case USER_PROP_HAS_MESSAGES:
01492         g_value_set_boolean (value, lightdm_user_get_has_messages (self));
01493         break;
01494     default:
01495         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
01496         break;
01497     }
01498 }
01499 
01500 static void
01501 lightdm_user_finalize (GObject *object)
01502 {
01503     LightDMUser *self = LIGHTDM_USER (object);
01504     LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
01505 
01506     g_free (priv->name);
01507     g_free (priv->real_name);
01508     g_free (priv->home_directory);
01509     g_free (priv->image);
01510     g_free (priv->background);
01511     g_strfreev (priv->layouts);
01512     if (priv->dmrc_file)
01513         g_key_file_free (priv->dmrc_file);
01514 }
01515 
01516 static void
01517 lightdm_user_class_init (LightDMUserClass *klass)
01518 {
01519     GObjectClass *object_class = G_OBJECT_CLASS (klass);
01520   
01521     g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
01522 
01523     object_class->set_property = lightdm_user_set_property;
01524     object_class->get_property = lightdm_user_get_property;
01525     object_class->finalize = lightdm_user_finalize;
01526 
01527     g_object_class_install_property (object_class,
01528                                      USER_PROP_NAME,
01529                                      g_param_spec_string ("name",
01530                                                           "name",
01531                                                           "Username",
01532                                                           NULL,
01533                                                           G_PARAM_READWRITE));
01534     g_object_class_install_property (object_class,
01535                                      USER_PROP_REAL_NAME,
01536                                      g_param_spec_string ("real-name",
01537                                                           "real-name",
01538                                                           "Users real name",
01539                                                           NULL,
01540                                                           G_PARAM_READWRITE));
01541     g_object_class_install_property (object_class,
01542                                      USER_PROP_DISPLAY_NAME,
01543                                      g_param_spec_string ("display-name",
01544                                                           "display-name",
01545                                                           "Users display name",
01546                                                           NULL,
01547                                                           G_PARAM_READABLE));
01548     g_object_class_install_property (object_class,
01549                                      USER_PROP_HOME_DIRECTORY,
01550                                      g_param_spec_string ("home-directory",
01551                                                           "home-directory",
01552                                                           "Home directory",
01553                                                           NULL,
01554                                                           G_PARAM_READWRITE));
01555     g_object_class_install_property (object_class,
01556                                      USER_PROP_IMAGE,
01557                                      g_param_spec_string ("image",
01558                                                           "image",
01559                                                           "Avatar image",
01560                                                           NULL,
01561                                                           G_PARAM_READWRITE));
01562     g_object_class_install_property (object_class,
01563                                      USER_PROP_BACKGROUND,
01564                                      g_param_spec_string ("background",
01565                                                           "background",
01566                                                           "User background",
01567                                                           NULL,
01568                                                           G_PARAM_READWRITE));
01569     g_object_class_install_property (object_class,
01570                                      USER_PROP_LANGUAGE,
01571                                      g_param_spec_string ("language",
01572                                                          "language",
01573                                                          "Language used by this user",
01574                                                          NULL,
01575                                                          G_PARAM_READABLE));
01576     g_object_class_install_property (object_class,
01577                                      USER_PROP_LAYOUT,
01578                                      g_param_spec_string ("layout",
01579                                                           "layout",
01580                                                           "Keyboard layout used by this user",
01581                                                           NULL,
01582                                                           G_PARAM_READABLE));
01583     g_object_class_install_property (object_class,
01584                                      USER_PROP_LAYOUTS,
01585                                      g_param_spec_boxed ("layouts",
01586                                                          "layouts",
01587                                                          "Keyboard layouts used by this user",
01588                                                          G_TYPE_STRV,
01589                                                          G_PARAM_READABLE));
01590     g_object_class_install_property (object_class,
01591                                      USER_PROP_SESSION,
01592                                      g_param_spec_string ("session",
01593                                                           "session",
01594                                                           "Session used by this user",
01595                                                           NULL,
01596                                                           G_PARAM_READABLE));
01597     g_object_class_install_property (object_class,
01598                                      USER_PROP_LOGGED_IN,
01599                                      g_param_spec_boolean ("logged-in",
01600                                                            "logged-in",
01601                                                            "TRUE if the user is currently in a session",
01602                                                            FALSE,
01603                                                            G_PARAM_READWRITE));
01604     g_object_class_install_property (object_class,
01605                                      USER_PROP_LOGGED_IN,
01606                                      g_param_spec_boolean ("has-messages",
01607                                                            "has-messages",
01608                                                            "TRUE if the user is has waiting messages",
01609                                                            FALSE,
01610                                                            G_PARAM_READWRITE));
01611 
01618     user_signals[CHANGED] =
01619         g_signal_new ("changed",
01620                       G_TYPE_FROM_CLASS (klass),
01621                       G_SIGNAL_RUN_LAST,
01622                       G_STRUCT_OFFSET (LightDMUserClass, changed),
01623                       NULL, NULL,
01624                       g_cclosure_marshal_VOID__VOID,
01625                       G_TYPE_NONE, 0);
01626 }
01627 
01628 static void
01629 session_init (Session *session)
01630 {
01631 }
01632 
01633 static void
01634 session_finalize (GObject *object)
01635 {
01636     Session *self = SESSION (object);
01637 
01638     g_free (self->path);
01639     g_free (self->username);
01640 }
01641 
01642 static void
01643 session_class_init (SessionClass *klass)
01644 {
01645     GObjectClass *object_class = G_OBJECT_CLASS (klass);
01646     object_class->finalize = session_finalize;
01647 }