]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
3089adfcbb8d51180729e0570cd6d4b83cb6a344
[sojka/lightdm.git] / liblightdm-gobject / greeter.c
1 /*
2  * Copyright (C) 2010 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; either version 3 of the License, or (at your option) any
8  * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
9  * license.
10  */
11
12 #include <config.h>
13
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <locale.h>
18 #include <sys/utsname.h>
19 #include <pwd.h>
20 #include <gio/gdesktopappinfo.h>
21 #include <security/pam_appl.h>
22 #include <libxklavier/xklavier.h>
23
24 #include "lightdm/greeter.h"
25 #include "user-private.h"
26
27 enum {
28     PROP_0,
29     PROP_HOSTNAME,
30     PROP_NUM_USERS,
31     PROP_USERS,
32     PROP_DEFAULT_LANGUAGE,
33     PROP_LAYOUTS,
34     PROP_LAYOUT,
35     PROP_SESSIONS,
36     PROP_DEFAULT_SESSION_HINT,
37     PROP_HIDE_USERS_HINT,
38     PROP_HAS_GUEST_ACCOUNT_HINT,
39     PROP_SELECT_USER_HINT,
40     PROP_SELECT_GUEST_HINT,
41     PROP_AUTOLOGIN_USER_HINT,
42     PROP_AUTOLOGIN_GUEST_HINT,
43     PROP_AUTOLOGIN_TIMEOUT_HINT,
44     PROP_AUTHENTICATION_USER,
45     PROP_IN_AUTHENTICATION,
46     PROP_IS_AUTHENTICATED,
47     PROP_CAN_SUSPEND,
48     PROP_CAN_HIBERNATE,
49     PROP_CAN_RESTART,
50     PROP_CAN_SHUTDOWN
51 };
52
53 enum {
54     CONNECTED,
55     SHOW_PROMPT,
56     SHOW_MESSAGE,
57     AUTHENTICATION_COMPLETE,
58     SESSION_FAILED,
59     AUTOLOGIN_TIMER_EXPIRED,
60     USER_ADDED,
61     USER_CHANGED,
62     USER_REMOVED,
63     QUIT,
64     LAST_SIGNAL
65 };
66 static guint signals[LAST_SIGNAL] = { 0 };
67
68 typedef struct
69 {
70     GDBusConnection *lightdm_bus;
71
72     GDBusConnection *system_bus;
73
74     GIOChannel *to_server_channel, *from_server_channel;
75     guint8 *read_buffer;
76     gsize n_read;
77
78     Display *display;
79
80     gchar *hostname;
81
82     /* File monitor for password file */
83     GFileMonitor *passwd_monitor;
84   
85     /* TRUE if have scanned users */
86     gboolean have_users;
87
88     /* List of users */
89     GList *users;
90   
91     gboolean have_languages;
92     GList *languages;
93
94     XklEngine *xkl_engine;
95     XklConfigRec *xkl_config;
96     gboolean have_layouts;
97     GList *layouts;
98     gchar *layout;
99
100     gboolean have_sessions;
101     GList *sessions;
102
103     gchar *authentication_user;
104     gboolean in_authentication;
105     gboolean is_authenticated;
106     guint32 authenticate_sequence_number;
107     gboolean cancelling_authentication;
108   
109     GHashTable *hints;
110
111     guint login_timeout;
112 } LdmGreeterPrivate;
113
114 G_DEFINE_TYPE (LdmGreeter, ldm_greeter, G_TYPE_OBJECT);
115
116 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LDM_TYPE_GREETER, LdmGreeterPrivate)
117
118 #define HEADER_SIZE 8
119 #define MAX_MESSAGE_LENGTH 1024
120
121 #define PASSWD_FILE      "/etc/passwd"
122 #define USER_CONFIG_FILE "/etc/lightdm/users.conf"
123
124 /* Messages from the greeter to the server */
125 typedef enum
126 {
127     GREETER_MESSAGE_CONNECT = 0,
128     GREETER_MESSAGE_LOGIN,
129     GREETER_MESSAGE_LOGIN_AS_GUEST,
130     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
131     GREETER_MESSAGE_START_SESSION,
132     GREETER_MESSAGE_CANCEL_AUTHENTICATION
133 } GreeterMessage;
134
135 /* Messages from the server to the greeter */
136 typedef enum
137 {
138     SERVER_MESSAGE_CONNECTED = 0,
139     SERVER_MESSAGE_QUIT,
140     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
141     SERVER_MESSAGE_END_AUTHENTICATION,
142     SERVER_MESSAGE_SESSION_FAILED,
143 } ServerMessage;
144
145 /**
146  * ldm_greeter_new:
147  *
148  * Create a new greeter.
149  *
150  * Return value: the new #LdmGreeter
151  **/
152 LdmGreeter *
153 ldm_greeter_new ()
154 {
155     return g_object_new (LDM_TYPE_GREETER, NULL);
156 }
157
158 static gboolean
159 timed_login_cb (gpointer data)
160 {
161     LdmGreeter *greeter = data;
162     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
163
164     priv->login_timeout = 0;
165     g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
166
167     return FALSE;
168 }
169
170 static guint32
171 int_length ()
172 {
173     return 4;
174 }
175
176 static void
177 write_message (LdmGreeter *greeter, guint8 *message, gsize message_length)
178 {
179     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
180     GError *error = NULL;
181
182     if (g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, NULL) != G_IO_STATUS_NORMAL)
183         g_warning ("Error writing to daemon: %s", error->message);
184     else
185         g_debug ("Wrote %zi bytes to daemon", message_length);
186     g_clear_error (&error);
187     g_io_channel_flush (priv->to_server_channel, NULL);
188 }
189
190 static void
191 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
192 {
193     if (*offset + 4 >= buffer_length)
194         return;
195     buffer[*offset] = value >> 24;
196     buffer[*offset+1] = (value >> 16) & 0xFF;
197     buffer[*offset+2] = (value >> 8) & 0xFF;
198     buffer[*offset+3] = value & 0xFF;
199     *offset += 4;
200 }
201
202 static void
203 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
204 {
205     gint length = strlen (value);
206     write_int (buffer, buffer_length, length, offset);
207     if (*offset + length >= buffer_length)
208         return;
209     memcpy (buffer + *offset, value, length);
210     *offset += length;
211 }
212
213 static guint32
214 read_int (LdmGreeter *greeter, gsize *offset)
215 {
216     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
217     guint32 value;
218     guint8 *buffer;
219
220     if (priv->n_read - *offset < int_length ())
221     {
222         g_warning ("Not enough space for int, need %i, got %zi", int_length (), priv->n_read - *offset);
223         return 0;
224     }
225
226     buffer = priv->read_buffer + *offset;
227     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
228     *offset += int_length ();
229
230     return value;
231 }
232
233 static gchar *
234 read_string (LdmGreeter *greeter, gsize *offset)
235 {
236     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
237     guint32 length;
238     gchar *value;
239
240     length = read_int (greeter, offset);
241     if (priv->n_read - *offset < length)
242     {
243         g_warning ("Not enough space for string, need %u, got %zu", length, priv->n_read - *offset);
244         return g_strdup ("");
245     }
246
247     value = g_malloc (sizeof (gchar) * (length + 1));
248     memcpy (value, priv->read_buffer + *offset, length);
249     value[length] = '\0';
250     *offset += length;
251
252     return value;
253 }
254
255 static guint32
256 string_length (const gchar *value)
257 {
258     return int_length () + strlen (value);
259 }
260
261 static void
262 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
263 {
264     write_int (buffer, buffer_length, id, offset);
265     write_int (buffer, buffer_length, length, offset);
266 }
267
268 static guint32 get_packet_length (LdmGreeter *greeter)
269 {
270     gsize offset = 4;
271     return read_int (greeter, &offset);
272 }
273
274 static void
275 handle_connected (LdmGreeter *greeter, guint32 length, gsize *offset)
276 {
277     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
278     gchar *version;
279     GString *hint_string;
280     int timeout;
281
282     version = read_string (greeter, offset);
283     hint_string = g_string_new ("");
284     while (*offset < length)
285     {
286         gchar *name, *value;
287       
288         name = read_string (greeter, offset);
289         value = read_string (greeter, offset);
290         g_hash_table_insert (priv->hints, name, value);
291         g_string_append_printf (hint_string, " %s=%s", name, value);
292     }
293
294     g_debug ("Connected version=%s%s", version, hint_string->str);
295     g_free (version);
296     g_string_free (hint_string, TRUE);
297
298     /* Set timeout for default login */
299     timeout = ldm_greeter_get_autologin_timeout_hint (greeter);
300     if (timeout)
301     {
302         g_debug ("Setting autologin timer for %d seconds", timeout);
303         priv->login_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
304     }
305     g_signal_emit (G_OBJECT (greeter), signals[CONNECTED], 0);
306 }
307
308 static void
309 handle_prompt_authentication (LdmGreeter *greeter, gsize *offset)
310 {
311     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
312     guint32 sequence_number, n_messages, i;
313
314     sequence_number = read_int (greeter, offset);
315     if (sequence_number != priv->authenticate_sequence_number)
316     {
317         g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
318         return;
319     }
320
321     if (priv->cancelling_authentication)
322     {
323         g_debug ("Ignoring prompt authentication as waiting for it to cancel");
324         return;
325     }
326
327     n_messages = read_int (greeter, offset);
328     g_debug ("Prompt user with %d message(s)", n_messages);
329
330     for (i = 0; i < n_messages; i++)
331     {
332         int msg_style;
333         gchar *msg;
334
335         msg_style = read_int (greeter, offset);
336         msg = read_string (greeter, offset);
337
338         // FIXME: Should stop on prompts?
339         switch (msg_style)
340         {
341         case PAM_PROMPT_ECHO_OFF:
342             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg, LDM_PROMPT_TYPE_SECRET);
343             break;
344         case PAM_PROMPT_ECHO_ON:
345             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg, LDM_PROMPT_TYPE_QUESTION);
346             break;
347         case PAM_ERROR_MSG:
348             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg, LDM_MESSAGE_TYPE_ERROR);
349             break;
350         case PAM_TEXT_INFO:
351             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg, LDM_MESSAGE_TYPE_INFO);
352             break;
353         }
354
355         g_free (msg);
356     }
357 }
358
359 static void
360 handle_end_authentication (LdmGreeter *greeter, gsize *offset)
361 {
362     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
363     guint32 sequence_number, return_code;
364
365     sequence_number = read_int (greeter, offset);
366     return_code = read_int (greeter, offset);
367
368     if (sequence_number != priv->authenticate_sequence_number)
369     {
370         g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
371         return;
372     }
373
374     g_debug ("Authentication complete with return code %d", return_code);
375     priv->cancelling_authentication = FALSE;
376     priv->is_authenticated = (return_code == 0);
377     if (!priv->is_authenticated)
378     {
379         g_free (priv->authentication_user);
380         priv->authentication_user = NULL;
381     }
382     g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
383     priv->in_authentication = FALSE;
384 }
385
386 static void
387 handle_session_failed (LdmGreeter *greeter, gsize *offset)
388
389     g_debug ("Session failed to start");
390     g_signal_emit (G_OBJECT (greeter), signals[SESSION_FAILED], 0);
391 }
392
393 static void
394 handle_quit (LdmGreeter *greeter, gsize *offset)
395 {
396     g_debug ("Got quit request from server");
397     g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
398 }
399
400 static gboolean
401 read_packet (LdmGreeter *greeter, gboolean block)
402 {
403     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
404     gsize n_to_read, n_read;
405     GError *error = NULL;
406
407     /* Read the header, or the whole packet if we already have that */
408     n_to_read = HEADER_SIZE;
409     if (priv->n_read >= HEADER_SIZE)
410         n_to_read += get_packet_length (greeter);
411
412     do
413     {
414         GIOStatus status;
415         status = g_io_channel_read_chars (priv->from_server_channel,
416                                           (gchar *) priv->read_buffer + priv->n_read,
417                                           n_to_read - priv->n_read,
418                                           &n_read,
419                                           &error);
420         if (status == G_IO_STATUS_ERROR)
421             g_warning ("Error reading from server: %s", error->message);
422         g_clear_error (&error);
423         if (status != G_IO_STATUS_NORMAL)
424             break;
425
426         g_debug ("Read %zi bytes from daemon", n_read);
427
428         priv->n_read += n_read;
429     } while (priv->n_read < n_to_read && block);
430
431     /* Stop if haven't got all the data we want */
432     if (priv->n_read != n_to_read)
433         return FALSE;
434
435     /* If have header, rerun for content */
436     if (priv->n_read == HEADER_SIZE)
437     {
438         n_to_read = get_packet_length (greeter);
439         if (n_to_read > 0)
440         {
441             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
442             return read_packet (greeter, block);
443         }
444     }
445
446     return TRUE;
447 }
448
449 static gboolean
450 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
451 {
452     LdmGreeter *greeter = data;
453     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
454     gsize offset;
455     guint32 id, length;
456
457     if (!read_packet (greeter, FALSE))
458         return TRUE;
459
460     offset = 0;
461     id = read_int (greeter, &offset);
462     length = read_int (greeter, &offset);
463     switch (id)
464     {
465     case SERVER_MESSAGE_CONNECTED:
466         handle_connected (greeter, length, &offset);
467         break;
468     case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
469         handle_prompt_authentication (greeter, &offset);
470         break;
471     case SERVER_MESSAGE_END_AUTHENTICATION:
472         handle_end_authentication (greeter, &offset);
473         break;
474     case SERVER_MESSAGE_SESSION_FAILED:
475         handle_session_failed (greeter, &offset);
476         break;
477     case SERVER_MESSAGE_QUIT:
478         handle_quit (greeter, &offset);
479         break;
480     default:
481         g_warning ("Unknown message from server: %d", id);
482         break;
483     }
484
485     priv->n_read = 0;
486
487     return TRUE;
488 }
489
490 /**
491  * ldm_greeter_connect_to_server:
492  * @greeter: The greeter to connect
493  *
494  * Connects the greeter to the display manager.
495  *
496  * Return value: TRUE if successfully connected
497  **/
498 gboolean
499 ldm_greeter_connect_to_server (LdmGreeter *greeter)
500 {
501     LdmGreeterPrivate *priv;
502     GError *error = NULL;
503     const gchar *bus_address, *fd;
504     guint8 message[MAX_MESSAGE_LENGTH];
505     gsize offset = 0;
506     GBusType bus_type = G_BUS_TYPE_SYSTEM;
507
508     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
509
510     priv = GET_PRIVATE (greeter);
511
512     priv->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
513     if (!priv->system_bus)
514         g_warning ("Failed to connect to system bus: %s", error->message);
515     g_clear_error (&error);
516
517     bus_address = getenv ("LDM_BUS");
518     if (bus_address && strcmp (bus_address, "SESSION") == 0)
519         bus_type = G_BUS_TYPE_SESSION;
520
521     priv->lightdm_bus = g_bus_get_sync (bus_type, NULL, &error);
522     if (!priv->lightdm_bus)
523         g_warning ("Failed to connect to LightDM bus: %s", error->message);
524     g_clear_error (&error);
525     if (!priv->lightdm_bus)
526         return FALSE;
527
528     fd = getenv ("LIGHTDM_TO_SERVER_FD");
529     if (!fd)
530     {
531         g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
532         return FALSE;
533     }
534     priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
535     g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
536
537     fd = getenv ("LIGHTDM_FROM_SERVER_FD");
538     if (!fd)
539     {
540         g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
541         return FALSE;
542     }
543     priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
544     g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
545     g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
546
547     g_debug ("Connecting to display manager...");
548     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
549     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
550     write_message (greeter, message, offset);
551
552     return TRUE;
553 }
554
555 /**
556  * ldm_greeter_get_hostname:
557  * @greeter: a #LdmGreeter
558  *
559  * Return value: The host this greeter is displaying
560  **/
561 const gchar *
562 ldm_greeter_get_hostname (LdmGreeter *greeter)
563 {
564     LdmGreeterPrivate *priv;
565
566     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
567
568     priv = GET_PRIVATE (greeter);
569
570     if (!priv->hostname)
571     {
572         struct utsname info;
573         uname (&info);
574         priv->hostname = g_strdup (info.nodename);
575     }
576
577     return priv->hostname;
578 }
579
580 static LdmUser *
581 get_user_by_name (LdmGreeter *greeter, const gchar *username)
582 {
583     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
584     GList *link;
585   
586     for (link = priv->users; link; link = link->next)
587     {
588         LdmUser *user = link->data;
589         if (strcmp (ldm_user_get_name (user), username) == 0)
590             return user;
591     }
592
593     return NULL;
594 }
595   
596 static gint
597 compare_user (gconstpointer a, gconstpointer b)
598 {
599     LdmUser *user_a = (LdmUser *) a, *user_b = (LdmUser *) b;
600     return strcmp (ldm_user_get_display_name (user_a), ldm_user_get_display_name (user_b));
601 }
602
603 static void
604 load_users (LdmGreeter *greeter)
605 {
606     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
607     GKeyFile *config;
608     gchar *value;
609     gint minimum_uid;
610     gchar **hidden_users, **hidden_shells;
611     GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
612     GError *error = NULL;
613
614     g_debug ("Loading user config from %s", USER_CONFIG_FILE);
615
616     config = g_key_file_new ();
617     if (!g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error) &&
618         !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
619         g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info
620     g_clear_error (&error);
621
622     if (g_key_file_has_key (config, "UserAccounts", "minimum-uid", NULL))
623         minimum_uid = g_key_file_get_integer (config, "UserAccounts", "minimum-uid", NULL);
624     else
625         minimum_uid = 500;
626
627     value = g_key_file_get_string (config, "UserAccounts", "hidden-users", NULL);
628     if (!value)
629         value = g_strdup ("nobody nobody4 noaccess");
630     hidden_users = g_strsplit (value, " ", -1);
631     g_free (value);
632
633     value = g_key_file_get_string (config, "UserAccounts", "hidden-shells", NULL);
634     if (!value)
635         value = g_strdup ("/bin/false /usr/sbin/nologin");
636     hidden_shells = g_strsplit (value, " ", -1);
637     g_free (value);
638
639     g_key_file_free (config);
640
641     setpwent ();
642
643     while (TRUE)
644     {
645         struct passwd *entry;
646         LdmUser *user;
647         char **tokens;
648         gchar *real_name, *image_path, *image;
649         int i;
650
651         errno = 0;
652         entry = getpwent ();
653         if (!entry)
654             break;
655
656         /* Ignore system users */
657         if (entry->pw_uid < minimum_uid)
658             continue;
659
660         /* Ignore users disabled by shell */
661         if (entry->pw_shell)
662         {
663             for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
664             if (hidden_shells[i])
665                 continue;
666         }
667
668         /* Ignore certain users */
669         for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
670         if (hidden_users[i])
671             continue;
672
673         tokens = g_strsplit (entry->pw_gecos, ",", -1);
674         if (tokens[0] != NULL && tokens[0][0] != '\0')
675             real_name = g_strdup (tokens[0]);
676         else
677             real_name = NULL;
678         g_strfreev (tokens);
679       
680         image_path = g_build_filename (entry->pw_dir, ".face", NULL);
681         if (!g_file_test (image_path, G_FILE_TEST_EXISTS))
682         {
683             g_free (image_path);
684             image_path = g_build_filename (entry->pw_dir, ".face.icon", NULL);
685             if (!g_file_test (image_path, G_FILE_TEST_EXISTS))
686             {
687                 g_free (image_path);
688                 image_path = NULL;
689             }
690         }
691         if (image_path)
692             image = g_filename_to_uri (image_path, NULL, NULL);
693         else
694             image = NULL;
695         g_free (image_path);
696
697         user = ldm_user_new (greeter, entry->pw_name, real_name, entry->pw_dir, image, FALSE);
698         g_free (real_name);
699         g_free (image);
700
701         /* Update existing users if have them */
702         for (link = priv->users; link; link = link->next)
703         {
704             LdmUser *info = link->data;
705             if (strcmp (ldm_user_get_name (info), ldm_user_get_name (user)) == 0)
706             {
707                 if (ldm_user_update (info, ldm_user_get_real_name (user), ldm_user_get_home_directory (user), ldm_user_get_image (user), ldm_user_get_logged_in (user)))
708                     changed_users = g_list_insert_sorted (changed_users, info, compare_user);
709                 g_object_unref (user);
710                 user = info;
711                 break;
712             }
713         }
714         if (!link)
715         {
716             /* Only notify once we have loaded the user list */
717             if (priv->have_users)
718                 new_users = g_list_insert_sorted (new_users, user, compare_user);
719         }
720         users = g_list_insert_sorted (users, user, compare_user);
721     }
722     g_strfreev (hidden_users);
723     g_strfreev (hidden_shells);
724
725     if (errno != 0)
726         g_warning ("Failed to read password database: %s", strerror (errno));
727
728     endpwent ();
729
730     /* Use new user list */
731     old_users = priv->users;
732     priv->users = users;
733   
734     /* Notify of changes */
735     for (link = new_users; link; link = link->next)
736     {
737         LdmUser *info = link->data;
738         g_debug ("User %s added", ldm_user_get_name (info));
739         g_signal_emit (greeter, signals[USER_ADDED], 0, info);
740     }
741     g_list_free (new_users);
742     for (link = changed_users; link; link = link->next)
743     {
744         LdmUser *info = link->data;
745         g_debug ("User %s changed", ldm_user_get_name (info));
746         g_signal_emit (greeter, signals[USER_CHANGED], 0, info);
747     }
748     g_list_free (changed_users);
749     for (link = old_users; link; link = link->next)
750     {
751         GList *new_link;
752
753         /* See if this user is in the current list */
754         for (new_link = priv->users; new_link; new_link = new_link->next)
755         {
756             if (new_link->data == link->data)
757                 break;
758         }
759
760         if (!new_link)
761         {
762             LdmUser *info = link->data;
763             g_debug ("User %s removed", ldm_user_get_name (info));
764             g_signal_emit (greeter, signals[USER_REMOVED], 0, info);
765             g_object_unref (info);
766         }
767     }
768     g_list_free (old_users);
769 }
770
771 static void
772 passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LdmGreeter *greeter)
773 {
774     if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
775     {
776         g_debug ("%s changed, reloading user list", g_file_get_path (file));
777         load_users (greeter);
778     }
779 }
780
781 static void
782 update_users (LdmGreeter *greeter)
783 {
784     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
785     GFile *passwd_file;
786     GError *error = NULL;
787
788     if (priv->have_users)
789         return;
790
791     load_users (greeter);
792
793     /* Watch for changes to user list */
794     passwd_file = g_file_new_for_path (PASSWD_FILE);
795     priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
796     g_object_unref (passwd_file);
797     if (!priv->passwd_monitor)
798         g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
799     else
800         g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), greeter);
801     g_clear_error (&error);
802
803     priv->have_users = TRUE;
804 }
805
806 /**
807  * ldm_greeter_get_num_users:
808  * @greeter: a #LdmGreeter
809  *
810  * Return value: The number of users able to log in
811  **/
812 gint
813 ldm_greeter_get_num_users (LdmGreeter *greeter)
814 {
815     g_return_val_if_fail (LDM_IS_GREETER (greeter), 0);
816     update_users (greeter);
817     return g_list_length (GET_PRIVATE (greeter)->users);
818 }
819
820 /**
821  * ldm_greeter_get_users:
822  * @greeter: A #LdmGreeter
823  *
824  * Get a list of users to present to the user.  This list may be a subset of the
825  * available users and may be empty depending on the server configuration.
826  *
827  * Return value: (element-type LdmUser) (transfer none): A list of #LdmUser that should be presented to the user.
828  **/
829 GList *
830 ldm_greeter_get_users (LdmGreeter *greeter)
831 {
832     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
833     update_users (greeter);
834     return GET_PRIVATE (greeter)->users;
835 }
836
837 /**
838  * ldm_greeter_get_user_by_name:
839  * @greeter: A #LdmGreeter
840  * @username: Name of user to get.
841  *
842  * Get infomation about a given user or NULL if this user doesn't exist.
843  *
844  * Return value: (transfer none): A #LdmUser entry for the given user.
845  **/
846 LdmUser *
847 ldm_greeter_get_user_by_name (LdmGreeter *greeter, const gchar *username)
848 {
849     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
850     g_return_val_if_fail (username != NULL, NULL);
851
852     update_users (greeter);
853
854     return get_user_by_name (greeter, username);
855 }
856
857 static void
858 update_languages (LdmGreeter *greeter)
859 {
860     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
861     gchar *stdout_text = NULL, *stderr_text = NULL;
862     gint exit_status;
863     gboolean result;
864     GError *error = NULL;
865
866     if (priv->have_languages)
867         return;
868
869     result = g_spawn_command_line_sync ("locale -a", &stdout_text, &stderr_text, &exit_status, &error);
870     if (!result || exit_status != 0)
871         g_warning ("Failed to get languages, locale -a returned %d: %s", exit_status, error->message);
872     else
873     {
874         gchar **tokens;
875         int i;
876
877         tokens = g_strsplit_set (stdout_text, "\n\r", -1);
878         for (i = 0; tokens[i]; i++)
879         {
880             LdmLanguage *language;
881             gchar *code;
882
883             code = g_strchug (tokens[i]);
884             if (code[0] == '\0')
885                 continue;
886
887             /* Ignore the non-interesting languages */
888             if (strcmp (code, "C") == 0 || strcmp (code, "POSIX") == 0)
889                 continue;
890
891             language = ldm_language_new (code);
892             priv->languages = g_list_append (priv->languages, language);
893         }
894
895         g_strfreev (tokens);
896     }
897
898     g_clear_error (&error);
899     g_free (stdout_text);
900     g_free (stderr_text);
901
902     priv->have_languages = TRUE;
903 }
904
905 /**
906  * ldm_greeter_get_default_language:
907  * @greeter: A #LdmGreeter
908  *
909  * Get the default language.
910  *
911  * Return value: The default language.
912  **/
913 const gchar *
914 ldm_greeter_get_default_language (LdmGreeter *greeter)
915 {
916     gchar *lang;
917     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
918     lang = getenv ("LANG");
919     if (lang)
920         return lang;
921     else
922         return "C";
923 }
924
925 /**
926  * ldm_greeter_get_languages:
927  * @greeter: A #LdmGreeter
928  *
929  * Get a list of languages to present to the user.
930  *
931  * Return value: (element-type LdmLanguage) (transfer none): A list of #LdmLanguage that should be presented to the user.
932  **/
933 GList *
934 ldm_greeter_get_languages (LdmGreeter *greeter)
935 {
936     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
937     update_languages (greeter);
938     return GET_PRIVATE (greeter)->languages;
939 }
940
941 static void
942 layout_cb (XklConfigRegistry *config,
943            const XklConfigItem *item,
944            gpointer data)
945 {
946     LdmGreeter *greeter = data;
947     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
948     LdmLayout *layout;
949
950     layout = ldm_layout_new (item->name, item->short_description, item->description);
951     priv->layouts = g_list_append (priv->layouts, layout);
952 }
953
954 static void
955 setup_display (LdmGreeter *greeter)
956 {
957     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
958     if (!priv->display)
959         priv->display = XOpenDisplay (NULL);
960 }
961
962 static void
963 setup_xkl (LdmGreeter *greeter)
964 {
965     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
966
967     setup_display (greeter);
968
969     priv->xkl_engine = xkl_engine_get_instance (priv->display);
970     priv->xkl_config = xkl_config_rec_new ();
971     if (!xkl_config_rec_get_from_server (priv->xkl_config, priv->xkl_engine))
972         g_warning ("Failed to get Xkl configuration from server");
973     priv->layout = g_strdup (priv->xkl_config->layouts[0]);
974 }
975
976 /**
977  * ldm_greeter_get_layouts:
978  * @greeter: A #LdmGreeter
979  *
980  * Get a list of keyboard layouts to present to the user.
981  *
982  * Return value: (element-type LdmLayout) (transfer none): A list of #LdmLayout that should be presented to the user.
983  **/
984 GList *
985 ldm_greeter_get_layouts (LdmGreeter *greeter)
986 {
987     LdmGreeterPrivate *priv;
988     XklConfigRegistry *registry;
989
990     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
991
992     priv = GET_PRIVATE (greeter);
993
994     if (priv->have_layouts)
995         return priv->layouts;
996
997     setup_xkl (greeter);
998
999     registry = xkl_config_registry_get_instance (priv->xkl_engine);
1000     xkl_config_registry_load (registry, FALSE);
1001     xkl_config_registry_foreach_layout (registry, layout_cb, greeter);
1002     g_object_unref (registry);
1003     priv->have_layouts = TRUE;
1004
1005     return priv->layouts;
1006 }
1007
1008 /**
1009  * ldm_greeter_set_layout:
1010  * @greeter: A #LdmGreeter
1011  * @layout: The layout to use
1012  *
1013  * Set the layout for this session.
1014  **/
1015 void
1016 ldm_greeter_set_layout (LdmGreeter *greeter, const gchar *layout)
1017 {
1018     LdmGreeterPrivate *priv;
1019     XklConfigRec *config;
1020
1021     g_return_if_fail (LDM_IS_GREETER (greeter));
1022     g_return_if_fail (layout != NULL);
1023
1024     priv = GET_PRIVATE (greeter);
1025
1026     g_debug ("Setting keyboard layout to %s", layout);
1027
1028     setup_xkl (greeter);
1029
1030     config = xkl_config_rec_new ();
1031     config->layouts = g_malloc (sizeof (gchar *) * 2);
1032     config->model = g_strdup (priv->xkl_config->model);
1033     config->layouts[0] = g_strdup (layout);
1034     config->layouts[1] = NULL;
1035     if (!xkl_config_rec_activate (config, priv->xkl_engine))
1036         g_warning ("Failed to activate XKL config");
1037     else
1038         priv->layout = g_strdup (layout);
1039     g_object_unref (config);
1040 }
1041
1042 /**
1043  * ldm_greeter_get_layout:
1044  * @greeter: A #LdmGreeter
1045  *
1046  * Get the current keyboard layout.
1047  *
1048  * Return value: The currently active layout for this user.
1049  **/
1050 const gchar *
1051 ldm_greeter_get_layout (LdmGreeter *greeter)
1052 {
1053     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1054     setup_xkl (greeter);
1055     return GET_PRIVATE (greeter)->layout;
1056 }
1057
1058 static void
1059 update_sessions (LdmGreeter *greeter)
1060 {
1061     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
1062     GDir *directory;
1063     GError *error = NULL;
1064
1065     if (priv->have_sessions)
1066         return;
1067
1068     directory = g_dir_open (XSESSIONS_DIR, 0, &error);
1069     if (!directory)
1070         g_warning ("Failed to open sessions directory: %s", error->message);
1071     g_clear_error (&error);
1072     if (!directory)
1073         return;
1074
1075     while (TRUE)
1076     {
1077         const gchar *filename;
1078         GKeyFile *key_file;
1079         gchar *key, *path;
1080         gboolean result;
1081
1082         filename = g_dir_read_name (directory);
1083         if (filename == NULL)
1084             break;
1085
1086         if (!g_str_has_suffix (filename, ".desktop"))
1087             continue;
1088
1089         key = g_strndup (filename, strlen (filename) - strlen (".desktop"));
1090         path = g_build_filename (XSESSIONS_DIR, filename, NULL);
1091         g_debug ("Loading session %s", path);
1092
1093         key_file = g_key_file_new ();
1094         result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
1095         if (!result)
1096             g_warning ("Failed to load session file %s: %s:", path, error->message);
1097         g_clear_error (&error);
1098
1099         if (result && !g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL))
1100         {
1101             gchar *domain, *name, *comment;
1102
1103 #ifdef G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN
1104             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN, NULL);
1105 #else
1106             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL);
1107 #endif
1108             name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, domain, NULL);
1109             comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, domain, NULL);
1110             if (!comment)
1111                 comment = g_strdup ("");
1112             if (name)
1113             {
1114                 g_debug ("Loaded session %s (%s, %s)", key, name, comment);
1115                 priv->sessions = g_list_append (priv->sessions, ldm_session_new (key, name, comment));
1116             }
1117             else
1118                 g_warning ("Invalid session %s: %s", path, error->message);
1119             g_free (domain);
1120             g_free (name);
1121             g_free (comment);
1122         }
1123
1124         g_free (key);
1125         g_free (path);
1126         g_key_file_free (key_file);
1127     }
1128
1129     g_dir_close (directory);
1130
1131     priv->have_sessions = TRUE;
1132 }
1133
1134 /**
1135  * ldm_greeter_get_sessions:
1136  * @greeter: A #LdmGreeter
1137  *
1138  * Get the available sessions.
1139  *
1140  * Return value: (element-type LdmSession) (transfer none): A list of #LdmSession
1141  **/
1142 GList *
1143 ldm_greeter_get_sessions (LdmGreeter *greeter)
1144 {
1145     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1146     update_sessions (greeter);
1147     return GET_PRIVATE (greeter)->sessions;
1148 }
1149
1150 /**
1151  * ldm_greeter_get_hint:
1152  * @greeter: A #LdmGreeter
1153  * @name: The hint name to query.
1154  *
1155  * Get a hint.
1156  *
1157  * Return value: The value for this hint or NULL if not set.
1158  **/
1159 const gchar *
1160 ldm_greeter_get_hint (LdmGreeter *greeter, const gchar *name)
1161 {
1162     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1163     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
1164 }
1165
1166 /**
1167  * ldm_greeter_get_default_session_hint:
1168  * @greeter: A #LdmGreeter
1169  *
1170  * Get the default session to use.
1171  *
1172  * Return value: The session name
1173  **/
1174 const gchar *
1175 ldm_greeter_get_default_session_hint (LdmGreeter *greeter)
1176 {
1177     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1178     return ldm_greeter_get_hint (greeter, "default-session");
1179 }
1180
1181 /**
1182  * ldm_greeter_get_hide_users_hint:
1183  * @greeter: A #LdmGreeter
1184  *
1185  * Check if user accounts should be shown.
1186  *
1187  * Return value: TRUE if the available users should not be shown.
1188  */
1189 gboolean
1190 ldm_greeter_get_hide_users_hint (LdmGreeter *greeter)
1191 {
1192     const gchar *value;
1193
1194     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1195     value = ldm_greeter_get_hint (greeter, "hide-users");
1196
1197     return g_strcmp0 (value, "true") == 0;
1198 }
1199
1200 /**
1201  * ldm_greeter_get_has_guest_account_hint:
1202  * @greeter: A #LdmGreeter
1203  *
1204  * Check if guest sessions are supported.
1205  *
1206  * Return value: TRUE if guest sessions are supported.
1207  */
1208 gboolean
1209 ldm_greeter_get_has_guest_account_hint (LdmGreeter *greeter)
1210 {
1211     const gchar *value;
1212
1213     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1214     value = ldm_greeter_get_hint (greeter, "has-guest-account");
1215   
1216     return g_strcmp0 (value, "true") == 0;
1217 }
1218
1219 /**
1220  * ldm_greeter_get_select_user_hint:
1221  * @greeter: A #LdmGreeter
1222  *
1223  * Get the user to select by default.
1224  *
1225  * Return value: A username
1226  */
1227 const gchar *
1228 ldm_greeter_get_select_user_hint (LdmGreeter *greeter)
1229 {
1230     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1231     return ldm_greeter_get_hint (greeter, "select-user");
1232 }
1233
1234 /**
1235  * ldm_greeter_get_select_guest_hint:
1236  * @greeter: A #LdmGreeter
1237  *
1238  * Check if the guest account should be selected by default.
1239  *
1240  * Return value: TRUE if the guest account should be selected by default.
1241  */
1242 gboolean
1243 ldm_greeter_get_select_guest_hint (LdmGreeter *greeter)
1244 {
1245     const gchar *value;
1246
1247     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1248     value = ldm_greeter_get_hint (greeter, "select-guest");
1249   
1250     return g_strcmp0 (value, "true") == 0;
1251 }
1252
1253 /**
1254  * ldm_greeter_get_autologin_user_hint:
1255  * @greeter: A #LdmGreeter
1256  *
1257  * Get the user account to automatically logg into when the timer expires.
1258  *
1259  * Return value: The user account to automatically log into.
1260  */
1261 const gchar *
1262 ldm_greeter_get_autologin_user_hint (LdmGreeter *greeter)
1263 {
1264     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1265     return ldm_greeter_get_hint (greeter, "autologin-user");
1266 }
1267
1268 /**
1269  * ldm_greeter_get_autologin_guest_hint:
1270  * @greeter: A #LdmGreeter
1271  *
1272  * Check if the guest account should be automatically logged into when the timer expires.
1273  *
1274  * Return value: TRUE if the guest account should be automatically logged into.
1275  */
1276 gboolean
1277 ldm_greeter_get_autologin_guest_hint (LdmGreeter *greeter)
1278 {
1279     const gchar *value;
1280
1281     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1282     value = ldm_greeter_get_hint (greeter, "autologin-guest");
1283   
1284     return g_strcmp0 (value, "true") == 0;
1285 }
1286
1287 /**
1288  * ldm_greeter_get_autologin_timeout_hint:
1289  * @greeter: A #LdmGreeter
1290  *
1291  * Get the number of seconds to wait before automaitcally logging in.
1292  *
1293  * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
1294  */
1295 gint
1296 ldm_greeter_get_autologin_timeout_hint (LdmGreeter *greeter)
1297 {
1298     const gchar *value;
1299     gint timeout = 0;
1300
1301     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1302     value = ldm_greeter_get_hint (greeter, "autologin-timeout");
1303     if (value)
1304         timeout = atoi (value);
1305     if (timeout < 0)
1306         timeout = 0;
1307
1308     return timeout;
1309 }
1310
1311 /**
1312  * ldm_greeter_cancel_timed_login:
1313  * @greeter: A #LdmGreeter
1314  *
1315  * Cancel the login as the default user.
1316  */
1317 void
1318 ldm_greeter_cancel_timed_login (LdmGreeter *greeter)
1319 {
1320     LdmGreeterPrivate *priv;
1321
1322     g_return_if_fail (LDM_IS_GREETER (greeter));
1323
1324     priv = GET_PRIVATE (greeter);
1325
1326     if (priv->login_timeout)
1327        g_source_remove (priv->login_timeout);
1328     priv->login_timeout = 0;
1329 }
1330
1331 /**
1332  * ldm_greeter_login:
1333  * @greeter: A #LdmGreeter
1334  * @username: (allow-none): A username or NULL to prompt for a username.
1335  *
1336  * Starts the authentication procedure for a user.
1337  **/
1338 void
1339 ldm_greeter_login (LdmGreeter *greeter, const char *username)
1340 {
1341     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
1342     guint8 message[MAX_MESSAGE_LENGTH];
1343     gsize offset = 0;
1344
1345     g_return_if_fail (LDM_IS_GREETER (greeter));
1346
1347     if (!username)
1348         username = "";
1349
1350     priv->cancelling_authentication = FALSE;
1351     priv->authenticate_sequence_number++;
1352     priv->in_authentication = TRUE;  
1353     priv->is_authenticated = FALSE;
1354     g_free (priv->authentication_user);
1355     priv->authentication_user = g_strdup (username);
1356
1357     g_debug ("Starting authentication for user %s...", username);
1358     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_LOGIN, int_length () + string_length (username), &offset);
1359     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1360     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1361     write_message (greeter, message, offset);
1362 }
1363
1364 /**
1365  * ldm_greeter_login_with_user_prompt:
1366  * @greeter: A #LdmGreeter
1367  *
1368  * Starts the authentication procedure, prompting the greeter for a username.
1369  **/
1370 void
1371 ldm_greeter_login_with_user_prompt (LdmGreeter *greeter)
1372 {
1373     ldm_greeter_login (greeter, NULL);
1374 }
1375
1376 /**
1377  * ldm_greeter_login_as_guest:
1378  * @greeter: A #LdmGreeter
1379  *
1380  * Starts the authentication procedure for the guest user.
1381  **/
1382 void
1383 ldm_greeter_login_as_guest (LdmGreeter *greeter)
1384 {
1385     LdmGreeterPrivate *priv;
1386     guint8 message[MAX_MESSAGE_LENGTH];
1387     gsize offset = 0;
1388
1389     g_return_if_fail (LDM_IS_GREETER (greeter));
1390
1391     priv = GET_PRIVATE (greeter);
1392
1393     priv->cancelling_authentication = FALSE;
1394     priv->authenticate_sequence_number++;
1395     priv->in_authentication = TRUE;
1396     priv->is_authenticated = FALSE;
1397     g_free (priv->authentication_user);
1398     priv->authentication_user = NULL;
1399
1400     g_debug ("Starting authentication for guest account...");
1401     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_LOGIN_AS_GUEST, int_length (), &offset);
1402     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1403     write_message (greeter, message, offset);
1404 }
1405
1406 /**
1407  * ldm_greeter_respond:
1408  * @greeter: A #LdmGreeter
1409  * @response: Response to a prompt
1410  *
1411  * Provide response to a prompt.
1412  **/
1413 void
1414 ldm_greeter_respond (LdmGreeter *greeter, const gchar *response)
1415 {
1416     guint8 message[MAX_MESSAGE_LENGTH];
1417     gsize offset = 0;
1418
1419     g_return_if_fail (LDM_IS_GREETER (greeter));
1420     g_return_if_fail (response != NULL);
1421
1422     g_debug ("Providing response to display manager");
1423     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (response), &offset);
1424     // FIXME: Could be multiple responses required
1425     write_int (message, MAX_MESSAGE_LENGTH, 1, &offset);
1426     write_string (message, MAX_MESSAGE_LENGTH, response, &offset);
1427     write_message (greeter, message, offset);
1428 }
1429
1430 /**
1431  * ldm_greeter_cancel_authentication:
1432  * @greeter: A #LdmGreeter
1433  *
1434  * Cancel the current user authentication.
1435  **/
1436 void
1437 ldm_greeter_cancel_authentication (LdmGreeter *greeter)
1438 {
1439     LdmGreeterPrivate *priv;
1440     guint8 message[MAX_MESSAGE_LENGTH];
1441     gsize offset = 0;
1442
1443     g_return_if_fail (LDM_IS_GREETER (greeter));
1444
1445     priv = GET_PRIVATE (greeter);
1446
1447     priv->cancelling_authentication = TRUE;
1448     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
1449     write_message (greeter, message, offset);
1450 }
1451
1452 /**
1453  * ldm_greeter_get_in_authentication:
1454  * @greeter: A #LdmGreeter
1455  *
1456  * Checks if the greeter is in the process of authenticating.
1457  *
1458  * Return value: TRUE if the greeter is authenticating a user.
1459  **/
1460 gboolean
1461 ldm_greeter_get_in_authentication (LdmGreeter *greeter)
1462 {
1463     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1464     return GET_PRIVATE (greeter)->in_authentication;
1465 }
1466
1467 /**
1468  * ldm_greeter_get_is_authenticated:
1469  * @greeter: A #LdmGreeter
1470  *
1471  * Checks if the greeter has successfully authenticated.
1472  *
1473  * Return value: TRUE if the greeter is authenticated for login.
1474  **/
1475 gboolean
1476 ldm_greeter_get_is_authenticated (LdmGreeter *greeter)
1477 {
1478     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1479     return GET_PRIVATE (greeter)->is_authenticated;
1480 }
1481
1482 /**
1483  * ldm_greeter_get_authentication_user:
1484  * @greeter: A #LdmGreeter
1485  *
1486  * Get the user that is being authenticated.
1487  *
1488  * Return value: The username of the authentication user being authenticated or NULL if no authentication in progress.
1489  */
1490 const gchar *
1491 ldm_greeter_get_authentication_user (LdmGreeter *greeter)
1492 {
1493     g_return_val_if_fail (LDM_IS_GREETER (greeter), NULL);
1494     return GET_PRIVATE (greeter)->authentication_user;
1495 }
1496
1497 /**
1498  * ldm_greeter_start_session:
1499  * @greeter: A #LdmGreeter
1500  * @session: (allow-none): The session to log into or NULL to use the default
1501  *
1502  * Start a session for the logged in user.
1503  **/
1504 void
1505 ldm_greeter_start_session (LdmGreeter *greeter, const gchar *session)
1506 {
1507     guint8 message[MAX_MESSAGE_LENGTH];
1508     gsize offset = 0;
1509
1510     g_return_if_fail (LDM_IS_GREETER (greeter));
1511   
1512     if (!session)
1513         session = "";
1514
1515     g_debug ("Starting session %s", session);
1516     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1517     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1518     write_message (greeter, message, offset);
1519 }
1520
1521 /**
1522  * ldm_greeter_start_session_with_defaults:
1523  * @greeter: A #LdmGreeter
1524  *
1525  * Login a user to a session using default settings for that user.
1526  **/
1527 void
1528 ldm_greeter_start_default_session (LdmGreeter *greeter)
1529 {
1530     ldm_greeter_start_session (greeter, NULL);
1531 }
1532
1533 static gboolean
1534 upower_call_function (LdmGreeter *greeter, const gchar *function, gboolean has_result)
1535 {
1536     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
1537     GDBusProxy *proxy;
1538     GVariant *result;
1539     GError *error = NULL;
1540     gboolean function_result = FALSE;
1541   
1542     if (!priv->system_bus)
1543         return FALSE;
1544
1545     proxy = g_dbus_proxy_new_sync (priv->system_bus,
1546                                    G_DBUS_PROXY_FLAGS_NONE,
1547                                    NULL,
1548                                    "org.freedesktop.UPower",
1549                                    "/org/freedesktop/UPower",
1550                                    "org.freedesktop.UPower",
1551                                    NULL, NULL);
1552     result = g_dbus_proxy_call_sync (proxy,
1553                                      function,
1554                                      NULL,
1555                                      G_DBUS_CALL_FLAGS_NONE,
1556                                      -1,
1557                                      NULL,
1558                                      &error);
1559     g_object_unref (proxy);
1560
1561     if (!result)
1562         g_warning ("Error calling UPower function %s: %s", function, error->message);
1563     g_clear_error (&error);
1564     if (!result)
1565         return FALSE;
1566
1567     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1568         g_variant_get (result, "(b)", &function_result);
1569
1570     g_variant_unref (result);
1571     return function_result;
1572 }
1573
1574 /**
1575  * ldm_greeter_get_can_suspend:
1576  * @greeter: A #LdmGreeter
1577  *
1578  * Checks if the greeter is authorized to do a system suspend.
1579  *
1580  * Return value: TRUE if the greeter can suspend the system
1581  **/
1582 gboolean
1583 ldm_greeter_get_can_suspend (LdmGreeter *greeter)
1584 {
1585     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1586     return upower_call_function (greeter, "SuspendAllowed", TRUE);
1587 }
1588
1589 /**
1590  * ldm_greeter_suspend:
1591  * @greeter: A #LdmGreeter
1592  *
1593  * Triggers a system suspend.
1594  **/
1595 void
1596 ldm_greeter_suspend (LdmGreeter *greeter)
1597 {
1598     g_return_if_fail (LDM_IS_GREETER (greeter));
1599     upower_call_function (greeter, "Suspend", FALSE);
1600 }
1601
1602 /**
1603  * ldm_greeter_get_can_hibernate:
1604  * @greeter: A #LdmGreeter
1605  *
1606  * Checks if the greeter is authorized to do a system hibernate.
1607  *
1608  * Return value: TRUE if the greeter can hibernate the system
1609  **/
1610 gboolean
1611 ldm_greeter_get_can_hibernate (LdmGreeter *greeter)
1612 {
1613     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1614     return upower_call_function (greeter, "HibernateAllowed", TRUE);
1615 }
1616
1617 /**
1618  * ldm_greeter_hibernate:
1619  * @greeter: A #LdmGreeter
1620  *
1621  * Triggers a system hibernate.
1622  **/
1623 void
1624 ldm_greeter_hibernate (LdmGreeter *greeter)
1625 {
1626     g_return_if_fail (LDM_IS_GREETER (greeter));
1627     upower_call_function (greeter, "Hibernate", FALSE);
1628 }
1629
1630 static gboolean
1631 ck_call_function (LdmGreeter *greeter, const gchar *function, gboolean has_result)
1632 {
1633     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
1634     GDBusProxy *proxy;
1635     GVariant *result;
1636     GError *error = NULL;
1637     gboolean function_result = FALSE;
1638
1639     if (!priv->system_bus)
1640         return FALSE;
1641
1642     proxy = g_dbus_proxy_new_sync (priv->system_bus,
1643                                    G_DBUS_PROXY_FLAGS_NONE,
1644                                    NULL,
1645                                    "org.freedesktop.ConsoleKit",
1646                                    "/org/freedesktop/ConsoleKit/Manager",
1647                                    "org.freedesktop.ConsoleKit.Manager",
1648                                    NULL, NULL);
1649     result = g_dbus_proxy_call_sync (proxy,
1650                                      function,
1651                                      NULL,
1652                                      G_DBUS_CALL_FLAGS_NONE,
1653                                      -1,
1654                                      NULL,
1655                                      &error);
1656     g_object_unref (proxy);
1657
1658     if (!result)
1659         g_warning ("Error calling ConsoleKit function %s: %s", function, error->message);
1660     g_clear_error (&error);
1661     if (!result)
1662         return FALSE;
1663
1664     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1665         g_variant_get (result, "(b)", &function_result);
1666
1667     g_variant_unref (result);
1668     return function_result;
1669 }
1670
1671 /**
1672  * ldm_greeter_get_can_restart:
1673  * @greeter: A #LdmGreeter
1674  *
1675  * Checks if the greeter is authorized to do a system restart.
1676  *
1677  * Return value: TRUE if the greeter can restart the system
1678  **/
1679 gboolean
1680 ldm_greeter_get_can_restart (LdmGreeter *greeter)
1681 {
1682     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1683     return ck_call_function (greeter, "CanRestart", TRUE);
1684 }
1685
1686 /**
1687  * ldm_greeter_restart:
1688  * @greeter: A #LdmGreeter
1689  *
1690  * Triggers a system restart.
1691  **/
1692 void
1693 ldm_greeter_restart (LdmGreeter *greeter)
1694 {
1695     g_return_if_fail (LDM_IS_GREETER (greeter));
1696     ck_call_function (greeter, "Restart", FALSE);
1697 }
1698
1699 /**
1700  * ldm_greeter_get_can_shutdown:
1701  * @greeter: A #LdmGreeter
1702  *
1703  * Checks if the greeter is authorized to do a system shutdown.
1704  *
1705  * Return value: TRUE if the greeter can shutdown the system
1706  **/
1707 gboolean
1708 ldm_greeter_get_can_shutdown (LdmGreeter *greeter)
1709 {
1710     g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE);
1711     return ck_call_function (greeter, "CanStop", TRUE);
1712 }
1713
1714 /**
1715  * ldm_greeter_shutdown:
1716  * @greeter: A #LdmGreeter
1717  *
1718  * Triggers a system shutdown.
1719  **/
1720 void
1721 ldm_greeter_shutdown (LdmGreeter *greeter)
1722 {
1723     g_return_if_fail (LDM_IS_GREETER (greeter));
1724     ck_call_function (greeter, "Stop", FALSE);
1725 }
1726
1727 static void
1728 ldm_greeter_init (LdmGreeter *greeter)
1729 {
1730     LdmGreeterPrivate *priv = GET_PRIVATE (greeter);
1731
1732     priv->read_buffer = g_malloc (HEADER_SIZE);
1733     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1734
1735     g_debug ("default-language=%s", ldm_greeter_get_default_language (greeter));
1736 }
1737
1738 static void
1739 ldm_greeter_set_property (GObject      *object,
1740                           guint         prop_id,
1741                           const GValue *value,
1742                           GParamSpec   *pspec)
1743 {
1744     LdmGreeter *self;
1745
1746     self = LDM_GREETER (object);
1747
1748     switch (prop_id) {
1749     case PROP_LAYOUT:
1750         ldm_greeter_set_layout(self, g_value_get_string (value));
1751         break;
1752     default:
1753         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1754         break;
1755     }
1756 }
1757
1758 static void
1759 ldm_greeter_get_property (GObject    *object,
1760                           guint       prop_id,
1761                           GValue     *value,
1762                           GParamSpec *pspec)
1763 {
1764     LdmGreeter *self;
1765
1766     self = LDM_GREETER (object);
1767
1768     switch (prop_id) {
1769     case PROP_HOSTNAME:
1770         g_value_set_string (value, ldm_greeter_get_hostname (self));
1771         break;
1772     case PROP_NUM_USERS:
1773         g_value_set_int (value, ldm_greeter_get_num_users (self));
1774         break;
1775     case PROP_USERS:
1776         break;
1777     case PROP_DEFAULT_LANGUAGE:
1778         g_value_set_string (value, ldm_greeter_get_default_language (self));
1779         break;
1780     case PROP_LAYOUTS:
1781         break;
1782     case PROP_LAYOUT:
1783         g_value_set_string (value, ldm_greeter_get_layout (self));
1784         break;
1785     case PROP_SESSIONS:
1786         break;
1787     case PROP_DEFAULT_SESSION_HINT:
1788         g_value_set_string (value, ldm_greeter_get_default_session_hint (self));
1789         break;
1790     case PROP_HIDE_USERS_HINT:
1791         g_value_set_boolean (value, ldm_greeter_get_hide_users_hint (self));
1792         break;
1793     case PROP_HAS_GUEST_ACCOUNT_HINT:
1794         g_value_set_boolean (value, ldm_greeter_get_has_guest_account_hint (self));
1795         break;
1796     case PROP_SELECT_USER_HINT:
1797         g_value_set_string (value, ldm_greeter_get_select_user_hint (self));
1798         break;
1799     case PROP_SELECT_GUEST_HINT:
1800         g_value_set_boolean (value, ldm_greeter_get_select_guest_hint (self));
1801         break;
1802     case PROP_AUTOLOGIN_USER_HINT:
1803         g_value_set_string (value, ldm_greeter_get_autologin_user_hint (self));
1804         break;
1805     case PROP_AUTOLOGIN_GUEST_HINT:
1806         g_value_set_boolean (value, ldm_greeter_get_autologin_guest_hint (self));
1807         break;
1808     case PROP_AUTOLOGIN_TIMEOUT_HINT:
1809         g_value_set_int (value, ldm_greeter_get_autologin_timeout_hint (self));
1810         break;
1811     case PROP_AUTHENTICATION_USER:
1812         g_value_set_string (value, ldm_greeter_get_authentication_user (self));
1813         break;
1814     case PROP_IN_AUTHENTICATION:
1815         g_value_set_boolean (value, ldm_greeter_get_in_authentication (self));
1816         break;
1817     case PROP_IS_AUTHENTICATED:
1818         g_value_set_boolean (value, ldm_greeter_get_is_authenticated (self));
1819         break;
1820     case PROP_CAN_SUSPEND:
1821         g_value_set_boolean (value, ldm_greeter_get_can_suspend (self));
1822         break;
1823     case PROP_CAN_HIBERNATE:
1824         g_value_set_boolean (value, ldm_greeter_get_can_hibernate (self));
1825         break;
1826     case PROP_CAN_RESTART:
1827         g_value_set_boolean (value, ldm_greeter_get_can_restart (self));
1828         break;
1829     case PROP_CAN_SHUTDOWN:
1830         g_value_set_boolean (value, ldm_greeter_get_can_shutdown (self));
1831         break;
1832     default:
1833         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1834         break;
1835     }
1836 }
1837
1838 static void
1839 marshal_VOID__STRING_INT (GClosure     *closure,
1840                           GValue       *return_value G_GNUC_UNUSED,
1841                           guint         n_param_values,
1842                           const GValue *param_values,
1843                           gpointer      invocation_hint G_GNUC_UNUSED,
1844                           gpointer      marshal_data)
1845 {
1846     typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer     data1,
1847                                                    gpointer     arg_1,
1848                                                    gint         arg_2,
1849                                                    gpointer     data2);
1850     register GMarshalFunc_VOID__STRING_INT callback;
1851     register GCClosure *cc = (GCClosure*) closure;
1852     register gpointer data1, data2;
1853
1854     g_return_if_fail (n_param_values == 3);
1855
1856     if (G_CCLOSURE_SWAP_DATA (closure))
1857     {
1858         data1 = closure->data;
1859         data2 = g_value_peek_pointer (param_values + 0);
1860     }
1861     else
1862     {
1863         data1 = g_value_peek_pointer (param_values + 0);
1864         data2 = closure->data;
1865     }
1866     callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback);
1867
1868     callback (data1,
1869               (param_values + 1)->data[0].v_pointer,
1870               (param_values + 2)->data[0].v_int,
1871               data2);
1872 }
1873
1874 static void
1875 ldm_greeter_finalize (GObject *object)
1876 {
1877     LdmGreeter *self = LDM_GREETER (object);
1878     LdmGreeterPrivate *priv = GET_PRIVATE (self);
1879
1880     g_hash_table_unref (priv->hints);
1881
1882     G_OBJECT_CLASS (ldm_greeter_parent_class)->finalize (object);
1883 }
1884
1885 static void
1886 ldm_greeter_class_init (LdmGreeterClass *klass)
1887 {
1888     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1889
1890     g_type_class_add_private (klass, sizeof (LdmGreeterPrivate));
1891
1892     object_class->set_property = ldm_greeter_set_property;
1893     object_class->get_property = ldm_greeter_get_property;
1894     object_class->finalize = ldm_greeter_finalize;
1895
1896     g_object_class_install_property (object_class,
1897                                      PROP_NUM_USERS,
1898                                      g_param_spec_string ("hostname",
1899                                                           "hostname",
1900                                                           "Hostname displaying greeter for",
1901                                                           NULL,
1902                                                           G_PARAM_READABLE));
1903     g_object_class_install_property (object_class,
1904                                      PROP_NUM_USERS,
1905                                      g_param_spec_int ("num-users",
1906                                                        "num-users",
1907                                                        "Number of login users",
1908                                                        0, G_MAXINT, 0,
1909                                                        G_PARAM_READABLE));
1910     /*g_object_class_install_property (object_class,
1911                                      PROP_USERS,
1912                                      g_param_spec_list ("users",
1913                                                         "users",
1914                                                         "Users that can login"));
1915     g_object_class_install_property (object_class,
1916                                      PROP_DEFAULT_LANGUAGE,
1917                                      g_param_spec_string ("default-language",
1918                                                           "default-language",
1919                                                           "Default language",
1920                                                           NULL,
1921                                                           G_PARAM_READWRITE));
1922     g_object_class_install_property (object_class,
1923                                      PROP_LAYOUTS,
1924                                      g_param_spec_list ("layouts",
1925                                                         "layouts",
1926                                                         "Available keyboard layouts"));*/
1927     g_object_class_install_property (object_class,
1928                                      PROP_LAYOUT,
1929                                      g_param_spec_string ("layout",
1930                                                           "layout",
1931                                                           "Current keyboard layout",
1932                                                           NULL,
1933                                                           G_PARAM_READWRITE));
1934     /*g_object_class_install_property (object_class,
1935                                      PROP_SESSIONS,
1936                                      g_param_spec_list ("sessions",
1937                                                         "sessions",
1938                                                         "Available sessions"));*/
1939     g_object_class_install_property (object_class,
1940                                      PROP_DEFAULT_SESSION_HINT,
1941                                      g_param_spec_string ("default-session-hint",
1942                                                           "default-session-hint",
1943                                                           "Default session hint",
1944                                                           NULL,
1945                                                           G_PARAM_READWRITE));
1946
1947     g_object_class_install_property (object_class,
1948                                      PROP_HIDE_USERS_HINT,
1949                                      g_param_spec_boolean ("hide-users-hint",
1950                                                            "hide-users-hint",
1951                                                            "hide users hint",
1952                                                            FALSE,
1953                                                            G_PARAM_READABLE));
1954
1955     g_object_class_install_property (object_class,
1956                                      PROP_HAS_GUEST_ACCOUNT_HINT,
1957                                      g_param_spec_boolean ("has-guest-account-hint",
1958                                                            "has-guest-account-hint",
1959                                                            "Has guest account hint",
1960                                                            FALSE,
1961                                                            G_PARAM_READABLE));
1962
1963     g_object_class_install_property (object_class,
1964                                      PROP_SELECT_USER_HINT,
1965                                      g_param_spec_string ("select-user-hint",
1966                                                           "select-user-hint",
1967                                                           "Select user hint",
1968                                                           NULL,
1969                                                           G_PARAM_READABLE));
1970
1971     g_object_class_install_property (object_class,
1972                                      PROP_SELECT_GUEST_HINT,
1973                                      g_param_spec_boolean ("select-guest-hint",
1974                                                            "select-guest-hint",
1975                                                            "Select guest account hint",
1976                                                            FALSE,
1977                                                            G_PARAM_READABLE));
1978
1979     g_object_class_install_property (object_class,
1980                                      PROP_AUTOLOGIN_USER_HINT,
1981                                      g_param_spec_string ("autologin-user-hint",
1982                                                           "autologin-user-hint",
1983                                                           "Autologin user hint",
1984                                                           NULL,
1985                                                           G_PARAM_READABLE));
1986
1987     g_object_class_install_property (object_class,
1988                                      PROP_AUTOLOGIN_GUEST_HINT,
1989                                      g_param_spec_boolean ("autologin-guest-hint",
1990                                                            "autologin-guest-hint",
1991                                                            "Autologin guest account hint",
1992                                                            FALSE,
1993                                                            G_PARAM_READABLE));
1994
1995     g_object_class_install_property (object_class,
1996                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
1997                                      g_param_spec_int ("autologin-timeout-hint",
1998                                                        "autologin-timeout-hint",
1999                                                        "Autologin timeout hint",
2000                                                        0, G_MAXINT, 0,
2001                                                        G_PARAM_READABLE));
2002
2003     g_object_class_install_property (object_class,
2004                                      PROP_AUTHENTICATION_USER,
2005                                      g_param_spec_string ("authentication-user",
2006                                                           "authentication-user",
2007                                                           "The user being authenticated",
2008                                                           NULL,
2009                                                           G_PARAM_READABLE));
2010     g_object_class_install_property (object_class,
2011                                      PROP_IN_AUTHENTICATION,
2012                                      g_param_spec_boolean ("in-authentication",
2013                                                            "in-authentication",
2014                                                            "TRUE if a user is being authenticated",
2015                                                            FALSE,
2016                                                            G_PARAM_READABLE));
2017     g_object_class_install_property (object_class,
2018                                      PROP_IS_AUTHENTICATED,
2019                                      g_param_spec_boolean ("is-authenticated",
2020                                                            "is-authenticated",
2021                                                            "TRUE if the selected user is authenticated",
2022                                                            FALSE,
2023                                                            G_PARAM_READABLE));
2024     g_object_class_install_property (object_class,
2025                                      PROP_CAN_SUSPEND,
2026                                      g_param_spec_boolean ("can-suspend",
2027                                                            "can-suspend",
2028                                                            "TRUE if allowed to suspend the system",
2029                                                            FALSE,
2030                                                            G_PARAM_READABLE));
2031     g_object_class_install_property (object_class,
2032                                      PROP_CAN_HIBERNATE,
2033                                      g_param_spec_boolean ("can-hibernate",
2034                                                            "can-hibernate",
2035                                                            "TRUE if allowed to hibernate the system",
2036                                                            FALSE,
2037                                                            G_PARAM_READABLE));
2038     g_object_class_install_property (object_class,
2039                                      PROP_CAN_RESTART,
2040                                      g_param_spec_boolean ("can-restart",
2041                                                            "can-restart",
2042                                                            "TRUE if allowed to restart the system",
2043                                                            FALSE,
2044                                                            G_PARAM_READABLE));
2045     g_object_class_install_property (object_class,
2046                                      PROP_CAN_SHUTDOWN,
2047                                      g_param_spec_boolean ("can-shutdown",
2048                                                            "can-shutdown",
2049                                                            "TRUE if allowed to shutdown the system",
2050                                                            FALSE,
2051                                                            G_PARAM_READABLE));
2052
2053     /**
2054      * LdmGreeter::connected:
2055      * @greeter: A #LdmGreeter
2056      *
2057      * The ::connected signal gets emitted when the greeter connects to the
2058      * LightDM server.
2059      **/
2060     signals[CONNECTED] =
2061         g_signal_new ("connected",
2062                       G_TYPE_FROM_CLASS (klass),
2063                       G_SIGNAL_RUN_LAST,
2064                       G_STRUCT_OFFSET (LdmGreeterClass, connected),
2065                       NULL, NULL,
2066                       g_cclosure_marshal_VOID__VOID,
2067                       G_TYPE_NONE, 0);
2068
2069     /**
2070      * LdmGreeter::show-prompt:
2071      * @greeter: A #LdmGreeter
2072      * @text: Prompt text
2073      * @type: Prompt type
2074      *
2075      * The ::show-prompt signal gets emitted when the greeter should show a
2076      * prompt to the user.  The given text should be displayed and an input
2077      * field for the user to provide a response.
2078      *
2079      * Call ldm_greeter_respond() with the resultant input or
2080      * ldm_greeter_cancel_authentication() to abort the authentication.
2081      **/
2082     signals[SHOW_PROMPT] =
2083         g_signal_new ("show-prompt",
2084                       G_TYPE_FROM_CLASS (klass),
2085                       G_SIGNAL_RUN_LAST,
2086                       G_STRUCT_OFFSET (LdmGreeterClass, show_prompt),
2087                       NULL, NULL,
2088                       marshal_VOID__STRING_INT,
2089                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
2090
2091     /**
2092      * LdmGreeter::show-message:
2093      * @greeter: A #LdmGreeter
2094      * @text: Message text
2095      * @type: Message type
2096      *
2097      * The ::show-message signal gets emitted when the greeter
2098      * should show a message to the user.
2099      **/
2100     signals[SHOW_MESSAGE] =
2101         g_signal_new ("show-message",
2102                       G_TYPE_FROM_CLASS (klass),
2103                       G_SIGNAL_RUN_LAST,
2104                       G_STRUCT_OFFSET (LdmGreeterClass, show_message),
2105                       NULL, NULL,
2106                       marshal_VOID__STRING_INT,
2107                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
2108
2109     /**
2110      * LdmGreeter::authentication-complete:
2111      * @greeter: A #LdmGreeter
2112      *
2113      * The ::authentication-complete signal gets emitted when the greeter
2114      * has completed authentication.
2115      *
2116      * Call ldm_greeter_get_is_authenticated() to check if the authentication
2117      * was successful.
2118      **/
2119     signals[AUTHENTICATION_COMPLETE] =
2120         g_signal_new ("authentication-complete",
2121                       G_TYPE_FROM_CLASS (klass),
2122                       G_SIGNAL_RUN_LAST,
2123                       G_STRUCT_OFFSET (LdmGreeterClass, authentication_complete),
2124                       NULL, NULL,
2125                       g_cclosure_marshal_VOID__VOID,
2126                       G_TYPE_NONE, 0);
2127
2128     /**
2129      * LdmGreeter::session-failed:
2130      * @greeter: A #LdmGreeter
2131      *
2132      * The ::session-failed signal gets emitted when the deamon has failed
2133      * to start the requested session.
2134      **/
2135     signals[SESSION_FAILED] =
2136         g_signal_new ("session-failed",
2137                       G_TYPE_FROM_CLASS (klass),
2138                       G_SIGNAL_RUN_LAST,
2139                       G_STRUCT_OFFSET (LdmGreeterClass, session_failed),
2140                       NULL, NULL,
2141                       g_cclosure_marshal_VOID__VOID,
2142                       G_TYPE_NONE, 0);
2143
2144     /**
2145      * LdmGreeter::autologin-timer-expired:
2146      * @greeter: A #LdmGreeter
2147      * @username: A username
2148      *
2149      * The ::timed-login signal gets emitted when the automatic login timer has expired.
2150      * The application should then call ldm_greeter_login().
2151      **/
2152     signals[AUTOLOGIN_TIMER_EXPIRED] =
2153         g_signal_new ("autologin-timer-expired",
2154                       G_TYPE_FROM_CLASS (klass),
2155                       G_SIGNAL_RUN_LAST,
2156                       G_STRUCT_OFFSET (LdmGreeterClass, autologin_timer_expired),
2157                       NULL, NULL,
2158                       g_cclosure_marshal_VOID__VOID,
2159                       G_TYPE_NONE, 0);
2160
2161     /**
2162      * LdmGreeter::user-added:
2163      * @greeter: A #LdmGreeter
2164      *
2165      * The ::user-added signal gets emitted when a user account is created.
2166      **/
2167     signals[USER_ADDED] =
2168         g_signal_new ("user-added",
2169                       G_TYPE_FROM_CLASS (klass),
2170                       G_SIGNAL_RUN_LAST,
2171                       G_STRUCT_OFFSET (LdmGreeterClass, user_added),
2172                       NULL, NULL,
2173                       g_cclosure_marshal_VOID__OBJECT,
2174                       G_TYPE_NONE, 1, LDM_TYPE_USER);
2175
2176     /**
2177      * LdmGreeter::user-changed:
2178      * @greeter: A #LdmGreeter
2179      *
2180      * The ::user-changed signal gets emitted when a user account is modified.
2181      **/
2182     signals[USER_CHANGED] =
2183         g_signal_new ("user-changed",
2184                       G_TYPE_FROM_CLASS (klass),
2185                       G_SIGNAL_RUN_LAST,
2186                       G_STRUCT_OFFSET (LdmGreeterClass, user_changed),
2187                       NULL, NULL,
2188                       g_cclosure_marshal_VOID__OBJECT,
2189                       G_TYPE_NONE, 1, LDM_TYPE_USER);
2190
2191     /**
2192      * LdmGreeter::user-removed:
2193      * @greeter: A #LdmGreeter
2194      *
2195      * The ::user-removed signal gets emitted when a user account is removed.
2196      **/
2197     signals[USER_REMOVED] =
2198         g_signal_new ("user-removed",
2199                       G_TYPE_FROM_CLASS (klass),
2200                       G_SIGNAL_RUN_LAST,
2201                       G_STRUCT_OFFSET (LdmGreeterClass, user_removed),
2202                       NULL, NULL,
2203                       g_cclosure_marshal_VOID__OBJECT,
2204                       G_TYPE_NONE, 1, LDM_TYPE_USER);
2205
2206     /**
2207      * LdmGreeter::quit:
2208      * @greeter: A #LdmGreeter
2209      *
2210      * The ::quit signal gets emitted when the greeter should exit.
2211      **/
2212     signals[QUIT] =
2213         g_signal_new ("quit",
2214                       G_TYPE_FROM_CLASS (klass),
2215                       G_SIGNAL_RUN_LAST,
2216                       G_STRUCT_OFFSET (LdmGreeterClass, quit),
2217                       NULL, NULL,
2218                       g_cclosure_marshal_VOID__VOID,
2219                       G_TYPE_NONE, 0);
2220 }