Merge lp:~mterry/lightdm/refactor-accounts into lp:lightdm

Proposed by Michael Terry
Status: Merged
Approved by: Robert Ancell
Approved revision: 1881
Merged at revision: 1892
Proposed branch: lp:~mterry/lightdm/refactor-accounts
Merge into: lp:lightdm
Diff against target: 3540 lines (+1558/-785)
20 files modified
Makefile.am (+1/-1)
common/Makefile.am (+23/-0)
common/dmrc.c (+20/-43)
common/dmrc.h (+3/-2)
common/privileges.c (+9/-9)
common/privileges.h (+2/-2)
common/user-list.c (+580/-351)
common/user-list.h (+111/-0)
configure.ac (+1/-0)
debian/patches/01_transition_ubuntu2d_ubuntu_desktop.patch (+6/-6)
liblightdm-gobject/Makefile.am (+4/-1)
liblightdm-gobject/session.c (+5/-6)
liblightdm-gobject/user.c (+736/-0)
src/Makefile.am (+2/-6)
src/accounts.c (+27/-347)
src/accounts.h (+0/-4)
src/lightdm.c (+8/-3)
src/session-child.c (+2/-2)
tests/src/test-gobject-greeter.c (+3/-2)
tests/src/test-runner.c (+15/-0)
To merge this branch: bzr merge lp:~mterry/lightdm/refactor-accounts
Reviewer Review Type Date Requested Status
Robert Ancell Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+205422@code.launchpad.net

Commit message

Refactor LightDMUser and User classes to use the same code internally

Description of the change

I was starting work on the shared user data directories feature (bug 1263418), when I realized I needed to do a bit of refactoring. I wanted to add knowledge to the lightdm daemon of the list of users on the system and to pay attention to user adds and removals.

But there was already a bit of overlap between liblightdm-gobject/user.c and src/accounts.c. Adding the above user-list info to src/accounts.c would make them so similar that it would be criminal to not try to consolidate them a bit.

So I've added a common/ directory with a static libcommon.a, used by liblightdm-gobject and the lightdm daemon. I realize "common" is a dumb name. But since LightDMUser and User were already claimed by other internal objects, I didn't feel like being overly clever with the naming. So CommonUser it was. I will change the namespace to whatever you like.

I've switched LightDMUser and User to internally use CommonUser without changing their own APIs. That was necessary for LightDMUser and a matter of convenience for User. A few small classes have moved from src/ to common/ to support CommonUser (I didn't bother Common-namespacing those small classes since they didn't conflict with other code).

Moving the Configuration class into common/ let me re-use it in liblightdm-gobject, where the same job was being done manually (not much of a savings in my branch right now, but that section of code should be changed to look in lightdm.conf.d as well as just lightdm.conf, and using Configuration will make that future FIXME much easier to solve).

This branch means that the lightdm daemon relies on AccountsService a bit more than it used to (its previous primary lookup for user info was passwd, whereas this branch now prefers AS with a fallback to passwd). So I had to build out a few pieces of the test framework to emulate AS a bit better.

This branch may be overkill to land before my shared data branch (as it means the lightdm daemon is monitoring the user list needlessly). But it doesn't hurt to start reviewing it. I've also changed the Session monitoring to be started lazily; only if the API consumer asks whether a user is logged in do we start monitoring (i.e. the lightdm daemon won't be monitoring Sessions needlessly).

To post a comment you must log in.
lp:~mterry/lightdm/refactor-accounts updated
1879. By Michael Terry

Merge from trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Ancell (robert-ancell) wrote :

Looks good.

The amount of shared code regarding users has been something that has felt inefficient so this approach seems good.
I've also had a slight concern that the daemon relying too heavily on accounts service might be a reliability issue, but I guess we just need to see how that goes. Also wondering how much accounts service would lean towards reporting "real" user accounts and not the system accounts we require.

Obviously the patch is enormous, but is mostly just moving / renaming so I'll rely heavily on the regression tests picking out any mistakes.

Also worth considering is if LightDM moves early into the boot when A-S is not available / not applicable what the daemon should do (switch passwd to a-s part after start? Restart from light to full mode?). This can be tackled if/when we cross that bridge though.

I'm not sure

I'll review more closely when I get back from travelling.

Revision history for this message
Michael Terry (mterry) wrote :

Regarding your concern about AS not reporting the system users we need... the current daemon code actually only ever calls common_user_list_get_user_by_name(), to which I've added the fallback to look up system users.

So common_user_list_get_users() returns a list of "normal" users. But if you ask for a specific user using by_name() (as the daemon has need to every now and then), it will first look in that normal list but if it can't find it, grab a system user from passwd.

lp:~mterry/lightdm/refactor-accounts updated
1880. By Michael Terry

Add better cleanup as lightdm daemon closes

1881. By Michael Terry

Update patches

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mterry/lightdm/refactor-accounts updated
1882. By Michael Terry

Add shared data manager and test

Revision history for this message
Robert Ancell (robert-ancell) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile.am'
2--- Makefile.am 2013-11-07 07:54:55 +0000
3+++ Makefile.am 2014-02-08 22:36:44 +0000
4@@ -1,4 +1,4 @@
5-SUBDIRS =
6+SUBDIRS = common
7 if COMPILE_LIBLIGHTDM_GOBJECT
8 SUBDIRS += liblightdm-gobject
9 endif
10
11=== added directory 'common'
12=== added file 'common/Makefile.am'
13--- common/Makefile.am 1970-01-01 00:00:00 +0000
14+++ common/Makefile.am 2014-02-08 22:36:44 +0000
15@@ -0,0 +1,23 @@
16+# -*- Mode: Automake; indent-tabs-mode: t; tab-width: 4 -*-
17+
18+noinst_LTLIBRARIES = libcommon.la
19+
20+libcommon_la_SOURCES = \
21+ configuration.c \
22+ configuration.h \
23+ dmrc.c \
24+ dmrc.h \
25+ privileges.c \
26+ privileges.h \
27+ user-list.c \
28+ user-list.h
29+
30+libcommon_la_CFLAGS = \
31+ $(WARN_CFLAGS) \
32+ $(GLIB_CFLAGS)
33+
34+libcommon_la_LIBADD = \
35+ $(GLIB_LDFLAGS)
36+
37+DISTCLEANFILES = \
38+ Makefile.in
39
40=== renamed file 'src/configuration.c' => 'common/configuration.c'
41=== renamed file 'src/configuration.h' => 'common/configuration.h'
42=== renamed file 'src/dmrc.c' => 'common/dmrc.c'
43--- src/dmrc.c 2013-06-13 03:17:43 +0000
44+++ common/dmrc.c 2014-02-08 22:36:44 +0000
45@@ -15,34 +15,26 @@
46
47 #include "dmrc.h"
48 #include "configuration.h"
49-#include "accounts.h"
50 #include "privileges.h"
51+#include "user-list.h"
52
53 GKeyFile *
54-dmrc_load (const gchar *username)
55+dmrc_load (CommonUser *user)
56 {
57- User *user;
58 GKeyFile *dmrc_file;
59 gchar *path;
60 gboolean have_dmrc, drop_privileges;
61
62 dmrc_file = g_key_file_new ();
63
64- user = accounts_get_user_by_name (username);
65- if (!user)
66- {
67- g_warning ("Cannot load .dmrc file, unable to get information on user %s", username);
68- return dmrc_file;
69- }
70-
71 /* Load from the user directory, if this fails (e.g. the user directory
72 * is not yet mounted) then load from the cache */
73- path = g_build_filename (user_get_home_directory (user), ".dmrc", NULL);
74+ path = g_build_filename (common_user_get_home_directory (user), ".dmrc", NULL);
75
76 /* Guard against privilege escalation through symlinks, etc. */
77 drop_privileges = geteuid () == 0;
78 if (drop_privileges)
79- privileges_drop (user);
80+ privileges_drop (common_user_get_uid (user), common_user_get_gid (user));
81 have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
82 if (drop_privileges)
83 privileges_reclaim ();
84@@ -53,7 +45,7 @@
85 {
86 gchar *filename, *cache_dir;
87
88- filename = g_strdup_printf ("%s.dmrc", user_get_name (user));
89+ filename = g_strdup_printf ("%s.dmrc", common_user_get_name (user));
90 cache_dir = config_get_string (config_get_instance (), "LightDM", "cache-directory");
91 path = g_build_filename (cache_dir, "dmrc", filename, NULL);
92 g_free (filename);
93@@ -63,46 +55,32 @@
94 g_free (path);
95 }
96
97- g_object_unref (user);
98-
99 return dmrc_file;
100 }
101
102 void
103-dmrc_save (GKeyFile *dmrc_file, const gchar *username)
104+dmrc_save (GKeyFile *dmrc_file, CommonUser *user)
105 {
106- User *user;
107 gchar *path, *filename, *cache_dir, *dmrc_cache_dir;
108 gchar *data;
109 gsize length;
110-
111- user = accounts_get_user_by_name (username);
112- if (!user)
113- {
114- g_warning ("Not saving DMRC file - unable to get information on user %s", username);
115- return;
116- }
117+ gboolean drop_privileges;
118
119 data = g_key_file_to_data (dmrc_file, &length, NULL);
120
121 /* Update the users .dmrc */
122- if (user)
123- {
124- gboolean drop_privileges;
125-
126- path = g_build_filename (user_get_home_directory (user), ".dmrc", NULL);
127-
128- /* Guard against privilege escalation through symlinks, etc. */
129- drop_privileges = geteuid () == 0;
130- if (drop_privileges)
131- privileges_drop (user);
132- g_debug ("Writing %s", path);
133- g_file_set_contents (path, data, length, NULL);
134- if (drop_privileges)
135- privileges_reclaim ();
136-
137- g_free (path);
138- }
139+ path = g_build_filename (common_user_get_home_directory (user), ".dmrc", NULL);
140+
141+ /* Guard against privilege escalation through symlinks, etc. */
142+ drop_privileges = geteuid () == 0;
143+ if (drop_privileges)
144+ privileges_drop (common_user_get_uid (user), common_user_get_gid (user));
145+ g_debug ("Writing %s", path);
146+ g_file_set_contents (path, data, length, NULL);
147+ if (drop_privileges)
148+ privileges_reclaim ();
149+
150+ g_free (path);
151
152 /* Update the .dmrc cache */
153 cache_dir = config_get_string (config_get_instance (), "LightDM", "cache-directory");
154@@ -110,12 +88,11 @@
155 if (g_mkdir_with_parents (dmrc_cache_dir, 0700) < 0)
156 g_warning ("Failed to make DMRC cache directory %s: %s", dmrc_cache_dir, strerror (errno));
157
158- filename = g_strdup_printf ("%s.dmrc", username);
159+ filename = g_strdup_printf ("%s.dmrc", common_user_get_name (user));
160 path = g_build_filename (dmrc_cache_dir, filename, NULL);
161 g_file_set_contents (path, data, length, NULL);
162
163 g_free (dmrc_cache_dir);
164 g_free (path);
165 g_free (filename);
166- g_object_unref (user);
167 }
168
169=== renamed file 'src/dmrc.h' => 'common/dmrc.h'
170--- src/dmrc.h 2013-04-23 03:07:03 +0000
171+++ common/dmrc.h 2014-02-08 22:36:44 +0000
172@@ -13,12 +13,13 @@
173 #define DMRC_H_
174
175 #include <glib.h>
176+#include "user-list.h"
177
178 G_BEGIN_DECLS
179
180-GKeyFile *dmrc_load (const gchar *username);
181+GKeyFile *dmrc_load (CommonUser *user);
182
183-void dmrc_save (GKeyFile *dmrc_file, const gchar *username);
184+void dmrc_save (GKeyFile *dmrc_file, CommonUser *user);
185
186 G_END_DECLS
187
188
189=== renamed file 'src/privileges.c' => 'common/privileges.c'
190--- src/privileges.c 2013-08-26 00:58:45 +0000
191+++ common/privileges.c 2014-02-08 22:36:44 +0000
192@@ -13,24 +13,24 @@
193 #define _GNU_SOURCE
194
195 #include <config.h>
196+#include <glib.h>
197+#include <unistd.h>
198 #include "privileges.h"
199
200 void
201-privileges_drop (User *user)
202+privileges_drop (uid_t uid, gid_t gid)
203 {
204- g_return_if_fail (user != NULL);
205-
206 #ifdef HAVE_SETRESGID
207- g_assert (setresgid (user_get_gid (user), user_get_gid (user), -1) == 0);
208+ g_assert (setresgid (gid, gid, -1) == 0);
209 #else
210- g_assert (setgid (user_get_gid (user)) == 0);
211- g_assert (setegid (user_get_gid (user)) == 0);
212+ g_assert (setgid (gid) == 0);
213+ g_assert (setegid (gid) == 0);
214 #endif
215 #ifdef HAVE_SETRESUID
216- g_assert (setresuid (user_get_uid (user), user_get_uid (user), -1) == 0);
217+ g_assert (setresuid (uid, uid, -1) == 0);
218 #else
219- g_assert (setuid (user_get_uid (user)) == 0);
220- g_assert (seteuid (user_get_uid (user)) == 0);
221+ g_assert (setuid (uid) == 0);
222+ g_assert (seteuid (uid) == 0);
223 #endif
224 }
225
226
227=== renamed file 'src/privileges.h' => 'common/privileges.h'
228--- src/privileges.h 2013-04-23 03:07:03 +0000
229+++ common/privileges.h 2014-02-08 22:36:44 +0000
230@@ -12,9 +12,9 @@
231 #ifndef PRIVILEGES_H_
232 #define PRIVILEGES_H_
233
234-#include "accounts.h"
235+#include <sys/types.h>
236
237-void privileges_drop (User *user);
238+void privileges_drop (uid_t uid, gid_t gid);
239
240 void privileges_reclaim (void);
241
242
243=== renamed file 'liblightdm-gobject/user.c' => 'common/user-list.c'
244--- liblightdm-gobject/user.c 2013-12-12 20:32:47 +0000
245+++ common/user-list.c 2014-02-08 22:36:44 +0000
246@@ -1,7 +1,9 @@
247 /* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
248 *
249 * Copyright (C) 2010 Robert Ancell.
250- * Author: Robert Ancell <robert.ancell@canonical.com>
251+ * Copyright (C) 2014 Canonical, Ltd.
252+ * Authors: Robert Ancell <robert.ancell@canonical.com>
253+ * Michael Terry <michael.terry@canonical.com>
254 *
255 * This library is free software; you can redistribute it and/or modify it under
256 * the terms of the GNU Lesser General Public License as published by the Free
257@@ -17,7 +19,8 @@
258 #include <pwd.h>
259 #include <gio/gio.h>
260
261-#include "lightdm/user.h"
262+#include "dmrc.h"
263+#include "user-list.h"
264
265 enum
266 {
267@@ -33,6 +36,7 @@
268 USER_PROP_REAL_NAME,
269 USER_PROP_DISPLAY_NAME,
270 USER_PROP_HOME_DIRECTORY,
271+ USER_PROP_SHELL,
272 USER_PROP_IMAGE,
273 USER_PROP_BACKGROUND,
274 USER_PROP_LANGUAGE,
275@@ -40,7 +44,9 @@
276 USER_PROP_LAYOUTS,
277 USER_PROP_SESSION,
278 USER_PROP_LOGGED_IN,
279- USER_PROP_HAS_MESSAGES
280+ USER_PROP_HAS_MESSAGES,
281+ USER_PROP_UID,
282+ USER_PROP_GID,
283 };
284
285 enum
286@@ -83,12 +89,12 @@
287
288 /* List of sessions */
289 GList *sessions;
290-} LightDMUserListPrivate;
291+} CommonUserListPrivate;
292
293 typedef struct
294 {
295 /* User list this user is part of */
296- LightDMUserList *user_list;
297+ CommonUserList *user_list;
298
299 /* TRUE if have loaded user properties */
300 gboolean loaded_values;
301@@ -96,9 +102,6 @@
302 /* Accounts service path */
303 gchar *path;
304
305- /* DMRC file */
306- GKeyFile *dmrc_file;
307-
308 /* Update signal from accounts service */
309 guint changed_signal;
310
311@@ -111,6 +114,9 @@
312 /* Home directory of user */
313 gchar *home_directory;
314
315+ /* Shell for user */
316+ gchar *shell;
317+
318 /* Image for user */
319 gchar *image;
320
321@@ -120,6 +126,12 @@
322 /* TRUE if this user has messages available */
323 gboolean has_messages;
324
325+ /* UID of user */
326+ guint64 uid;
327+
328+ /* GID of user */
329+ guint64 gid;
330+
331 /* User chosen language */
332 gchar *language;
333
334@@ -128,74 +140,82 @@
335
336 /* User default session */
337 gchar *session;
338-} LightDMUserPrivate;
339+} CommonUserPrivate;
340
341 typedef struct
342 {
343 GObject parent_instance;
344 gchar *path;
345 gchar *username;
346-} Session;
347+} CommonSession;
348
349 typedef struct
350 {
351 GObjectClass parent_class;
352-} SessionClass;
353-
354-G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
355-G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
356-#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
357-GType session_get_type (void);
358-G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
359-
360-#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
361-#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
362+} CommonSessionClass;
363+
364+G_DEFINE_TYPE (CommonUserList, common_user_list, G_TYPE_OBJECT);
365+G_DEFINE_TYPE (CommonUser, common_user, G_TYPE_OBJECT);
366+#define COMMON_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), common_session_get_type (), CommonSession))
367+GType common_session_get_type (void);
368+G_DEFINE_TYPE (CommonSession, common_session, G_TYPE_OBJECT);
369+
370+#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), COMMON_TYPE_USER_LIST, CommonUserListPrivate)
371+#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), COMMON_TYPE_USER, CommonUserPrivate)
372
373 #define PASSWD_FILE "/etc/passwd"
374 #define USER_CONFIG_FILE "/etc/lightdm/users.conf"
375
376-static LightDMUserList *singleton = NULL;
377+static CommonUserList *singleton = NULL;
378
379 /**
380- * lightdm_user_list_get_instance:
381+ * common_user_list_get_instance:
382 *
383 * Get the user list.
384 *
385- * Return value: (transfer none): the #LightDMUserList
386+ * Return value: (transfer none): the #CommonUserList
387 **/
388-LightDMUserList *
389-lightdm_user_list_get_instance (void)
390+CommonUserList *
391+common_user_list_get_instance (void)
392 {
393 if (!singleton)
394- singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
395+ singleton = g_object_new (COMMON_TYPE_USER_LIST, NULL);
396 return singleton;
397 }
398
399-static LightDMUser *
400-get_user_by_name (LightDMUserList *user_list, const gchar *username)
401-{
402- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
403+void
404+common_user_list_cleanup (void)
405+{
406+ if (singleton)
407+ g_object_unref (singleton);
408+ singleton = NULL;
409+}
410+
411+static CommonUser *
412+get_user_by_name (CommonUserList *user_list, const gchar *username)
413+{
414+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
415 GList *link;
416
417 for (link = priv->users; link; link = link->next)
418 {
419- LightDMUser *user = link->data;
420- if (g_strcmp0 (lightdm_user_get_name (user), username) == 0)
421+ CommonUser *user = link->data;
422+ if (g_strcmp0 (common_user_get_name (user), username) == 0)
423 return user;
424 }
425
426 return NULL;
427 }
428
429-static LightDMUser *
430-get_user_by_path (LightDMUserList *user_list, const gchar *path)
431+static CommonUser *
432+get_user_by_path (CommonUserList *user_list, const gchar *path)
433 {
434- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
435+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
436 GList *link;
437
438 for (link = priv->users; link; link = link->next)
439 {
440- LightDMUser *user = link->data;
441+ CommonUser *user = link->data;
442 if (g_strcmp0 (GET_USER_PRIVATE (user)->path, path) == 0)
443 return user;
444 }
445@@ -206,25 +226,28 @@
446 static gint
447 compare_user (gconstpointer a, gconstpointer b)
448 {
449- LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
450- return g_strcmp0 (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
451+ CommonUser *user_a = (CommonUser *) a, *user_b = (CommonUser *) b;
452+ return g_strcmp0 (common_user_get_display_name (user_a), common_user_get_display_name (user_b));
453 }
454
455 static gboolean
456-update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
457+update_passwd_user (CommonUser *user, const gchar *real_name, const gchar *home_directory, const gchar *shell, const gchar *image)
458 {
459- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
460+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
461
462 /* Skip if already set to this */
463- if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
464- g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
465- g_strcmp0 (lightdm_user_get_image (user), image) == 0)
466+ if (g_strcmp0 (common_user_get_real_name (user), real_name) == 0 &&
467+ g_strcmp0 (common_user_get_home_directory (user), home_directory) == 0 &&
468+ g_strcmp0 (common_user_get_shell (user), shell) == 0 &&
469+ g_strcmp0 (common_user_get_image (user), image) == 0)
470 return FALSE;
471
472 g_free (priv->real_name);
473 priv->real_name = g_strdup (real_name);
474 g_free (priv->home_directory);
475 priv->home_directory = g_strdup (home_directory);
476+ g_free (priv->shell);
477+ priv->shell = g_strdup (shell);
478 g_free (priv->image);
479 priv->image = g_strdup (image);
480
481@@ -232,15 +255,54 @@
482 }
483
484 static void
485-user_changed_cb (LightDMUser *user)
486+user_changed_cb (CommonUser *user)
487 {
488 g_signal_emit (GET_USER_PRIVATE (user)->user_list, list_signals[USER_CHANGED], 0, user);
489 }
490
491+static CommonUser *
492+make_passwd_user (CommonUserList *user_list, struct passwd *entry)
493+{
494+ CommonUser *user = g_object_new (COMMON_TYPE_USER, NULL);
495+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
496+ char **tokens;
497+ gchar *real_name, *image;
498+
499+ tokens = g_strsplit (entry->pw_gecos, ",", -1);
500+ if (tokens[0] != NULL && tokens[0][0] != '\0')
501+ real_name = g_strdup (tokens[0]);
502+ else
503+ real_name = g_strdup ("");
504+ g_strfreev (tokens);
505+
506+ image = g_build_filename (entry->pw_dir, ".face", NULL);
507+ if (!g_file_test (image, G_FILE_TEST_EXISTS))
508+ {
509+ g_free (image);
510+ image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
511+ if (!g_file_test (image, G_FILE_TEST_EXISTS))
512+ {
513+ g_free (image);
514+ image = NULL;
515+ }
516+ }
517+
518+ priv->user_list = user_list;
519+ priv->name = g_strdup (entry->pw_name);
520+ priv->real_name = real_name;
521+ priv->home_directory = g_strdup (entry->pw_dir);
522+ priv->shell = g_strdup (entry->pw_shell);
523+ priv->image = image;
524+ priv->uid = entry->pw_uid;
525+ priv->gid = entry->pw_gid;
526+
527+ return user;
528+}
529+
530 static void
531-load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
532+load_passwd_file (CommonUserList *user_list, gboolean emit_add_signal)
533 {
534- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
535+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
536 GKeyFile *config;
537 gchar *value;
538 gint minimum_uid;
539@@ -280,10 +342,7 @@
540 while (TRUE)
541 {
542 struct passwd *entry;
543- LightDMUser *user;
544- LightDMUserPrivate *user_priv;
545- char **tokens;
546- gchar *real_name, *image;
547+ CommonUser *user;
548 int i;
549
550 errno = 0;
551@@ -308,44 +367,15 @@
552 if (hidden_users[i])
553 continue;
554
555- tokens = g_strsplit (entry->pw_gecos, ",", -1);
556- if (tokens[0] != NULL && tokens[0][0] != '\0')
557- real_name = g_strdup (tokens[0]);
558- else
559- real_name = g_strdup ("");
560- g_strfreev (tokens);
561-
562- image = g_build_filename (entry->pw_dir, ".face", NULL);
563- if (!g_file_test (image, G_FILE_TEST_EXISTS))
564- {
565- g_free (image);
566- image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
567- if (!g_file_test (image, G_FILE_TEST_EXISTS))
568- {
569- g_free (image);
570- image = NULL;
571- }
572- }
573-
574- user = g_object_new (LIGHTDM_TYPE_USER, NULL);
575- user_priv = GET_USER_PRIVATE (user);
576- user_priv->user_list = user_list;
577- g_free (user_priv->name);
578- user_priv->name = g_strdup (entry->pw_name);
579- g_free (user_priv->real_name);
580- user_priv->real_name = real_name;
581- g_free (user_priv->home_directory);
582- user_priv->home_directory = g_strdup (entry->pw_dir);
583- g_free (user_priv->image);
584- user_priv->image = image;
585+ user = make_passwd_user (user_list, entry);
586
587 /* Update existing users if have them */
588 for (link = priv->users; link; link = link->next)
589 {
590- LightDMUser *info = link->data;
591- if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
592+ CommonUser *info = link->data;
593+ if (strcmp (common_user_get_name (info), common_user_get_name (user)) == 0)
594 {
595- if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
596+ if (update_passwd_user (info, common_user_get_real_name (user), common_user_get_home_directory (user), common_user_get_shell (user), common_user_get_image (user)))
597 changed_users = g_list_insert_sorted (changed_users, info, compare_user);
598 g_object_unref (user);
599 user = info;
600@@ -375,8 +405,8 @@
601 /* Notify of changes */
602 for (link = new_users; link; link = link->next)
603 {
604- LightDMUser *info = link->data;
605- g_debug ("User %s added", lightdm_user_get_name (info));
606+ CommonUser *info = link->data;
607+ g_debug ("User %s added", common_user_get_name (info));
608 g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), NULL);
609 if (emit_add_signal)
610 g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
611@@ -384,8 +414,8 @@
612 g_list_free (new_users);
613 for (link = changed_users; link; link = link->next)
614 {
615- LightDMUser *info = link->data;
616- g_debug ("User %s changed", lightdm_user_get_name (info));
617+ CommonUser *info = link->data;
618+ g_debug ("User %s changed", common_user_get_name (info));
619 g_signal_emit (info, user_signals[CHANGED], 0);
620 }
621 g_list_free (changed_users);
622@@ -402,8 +432,8 @@
623
624 if (!new_link)
625 {
626- LightDMUser *info = link->data;
627- g_debug ("User %s removed", lightdm_user_get_name (info));
628+ CommonUser *info = link->data;
629+ g_debug ("User %s removed", common_user_get_name (info));
630 g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
631 g_object_unref (info);
632 }
633@@ -412,7 +442,7 @@
634 }
635
636 static void
637-passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
638+passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, CommonUserList *user_list)
639 {
640 if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
641 {
642@@ -421,7 +451,7 @@
643 }
644 }
645
646-static gboolean load_accounts_user (LightDMUser *user);
647+static gboolean load_accounts_user (CommonUser *user);
648
649 static void
650 accounts_user_changed_cb (GDBusConnection *connection,
651@@ -432,8 +462,8 @@
652 GVariant *parameters,
653 gpointer data)
654 {
655- LightDMUser *user = data;
656- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
657+ CommonUser *user = data;
658+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
659
660 g_debug ("User %s changed", priv->path);
661 if (load_accounts_user (user))
662@@ -441,9 +471,9 @@
663 }
664
665 static gboolean
666-load_accounts_user (LightDMUser *user)
667+load_accounts_user (CommonUser *user)
668 {
669- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
670+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
671 GVariant *result, *value;
672 GVariantIter *iter;
673 gchar *name;
674@@ -498,6 +528,11 @@
675 g_free (priv->home_directory);
676 priv->home_directory = g_variant_dup_string (value, NULL);
677 }
678+ else if (strcmp (name, "Shell") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
679+ {
680+ g_free (priv->shell);
681+ priv->shell = g_variant_dup_string (value, NULL);
682+ }
683 else if (strcmp (name, "SystemAccount") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
684 system_account = g_variant_get_boolean (value);
685 else if (strcmp (name, "Language") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
686@@ -543,6 +578,8 @@
687 }
688 else if (strcmp (name, "XHasMessages") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
689 priv->has_messages = g_variant_get_boolean (value);
690+ else if (strcmp (name, "Uid") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT64))
691+ priv->uid = g_variant_get_uint64 (value);
692 }
693 g_variant_iter_free (iter);
694
695@@ -554,13 +591,13 @@
696 }
697
698 static void
699-add_accounts_user (LightDMUserList *user_list, const gchar *path, gboolean emit_signal)
700+add_accounts_user (CommonUserList *user_list, const gchar *path, gboolean emit_signal)
701 {
702- LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (user_list);
703- LightDMUser *user;
704- LightDMUserPrivate *priv;
705+ CommonUserListPrivate *list_priv = GET_LIST_PRIVATE (user_list);
706+ CommonUser *user;
707+ CommonUserPrivate *priv;
708
709- user = g_object_new (LIGHTDM_TYPE_USER, NULL);
710+ user = g_object_new (COMMON_TYPE_USER, NULL);
711 priv = GET_USER_PRIVATE (user);
712
713 g_debug ("User %s added", path);
714@@ -586,9 +623,9 @@
715 GVariant *parameters,
716 gpointer data)
717 {
718- LightDMUserList *user_list = data;
719+ CommonUserList *user_list = data;
720 gchar *path;
721- LightDMUser *user;
722+ CommonUser *user;
723
724 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
725 {
726@@ -613,10 +650,10 @@
727 GVariant *parameters,
728 gpointer data)
729 {
730- LightDMUserList *user_list = data;
731- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
732+ CommonUserList *user_list = data;
733+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
734 gchar *path;
735- LightDMUser *user;
736+ CommonUser *user;
737
738 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
739 {
740@@ -639,11 +676,11 @@
741 }
742 }
743
744-static Session *
745-load_session (LightDMUserList *user_list, const gchar *path)
746+static CommonSession *
747+load_session (CommonUserList *user_list, const gchar *path)
748 {
749- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
750- Session *session = NULL;
751+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
752+ CommonSession *session = NULL;
753 GVariant *result, *username;
754 GError *error = NULL;
755
756@@ -672,7 +709,7 @@
757 g_variant_get (username, "&s", &name);
758
759 g_debug ("Loaded session %s (%s)", path, name);
760- session = g_object_new (session_get_type (), NULL);
761+ session = g_object_new (common_session_get_type (), NULL);
762 session->username = g_strdup (name);
763 session->path = g_strdup (path);
764 priv->sessions = g_list_append (priv->sessions, session);
765@@ -692,10 +729,10 @@
766 GVariant *parameters,
767 gpointer data)
768 {
769- LightDMUserList *user_list = data;
770+ CommonUserList *user_list = data;
771 gchar *path;
772- Session *session;
773- LightDMUser *user = NULL;
774+ CommonSession *session;
775+ CommonUser *user = NULL;
776
777 if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
778 {
779@@ -720,8 +757,8 @@
780 GVariant *parameters,
781 gpointer data)
782 {
783- LightDMUserList *user_list = data;
784- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
785+ CommonUserList *user_list = data;
786+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
787 gchar *path;
788 GList *link;
789
790@@ -735,10 +772,10 @@
791
792 for (link = priv->sessions; link; link = link->next)
793 {
794- Session *session = link->data;
795+ CommonSession *session = link->data;
796 if (strcmp (session->path, path) == 0)
797 {
798- LightDMUser *user;
799+ CommonUser *user;
800
801 g_debug ("Session %s removed", path);
802 priv->sessions = g_list_remove_link (priv->sessions, link);
803@@ -752,9 +789,75 @@
804 }
805
806 static void
807-load_users (LightDMUserList *user_list)
808-{
809- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
810+load_sessions (CommonUserList *user_list)
811+{
812+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
813+ GVariant *result;
814+ GError *error = NULL;
815+
816+ priv->session_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
817+ "org.freedesktop.DisplayManager",
818+ "org.freedesktop.DisplayManager",
819+ "SessionAdded",
820+ "/org/freedesktop/DisplayManager",
821+ NULL,
822+ G_DBUS_SIGNAL_FLAGS_NONE,
823+ session_added_cb,
824+ user_list,
825+ NULL);
826+ priv->session_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
827+ "org.freedesktop.DisplayManager",
828+ "org.freedesktop.DisplayManager",
829+ "SessionRemoved",
830+ "/org/freedesktop/DisplayManager",
831+ NULL,
832+ G_DBUS_SIGNAL_FLAGS_NONE,
833+ session_removed_cb,
834+ user_list,
835+ NULL);
836+ result = g_dbus_connection_call_sync (priv->bus,
837+ "org.freedesktop.DisplayManager",
838+ "/org/freedesktop/DisplayManager",
839+ "org.freedesktop.DBus.Properties",
840+ "Get",
841+ g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
842+ G_VARIANT_TYPE ("(v)"),
843+ G_DBUS_CALL_FLAGS_NONE,
844+ -1,
845+ NULL,
846+ &error);
847+ if (error)
848+ g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
849+ g_clear_error (&error);
850+ if (result)
851+ {
852+ if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
853+ {
854+ GVariant *value;
855+ GVariantIter *iter;
856+ const gchar *path;
857+
858+ g_variant_get (result, "(v)", &value);
859+
860+ g_debug ("Loading sessions from org.freedesktop.DisplayManager");
861+ g_variant_get (value, "ao", &iter);
862+ while (g_variant_iter_loop (iter, "&o", &path))
863+ load_session (user_list, path);
864+ g_variant_iter_free (iter);
865+
866+ g_variant_unref (value);
867+ }
868+ else
869+ g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
870+
871+ g_variant_unref (result);
872+ }
873+}
874+
875+static void
876+load_users (CommonUserList *user_list)
877+{
878+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
879 GVariant *result;
880 GError *error = NULL;
881
882@@ -831,128 +934,83 @@
883 g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
884 g_clear_error (&error);
885 }
886-
887- priv->session_added_signal = g_dbus_connection_signal_subscribe (priv->bus,
888- "org.freedesktop.DisplayManager",
889- "org.freedesktop.DisplayManager",
890- "SessionAdded",
891- "/org/freedesktop/DisplayManager",
892- NULL,
893- G_DBUS_SIGNAL_FLAGS_NONE,
894- session_added_cb,
895- user_list,
896- NULL);
897- priv->session_removed_signal = g_dbus_connection_signal_subscribe (priv->bus,
898- "org.freedesktop.DisplayManager",
899- "org.freedesktop.DisplayManager",
900- "SessionRemoved",
901- "/org/freedesktop/DisplayManager",
902- NULL,
903- G_DBUS_SIGNAL_FLAGS_NONE,
904- session_removed_cb,
905-
906- user_list,
907- NULL);
908- result = g_dbus_connection_call_sync (priv->bus,
909- "org.freedesktop.DisplayManager",
910- "/org/freedesktop/DisplayManager",
911- "org.freedesktop.DBus.Properties",
912- "Get",
913- g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
914- G_VARIANT_TYPE ("(v)"),
915- G_DBUS_CALL_FLAGS_NONE,
916- -1,
917- NULL,
918- &error);
919- if (error)
920- g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
921- g_clear_error (&error);
922- if (result)
923- {
924- if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
925- {
926- GVariant *value;
927- GVariantIter *iter;
928- const gchar *path;
929-
930- g_variant_get (result, "(v)", &value);
931-
932- g_debug ("Loading sessions from org.freedesktop.DisplayManager");
933- g_variant_get (value, "ao", &iter);
934- while (g_variant_iter_loop (iter, "&o", &path))
935- load_session (user_list, path);
936- g_variant_iter_free (iter);
937-
938- g_variant_unref (value);
939- }
940- else
941- g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
942-
943- g_variant_unref (result);
944- }
945 }
946
947 /**
948- * lightdm_user_list_get_length:
949- * @user_list: a #LightDMUserList
950+ * common_user_list_get_length:
951+ * @user_list: a #CommonUserList
952 *
953 * Return value: The number of users able to log in
954 **/
955 gint
956-lightdm_user_list_get_length (LightDMUserList *user_list)
957+common_user_list_get_length (CommonUserList *user_list)
958 {
959- g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
960+ g_return_val_if_fail (COMMON_IS_USER_LIST (user_list), 0);
961 load_users (user_list);
962 return g_list_length (GET_LIST_PRIVATE (user_list)->users);
963 }
964
965 /**
966- * lightdm_user_list_get_users:
967- * @user_list: A #LightDMUserList
968+ * common_user_list_get_users:
969+ * @user_list: A #CommonUserList
970 *
971 * Get a list of users to present to the user. This list may be a subset of the
972 * available users and may be empty depending on the server configuration.
973 *
974- * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user.
975+ * Return value: (element-type CommonUser) (transfer none): A list of #CommonUser that should be presented to the user.
976 **/
977 GList *
978-lightdm_user_list_get_users (LightDMUserList *user_list)
979+common_user_list_get_users (CommonUserList *user_list)
980 {
981- g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
982+ g_return_val_if_fail (COMMON_IS_USER_LIST (user_list), NULL);
983 load_users (user_list);
984 return GET_LIST_PRIVATE (user_list)->users;
985 }
986
987 /**
988- * lightdm_user_list_get_user_by_name:
989- * @user_list: A #LightDMUserList
990+ * common_user_list_get_user_by_name:
991+ * @user_list: A #CommonUserList
992 * @username: Name of user to get.
993 *
994 * Get infomation about a given user or #NULL if this user doesn't exist.
995+ * Includes hidden and system users, unlike the list from
996+ * common_user_list_get_users.
997 *
998- * Return value: (transfer none): A #LightDMUser entry for the given user.
999+ * Return value: (transfer full): A #CommonUser entry for the given user.
1000 **/
1001-LightDMUser *
1002-lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
1003+CommonUser *
1004+common_user_list_get_user_by_name (CommonUserList *user_list, const gchar *username)
1005 {
1006- g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
1007+ g_return_val_if_fail (COMMON_IS_USER_LIST (user_list), NULL);
1008 g_return_val_if_fail (username != NULL, NULL);
1009
1010 load_users (user_list);
1011
1012- return get_user_by_name (user_list, username);
1013+ CommonUser *user = get_user_by_name (user_list, username);
1014+ if (user)
1015+ return g_object_ref (user);
1016+
1017+ /* Sometimes we need to look up users that aren't in AccountsService.
1018+ Notably we need to look up the user that the greeter runs as, which
1019+ is usually 'lightdm'. For such cases, we manually create a one-off
1020+ CommonUser object and pre-seed with passwd info. */
1021+ struct passwd *entry = getpwnam (username);
1022+ if (entry != NULL)
1023+ return make_passwd_user (user_list, entry);
1024+
1025+ return NULL;
1026 }
1027
1028 static void
1029-lightdm_user_list_init (LightDMUserList *user_list)
1030+common_user_list_init (CommonUserList *user_list)
1031 {
1032- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
1033+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
1034
1035 priv->bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
1036 }
1037
1038 static void
1039-lightdm_user_list_set_property (GObject *object,
1040+common_user_list_set_property (GObject *object,
1041 guint prop_id,
1042 const GValue *value,
1043 GParamSpec *pspec)
1044@@ -961,19 +1019,19 @@
1045 }
1046
1047 static void
1048-lightdm_user_list_get_property (GObject *object,
1049+common_user_list_get_property (GObject *object,
1050 guint prop_id,
1051 GValue *value,
1052 GParamSpec *pspec)
1053 {
1054- LightDMUserList *self;
1055+ CommonUserList *self;
1056
1057- self = LIGHTDM_USER_LIST (object);
1058+ self = COMMON_USER_LIST (object);
1059
1060 switch (prop_id)
1061 {
1062 case LIST_PROP_NUM_USERS:
1063- g_value_set_int (value, lightdm_user_list_get_length (self));
1064+ g_value_set_int (value, common_user_list_get_length (self));
1065 break;
1066 default:
1067 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1068@@ -982,10 +1040,10 @@
1069 }
1070
1071 static void
1072-lightdm_user_list_finalize (GObject *object)
1073+common_user_list_finalize (GObject *object)
1074 {
1075- LightDMUserList *self = LIGHTDM_USER_LIST (object);
1076- LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
1077+ CommonUserList *self = COMMON_USER_LIST (object);
1078+ CommonUserListPrivate *priv = GET_LIST_PRIVATE (self);
1079
1080 /* Remove children first, they might access us */
1081 g_list_free_full (priv->users, g_object_unref);
1082@@ -1003,19 +1061,19 @@
1083 if (priv->passwd_monitor)
1084 g_object_unref (priv->passwd_monitor);
1085
1086- G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
1087+ G_OBJECT_CLASS (common_user_list_parent_class)->finalize (object);
1088 }
1089
1090 static void
1091-lightdm_user_list_class_init (LightDMUserListClass *klass)
1092+common_user_list_class_init (CommonUserListClass *klass)
1093 {
1094 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1095
1096- g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
1097+ g_type_class_add_private (klass, sizeof (CommonUserListPrivate));
1098
1099- object_class->set_property = lightdm_user_list_set_property;
1100- object_class->get_property = lightdm_user_list_get_property;
1101- object_class->finalize = lightdm_user_list_finalize;
1102+ object_class->set_property = common_user_list_set_property;
1103+ object_class->get_property = common_user_list_get_property;
1104+ object_class->finalize = common_user_list_finalize;
1105
1106 g_object_class_install_property (object_class,
1107 LIST_PROP_NUM_USERS,
1108@@ -1025,9 +1083,9 @@
1109 0, G_MAXINT, 0,
1110 G_PARAM_READABLE));
1111 /**
1112- * LightDMUserList::user-added:
1113- * @user_list: A #LightDMUserList
1114- * @user: The #LightDM user that has been added.
1115+ * CommonUserList::user-added:
1116+ * @user_list: A #CommonUserList
1117+ * @user: The #CommonUser that has been added.
1118 *
1119 * The ::user-added signal gets emitted when a user account is created.
1120 **/
1121@@ -1035,15 +1093,15 @@
1122 g_signal_new ("user-added",
1123 G_TYPE_FROM_CLASS (klass),
1124 G_SIGNAL_RUN_LAST,
1125- G_STRUCT_OFFSET (LightDMUserListClass, user_added),
1126+ G_STRUCT_OFFSET (CommonUserListClass, user_added),
1127 NULL, NULL,
1128 NULL,
1129- G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1130+ G_TYPE_NONE, 1, COMMON_TYPE_USER);
1131
1132 /**
1133- * LightDMUserList::user-changed:
1134- * @user_list: A #LightDMUserList
1135- * @user: The #LightDM user that has been changed.
1136+ * CommonUserList::user-changed:
1137+ * @user_list: A #CommonUserList
1138+ * @user: The #CommonUser that has been changed.
1139 *
1140 * The ::user-changed signal gets emitted when a user account is modified.
1141 **/
1142@@ -1051,15 +1109,15 @@
1143 g_signal_new ("user-changed",
1144 G_TYPE_FROM_CLASS (klass),
1145 G_SIGNAL_RUN_LAST,
1146- G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
1147+ G_STRUCT_OFFSET (CommonUserListClass, user_changed),
1148 NULL, NULL,
1149 NULL,
1150- G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1151+ G_TYPE_NONE, 1, COMMON_TYPE_USER);
1152
1153 /**
1154- * LightDMUserList::user-removed:
1155- * @user_list: A #LightDMUserList
1156- * @user: The #LightDM user that has been removed.
1157+ * CommonUserList::user-removed:
1158+ * @user_list: A #CommonUserList
1159+ * @user: The #CommonUser that has been removed.
1160 *
1161 * The ::user-removed signal gets emitted when a user account is removed.
1162 **/
1163@@ -1067,55 +1125,93 @@
1164 g_signal_new ("user-removed",
1165 G_TYPE_FROM_CLASS (klass),
1166 G_SIGNAL_RUN_LAST,
1167- G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
1168+ G_STRUCT_OFFSET (CommonUserListClass, user_removed),
1169 NULL, NULL,
1170 NULL,
1171- G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
1172-}
1173-
1174-static void
1175-load_dmrc (LightDMUser *user)
1176-{
1177- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1178- gchar *path;
1179- //gboolean have_dmrc;
1180-
1181- if (!priv->dmrc_file)
1182- priv->dmrc_file = g_key_file_new ();
1183-
1184- /* Load from the user directory */
1185- path = g_build_filename (priv->home_directory, ".dmrc", NULL);
1186- /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
1187- g_free (path);
1188-
1189- /* If no ~/.dmrc, then load from the cache */
1190- // FIXME
1191+ G_TYPE_NONE, 1, COMMON_TYPE_USER);
1192+}
1193+
1194+static gboolean
1195+call_method (CommonUser *user, const gchar *method, GVariant *args,
1196+ const gchar *expected, GVariant **result)
1197+{
1198+ GVariant *answer;
1199+ GError *error = NULL;
1200+ CommonUserPrivate *user_priv = GET_USER_PRIVATE (user);
1201+ CommonUserListPrivate *list_priv = GET_LIST_PRIVATE (user_priv->user_list);
1202+
1203+ answer = g_dbus_connection_call_sync (list_priv->bus,
1204+ "org.freedesktop.Accounts",
1205+ user_priv->path,
1206+ "org.freedesktop.Accounts.User",
1207+ method,
1208+ args,
1209+ G_VARIANT_TYPE (expected),
1210+ G_DBUS_CALL_FLAGS_NONE,
1211+ -1,
1212+ NULL,
1213+ &error);
1214+ if (error)
1215+ g_warning ("Could not call %s: %s", method, error->message);
1216+ g_clear_error (&error);
1217+
1218+ if (!answer)
1219+ return FALSE;
1220+
1221+ if (result)
1222+ *result = answer;
1223+ else
1224+ g_variant_unref (answer);
1225+
1226+ return TRUE;
1227+}
1228+
1229+static void
1230+save_string_to_dmrc (CommonUser *user, const gchar *group,
1231+ const gchar *key, const gchar *value)
1232+{
1233+ GKeyFile *dmrc;
1234+
1235+ dmrc = dmrc_load (user);
1236+ g_key_file_set_string (dmrc, group, key, value);
1237+ dmrc_save (dmrc, user);
1238+
1239+ g_key_file_free (dmrc);
1240+}
1241+
1242+static void
1243+load_dmrc (CommonUser *user)
1244+{
1245+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
1246+ GKeyFile *dmrc;
1247+
1248+ dmrc = dmrc_load (user);
1249
1250 // FIXME: Watch for changes
1251
1252 /* The Language field contains the locale */
1253- if (priv->language)
1254- g_free (priv->language);
1255- priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
1256+ g_free (priv->language);
1257+ priv->language = g_key_file_get_string (dmrc, "Desktop", "Language", NULL);
1258
1259- if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
1260+ if (g_key_file_has_key (dmrc, "Desktop", "Layout", NULL))
1261 {
1262 g_strfreev (priv->layouts);
1263 priv->layouts = g_malloc (sizeof (gchar *) * 2);
1264- priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
1265+ priv->layouts[0] = g_key_file_get_string (dmrc, "Desktop", "Layout", NULL);
1266 priv->layouts[1] = NULL;
1267 }
1268
1269- if (priv->session)
1270- g_free (priv->session);
1271- priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
1272+ g_free (priv->session);
1273+ priv->session = g_key_file_get_string (dmrc, "Desktop", "Session", NULL);
1274+
1275+ g_key_file_free (dmrc);
1276 }
1277
1278 /* Loads language/layout/session info for user */
1279 static void
1280-load_user_values (LightDMUser *user)
1281+load_user_values (CommonUser *user)
1282 {
1283- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1284+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
1285
1286 if (priv->loaded_values)
1287 return;
1288@@ -1126,51 +1222,51 @@
1289 }
1290
1291 /**
1292- * lightdm_user_get_name:
1293- * @user: A #LightDMUser
1294+ * common_user_get_name:
1295+ * @user: A #CommonUser
1296 *
1297 * Get the name of a user.
1298 *
1299 * Return value: The name of the given user
1300 **/
1301 const gchar *
1302-lightdm_user_get_name (LightDMUser *user)
1303+common_user_get_name (CommonUser *user)
1304 {
1305- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1306+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1307 load_user_values (user);
1308 return GET_USER_PRIVATE (user)->name;
1309 }
1310
1311 /**
1312- * lightdm_user_get_real_name:
1313- * @user: A #LightDMUser
1314+ * common_user_get_real_name:
1315+ * @user: A #CommonUser
1316 *
1317 * Get the real name of a user.
1318 *
1319 * Return value: The real name of the given user
1320 **/
1321 const gchar *
1322-lightdm_user_get_real_name (LightDMUser *user)
1323+common_user_get_real_name (CommonUser *user)
1324 {
1325- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1326+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1327 load_user_values (user);
1328 return GET_USER_PRIVATE (user)->real_name;
1329 }
1330
1331 /**
1332- * lightdm_user_get_display_name:
1333- * @user: A #LightDMUser
1334+ * common_user_get_display_name:
1335+ * @user: A #CommonUser
1336 *
1337 * Get the display name of a user.
1338 *
1339 * Return value: The display name of the given user
1340 **/
1341 const gchar *
1342-lightdm_user_get_display_name (LightDMUser *user)
1343+common_user_get_display_name (CommonUser *user)
1344 {
1345- LightDMUserPrivate *priv;
1346+ CommonUserPrivate *priv;
1347
1348- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1349+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1350
1351 load_user_values (user);
1352
1353@@ -1182,140 +1278,198 @@
1354 }
1355
1356 /**
1357- * lightdm_user_get_home_directory:
1358- * @user: A #LightDMUser
1359+ * common_user_get_home_directory:
1360+ * @user: A #CommonUser
1361 *
1362 * Get the home directory for a user.
1363 *
1364 * Return value: The users home directory
1365 */
1366 const gchar *
1367-lightdm_user_get_home_directory (LightDMUser *user)
1368+common_user_get_home_directory (CommonUser *user)
1369 {
1370- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1371+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1372 load_user_values (user);
1373 return GET_USER_PRIVATE (user)->home_directory;
1374 }
1375
1376 /**
1377- * lightdm_user_get_image:
1378- * @user: A #LightDMUser
1379+ * common_user_get_shell:
1380+ * @user: A #CommonUser
1381+ *
1382+ * Get the shell for a user.
1383+ *
1384+ * Return value: The user's shell
1385+ */
1386+const gchar *
1387+common_user_get_shell (CommonUser *user)
1388+{
1389+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1390+ load_user_values (user);
1391+ return GET_USER_PRIVATE (user)->shell;
1392+}
1393+
1394+/**
1395+ * common_user_get_image:
1396+ * @user: A #CommonUser
1397 *
1398 * Get the image URI for a user.
1399 *
1400 * Return value: The image URI for the given user or #NULL if no URI
1401 **/
1402 const gchar *
1403-lightdm_user_get_image (LightDMUser *user)
1404+common_user_get_image (CommonUser *user)
1405 {
1406- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1407+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1408 load_user_values (user);
1409 return GET_USER_PRIVATE (user)->image;
1410 }
1411
1412 /**
1413- * lightdm_user_get_background:
1414- * @user: A #LightDMUser
1415+ * common_user_get_background:
1416+ * @user: A #CommonUser
1417 *
1418 * Get the background file path for a user.
1419 *
1420 * Return value: The background file path for the given user or #NULL if no path
1421 **/
1422 const gchar *
1423-lightdm_user_get_background (LightDMUser *user)
1424+common_user_get_background (CommonUser *user)
1425 {
1426- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1427+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1428 load_user_values (user);
1429 return GET_USER_PRIVATE (user)->background;
1430 }
1431
1432 /**
1433- * lightdm_user_get_language:
1434- * @user: A #LightDMUser
1435+ * common_user_get_language:
1436+ * @user: A #CommonUser
1437 *
1438 * Get the language for a user.
1439 *
1440 * 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.
1441 **/
1442 const gchar *
1443-lightdm_user_get_language (LightDMUser *user)
1444+common_user_get_language (CommonUser *user)
1445 {
1446- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1447+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1448 load_user_values (user);
1449- return GET_USER_PRIVATE (user)->language;
1450-}
1451-
1452-/**
1453- * lightdm_user_get_layout:
1454- * @user: A #LightDMUser
1455+ const gchar *language = GET_USER_PRIVATE (user)->language;
1456+ return (language && language[0] == 0) ? NULL : language; /* Treat "" as NULL */
1457+}
1458+
1459+/**
1460+ * common_user_set_language:
1461+ * @user: A #CommonUser
1462+ * @language: The user's new language
1463+ *
1464+ * Set the language for a user.
1465+ **/
1466+void
1467+common_user_set_language (CommonUser *user, const gchar *language)
1468+{
1469+ g_return_if_fail (COMMON_IS_USER (user));
1470+ if (g_strcmp0 (common_user_get_language (user), language) != 0)
1471+ {
1472+ call_method (user, "SetLanguage", g_variant_new ("(s)", language), "()", NULL);
1473+ save_string_to_dmrc (user, "Desktop", "Language", language);
1474+ }
1475+}
1476+
1477+/**
1478+ * common_user_get_layout:
1479+ * @user: A #CommonUser
1480 *
1481 * Get the keyboard layout for a user.
1482 *
1483 * 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.
1484 **/
1485 const gchar *
1486-lightdm_user_get_layout (LightDMUser *user)
1487+common_user_get_layout (CommonUser *user)
1488 {
1489- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1490+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1491 load_user_values (user);
1492 return GET_USER_PRIVATE (user)->layouts[0];
1493 }
1494
1495 /**
1496- * lightdm_user_get_layouts:
1497- * @user: A #LightDMUser
1498+ * common_user_get_layouts:
1499+ * @user: A #CommonUser
1500 *
1501 * Get the configured keyboard layouts for a user.
1502 *
1503 * 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.
1504 **/
1505 const gchar * const *
1506-lightdm_user_get_layouts (LightDMUser *user)
1507+common_user_get_layouts (CommonUser *user)
1508 {
1509- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1510+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1511 load_user_values (user);
1512 return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
1513 }
1514
1515 /**
1516- * lightdm_user_get_session:
1517- * @user: A #LightDMUser
1518+ * common_user_get_session:
1519+ * @user: A #CommonUser
1520 *
1521 * Get the session for a user.
1522 *
1523 * Return value: The session for the given user or #NULL if using system defaults.
1524 **/
1525 const gchar *
1526-lightdm_user_get_session (LightDMUser *user)
1527+common_user_get_session (CommonUser *user)
1528 {
1529- g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
1530+ g_return_val_if_fail (COMMON_IS_USER (user), NULL);
1531 load_user_values (user);
1532- return GET_USER_PRIVATE (user)->session;
1533-}
1534-
1535-/**
1536- * lightdm_user_get_logged_in:
1537- * @user: A #LightDMUser
1538+ const gchar *session = GET_USER_PRIVATE (user)->session;
1539+ return (session && session[0] == 0) ? NULL : session; /* Treat "" as NULL */
1540+}
1541+
1542+/**
1543+ * common_user_set_session:
1544+ * @user: A #CommonUser
1545+ * @language: The user's new session
1546+ *
1547+ * Set the session for a user.
1548+ **/
1549+void
1550+common_user_set_session (CommonUser *user, const gchar *session)
1551+{
1552+ g_return_if_fail (COMMON_IS_USER (user));
1553+ if (g_strcmp0 (common_user_get_session (user), session) != 0)
1554+ {
1555+ call_method (user, "SetXSession", g_variant_new ("(s)", session), "()", NULL);
1556+ save_string_to_dmrc (user, "Desktop", "Session", session);
1557+ }
1558+}
1559+
1560+/**
1561+ * common_user_get_logged_in:
1562+ * @user: A #CommonUser
1563 *
1564 * Check if a user is logged in.
1565 *
1566 * Return value: #TRUE if the user is currently logged in.
1567 **/
1568 gboolean
1569-lightdm_user_get_logged_in (LightDMUser *user)
1570+common_user_get_logged_in (CommonUser *user)
1571 {
1572- LightDMUserPrivate *priv;
1573- LightDMUserListPrivate *list_priv;
1574+ CommonUserPrivate *priv;
1575+ CommonUserListPrivate *list_priv;
1576 GList *link;
1577
1578- g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1579+ g_return_val_if_fail (COMMON_IS_USER (user), FALSE);
1580
1581 priv = GET_USER_PRIVATE (user);
1582 list_priv = GET_LIST_PRIVATE (priv->user_list);
1583
1584+ // Lazily decide to load/listen to sessions
1585+ if (list_priv->session_added_signal == 0)
1586+ load_sessions (priv->user_list);
1587+
1588 for (link = list_priv->sessions; link; link = link->next)
1589 {
1590- Session *session = link->data;
1591+ CommonSession *session = link->data;
1592 if (strcmp (session->username, priv->name) == 0)
1593 return TRUE;
1594 }
1595@@ -1324,31 +1478,73 @@
1596 }
1597
1598 /**
1599- * lightdm_user_get_has_messages:
1600- * @user: A #LightDMUser
1601+ * common_user_get_has_messages:
1602+ * @user: A #CommonUser
1603 *
1604 * Check if a user has waiting messages.
1605 *
1606 * Return value: #TRUE if the user has waiting messages.
1607 **/
1608 gboolean
1609-lightdm_user_get_has_messages (LightDMUser *user)
1610+common_user_get_has_messages (CommonUser *user)
1611 {
1612- g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
1613+ g_return_val_if_fail (COMMON_IS_USER (user), FALSE);
1614 load_user_values (user);
1615 return GET_USER_PRIVATE (user)->has_messages;
1616 }
1617
1618+/**
1619+ * common_user_get_uid:
1620+ * @user: A #CommonUser
1621+ *
1622+ * Get the uid of a user
1623+ *
1624+ * Return value: The user's uid
1625+ **/
1626+uid_t
1627+common_user_get_uid (CommonUser *user)
1628+{
1629+ g_return_val_if_fail (COMMON_IS_USER (user), 0);
1630+ load_user_values (user);
1631+ return GET_USER_PRIVATE (user)->uid;
1632+}
1633+
1634+/**
1635+ * common_user_get_gid:
1636+ * @user: A #CommonUser
1637+ *
1638+ * Get the gid of a user
1639+ *
1640+ * Return value: The user's gid
1641+ **/
1642+gid_t
1643+common_user_get_gid (CommonUser *user)
1644+{
1645+ g_return_val_if_fail (COMMON_IS_USER (user), 0);
1646+ load_user_values (user);
1647+ /* gid is not actually stored in AccountsService, so if our user is from
1648+ AccountsService, we have to look up manually in passwd. gid won't
1649+ change, so just look up the first time we're asked and never again. */
1650+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
1651+ if (priv->uid != 0 && priv->gid == 0)
1652+ {
1653+ struct passwd *entry = getpwuid (priv->uid);
1654+ if (entry != NULL)
1655+ priv->gid = entry->pw_gid;
1656+ }
1657+ return priv->gid;
1658+}
1659+
1660 static void
1661-lightdm_user_init (LightDMUser *user)
1662+common_user_init (CommonUser *user)
1663 {
1664- LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
1665+ CommonUserPrivate *priv = GET_USER_PRIVATE (user);
1666 priv->layouts = g_malloc (sizeof (gchar *) * 1);
1667 priv->layouts[0] = NULL;
1668 }
1669
1670 static void
1671-lightdm_user_set_property (GObject *object,
1672+common_user_set_property (GObject *object,
1673 guint prop_id,
1674 const GValue *value,
1675 GParamSpec *pspec)
1676@@ -1357,52 +1553,61 @@
1677 }
1678
1679 static void
1680-lightdm_user_get_property (GObject *object,
1681+common_user_get_property (GObject *object,
1682 guint prop_id,
1683 GValue *value,
1684 GParamSpec *pspec)
1685 {
1686- LightDMUser *self;
1687+ CommonUser *self;
1688
1689- self = LIGHTDM_USER (object);
1690+ self = COMMON_USER (object);
1691
1692 switch (prop_id)
1693 {
1694 case USER_PROP_NAME:
1695- g_value_set_string (value, lightdm_user_get_name (self));
1696+ g_value_set_string (value, common_user_get_name (self));
1697 break;
1698 case USER_PROP_REAL_NAME:
1699- g_value_set_string (value, lightdm_user_get_real_name (self));
1700+ g_value_set_string (value, common_user_get_real_name (self));
1701 break;
1702 case USER_PROP_DISPLAY_NAME:
1703- g_value_set_string (value, lightdm_user_get_display_name (self));
1704+ g_value_set_string (value, common_user_get_display_name (self));
1705 break;
1706 case USER_PROP_HOME_DIRECTORY:
1707- g_value_set_string (value, lightdm_user_get_home_directory (self));
1708+ g_value_set_string (value, common_user_get_home_directory (self));
1709+ break;
1710+ case USER_PROP_SHELL:
1711+ g_value_set_string (value, common_user_get_shell (self));
1712 break;
1713 case USER_PROP_IMAGE:
1714- g_value_set_string (value, lightdm_user_get_image (self));
1715+ g_value_set_string (value, common_user_get_image (self));
1716 break;
1717 case USER_PROP_BACKGROUND:
1718- g_value_set_string (value, lightdm_user_get_background (self));
1719+ g_value_set_string (value, common_user_get_background (self));
1720 break;
1721 case USER_PROP_LANGUAGE:
1722- g_value_set_string (value, lightdm_user_get_language (self));
1723+ g_value_set_string (value, common_user_get_language (self));
1724 break;
1725 case USER_PROP_LAYOUT:
1726- g_value_set_string (value, lightdm_user_get_layout (self));
1727+ g_value_set_string (value, common_user_get_layout (self));
1728 break;
1729 case USER_PROP_LAYOUTS:
1730- g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self)));
1731+ g_value_set_boxed (value, g_strdupv ((gchar **) common_user_get_layouts (self)));
1732 break;
1733 case USER_PROP_SESSION:
1734- g_value_set_string (value, lightdm_user_get_session (self));
1735+ g_value_set_string (value, common_user_get_session (self));
1736 break;
1737 case USER_PROP_LOGGED_IN:
1738- g_value_set_boolean (value, lightdm_user_get_logged_in (self));
1739+ g_value_set_boolean (value, common_user_get_logged_in (self));
1740 break;
1741 case USER_PROP_HAS_MESSAGES:
1742- g_value_set_boolean (value, lightdm_user_get_has_messages (self));
1743+ g_value_set_boolean (value, common_user_get_has_messages (self));
1744+ break;
1745+ case USER_PROP_UID:
1746+ g_value_set_uint64 (value, common_user_get_uid (self));
1747+ break;
1748+ case USER_PROP_GID:
1749+ g_value_set_uint64 (value, common_user_get_gid (self));
1750 break;
1751 default:
1752 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1753@@ -1411,10 +1616,10 @@
1754 }
1755
1756 static void
1757-lightdm_user_finalize (GObject *object)
1758+common_user_finalize (GObject *object)
1759 {
1760- LightDMUser *self = LIGHTDM_USER (object);
1761- LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
1762+ CommonUser *self = COMMON_USER (object);
1763+ CommonUserPrivate *priv = GET_USER_PRIVATE (self);
1764
1765 g_free (priv->path);
1766 if (priv->changed_signal)
1767@@ -1422,23 +1627,22 @@
1768 g_free (priv->name);
1769 g_free (priv->real_name);
1770 g_free (priv->home_directory);
1771+ g_free (priv->shell);
1772 g_free (priv->image);
1773 g_free (priv->background);
1774 g_strfreev (priv->layouts);
1775- if (priv->dmrc_file)
1776- g_key_file_free (priv->dmrc_file);
1777 }
1778
1779 static void
1780-lightdm_user_class_init (LightDMUserClass *klass)
1781+common_user_class_init (CommonUserClass *klass)
1782 {
1783 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1784
1785- g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
1786+ g_type_class_add_private (klass, sizeof (CommonUserPrivate));
1787
1788- object_class->set_property = lightdm_user_set_property;
1789- object_class->get_property = lightdm_user_get_property;
1790- object_class->finalize = lightdm_user_finalize;
1791+ object_class->set_property = common_user_set_property;
1792+ object_class->get_property = common_user_get_property;
1793+ object_class->finalize = common_user_finalize;
1794
1795 g_object_class_install_property (object_class,
1796 USER_PROP_NAME,
1797@@ -1469,6 +1673,13 @@
1798 NULL,
1799 G_PARAM_READWRITE));
1800 g_object_class_install_property (object_class,
1801+ USER_PROP_SHELL,
1802+ g_param_spec_string ("shell",
1803+ "shell",
1804+ "Shell",
1805+ NULL,
1806+ G_PARAM_READWRITE));
1807+ g_object_class_install_property (object_class,
1808 USER_PROP_IMAGE,
1809 g_param_spec_string ("image",
1810 "image",
1811@@ -1524,10 +1735,28 @@
1812 "TRUE if the user is has waiting messages",
1813 FALSE,
1814 G_PARAM_READWRITE));
1815+ g_object_class_install_property (object_class,
1816+ USER_PROP_UID,
1817+ g_param_spec_uint64 ("uid",
1818+ "uid",
1819+ "Uid",
1820+ 0,
1821+ G_MAXUINT64,
1822+ 0,
1823+ G_PARAM_READWRITE));
1824+ g_object_class_install_property (object_class,
1825+ USER_PROP_GID,
1826+ g_param_spec_uint64 ("gd",
1827+ "gid",
1828+ "Gid",
1829+ 0,
1830+ G_MAXUINT64,
1831+ 0,
1832+ G_PARAM_READWRITE));
1833
1834 /**
1835- * LightDMUser::changed:
1836- * @user: A #LightDMUser
1837+ * CommonUser::changed:
1838+ * @user: A #CommonUser
1839 *
1840 * The ::changed signal gets emitted this user account is modified.
1841 **/
1842@@ -1535,29 +1764,29 @@
1843 g_signal_new ("changed",
1844 G_TYPE_FROM_CLASS (klass),
1845 G_SIGNAL_RUN_LAST,
1846- G_STRUCT_OFFSET (LightDMUserClass, changed),
1847+ G_STRUCT_OFFSET (CommonUserClass, changed),
1848 NULL, NULL,
1849 NULL,
1850 G_TYPE_NONE, 0);
1851 }
1852
1853 static void
1854-session_init (Session *session)
1855+common_session_init (CommonSession *common_session)
1856 {
1857 }
1858
1859 static void
1860-session_finalize (GObject *object)
1861+common_session_finalize (GObject *object)
1862 {
1863- Session *self = SESSION (object);
1864+ CommonSession *self = COMMON_SESSION (object);
1865
1866 g_free (self->path);
1867 g_free (self->username);
1868 }
1869
1870 static void
1871-session_class_init (SessionClass *klass)
1872+common_session_class_init (CommonSessionClass *klass)
1873 {
1874 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1875- object_class->finalize = session_finalize;
1876+ object_class->finalize = common_session_finalize;
1877 }
1878
1879=== added file 'common/user-list.h'
1880--- common/user-list.h 1970-01-01 00:00:00 +0000
1881+++ common/user-list.h 2014-02-08 22:36:44 +0000
1882@@ -0,0 +1,111 @@
1883+/*
1884+ * Copyright (C) 2010 Robert Ancell.
1885+ * Copyright (C) 2014 Canonical, Ltd.
1886+ * Authors: Robert Ancell <robert.ancell@canonical.com>
1887+ * Michael Terry <michael.terry@canonical.com>
1888+ *
1889+ * This library is free software; you can redistribute it and/or modify it under
1890+ * the terms of the GNU Lesser General Public License as published by the Free
1891+ * Software Foundation; either version 2 or version 3 of the License.
1892+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
1893+ */
1894+
1895+#ifndef COMMON_USER_LIST_H_
1896+#define COMMON_USER_LIST_H_
1897+
1898+#include <glib-object.h>
1899+#include <sys/types.h>
1900+
1901+G_BEGIN_DECLS
1902+
1903+#define COMMON_TYPE_USER_LIST (common_user_list_get_type())
1904+#define COMMON_USER_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMMON_TYPE_USER_LIST, CommonUserList));
1905+#define COMMON_USER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COMMON_TYPE_USER_LIST, CommonUserListClass))
1906+#define COMMON_IS_USER_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMMON_TYPE_USER_LIST))
1907+#define COMMON_IS_USER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COMMON_TYPE_USER_LIST))
1908+#define COMMON_USER_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COMMON_TYPE_USER_LIST, CommonUserListClass))
1909+
1910+#define COMMON_TYPE_USER (common_user_get_type())
1911+#define COMMON_USER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMMON_TYPE_USER, CommonUser));
1912+#define COMMON_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), COMMON_TYPE_USER, CommonUserClass))
1913+#define COMMON_IS_USER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMMON_TYPE_USER))
1914+#define COMMON_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), COMMON_TYPE_USER))
1915+#define COMMON_USER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), COMMON_TYPE_USER, CommonUserClass))
1916+
1917+typedef struct
1918+{
1919+ GObject parent_instance;
1920+} CommonUser;
1921+
1922+typedef struct
1923+{
1924+ GObjectClass parent_class;
1925+
1926+ void (*changed)(CommonUser *user);
1927+} CommonUserClass;
1928+
1929+typedef struct
1930+{
1931+ GObject parent_instance;
1932+} CommonUserList;
1933+
1934+typedef struct
1935+{
1936+ GObjectClass parent_class;
1937+
1938+ void (*user_added)(CommonUserList *user_list, CommonUser *user);
1939+ void (*user_changed)(CommonUserList *user_list, CommonUser *user);
1940+ void (*user_removed)(CommonUserList *user_list, CommonUser *user);
1941+} CommonUserListClass;
1942+
1943+GType common_user_list_get_type (void);
1944+
1945+GType common_user_get_type (void);
1946+
1947+CommonUserList *common_user_list_get_instance (void);
1948+
1949+void common_user_list_cleanup (void);
1950+
1951+gint common_user_list_get_length (CommonUserList *user_list);
1952+
1953+CommonUser *common_user_list_get_user_by_name (CommonUserList *user_list, const gchar *username);
1954+
1955+GList *common_user_list_get_users (CommonUserList *user_list);
1956+
1957+const gchar *common_user_get_name (CommonUser *user);
1958+
1959+const gchar *common_user_get_real_name (CommonUser *user);
1960+
1961+const gchar *common_user_get_display_name (CommonUser *user);
1962+
1963+const gchar *common_user_get_home_directory (CommonUser *user);
1964+
1965+const gchar *common_user_get_shell (CommonUser *user);
1966+
1967+const gchar *common_user_get_image (CommonUser *user);
1968+
1969+const gchar *common_user_get_background (CommonUser *user);
1970+
1971+const gchar *common_user_get_language (CommonUser *user);
1972+
1973+void common_user_set_language (CommonUser *user, const gchar *language);
1974+
1975+const gchar *common_user_get_layout (CommonUser *user);
1976+
1977+const gchar * const *common_user_get_layouts (CommonUser *user);
1978+
1979+const gchar *common_user_get_session (CommonUser *user);
1980+
1981+void common_user_set_session (CommonUser *user, const gchar *session);
1982+
1983+gboolean common_user_get_logged_in (CommonUser *user);
1984+
1985+gboolean common_user_get_has_messages (CommonUser *user);
1986+
1987+uid_t common_user_get_uid (CommonUser *user);
1988+
1989+gid_t common_user_get_gid (CommonUser *user);
1990+
1991+G_END_DECLS
1992+
1993+#endif /* COMMON_USER_LIST_H_ */
1994
1995=== modified file 'configure.ac'
1996--- configure.ac 2014-02-06 15:35:02 +0000
1997+++ configure.ac 2014-02-08 22:36:44 +0000
1998@@ -211,6 +211,7 @@
1999
2000 AC_CONFIG_FILES([
2001 Makefile
2002+common/Makefile
2003 data/Makefile
2004 doc/Makefile
2005 help/Makefile
2006
2007=== modified file 'debian/patches/01_transition_ubuntu2d_ubuntu_desktop.patch'
2008--- debian/patches/01_transition_ubuntu2d_ubuntu_desktop.patch 2013-12-09 04:14:30 +0000
2009+++ debian/patches/01_transition_ubuntu2d_ubuntu_desktop.patch 2014-02-08 22:36:44 +0000
2010@@ -1,16 +1,16 @@
2011 # Description: Remove unity-2d (not anymore supported) and transition to unity
2012 # starting from quantal. llvmpipe is used in case no hardware
2013 # acceleration is available.
2014-=== modified file 'liblightdm-gobject/user.c'
2015-Index: trunk/liblightdm-gobject/user.c
2016+=== modified file 'common/user-list.c'
2017+Index: trunk/common/user-list.c
2018 ===================================================================
2019---- trunk.orig/liblightdm-gobject/user.c 2013-12-09 17:13:47.918244873 +1300
2020-+++ trunk/liblightdm-gobject/user.c 2013-12-09 17:13:47.910244873 +1300
2021-@@ -1123,6 +1123,12 @@
2022+--- trunk.orig/common/user-list.c 2014-02-08 17:09:03.157580601 -0500
2023++++ trunk/common/user-list.c 2014-02-08 17:34:52.897555476 -0500
2024+@@ -1219,6 +1219,12 @@
2025
2026 if (!priv->path)
2027 load_dmrc (user);
2028-+
2029++
2030 + if (g_strcmp0 (priv->session, "ubuntu-2d") == 0)
2031 + {
2032 + g_free(priv->session);
2033
2034=== modified file 'liblightdm-gobject/Makefile.am'
2035--- liblightdm-gobject/Makefile.am 2013-07-23 02:24:45 +0000
2036+++ liblightdm-gobject/Makefile.am 2014-02-08 22:36:44 +0000
2037@@ -1,9 +1,12 @@
2038 lib_LTLIBRARIES = liblightdm-gobject-1.la
2039
2040 liblightdm_gobject_1_la_LDFLAGS = -export-symbols-regex \^lightdm_.*
2041-liblightdm_gobject_1_la_LIBADD = $(LIBLIGHTDM_GOBJECT_LIBS)
2042+liblightdm_gobject_1_la_LIBADD = \
2043+ $(LIBLIGHTDM_GOBJECT_LIBS) \
2044+ $(top_builddir)/common/libcommon.la
2045 liblightdm_gobject_1_la_CFLAGS = $(LIBLIGHTDM_GOBJECT_CFLAGS) \
2046 $(WARN_CFLAGS) \
2047+ -I"$(top_srcdir)/common" \
2048 -DCONFIG_DIR=\"$(sysconfdir)/lightdm\" \
2049 -DSESSIONS_DIR=\"$(pkgdatadir)/sessions:$(datadir)/xsessions\" \
2050 -DREMOTE_SESSIONS_DIR=\"$(pkgdatadir)/remote-sessions\"
2051
2052=== modified file 'liblightdm-gobject/session.c'
2053--- liblightdm-gobject/session.c 2013-12-12 20:32:47 +0000
2054+++ liblightdm-gobject/session.c 2014-02-08 22:36:44 +0000
2055@@ -11,6 +11,7 @@
2056 #include <string.h>
2057 #include <gio/gdesktopappinfo.h>
2058
2059+#include "configuration.h"
2060 #include "lightdm/session.h"
2061
2062 enum {
2063@@ -191,7 +192,6 @@
2064 static void
2065 update_sessions (void)
2066 {
2067- GKeyFile *config_key_file = NULL;
2068 gchar *config_path = NULL;
2069 gchar *sessions_dir;
2070 gchar *remote_sessions_dir;
2071@@ -207,8 +207,8 @@
2072 /* Use session directory from configuration */
2073 /* FIXME: This should be sent in the greeter connection */
2074 config_path = g_build_filename (CONFIG_DIR, "lightdm.conf", NULL);
2075- config_key_file = g_key_file_new ();
2076- result = g_key_file_load_from_file (config_key_file, config_path, G_KEY_FILE_NONE, &error);
2077+ /* FIXME: This should load from lightdm.conf.d as well */
2078+ result = config_load_from_file (config_get_instance (), config_path, &error);
2079 if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
2080 g_warning ("Failed to open configuration file: %s", error->message);
2081 g_clear_error (&error);
2082@@ -216,21 +216,20 @@
2083 {
2084 gchar *value;
2085
2086- value = g_key_file_get_string (config_key_file, "LightDM", "sessions-directory", NULL);
2087+ value = config_get_string (config_get_instance (), "LightDM", "sessions-directory");
2088 if (value)
2089 {
2090 g_free (sessions_dir);
2091 sessions_dir = value;
2092 }
2093
2094- value = g_key_file_get_string (config_key_file, "LightDM", "remote-sessions-directory", NULL);
2095+ value = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory");
2096 if (value)
2097 {
2098 g_free (remote_sessions_dir);
2099 remote_sessions_dir = value;
2100 }
2101 }
2102- g_key_file_free (config_key_file);
2103 g_free (config_path);
2104
2105 local_sessions = load_sessions (sessions_dir);
2106
2107=== added file 'liblightdm-gobject/user.c'
2108--- liblightdm-gobject/user.c 1970-01-01 00:00:00 +0000
2109+++ liblightdm-gobject/user.c 2014-02-08 22:36:44 +0000
2110@@ -0,0 +1,736 @@
2111+/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
2112+ *
2113+ * Copyright (C) 2010 Robert Ancell.
2114+ * Copyright (C) 2014 Canonical, Ltd.
2115+ * Authors: Robert Ancell <robert.ancell@canonical.com>
2116+ * Michael Terry <michael.terry@canonical.com>
2117+ *
2118+ * This library is free software; you can redistribute it and/or modify it under
2119+ * the terms of the GNU Lesser General Public License as published by the Free
2120+ * Software Foundation; either version 2 or version 3 of the License.
2121+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
2122+ */
2123+
2124+#include <config.h>
2125+
2126+#include "user-list.h"
2127+#include "lightdm/user.h"
2128+
2129+enum
2130+{
2131+ LIST_PROP_0,
2132+ LIST_PROP_NUM_USERS,
2133+ LIST_PROP_USERS,
2134+};
2135+
2136+enum
2137+{
2138+ USER_PROP_0,
2139+ USER_PROP_COMMON_USER,
2140+ USER_PROP_NAME,
2141+ USER_PROP_REAL_NAME,
2142+ USER_PROP_DISPLAY_NAME,
2143+ USER_PROP_HOME_DIRECTORY,
2144+ USER_PROP_IMAGE,
2145+ USER_PROP_BACKGROUND,
2146+ USER_PROP_LANGUAGE,
2147+ USER_PROP_LAYOUT,
2148+ USER_PROP_LAYOUTS,
2149+ USER_PROP_SESSION,
2150+ USER_PROP_LOGGED_IN,
2151+ USER_PROP_HAS_MESSAGES
2152+};
2153+
2154+enum
2155+{
2156+ USER_ADDED,
2157+ USER_CHANGED,
2158+ USER_REMOVED,
2159+ LAST_LIST_SIGNAL
2160+};
2161+static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
2162+
2163+enum
2164+{
2165+ CHANGED,
2166+ LAST_USER_SIGNAL
2167+};
2168+static guint user_signals[LAST_USER_SIGNAL] = { 0 };
2169+
2170+typedef struct
2171+{
2172+ gboolean initialized;
2173+
2174+ /* Wrapper list, kept locally to preserve transfer-none promises */
2175+ GList *lightdm_list;
2176+} LightDMUserListPrivate;
2177+
2178+typedef struct
2179+{
2180+ CommonUser *common_user;
2181+} LightDMUserPrivate;
2182+
2183+G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
2184+G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
2185+
2186+#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
2187+#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
2188+
2189+static LightDMUserList *singleton = NULL;
2190+
2191+/**
2192+ * lightdm_user_list_get_instance:
2193+ *
2194+ * Get the user list.
2195+ *
2196+ * Return value: (transfer none): the #LightDMUserList
2197+ **/
2198+LightDMUserList *
2199+lightdm_user_list_get_instance (void)
2200+{
2201+ if (!singleton)
2202+ singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
2203+ return singleton;
2204+}
2205+
2206+static void
2207+user_changed_cb (CommonUser *common_user, LightDMUser *lightdm_user)
2208+{
2209+ g_signal_emit (lightdm_user, user_signals[CHANGED], 0);
2210+}
2211+
2212+static LightDMUser *
2213+wrap_common_user (CommonUser *user)
2214+{
2215+ LightDMUser *lightdm_user = g_object_new (LIGHTDM_TYPE_USER, "common-user", user, NULL);
2216+ g_signal_connect (user, "changed", G_CALLBACK (user_changed_cb), lightdm_user);
2217+ return lightdm_user;
2218+}
2219+
2220+static void
2221+user_list_added_cb (CommonUserList *common_list, CommonUser *common_user, LightDMUserList *user_list)
2222+{
2223+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
2224+ GList *common_users = common_user_list_get_users (common_list);
2225+ LightDMUser *lightdm_user = wrap_common_user (common_user);
2226+ priv->lightdm_list = g_list_insert (priv->lightdm_list, lightdm_user, g_list_index (common_users, common_user));
2227+ g_signal_emit (user_list, list_signals[USER_ADDED], 0, lightdm_user);
2228+}
2229+
2230+static void
2231+user_list_changed_cb (CommonUserList *common_list, CommonUser *common_user, LightDMUserList *user_list)
2232+{
2233+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
2234+ GList *common_users = common_user_list_get_users (common_list);
2235+ LightDMUser *lightdm_user = g_list_nth_data (priv->lightdm_list, g_list_index (common_users, common_user));
2236+ g_signal_emit (user_list, list_signals[USER_CHANGED], 0, lightdm_user);
2237+}
2238+
2239+static void
2240+user_list_removed_cb (CommonUserList *common_list, CommonUser *common_user, LightDMUserList *user_list)
2241+{
2242+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
2243+ GList *link;
2244+
2245+ for (link = priv->lightdm_list; link; link = link->next)
2246+ {
2247+ LightDMUser *lightdm_user = link->data;
2248+ LightDMUserPrivate *user_priv = GET_USER_PRIVATE (lightdm_user);
2249+ if (user_priv->common_user == common_user)
2250+ {
2251+ priv->lightdm_list = g_list_delete_link (priv->lightdm_list, link);
2252+ g_signal_emit (user_list, list_signals[USER_REMOVED], 0, lightdm_user);
2253+ g_object_unref (lightdm_user);
2254+ break;
2255+ }
2256+ }
2257+}
2258+
2259+static void
2260+initialize_user_list_if_needed (LightDMUserList *user_list)
2261+{
2262+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
2263+ GList *common_users;
2264+ GList *link;
2265+
2266+ if (priv->initialized)
2267+ return;
2268+
2269+ common_users = common_user_list_get_users (common_user_list_get_instance ());
2270+ for (link = common_users; link; link = link->next)
2271+ {
2272+ CommonUser *user = link->data;
2273+ LightDMUser *lightdm_user = wrap_common_user (user);
2274+ priv->lightdm_list = g_list_prepend (priv->lightdm_list, lightdm_user);
2275+ }
2276+ priv->lightdm_list = g_list_reverse (priv->lightdm_list);
2277+
2278+ CommonUserList *common_list = common_user_list_get_instance ();
2279+ g_signal_connect (common_list, "user-added", G_CALLBACK (user_list_added_cb), user_list);
2280+ g_signal_connect (common_list, "user-changed", G_CALLBACK (user_list_changed_cb), user_list);
2281+ g_signal_connect (common_list, "user-removed", G_CALLBACK (user_list_removed_cb), user_list);
2282+
2283+ priv->initialized = TRUE;
2284+}
2285+
2286+/**
2287+ * lightdm_user_list_get_length:
2288+ * @user_list: a #LightDMUserList
2289+ *
2290+ * Return value: The number of users able to log in
2291+ **/
2292+gint
2293+lightdm_user_list_get_length (LightDMUserList *user_list)
2294+{
2295+ g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
2296+ initialize_user_list_if_needed (user_list);
2297+ return g_list_length (GET_LIST_PRIVATE (user_list)->lightdm_list);
2298+}
2299+
2300+/**
2301+ * lightdm_user_list_get_users:
2302+ * @user_list: A #LightDMUserList
2303+ *
2304+ * Get a list of users to present to the user. This list may be a subset of the
2305+ * available users and may be empty depending on the server configuration.
2306+ *
2307+ * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user.
2308+ **/
2309+GList *
2310+lightdm_user_list_get_users (LightDMUserList *user_list)
2311+{
2312+ g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
2313+ initialize_user_list_if_needed (user_list);
2314+ return GET_LIST_PRIVATE (user_list)->lightdm_list;
2315+}
2316+
2317+/**
2318+ * lightdm_user_list_get_user_by_name:
2319+ * @user_list: A #LightDMUserList
2320+ * @username: Name of user to get.
2321+ *
2322+ * Get infomation about a given user or #NULL if this user doesn't exist.
2323+ *
2324+ * Return value: (transfer none): A #LightDMUser entry for the given user.
2325+ **/
2326+LightDMUser *
2327+lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
2328+{
2329+ GList *link;
2330+
2331+ g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
2332+ g_return_val_if_fail (username != NULL, NULL);
2333+
2334+ initialize_user_list_if_needed (user_list);
2335+
2336+ for (link = GET_LIST_PRIVATE (user_list)->lightdm_list; link; link = link->next)
2337+ {
2338+ LightDMUser *user = link->data;
2339+ if (g_strcmp0 (lightdm_user_get_name (user), username) == 0)
2340+ return user;
2341+ }
2342+
2343+ return NULL;
2344+}
2345+
2346+static void
2347+lightdm_user_list_init (LightDMUserList *user_list)
2348+{
2349+}
2350+
2351+static void
2352+lightdm_user_list_set_property (GObject *object,
2353+ guint prop_id,
2354+ const GValue *value,
2355+ GParamSpec *pspec)
2356+{
2357+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2358+}
2359+
2360+static void
2361+lightdm_user_list_get_property (GObject *object,
2362+ guint prop_id,
2363+ GValue *value,
2364+ GParamSpec *pspec)
2365+{
2366+ LightDMUserList *self;
2367+
2368+ self = LIGHTDM_USER_LIST (object);
2369+
2370+ switch (prop_id)
2371+ {
2372+ case LIST_PROP_NUM_USERS:
2373+ g_value_set_int (value, lightdm_user_list_get_length (self));
2374+ break;
2375+ default:
2376+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2377+ break;
2378+ }
2379+}
2380+
2381+static void
2382+lightdm_user_list_finalize (GObject *object)
2383+{
2384+ LightDMUserList *self = LIGHTDM_USER_LIST (object);
2385+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
2386+
2387+ g_list_free_full (priv->lightdm_list, g_object_unref);
2388+
2389+ G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
2390+}
2391+
2392+static void
2393+lightdm_user_list_class_init (LightDMUserListClass *klass)
2394+{
2395+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
2396+
2397+ g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
2398+
2399+ object_class->set_property = lightdm_user_list_set_property;
2400+ object_class->get_property = lightdm_user_list_get_property;
2401+ object_class->finalize = lightdm_user_list_finalize;
2402+
2403+ g_object_class_install_property (object_class,
2404+ LIST_PROP_NUM_USERS,
2405+ g_param_spec_int ("num-users",
2406+ "num-users",
2407+ "Number of login users",
2408+ 0, G_MAXINT, 0,
2409+ G_PARAM_READABLE));
2410+ /**
2411+ * LightDMUserList::user-added:
2412+ * @user_list: A #LightDMUserList
2413+ * @user: The #LightDM user that has been added.
2414+ *
2415+ * The ::user-added signal gets emitted when a user account is created.
2416+ **/
2417+ list_signals[USER_ADDED] =
2418+ g_signal_new ("user-added",
2419+ G_TYPE_FROM_CLASS (klass),
2420+ G_SIGNAL_RUN_LAST,
2421+ G_STRUCT_OFFSET (LightDMUserListClass, user_added),
2422+ NULL, NULL,
2423+ NULL,
2424+ G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
2425+
2426+ /**
2427+ * LightDMUserList::user-changed:
2428+ * @user_list: A #LightDMUserList
2429+ * @user: The #LightDM user that has been changed.
2430+ *
2431+ * The ::user-changed signal gets emitted when a user account is modified.
2432+ **/
2433+ list_signals[USER_CHANGED] =
2434+ g_signal_new ("user-changed",
2435+ G_TYPE_FROM_CLASS (klass),
2436+ G_SIGNAL_RUN_LAST,
2437+ G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
2438+ NULL, NULL,
2439+ NULL,
2440+ G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
2441+
2442+ /**
2443+ * LightDMUserList::user-removed:
2444+ * @user_list: A #LightDMUserList
2445+ * @user: The #LightDM user that has been removed.
2446+ *
2447+ * The ::user-removed signal gets emitted when a user account is removed.
2448+ **/
2449+ list_signals[USER_REMOVED] =
2450+ g_signal_new ("user-removed",
2451+ G_TYPE_FROM_CLASS (klass),
2452+ G_SIGNAL_RUN_LAST,
2453+ G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
2454+ NULL, NULL,
2455+ NULL,
2456+ G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
2457+}
2458+
2459+/**
2460+ * lightdm_user_get_name:
2461+ * @user: A #LightDMUser
2462+ *
2463+ * Get the name of a user.
2464+ *
2465+ * Return value: The name of the given user
2466+ **/
2467+const gchar *
2468+lightdm_user_get_name (LightDMUser *user)
2469+{
2470+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2471+ return common_user_get_name (GET_USER_PRIVATE (user)->common_user);
2472+}
2473+
2474+/**
2475+ * lightdm_user_get_real_name:
2476+ * @user: A #LightDMUser
2477+ *
2478+ * Get the real name of a user.
2479+ *
2480+ * Return value: The real name of the given user
2481+ **/
2482+const gchar *
2483+lightdm_user_get_real_name (LightDMUser *user)
2484+{
2485+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2486+ return common_user_get_real_name (GET_USER_PRIVATE (user)->common_user);
2487+}
2488+
2489+/**
2490+ * lightdm_user_get_display_name:
2491+ * @user: A #LightDMUser
2492+ *
2493+ * Get the display name of a user.
2494+ *
2495+ * Return value: The display name of the given user
2496+ **/
2497+const gchar *
2498+lightdm_user_get_display_name (LightDMUser *user)
2499+{
2500+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2501+ return common_user_get_display_name (GET_USER_PRIVATE (user)->common_user);
2502+}
2503+
2504+/**
2505+ * lightdm_user_get_home_directory:
2506+ * @user: A #LightDMUser
2507+ *
2508+ * Get the home directory for a user.
2509+ *
2510+ * Return value: The users home directory
2511+ */
2512+const gchar *
2513+lightdm_user_get_home_directory (LightDMUser *user)
2514+{
2515+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2516+ return common_user_get_home_directory (GET_USER_PRIVATE (user)->common_user);
2517+}
2518+
2519+/**
2520+ * lightdm_user_get_image:
2521+ * @user: A #LightDMUser
2522+ *
2523+ * Get the image URI for a user.
2524+ *
2525+ * Return value: The image URI for the given user or #NULL if no URI
2526+ **/
2527+const gchar *
2528+lightdm_user_get_image (LightDMUser *user)
2529+{
2530+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2531+ return common_user_get_image (GET_USER_PRIVATE (user)->common_user);
2532+}
2533+
2534+/**
2535+ * lightdm_user_get_background:
2536+ * @user: A #LightDMUser
2537+ *
2538+ * Get the background file path for a user.
2539+ *
2540+ * Return value: The background file path for the given user or #NULL if no path
2541+ **/
2542+const gchar *
2543+lightdm_user_get_background (LightDMUser *user)
2544+{
2545+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2546+ return common_user_get_background (GET_USER_PRIVATE (user)->common_user);
2547+}
2548+
2549+/**
2550+ * lightdm_user_get_language:
2551+ * @user: A #LightDMUser
2552+ *
2553+ * Get the language for a user.
2554+ *
2555+ * 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.
2556+ **/
2557+const gchar *
2558+lightdm_user_get_language (LightDMUser *user)
2559+{
2560+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2561+ return common_user_get_language (GET_USER_PRIVATE (user)->common_user);
2562+}
2563+
2564+/**
2565+ * lightdm_user_get_layout:
2566+ * @user: A #LightDMUser
2567+ *
2568+ * Get the keyboard layout for a user.
2569+ *
2570+ * 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.
2571+ **/
2572+const gchar *
2573+lightdm_user_get_layout (LightDMUser *user)
2574+{
2575+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2576+ return common_user_get_layout (GET_USER_PRIVATE (user)->common_user);
2577+}
2578+
2579+/**
2580+ * lightdm_user_get_layouts:
2581+ * @user: A #LightDMUser
2582+ *
2583+ * Get the configured keyboard layouts for a user.
2584+ *
2585+ * 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.
2586+ **/
2587+const gchar * const *
2588+lightdm_user_get_layouts (LightDMUser *user)
2589+{
2590+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2591+ return common_user_get_layouts (GET_USER_PRIVATE (user)->common_user);
2592+}
2593+
2594+/**
2595+ * lightdm_user_get_session:
2596+ * @user: A #LightDMUser
2597+ *
2598+ * Get the session for a user.
2599+ *
2600+ * Return value: The session for the given user or #NULL if using system defaults.
2601+ **/
2602+const gchar *
2603+lightdm_user_get_session (LightDMUser *user)
2604+{
2605+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
2606+ return common_user_get_session (GET_USER_PRIVATE (user)->common_user);
2607+}
2608+
2609+/**
2610+ * lightdm_user_get_logged_in:
2611+ * @user: A #LightDMUser
2612+ *
2613+ * Check if a user is logged in.
2614+ *
2615+ * Return value: #TRUE if the user is currently logged in.
2616+ **/
2617+gboolean
2618+lightdm_user_get_logged_in (LightDMUser *user)
2619+{
2620+ g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
2621+ return common_user_get_logged_in (GET_USER_PRIVATE (user)->common_user);
2622+}
2623+
2624+/**
2625+ * lightdm_user_get_has_messages:
2626+ * @user: A #LightDMUser
2627+ *
2628+ * Check if a user has waiting messages.
2629+ *
2630+ * Return value: #TRUE if the user has waiting messages.
2631+ **/
2632+gboolean
2633+lightdm_user_get_has_messages (LightDMUser *user)
2634+{
2635+ g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
2636+ return common_user_get_has_messages (GET_USER_PRIVATE (user)->common_user);
2637+}
2638+
2639+static void
2640+lightdm_user_init (LightDMUser *user)
2641+{
2642+}
2643+
2644+static void
2645+lightdm_user_set_property (GObject *object,
2646+ guint prop_id,
2647+ const GValue *value,
2648+ GParamSpec *pspec)
2649+{
2650+ LightDMUser *self = LIGHTDM_USER (object);
2651+ LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
2652+
2653+ switch (prop_id)
2654+ {
2655+ case USER_PROP_COMMON_USER:
2656+ priv->common_user = g_value_dup_object (value);
2657+ break;
2658+ default:
2659+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2660+ break;
2661+ }
2662+}
2663+
2664+static void
2665+lightdm_user_get_property (GObject *object,
2666+ guint prop_id,
2667+ GValue *value,
2668+ GParamSpec *pspec)
2669+{
2670+ LightDMUser *self;
2671+
2672+ self = LIGHTDM_USER (object);
2673+
2674+ switch (prop_id)
2675+ {
2676+ case USER_PROP_NAME:
2677+ g_value_set_string (value, lightdm_user_get_name (self));
2678+ break;
2679+ case USER_PROP_REAL_NAME:
2680+ g_value_set_string (value, lightdm_user_get_real_name (self));
2681+ break;
2682+ case USER_PROP_DISPLAY_NAME:
2683+ g_value_set_string (value, lightdm_user_get_display_name (self));
2684+ break;
2685+ case USER_PROP_HOME_DIRECTORY:
2686+ g_value_set_string (value, lightdm_user_get_home_directory (self));
2687+ break;
2688+ case USER_PROP_IMAGE:
2689+ g_value_set_string (value, lightdm_user_get_image (self));
2690+ break;
2691+ case USER_PROP_BACKGROUND:
2692+ g_value_set_string (value, lightdm_user_get_background (self));
2693+ break;
2694+ case USER_PROP_LANGUAGE:
2695+ g_value_set_string (value, lightdm_user_get_language (self));
2696+ break;
2697+ case USER_PROP_LAYOUT:
2698+ g_value_set_string (value, lightdm_user_get_layout (self));
2699+ break;
2700+ case USER_PROP_LAYOUTS:
2701+ g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self)));
2702+ break;
2703+ case USER_PROP_SESSION:
2704+ g_value_set_string (value, lightdm_user_get_session (self));
2705+ break;
2706+ case USER_PROP_LOGGED_IN:
2707+ g_value_set_boolean (value, lightdm_user_get_logged_in (self));
2708+ break;
2709+ case USER_PROP_HAS_MESSAGES:
2710+ g_value_set_boolean (value, lightdm_user_get_has_messages (self));
2711+ break;
2712+ default:
2713+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2714+ break;
2715+ }
2716+}
2717+
2718+static void
2719+lightdm_user_finalize (GObject *object)
2720+{
2721+ LightDMUser *self = LIGHTDM_USER (object);
2722+ LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
2723+
2724+ g_object_unref (priv->common_user);
2725+
2726+ G_OBJECT_CLASS (lightdm_user_parent_class)->finalize (object);
2727+}
2728+
2729+static void
2730+lightdm_user_class_init (LightDMUserClass *klass)
2731+{
2732+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
2733+
2734+ g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
2735+
2736+ object_class->set_property = lightdm_user_set_property;
2737+ object_class->get_property = lightdm_user_get_property;
2738+ object_class->finalize = lightdm_user_finalize;
2739+
2740+ g_object_class_install_property (object_class,
2741+ USER_PROP_COMMON_USER,
2742+ g_param_spec_object ("common-user",
2743+ "common-user",
2744+ "Internal user object",
2745+ COMMON_TYPE_USER,
2746+ G_PARAM_PRIVATE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_WRITABLE));
2747+ g_object_class_install_property (object_class,
2748+ USER_PROP_NAME,
2749+ g_param_spec_string ("name",
2750+ "name",
2751+ "Username",
2752+ NULL,
2753+ G_PARAM_READWRITE));
2754+ g_object_class_install_property (object_class,
2755+ USER_PROP_REAL_NAME,
2756+ g_param_spec_string ("real-name",
2757+ "real-name",
2758+ "Users real name",
2759+ NULL,
2760+ G_PARAM_READWRITE));
2761+ g_object_class_install_property (object_class,
2762+ USER_PROP_DISPLAY_NAME,
2763+ g_param_spec_string ("display-name",
2764+ "display-name",
2765+ "Users display name",
2766+ NULL,
2767+ G_PARAM_READABLE));
2768+ g_object_class_install_property (object_class,
2769+ USER_PROP_HOME_DIRECTORY,
2770+ g_param_spec_string ("home-directory",
2771+ "home-directory",
2772+ "Home directory",
2773+ NULL,
2774+ G_PARAM_READWRITE));
2775+ g_object_class_install_property (object_class,
2776+ USER_PROP_IMAGE,
2777+ g_param_spec_string ("image",
2778+ "image",
2779+ "Avatar image",
2780+ NULL,
2781+ G_PARAM_READWRITE));
2782+ g_object_class_install_property (object_class,
2783+ USER_PROP_BACKGROUND,
2784+ g_param_spec_string ("background",
2785+ "background",
2786+ "User background",
2787+ NULL,
2788+ G_PARAM_READWRITE));
2789+ g_object_class_install_property (object_class,
2790+ USER_PROP_LANGUAGE,
2791+ g_param_spec_string ("language",
2792+ "language",
2793+ "Language used by this user",
2794+ NULL,
2795+ G_PARAM_READABLE));
2796+ g_object_class_install_property (object_class,
2797+ USER_PROP_LAYOUT,
2798+ g_param_spec_string ("layout",
2799+ "layout",
2800+ "Keyboard layout used by this user",
2801+ NULL,
2802+ G_PARAM_READABLE));
2803+ g_object_class_install_property (object_class,
2804+ USER_PROP_LAYOUTS,
2805+ g_param_spec_boxed ("layouts",
2806+ "layouts",
2807+ "Keyboard layouts used by this user",
2808+ G_TYPE_STRV,
2809+ G_PARAM_READABLE));
2810+ g_object_class_install_property (object_class,
2811+ USER_PROP_SESSION,
2812+ g_param_spec_string ("session",
2813+ "session",
2814+ "Session used by this user",
2815+ NULL,
2816+ G_PARAM_READABLE));
2817+ g_object_class_install_property (object_class,
2818+ USER_PROP_LOGGED_IN,
2819+ g_param_spec_boolean ("logged-in",
2820+ "logged-in",
2821+ "TRUE if the user is currently in a session",
2822+ FALSE,
2823+ G_PARAM_READWRITE));
2824+ g_object_class_install_property (object_class,
2825+ USER_PROP_LOGGED_IN,
2826+ g_param_spec_boolean ("has-messages",
2827+ "has-messages",
2828+ "TRUE if the user is has waiting messages",
2829+ FALSE,
2830+ G_PARAM_READWRITE));
2831+
2832+ /**
2833+ * LightDMUser::changed:
2834+ * @user: A #LightDMUser
2835+ *
2836+ * The ::changed signal gets emitted this user account is modified.
2837+ **/
2838+ user_signals[CHANGED] =
2839+ g_signal_new ("changed",
2840+ G_TYPE_FROM_CLASS (klass),
2841+ G_SIGNAL_RUN_LAST,
2842+ G_STRUCT_OFFSET (LightDMUserClass, changed),
2843+ NULL, NULL,
2844+ NULL,
2845+ G_TYPE_NONE, 0);
2846+}
2847
2848=== modified file 'src/Makefile.am'
2849--- src/Makefile.am 2014-02-06 15:35:02 +0000
2850+++ src/Makefile.am 2014-02-08 22:36:44 +0000
2851@@ -4,16 +4,12 @@
2852 lightdm_SOURCES = \
2853 accounts.c \
2854 accounts.h \
2855- configuration.c \
2856- configuration.h \
2857 console-kit.c \
2858 console-kit.h \
2859 display-manager.c \
2860 display-manager.h \
2861 display-server.c \
2862 display-server.h \
2863- dmrc.c \
2864- dmrc.h \
2865 greeter.c \
2866 greeter.h \
2867 guest-account.c \
2868@@ -27,8 +23,6 @@
2869 mir-server.h \
2870 plymouth.c \
2871 plymouth.h \
2872- privileges.c \
2873- privileges.h \
2874 process.c \
2875 process.h \
2876 seat.c \
2877@@ -80,6 +74,7 @@
2878 lightdm_CFLAGS = \
2879 $(WARN_CFLAGS) \
2880 $(LIGHTDM_CFLAGS) \
2881+ -I"$(top_srcdir)/common" \
2882 -DSBIN_DIR=\"$(sbindir)\" \
2883 -DCONFIG_DIR=\"$(sysconfdir)/lightdm\" \
2884 -DLOG_DIR=\"$(localstatedir)/log/lightdm\" \
2885@@ -92,6 +87,7 @@
2886
2887 lightdm_LDADD = \
2888 $(LIGHTDM_LIBS) \
2889+ $(top_builddir)/common/libcommon.la \
2890 -lgcrypt \
2891 -lpam
2892
2893
2894=== modified file 'src/accounts.c'
2895--- src/accounts.c 2013-06-17 23:14:43 +0000
2896+++ src/accounts.c 2014-02-08 22:36:44 +0000
2897@@ -10,273 +10,34 @@
2898 * license.
2899 */
2900
2901-#include <errno.h>
2902 #include <pwd.h>
2903 #include <stdlib.h>
2904-#include <string.h>
2905
2906 #include "accounts.h"
2907-#include "dmrc.h"
2908+#include "user-list.h"
2909
2910 struct UserPrivate
2911 {
2912- /* Name of user */
2913- gchar *name;
2914-
2915- /* Accounts interface proxy */
2916- GDBusProxy *proxy;
2917-
2918- /* User ID */
2919- uid_t uid;
2920-
2921- /* Group ID */
2922- gid_t gid;
2923-
2924- /* GECOS information */
2925- gchar *gecos;
2926-
2927- /* Home directory */
2928- gchar *home_directory;
2929-
2930- /* Shell */
2931- gchar *shell;
2932-
2933- /* Language */
2934- gchar *language;
2935-
2936- /* X session */
2937- gchar *xsession;
2938+ /* Internal user object */
2939+ CommonUser *common_user;
2940 };
2941
2942 G_DEFINE_TYPE (User, user, G_TYPE_OBJECT);
2943
2944-/* Connection to AccountsService */
2945-static GDBusProxy *accounts_service_proxy = NULL;
2946-static gboolean have_accounts_service_proxy = FALSE;
2947-
2948-static gboolean
2949-call_method (GDBusProxy *proxy, const gchar *method, GVariant *args,
2950- const gchar *expected, GVariant **result)
2951-{
2952- GVariant *answer;
2953- GError *error = NULL;
2954-
2955- if (!proxy)
2956- return FALSE;
2957-
2958- answer = g_dbus_proxy_call_sync (proxy,
2959- method,
2960- args,
2961- G_DBUS_CALL_FLAGS_NONE,
2962- -1,
2963- NULL,
2964- &error);
2965- if (error)
2966- g_warning ("Could not call %s: %s", method, error->message);
2967- g_clear_error (&error);
2968-
2969- if (!answer)
2970- return FALSE;
2971-
2972- if (!g_variant_is_of_type (answer, G_VARIANT_TYPE (expected)))
2973- {
2974- g_warning ("Unexpected response from %s: %s",
2975- method, g_variant_get_type_string (answer));
2976- g_variant_unref (answer);
2977- return FALSE;
2978- }
2979-
2980- if (result)
2981- *result = answer;
2982- else
2983- g_variant_unref (answer);
2984-
2985- return TRUE;
2986-}
2987-
2988-static gboolean
2989-get_property (GDBusProxy *proxy, const gchar *property,
2990- const gchar *expected, GVariant **result)
2991-{
2992- GVariant *answer;
2993-
2994- answer = g_dbus_proxy_get_cached_property (proxy, property);
2995-
2996- if (!answer)
2997- {
2998- g_warning ("Could not get accounts property %s", property);
2999- return FALSE;
3000- }
3001-
3002- if (!g_variant_is_of_type (answer, G_VARIANT_TYPE (expected)))
3003- {
3004- g_warning ("Unexpected accounts property type for %s: %s",
3005- property, g_variant_get_type_string (answer));
3006- g_variant_unref (answer);
3007- return FALSE;
3008- }
3009-
3010- if (result)
3011- *result = answer;
3012- else
3013- g_variant_unref (answer);
3014- return TRUE;
3015-}
3016-
3017-static void
3018-save_string_to_dmrc (const gchar *username, const gchar *group,
3019- const gchar *key, const gchar *value)
3020-{
3021- GKeyFile *dmrc;
3022-
3023- dmrc = dmrc_load (username);
3024- g_key_file_set_string (dmrc, group, key, value);
3025- dmrc_save (dmrc, username);
3026-
3027- g_key_file_free (dmrc);
3028-}
3029-
3030-static gchar *
3031-get_string_from_dmrc (const gchar *username, const gchar *group,
3032- const gchar *key)
3033-{
3034- GKeyFile *dmrc;
3035- gchar *value;
3036-
3037- dmrc = dmrc_load (username);
3038- value = g_key_file_get_string (dmrc, group, key, NULL);
3039-
3040- g_key_file_free (dmrc);
3041- return value;
3042-}
3043-
3044-static GDBusProxy *
3045-get_accounts_service_proxy (void)
3046-{
3047- GError *error = NULL;
3048-
3049- if (have_accounts_service_proxy)
3050- return accounts_service_proxy;
3051-
3052- have_accounts_service_proxy = TRUE;
3053- accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
3054- G_DBUS_PROXY_FLAGS_NONE,
3055- NULL,
3056- "org.freedesktop.Accounts",
3057- "/org/freedesktop/Accounts",
3058- "org.freedesktop.Accounts",
3059- NULL, &error);
3060- if (error)
3061- g_warning ("Could not get accounts proxy: %s", error->message);
3062- g_clear_error (&error);
3063-
3064- if (accounts_service_proxy)
3065- {
3066- gchar *name;
3067- name = g_dbus_proxy_get_name_owner (accounts_service_proxy);
3068- if (!name)
3069- {
3070- g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file");
3071- g_object_unref (accounts_service_proxy);
3072- accounts_service_proxy = NULL;
3073- }
3074- g_free (name);
3075- }
3076-
3077- return accounts_service_proxy;
3078-}
3079-
3080-static GDBusProxy *
3081-get_accounts_proxy_for_user (const gchar *user)
3082-{
3083- GDBusProxy *proxy;
3084- GError *error = NULL;
3085- GVariant *result;
3086- gboolean success;
3087- gchar *user_path = NULL;
3088-
3089- g_return_val_if_fail (user != NULL, NULL);
3090-
3091- proxy = get_accounts_service_proxy ();
3092- if (!proxy)
3093- return NULL;
3094-
3095- success = call_method (proxy, "FindUserByName", g_variant_new ("(s)", user), "(o)", &result);
3096-
3097- if (!success)
3098- return NULL;
3099-
3100- g_variant_get (result, "(o)", &user_path);
3101- g_variant_unref (result);
3102-
3103- if (!user_path)
3104- return NULL;
3105-
3106- proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
3107- G_DBUS_PROXY_FLAGS_NONE,
3108- NULL,
3109- "org.freedesktop.Accounts",
3110- user_path,
3111- "org.freedesktop.Accounts.User",
3112- NULL, &error);
3113- if (error)
3114- g_warning ("Could not get accounts user proxy: %s", error->message);
3115- g_clear_error (&error);
3116- g_free (user_path);
3117-
3118- return proxy;
3119-}
3120-
3121-static User *
3122-user_from_passwd (struct passwd *user_info)
3123-{
3124- User *user;
3125-
3126- user = g_object_new (USER_TYPE, NULL);
3127- user->priv->name = g_strdup (user_info->pw_name);
3128- user->priv->uid = user_info->pw_uid;
3129- user->priv->gid = user_info->pw_gid;
3130- user->priv->gecos = g_strdup (user_info->pw_gecos);
3131- user->priv->home_directory = g_strdup (user_info->pw_dir);
3132- user->priv->shell = g_strdup (user_info->pw_shell);
3133- user->priv->proxy = get_accounts_proxy_for_user (user->priv->name);
3134-
3135- return user;
3136-}
3137-
3138 User *
3139 accounts_get_user_by_name (const gchar *username)
3140 {
3141- struct passwd *user_info;
3142 User *user = NULL;
3143+ CommonUser *common_user;
3144
3145 g_return_val_if_fail (username != NULL, NULL);
3146
3147- errno = 0;
3148- user_info = getpwnam (username);
3149- if (user_info)
3150- user = user_from_passwd (user_info);
3151-
3152- if (!user && errno != 0)
3153- g_warning ("Unable to get information on user %s: %s", username, strerror (errno));
3154-
3155- return user;
3156-}
3157-
3158-User *
3159-accounts_get_user_by_uid (uid_t uid)
3160-{
3161- User *user = NULL;
3162-
3163- errno = 0;
3164- struct passwd *user_info;
3165-
3166- user_info = getpwuid (uid);
3167- if (user_info)
3168- user = user_from_passwd (user_info);
3169-
3170- if (!user && errno != 0)
3171- g_warning ("Unable to get information on user %d: %s", uid, strerror (errno));
3172+ common_user = common_user_list_get_user_by_name (common_user_list_get_instance (), username);
3173+ if (common_user != NULL)
3174+ {
3175+ user = g_object_new (USER_TYPE, NULL);
3176+ user->priv->common_user = common_user;
3177+ }
3178
3179 return user;
3180 }
3181@@ -284,136 +45,74 @@
3182 User *
3183 accounts_get_current_user ()
3184 {
3185- return user_from_passwd (getpwuid (getuid ()));
3186+ struct passwd *entry = getpwuid (getuid ());
3187+ if (entry != NULL)
3188+ return accounts_get_user_by_name (entry->pw_name);
3189+ else
3190+ return NULL;
3191 }
3192
3193 const gchar *
3194 user_get_name (User *user)
3195 {
3196 g_return_val_if_fail (user != NULL, NULL);
3197- return user->priv->name;
3198+ return common_user_get_name (user->priv->common_user);
3199 }
3200
3201 uid_t
3202 user_get_uid (User *user)
3203 {
3204 g_return_val_if_fail (user != NULL, 0);
3205- return user->priv->uid;
3206+ return common_user_get_uid (user->priv->common_user);
3207 }
3208
3209 gid_t
3210 user_get_gid (User *user)
3211 {
3212 g_return_val_if_fail (user != NULL, 0);
3213- return user->priv->gid;
3214-}
3215-
3216-const gchar *
3217-user_get_gecos (User *user)
3218-{
3219- g_return_val_if_fail (user != NULL, NULL);
3220- return user->priv->gecos;
3221+ return common_user_get_gid (user->priv->common_user);
3222 }
3223
3224 const gchar *
3225 user_get_home_directory (User *user)
3226 {
3227 g_return_val_if_fail (user != NULL, NULL);
3228- return user->priv->home_directory;
3229+ return common_user_get_home_directory (user->priv->common_user);
3230 }
3231
3232 const gchar *
3233 user_get_shell (User *user)
3234 {
3235 g_return_val_if_fail (user != NULL, NULL);
3236- return user->priv->shell;
3237+ return common_user_get_shell (user->priv->common_user);
3238 }
3239
3240 void
3241 user_set_language (User *user, const gchar *language)
3242 {
3243 g_return_if_fail (user != NULL);
3244-
3245- call_method (user->priv->proxy, "SetLanguage", g_variant_new ("(s)", language), "()", NULL);
3246- save_string_to_dmrc (user->priv->name, "Desktop", "Language", language);
3247+ common_user_set_language (user->priv->common_user, language);
3248 }
3249
3250 const gchar *
3251 user_get_language (User *user)
3252 {
3253- GVariant *variant, *inner;
3254- gboolean success;
3255-
3256 g_return_val_if_fail (user != NULL, NULL);
3257-
3258- g_free (user->priv->language);
3259- if (user->priv->proxy)
3260- {
3261- /* the "Language" property cannot be retrieved with get_property () here since it
3262- * uses g_dbus_proxy_get_cached_property () which would return the previous (cached) value
3263- * of the "Language" property
3264- */
3265- success = call_method (user->priv->proxy, "org.freedesktop.DBus.Properties.Get", g_variant_new ("(ss)", g_dbus_proxy_get_interface_name(user->priv->proxy), "Language"), "(v)", &variant);
3266- if (success)
3267- {
3268- g_variant_get (variant, "(v)", &inner);
3269- user->priv->language = g_variant_dup_string (inner, NULL);
3270- g_variant_unref (inner);
3271- g_variant_unref (variant);
3272- }
3273- else
3274- user->priv->language = NULL;
3275- }
3276- else
3277- user->priv->language = get_string_from_dmrc (user->priv->name, "Desktop", "Language");
3278-
3279- /* Treat a blank language as unset */
3280- if (g_strcmp0 (user->priv->language, "") == 0)
3281- {
3282- g_free (user->priv->language);
3283- user->priv->language = NULL;
3284- }
3285-
3286- return user->priv->language;
3287+ return common_user_get_language (user->priv->common_user);
3288 }
3289
3290 void
3291 user_set_xsession (User *user, const gchar *xsession)
3292 {
3293 g_return_if_fail (user != NULL);
3294-
3295- call_method (user->priv->proxy, "SetXSession", g_variant_new ("(s)", xsession), "()", NULL);
3296- save_string_to_dmrc (user->priv->name, "Desktop", "Session", xsession);
3297+ common_user_set_session (user->priv->common_user, xsession);
3298 }
3299
3300 const gchar *
3301 user_get_xsession (User *user)
3302 {
3303- GVariant *result;
3304-
3305 g_return_val_if_fail (user != NULL, NULL);
3306-
3307- g_free (user->priv->xsession);
3308- if (user->priv->proxy)
3309- {
3310- if (get_property (user->priv->proxy, "XSession", "s", &result))
3311- {
3312- g_variant_get (result, "s", &user->priv->xsession);
3313- g_variant_unref (result);
3314- }
3315- else
3316- user->priv->xsession = NULL;
3317- }
3318- else
3319- user->priv->xsession = get_string_from_dmrc (user->priv->name, "Desktop", "Session");
3320-
3321- if (g_strcmp0 (user->priv->xsession, "") == 0)
3322- {
3323- g_free (user->priv->xsession);
3324- user->priv->xsession = NULL;
3325- }
3326-
3327- return user->priv->xsession;
3328+ return common_user_get_session (user->priv->common_user);
3329 }
3330
3331 static void
3332@@ -429,38 +128,19 @@
3333
3334 self = USER (object);
3335
3336- if (self->priv->proxy)
3337- {
3338- g_object_unref (self->priv->proxy);
3339- self->priv->proxy = NULL;
3340- }
3341+ if (self->priv->common_user)
3342+ g_object_unref (self->priv->common_user);
3343+ self->priv->common_user = NULL;
3344
3345 G_OBJECT_CLASS (user_parent_class)->dispose (object);
3346 }
3347
3348 static void
3349-user_finalize (GObject *object)
3350-{
3351- User *self;
3352-
3353- self = USER (object);
3354-
3355- g_free (self->priv->name);
3356- g_free (self->priv->gecos);
3357- g_free (self->priv->home_directory);
3358- g_free (self->priv->shell);
3359- g_free (self->priv->language);
3360-
3361- G_OBJECT_CLASS (user_parent_class)->finalize (object);
3362-}
3363-
3364-static void
3365 user_class_init (UserClass *klass)
3366 {
3367 GObjectClass *object_class = G_OBJECT_CLASS (klass);
3368
3369 object_class->dispose = user_dispose;
3370- object_class->finalize = user_finalize;
3371
3372 g_type_class_add_private (klass, sizeof (UserPrivate));
3373 }
3374
3375=== modified file 'src/accounts.h'
3376--- src/accounts.h 2013-04-24 01:51:02 +0000
3377+++ src/accounts.h 2014-02-08 22:36:44 +0000
3378@@ -36,8 +36,6 @@
3379
3380 User *accounts_get_user_by_name (const gchar *username);
3381
3382-User *accounts_get_user_by_uid (uid_t uid);
3383-
3384 User *accounts_get_current_user (void);
3385
3386 GType user_get_type (void);
3387@@ -48,8 +46,6 @@
3388
3389 gid_t user_get_gid (User *user);
3390
3391-const gchar *user_get_gecos (User *user);
3392-
3393 const gchar *user_get_home_directory (User *user);
3394
3395 const gchar *user_get_shell (User *user);
3396
3397=== modified file 'src/lightdm.c'
3398--- src/lightdm.c 2013-11-25 21:40:16 +0000
3399+++ src/lightdm.c 2014-02-08 22:36:44 +0000
3400@@ -30,6 +30,7 @@
3401 #include "x-server.h"
3402 #include "process.h"
3403 #include "session-child.h"
3404+#include "user-list.h"
3405
3406 static gchar *config_path = NULL;
3407 static GMainLoop *loop = NULL;
3408@@ -42,7 +43,7 @@
3409 static VNCServer *vnc_server = NULL;
3410 static guint bus_id = 0;
3411 static GDBusConnection *bus = NULL;
3412-static guint bus_id;
3413+static guint reg_id = 0;
3414 static GDBusNodeInfo *seat_info;
3415 static GHashTable *seat_bus_entries = NULL;
3416 static guint seat_index = 0;
3417@@ -787,13 +788,13 @@
3418 session_info = g_dbus_node_info_new_for_xml (session_interface, NULL);
3419 g_assert (session_info != NULL);
3420
3421- bus_id = g_dbus_connection_register_object (connection,
3422+ reg_id = g_dbus_connection_register_object (connection,
3423 "/org/freedesktop/DisplayManager",
3424 display_manager_info->interfaces[0],
3425 &display_manager_vtable,
3426 NULL, NULL,
3427 &error);
3428- if (bus_id == 0)
3429+ if (reg_id == 0)
3430 g_warning ("Failed to register display manager: %s", error->message);
3431 g_clear_error (&error);
3432 g_dbus_node_info_unref (display_manager_info);
3433@@ -1319,11 +1320,15 @@
3434
3435 g_main_loop_run (loop);
3436
3437+ /* Clean up user list */
3438+ common_user_list_cleanup ();
3439+
3440 /* Clean up display manager */
3441 g_object_unref (display_manager);
3442 display_manager = NULL;
3443
3444 /* Remove D-Bus interface */
3445+ g_dbus_connection_unregister_object (bus, reg_id);
3446 g_bus_unown_name (bus_id);
3447 if (seat_bus_entries)
3448 g_hash_table_unref (seat_bus_entries);
3449
3450=== modified file 'src/session-child.c'
3451--- src/session-child.c 2014-02-06 15:04:11 +0000
3452+++ src/session-child.c 2014-02-08 22:36:44 +0000
3453@@ -512,7 +512,7 @@
3454
3455 drop_privileges = geteuid () == 0;
3456 if (drop_privileges)
3457- privileges_drop (user);
3458+ privileges_drop (user_get_uid (user), user_get_gid (user));
3459 result = x_authority_write (x_authority, XAUTH_WRITE_MODE_REPLACE, x_authority_filename, &error);
3460 if (drop_privileges)
3461 privileges_reclaim ();
3462@@ -660,7 +660,7 @@
3463
3464 drop_privileges = geteuid () == 0;
3465 if (drop_privileges)
3466- privileges_drop (user);
3467+ privileges_drop (user_get_uid (user), user_get_gid (user));
3468 result = x_authority_write (x_authority, XAUTH_WRITE_MODE_REMOVE, x_authority_filename, &error);
3469 if (drop_privileges)
3470 privileges_reclaim ();
3471
3472=== modified file 'tests/src/test-gobject-greeter.c'
3473--- tests/src/test-gobject-greeter.c 2013-10-30 17:30:12 +0000
3474+++ tests/src/test-gobject-greeter.c 2014-02-08 22:36:44 +0000
3475@@ -218,7 +218,7 @@
3476 if (strcmp (name, "LOG-USER") == 0)
3477 {
3478 LightDMUser *user;
3479- const gchar *username, *image, *background, *layout, *session;
3480+ const gchar *username, *image, *background, *language, *layout, *session;
3481 const gchar * const * layouts;
3482 gchar **fields = NULL;
3483 gchar *layouts_text;
3484@@ -237,6 +237,7 @@
3485 user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
3486 image = lightdm_user_get_image (user);
3487 background = lightdm_user_get_background (user);
3488+ language = lightdm_user_get_language (user);
3489 layout = lightdm_user_get_layout (user);
3490 layouts = lightdm_user_get_layouts (user);
3491 layouts_text = g_strjoinv (";", (gchar **) layouts);
3492@@ -255,7 +256,7 @@
3493 else if (strcmp (fields[i], "BACKGROUND") == 0)
3494 g_string_append_printf (status_text, " BACKGROUND=%s", background ? background : "");
3495 else if (strcmp (fields[i], "LANGUAGE") == 0)
3496- g_string_append_printf (status_text, " LANGUAGE=%s", lightdm_user_get_language (user));
3497+ g_string_append_printf (status_text, " LANGUAGE=%s", language ? language : "");
3498 else if (strcmp (fields[i], "LAYOUT") == 0)
3499 g_string_append_printf (status_text, " LAYOUT=%s", layout ? layout : "");
3500 else if (strcmp (fields[i], "LAYOUTS") == 0)
3501
3502=== modified file 'tests/src/test-runner.c'
3503--- tests/src/test-runner.c 2013-11-07 00:37:07 +0000
3504+++ tests/src/test-runner.c 2014-02-08 22:36:44 +0000
3505@@ -1715,6 +1715,15 @@
3506 user->xsession = g_strdup (xsession);
3507
3508 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
3509+
3510+ /* And notify others that it took */
3511+ g_dbus_connection_emit_signal (accounts_connection,
3512+ NULL,
3513+ user->path,
3514+ "org.freedesktop.Accounts.User",
3515+ "Changed",
3516+ g_variant_new ("()"),
3517+ NULL);
3518 }
3519 else
3520 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
3521@@ -1745,6 +1754,10 @@
3522 return g_variant_new_string (user->language ? user->language : "");
3523 else if (strcmp (property_name, "IconFile") == 0)
3524 return g_variant_new_string (user->image ? user->image : "");
3525+ else if (strcmp (property_name, "Shell") == 0)
3526+ return g_variant_new_string ("/bin/sh");
3527+ else if (strcmp (property_name, "Uid") == 0)
3528+ return g_variant_new_uint64 (user->uid);
3529 else if (strcmp (property_name, "XSession") == 0)
3530 return g_variant_new_string (user->xsession ? user->xsession : "");
3531 else if (strcmp (property_name, "XKeyboardLayouts") == 0)
3532@@ -1800,6 +1813,8 @@
3533 " <property name='BackgroundFile' type='s' access='read'/>"
3534 " <property name='Language' type='s' access='read'/>"
3535 " <property name='IconFile' type='s' access='read'/>"
3536+ " <property name='Shell' type='s' access='read'/>"
3537+ " <property name='Uid' type='t' access='read'/>"
3538 " <property name='XSession' type='s' access='read'/>"
3539 " <property name='XKeyboardLayouts' type='as' access='read'/>"
3540 " <property name='XHasMessages' type='b' access='read'/>"

Subscribers

People subscribed via source and target branches