]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - liblightdm-gobject/greeter.c
Get rid of lightdm_greeter_get_user_list
[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
26 enum {
27     PROP_0,
28     PROP_HOSTNAME,
29     PROP_DEFAULT_LANGUAGE,
30     PROP_LAYOUTS,
31     PROP_LAYOUT,
32     PROP_SESSIONS,
33     PROP_DEFAULT_SESSION_HINT,
34     PROP_HIDE_USERS_HINT,
35     PROP_HAS_GUEST_ACCOUNT_HINT,
36     PROP_SELECT_USER_HINT,
37     PROP_SELECT_GUEST_HINT,
38     PROP_AUTOLOGIN_USER_HINT,
39     PROP_AUTOLOGIN_GUEST_HINT,
40     PROP_AUTOLOGIN_TIMEOUT_HINT,
41     PROP_AUTHENTICATION_USER,
42     PROP_IN_AUTHENTICATION,
43     PROP_IS_AUTHENTICATED,
44     PROP_CAN_SUSPEND,
45     PROP_CAN_HIBERNATE,
46     PROP_CAN_RESTART,
47     PROP_CAN_SHUTDOWN
48 };
49
50 enum {
51     CONNECTED,
52     SHOW_PROMPT,
53     SHOW_MESSAGE,
54     AUTHENTICATION_COMPLETE,
55     SESSION_FAILED,
56     AUTOLOGIN_TIMER_EXPIRED,
57     QUIT,
58     LAST_SIGNAL
59 };
60 static guint signals[LAST_SIGNAL] = { 0 };
61
62 typedef struct
63 {
64     GDBusConnection *system_bus;
65
66     GIOChannel *to_server_channel, *from_server_channel;
67     guint8 *read_buffer;
68     gsize n_read;
69
70     Display *display;
71
72     gchar *hostname;
73
74     LightDMUserList *user_list;
75   
76     gboolean have_languages;
77     GList *languages;
78
79     XklEngine *xkl_engine;
80     XklConfigRec *xkl_config;
81     gboolean have_layouts;
82     GList *layouts;
83     gchar *layout;
84
85     gboolean have_sessions;
86     GList *sessions;
87
88     gchar *authentication_user;
89     gboolean in_authentication;
90     gboolean is_authenticated;
91     guint32 authenticate_sequence_number;
92     gboolean cancelling_authentication;
93   
94     GHashTable *hints;
95
96     guint login_timeout;
97 } LightDMGreeterPrivate;
98
99 G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
100
101 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
102
103 #define HEADER_SIZE 8
104 #define MAX_MESSAGE_LENGTH 1024
105
106 /* Messages from the greeter to the server */
107 typedef enum
108 {
109     GREETER_MESSAGE_CONNECT = 0,
110     GREETER_MESSAGE_LOGIN,
111     GREETER_MESSAGE_LOGIN_AS_GUEST,
112     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
113     GREETER_MESSAGE_START_SESSION,
114     GREETER_MESSAGE_CANCEL_AUTHENTICATION
115 } GreeterMessage;
116
117 /* Messages from the server to the greeter */
118 typedef enum
119 {
120     SERVER_MESSAGE_CONNECTED = 0,
121     SERVER_MESSAGE_QUIT,
122     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
123     SERVER_MESSAGE_END_AUTHENTICATION,
124     SERVER_MESSAGE_SESSION_FAILED,
125 } ServerMessage;
126
127 /**
128  * lightdm_greeter_new:
129  *
130  * Create a new greeter.
131  *
132  * Return value: the new #LightDMGreeter
133  **/
134 LightDMGreeter *
135 lightdm_greeter_new ()
136 {
137     return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
138 }
139
140 static gboolean
141 timed_login_cb (gpointer data)
142 {
143     LightDMGreeter *greeter = data;
144     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
145
146     priv->login_timeout = 0;
147     g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
148
149     return FALSE;
150 }
151
152 static guint32
153 int_length ()
154 {
155     return 4;
156 }
157
158 static void
159 write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
160 {
161     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
162     GError *error = NULL;
163
164     if (g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, NULL) != G_IO_STATUS_NORMAL)
165         g_warning ("Error writing to daemon: %s", error->message);
166     else
167         g_debug ("Wrote %zi bytes to daemon", message_length);
168     g_clear_error (&error);
169     g_io_channel_flush (priv->to_server_channel, NULL);
170 }
171
172 static void
173 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
174 {
175     if (*offset + 4 >= buffer_length)
176         return;
177     buffer[*offset] = value >> 24;
178     buffer[*offset+1] = (value >> 16) & 0xFF;
179     buffer[*offset+2] = (value >> 8) & 0xFF;
180     buffer[*offset+3] = value & 0xFF;
181     *offset += 4;
182 }
183
184 static void
185 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
186 {
187     gint length = strlen (value);
188     write_int (buffer, buffer_length, length, offset);
189     if (*offset + length >= buffer_length)
190         return;
191     memcpy (buffer + *offset, value, length);
192     *offset += length;
193 }
194
195 static guint32
196 read_int (LightDMGreeter *greeter, gsize *offset)
197 {
198     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
199     guint32 value;
200     guint8 *buffer;
201
202     if (priv->n_read - *offset < int_length ())
203     {
204         g_warning ("Not enough space for int, need %i, got %zi", int_length (), priv->n_read - *offset);
205         return 0;
206     }
207
208     buffer = priv->read_buffer + *offset;
209     value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
210     *offset += int_length ();
211
212     return value;
213 }
214
215 static gchar *
216 read_string (LightDMGreeter *greeter, gsize *offset)
217 {
218     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
219     guint32 length;
220     gchar *value;
221
222     length = read_int (greeter, offset);
223     if (priv->n_read - *offset < length)
224     {
225         g_warning ("Not enough space for string, need %u, got %zu", length, priv->n_read - *offset);
226         return g_strdup ("");
227     }
228
229     value = g_malloc (sizeof (gchar) * (length + 1));
230     memcpy (value, priv->read_buffer + *offset, length);
231     value[length] = '\0';
232     *offset += length;
233
234     return value;
235 }
236
237 static guint32
238 string_length (const gchar *value)
239 {
240     return int_length () + strlen (value);
241 }
242
243 static void
244 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
245 {
246     write_int (buffer, buffer_length, id, offset);
247     write_int (buffer, buffer_length, length, offset);
248 }
249
250 static guint32 get_packet_length (LightDMGreeter *greeter)
251 {
252     gsize offset = 4;
253     return read_int (greeter, &offset);
254 }
255
256 static void
257 handle_connected (LightDMGreeter *greeter, guint32 length, gsize *offset)
258 {
259     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
260     gchar *version;
261     GString *hint_string;
262     int timeout;
263
264     version = read_string (greeter, offset);
265     hint_string = g_string_new ("");
266     while (*offset < length)
267     {
268         gchar *name, *value;
269       
270         name = read_string (greeter, offset);
271         value = read_string (greeter, offset);
272         g_hash_table_insert (priv->hints, name, value);
273         g_string_append_printf (hint_string, " %s=%s", name, value);
274     }
275
276     g_debug ("Connected version=%s%s", version, hint_string->str);
277     g_free (version);
278     g_string_free (hint_string, TRUE);
279
280     /* Set timeout for default login */
281     timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
282     if (timeout)
283     {
284         g_debug ("Setting autologin timer for %d seconds", timeout);
285         priv->login_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
286     }
287     g_signal_emit (G_OBJECT (greeter), signals[CONNECTED], 0);
288 }
289
290 static void
291 handle_prompt_authentication (LightDMGreeter *greeter, gsize *offset)
292 {
293     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
294     guint32 sequence_number, n_messages, i;
295
296     sequence_number = read_int (greeter, offset);
297     if (sequence_number != priv->authenticate_sequence_number)
298     {
299         g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
300         return;
301     }
302
303     if (priv->cancelling_authentication)
304     {
305         g_debug ("Ignoring prompt authentication as waiting for it to cancel");
306         return;
307     }
308
309     n_messages = read_int (greeter, offset);
310     g_debug ("Prompt user with %d message(s)", n_messages);
311
312     for (i = 0; i < n_messages; i++)
313     {
314         int msg_style;
315         gchar *msg;
316
317         msg_style = read_int (greeter, offset);
318         msg = read_string (greeter, offset);
319
320         // FIXME: Should stop on prompts?
321         switch (msg_style)
322         {
323         case PAM_PROMPT_ECHO_OFF:
324             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg, LIGHTDM_PROMPT_TYPE_SECRET);
325             break;
326         case PAM_PROMPT_ECHO_ON:
327             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg, LIGHTDM_PROMPT_TYPE_QUESTION);
328             break;
329         case PAM_ERROR_MSG:
330             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg, LIGHTDM_MESSAGE_TYPE_ERROR);
331             break;
332         case PAM_TEXT_INFO:
333             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg, LIGHTDM_MESSAGE_TYPE_INFO);
334             break;
335         }
336
337         g_free (msg);
338     }
339 }
340
341 static void
342 handle_end_authentication (LightDMGreeter *greeter, gsize *offset)
343 {
344     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
345     guint32 sequence_number, return_code;
346
347     sequence_number = read_int (greeter, offset);
348     return_code = read_int (greeter, offset);
349
350     if (sequence_number != priv->authenticate_sequence_number)
351     {
352         g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
353         return;
354     }
355
356     g_debug ("Authentication complete with return code %d", return_code);
357     priv->cancelling_authentication = FALSE;
358     priv->is_authenticated = (return_code == 0);
359     if (!priv->is_authenticated)
360     {
361         g_free (priv->authentication_user);
362         priv->authentication_user = NULL;
363     }
364     g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
365     priv->in_authentication = FALSE;
366 }
367
368 static void
369 handle_session_failed (LightDMGreeter *greeter, gsize *offset)
370
371     g_debug ("Session failed to start");
372     g_signal_emit (G_OBJECT (greeter), signals[SESSION_FAILED], 0);
373 }
374
375 static void
376 handle_quit (LightDMGreeter *greeter, gsize *offset)
377 {
378     g_debug ("Got quit request from server");
379     g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
380 }
381
382 static gboolean
383 read_packet (LightDMGreeter *greeter, gboolean block)
384 {
385     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
386     gsize n_to_read, n_read;
387     GError *error = NULL;
388
389     /* Read the header, or the whole packet if we already have that */
390     n_to_read = HEADER_SIZE;
391     if (priv->n_read >= HEADER_SIZE)
392         n_to_read += get_packet_length (greeter);
393
394     do
395     {
396         GIOStatus status;
397         status = g_io_channel_read_chars (priv->from_server_channel,
398                                           (gchar *) priv->read_buffer + priv->n_read,
399                                           n_to_read - priv->n_read,
400                                           &n_read,
401                                           &error);
402         if (status == G_IO_STATUS_ERROR)
403             g_warning ("Error reading from server: %s", error->message);
404         g_clear_error (&error);
405         if (status != G_IO_STATUS_NORMAL)
406             break;
407
408         g_debug ("Read %zi bytes from daemon", n_read);
409
410         priv->n_read += n_read;
411     } while (priv->n_read < n_to_read && block);
412
413     /* Stop if haven't got all the data we want */
414     if (priv->n_read != n_to_read)
415         return FALSE;
416
417     /* If have header, rerun for content */
418     if (priv->n_read == HEADER_SIZE)
419     {
420         n_to_read = get_packet_length (greeter);
421         if (n_to_read > 0)
422         {
423             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
424             return read_packet (greeter, block);
425         }
426     }
427
428     return TRUE;
429 }
430
431 static gboolean
432 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
433 {
434     LightDMGreeter *greeter = data;
435     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
436     gsize offset;
437     guint32 id, length;
438
439     if (!read_packet (greeter, FALSE))
440         return TRUE;
441
442     offset = 0;
443     id = read_int (greeter, &offset);
444     length = read_int (greeter, &offset);
445     switch (id)
446     {
447     case SERVER_MESSAGE_CONNECTED:
448         handle_connected (greeter, length, &offset);
449         break;
450     case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
451         handle_prompt_authentication (greeter, &offset);
452         break;
453     case SERVER_MESSAGE_END_AUTHENTICATION:
454         handle_end_authentication (greeter, &offset);
455         break;
456     case SERVER_MESSAGE_SESSION_FAILED:
457         handle_session_failed (greeter, &offset);
458         break;
459     case SERVER_MESSAGE_QUIT:
460         handle_quit (greeter, &offset);
461         break;
462     default:
463         g_warning ("Unknown message from server: %d", id);
464         break;
465     }
466
467     priv->n_read = 0;
468
469     return TRUE;
470 }
471
472 /**
473  * lightdm_greeter_connect_to_server:
474  * @greeter: The greeter to connect
475  *
476  * Connects the greeter to the display manager.
477  *
478  * Return value: #TRUE if successfully connected
479  **/
480 gboolean
481 lightdm_greeter_connect_to_server (LightDMGreeter *greeter)
482 {
483     LightDMGreeterPrivate *priv;
484     GError *error = NULL;
485     const gchar *fd;
486     guint8 message[MAX_MESSAGE_LENGTH];
487     gsize offset = 0;
488
489     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
490
491     priv = GET_PRIVATE (greeter);
492
493     priv->system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
494     if (!priv->system_bus)
495         g_warning ("Failed to connect to system bus: %s", error->message);
496     g_clear_error (&error);
497
498     fd = getenv ("LIGHTDM_TO_SERVER_FD");
499     if (!fd)
500     {
501         g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
502         return FALSE;
503     }
504     priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
505     g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
506
507     fd = getenv ("LIGHTDM_FROM_SERVER_FD");
508     if (!fd)
509     {
510         g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
511         return FALSE;
512     }
513     priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
514     g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
515     g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
516
517     g_debug ("Connecting to display manager...");
518     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
519     write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
520     write_message (greeter, message, offset);
521
522     return TRUE;
523 }
524
525 /**
526  * lightdm_greeter_get_hostname:
527  * @greeter: a #LightDMGreeter
528  *
529  * Return value: The host this greeter is displaying
530  **/
531 const gchar *
532 lightdm_greeter_get_hostname (LightDMGreeter *greeter)
533 {
534     LightDMGreeterPrivate *priv;
535
536     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
537
538     priv = GET_PRIVATE (greeter);
539
540     if (!priv->hostname)
541     {
542         struct utsname info;
543         uname (&info);
544         priv->hostname = g_strdup (info.nodename);
545     }
546
547     return priv->hostname;
548 }
549
550 static void
551 update_languages (LightDMGreeter *greeter)
552 {
553     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
554     gchar *stdout_text = NULL, *stderr_text = NULL;
555     gint exit_status;
556     gboolean result;
557     GError *error = NULL;
558
559     if (priv->have_languages)
560         return;
561
562     result = g_spawn_command_line_sync ("locale -a", &stdout_text, &stderr_text, &exit_status, &error);
563     if (!result || exit_status != 0)
564         g_warning ("Failed to get languages, locale -a returned %d: %s", exit_status, error->message);
565     else
566     {
567         gchar **tokens;
568         int i;
569
570         tokens = g_strsplit_set (stdout_text, "\n\r", -1);
571         for (i = 0; tokens[i]; i++)
572         {
573             LightDMLanguage *language;
574             gchar *code;
575
576             code = g_strchug (tokens[i]);
577             if (code[0] == '\0')
578                 continue;
579
580             /* Ignore the non-interesting languages */
581             if (strcmp (code, "C") == 0 || strcmp (code, "POSIX") == 0)
582                 continue;
583
584             language = g_object_new (LIGHTDM_TYPE_LANGUAGE, "code", code, NULL);
585             priv->languages = g_list_append (priv->languages, language);
586         }
587
588         g_strfreev (tokens);
589     }
590
591     g_clear_error (&error);
592     g_free (stdout_text);
593     g_free (stderr_text);
594
595     priv->have_languages = TRUE;
596 }
597
598 /**
599  * lightdm_greeter_get_default_language:
600  * @greeter: A #LightDMGreeter
601  *
602  * Get the default language.
603  *
604  * Return value: The default language.
605  **/
606 const gchar *
607 lightdm_greeter_get_default_language (LightDMGreeter *greeter)
608 {
609     gchar *lang;
610     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
611     lang = getenv ("LANG");
612     if (lang)
613         return lang;
614     else
615         return "C";
616 }
617
618 /**
619  * lightdm_greeter_get_languages:
620  * @greeter: A #LightDMGreeter
621  *
622  * Get a list of languages to present to the user.
623  *
624  * Return value: (element-type LightDMLanguage) (transfer none): A list of #LightDMLanguage that should be presented to the user.
625  **/
626 GList *
627 lightdm_greeter_get_languages (LightDMGreeter *greeter)
628 {
629     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
630     update_languages (greeter);
631     return GET_PRIVATE (greeter)->languages;
632 }
633
634 static void
635 layout_cb (XklConfigRegistry *config,
636            const XklConfigItem *item,
637            gpointer data)
638 {
639     LightDMGreeter *greeter = data;
640     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
641     LightDMLayout *layout;
642
643     layout = g_object_new (LIGHTDM_TYPE_LAYOUT, "name", item->name, "short-description", item->short_description, "description", item->description, NULL);
644     priv->layouts = g_list_append (priv->layouts, layout);
645 }
646
647 static void
648 setup_display (LightDMGreeter *greeter)
649 {
650     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
651     if (!priv->display)
652         priv->display = XOpenDisplay (NULL);
653 }
654
655 static void
656 setup_xkl (LightDMGreeter *greeter)
657 {
658     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
659
660     setup_display (greeter);
661
662     priv->xkl_engine = xkl_engine_get_instance (priv->display);
663     priv->xkl_config = xkl_config_rec_new ();
664     if (!xkl_config_rec_get_from_server (priv->xkl_config, priv->xkl_engine))
665         g_warning ("Failed to get Xkl configuration from server");
666     priv->layout = g_strdup (priv->xkl_config->layouts[0]);
667 }
668
669 /**
670  * lightdm_greeter_get_layouts:
671  * @greeter: A #LightDMGreeter
672  *
673  * Get a list of keyboard layouts to present to the user.
674  *
675  * Return value: (element-type LightDMLayout) (transfer none): A list of #LightDMLayout that should be presented to the user.
676  **/
677 GList *
678 lightdm_greeter_get_layouts (LightDMGreeter *greeter)
679 {
680     LightDMGreeterPrivate *priv;
681     XklConfigRegistry *registry;
682
683     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
684
685     priv = GET_PRIVATE (greeter);
686
687     if (priv->have_layouts)
688         return priv->layouts;
689
690     setup_xkl (greeter);
691
692     registry = xkl_config_registry_get_instance (priv->xkl_engine);
693     xkl_config_registry_load (registry, FALSE);
694     xkl_config_registry_foreach_layout (registry, layout_cb, greeter);
695     g_object_unref (registry);
696     priv->have_layouts = TRUE;
697
698     return priv->layouts;
699 }
700
701 /**
702  * lightdm_greeter_set_layout:
703  * @greeter: A #LightDMGreeter
704  * @layout: The layout to use
705  *
706  * Set the layout for this session.
707  **/
708 void
709 lightdm_greeter_set_layout (LightDMGreeter *greeter, const gchar *layout)
710 {
711     LightDMGreeterPrivate *priv;
712     XklConfigRec *config;
713
714     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
715     g_return_if_fail (layout != NULL);
716
717     priv = GET_PRIVATE (greeter);
718
719     g_debug ("Setting keyboard layout to %s", layout);
720
721     setup_xkl (greeter);
722
723     config = xkl_config_rec_new ();
724     config->layouts = g_malloc (sizeof (gchar *) * 2);
725     config->model = g_strdup (priv->xkl_config->model);
726     config->layouts[0] = g_strdup (layout);
727     config->layouts[1] = NULL;
728     if (!xkl_config_rec_activate (config, priv->xkl_engine))
729         g_warning ("Failed to activate XKL config");
730     else
731         priv->layout = g_strdup (layout);
732     g_object_unref (config);
733 }
734
735 /**
736  * lightdm_greeter_get_layout:
737  * @greeter: A #LightDMGreeter
738  *
739  * Get the current keyboard layout.
740  *
741  * Return value: The currently active layout for this user.
742  **/
743 const gchar *
744 lightdm_greeter_get_layout (LightDMGreeter *greeter)
745 {
746     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
747     setup_xkl (greeter);
748     return GET_PRIVATE (greeter)->layout;
749 }
750
751 static void
752 update_sessions (LightDMGreeter *greeter)
753 {
754     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
755     GDir *directory;
756     GError *error = NULL;
757
758     if (priv->have_sessions)
759         return;
760
761     directory = g_dir_open (XSESSIONS_DIR, 0, &error);
762     if (!directory)
763         g_warning ("Failed to open sessions directory: %s", error->message);
764     g_clear_error (&error);
765     if (!directory)
766         return;
767
768     while (TRUE)
769     {
770         const gchar *filename;
771         GKeyFile *key_file;
772         gchar *key, *path;
773         gboolean result;
774
775         filename = g_dir_read_name (directory);
776         if (filename == NULL)
777             break;
778
779         if (!g_str_has_suffix (filename, ".desktop"))
780             continue;
781
782         key = g_strndup (filename, strlen (filename) - strlen (".desktop"));
783         path = g_build_filename (XSESSIONS_DIR, filename, NULL);
784         g_debug ("Loading session %s", path);
785
786         key_file = g_key_file_new ();
787         result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
788         if (!result)
789             g_warning ("Failed to load session file %s: %s:", path, error->message);
790         g_clear_error (&error);
791
792         if (result && !g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL))
793         {
794             gchar *domain, *name, *comment;
795
796 #ifdef G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN
797             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN, NULL);
798 #else
799             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL);
800 #endif
801             name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, domain, NULL);
802             comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, domain, NULL);
803             if (!comment)
804                 comment = g_strdup ("");
805             if (name)
806             {
807                 g_debug ("Loaded session %s (%s, %s)", key, name, comment);
808                 priv->sessions = g_list_append (priv->sessions, g_object_new (LIGHTDM_TYPE_SESSION, "key", key, "name", name, "comment", comment, NULL));
809             }
810             else
811                 g_warning ("Invalid session %s: %s", path, error->message);
812             g_free (domain);
813             g_free (name);
814             g_free (comment);
815         }
816
817         g_free (key);
818         g_free (path);
819         g_key_file_free (key_file);
820     }
821
822     g_dir_close (directory);
823
824     priv->have_sessions = TRUE;
825 }
826
827 /**
828  * lightdm_greeter_get_sessions:
829  * @greeter: A #LightDMGreeter
830  *
831  * Get the available sessions.
832  *
833  * Return value: (element-type LightDMSession) (transfer none): A list of #LightDMSession
834  **/
835 GList *
836 lightdm_greeter_get_sessions (LightDMGreeter *greeter)
837 {
838     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
839     update_sessions (greeter);
840     return GET_PRIVATE (greeter)->sessions;
841 }
842
843 /**
844  * lightdm_greeter_get_hint:
845  * @greeter: A #LightDMGreeter
846  * @name: The hint name to query.
847  *
848  * Get a hint.
849  *
850  * Return value: The value for this hint or #NULL if not set.
851  **/
852 const gchar *
853 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
854 {
855     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
856     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
857 }
858
859 /**
860  * lightdm_greeter_get_default_session_hint:
861  * @greeter: A #LightDMGreeter
862  *
863  * Get the default session to use.
864  *
865  * Return value: The session name
866  **/
867 const gchar *
868 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
869 {
870     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
871     return lightdm_greeter_get_hint (greeter, "default-session");
872 }
873
874 /**
875  * lightdm_greeter_get_hide_users_hint:
876  * @greeter: A #LightDMGreeter
877  *
878  * Check if user accounts should be shown.
879  *
880  * Return value: #TRUE if the available users should not be shown.
881  */
882 gboolean
883 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
884 {
885     const gchar *value;
886
887     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
888     value = lightdm_greeter_get_hint (greeter, "hide-users");
889
890     return g_strcmp0 (value, "true") == 0;
891 }
892
893 /**
894  * lightdm_greeter_get_has_guest_account_hint:
895  * @greeter: A #LightDMGreeter
896  *
897  * Check if guest sessions are supported.
898  *
899  * Return value: #TRUE if guest sessions are supported.
900  */
901 gboolean
902 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
903 {
904     const gchar *value;
905
906     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
907     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
908   
909     return g_strcmp0 (value, "true") == 0;
910 }
911
912 /**
913  * lightdm_greeter_get_select_user_hint:
914  * @greeter: A #LightDMGreeter
915  *
916  * Get the user to select by default.
917  *
918  * Return value: A username
919  */
920 const gchar *
921 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
922 {
923     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
924     return lightdm_greeter_get_hint (greeter, "select-user");
925 }
926
927 /**
928  * lightdm_greeter_get_select_guest_hint:
929  * @greeter: A #LightDMGreeter
930  *
931  * Check if the guest account should be selected by default.
932  *
933  * Return value: #TRUE if the guest account should be selected by default.
934  */
935 gboolean
936 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
937 {
938     const gchar *value;
939
940     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
941     value = lightdm_greeter_get_hint (greeter, "select-guest");
942   
943     return g_strcmp0 (value, "true") == 0;
944 }
945
946 /**
947  * lightdm_greeter_get_autologin_user_hint:
948  * @greeter: A #LightDMGreeter
949  *
950  * Get the user account to automatically logg into when the timer expires.
951  *
952  * Return value: The user account to automatically log into.
953  */
954 const gchar *
955 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
956 {
957     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
958     return lightdm_greeter_get_hint (greeter, "autologin-user");
959 }
960
961 /**
962  * lightdm_greeter_get_autologin_guest_hint:
963  * @greeter: A #LightDMGreeter
964  *
965  * Check if the guest account should be automatically logged into when the timer expires.
966  *
967  * Return value: #TRUE if the guest account should be automatically logged into.
968  */
969 gboolean
970 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
971 {
972     const gchar *value;
973
974     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
975     value = lightdm_greeter_get_hint (greeter, "autologin-guest");
976   
977     return g_strcmp0 (value, "true") == 0;
978 }
979
980 /**
981  * lightdm_greeter_get_autologin_timeout_hint:
982  * @greeter: A #LightDMGreeter
983  *
984  * Get the number of seconds to wait before automaitcally logging in.
985  *
986  * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
987  */
988 gint
989 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
990 {
991     const gchar *value;
992     gint timeout = 0;
993
994     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
995     value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
996     if (value)
997         timeout = atoi (value);
998     if (timeout < 0)
999         timeout = 0;
1000
1001     return timeout;
1002 }
1003
1004 /**
1005  * lightdm_greeter_cancel_timed_login:
1006  * @greeter: A #LightDMGreeter
1007  *
1008  * Cancel the login as the default user.
1009  */
1010 void
1011 lightdm_greeter_cancel_timed_login (LightDMGreeter *greeter)
1012 {
1013     LightDMGreeterPrivate *priv;
1014
1015     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1016
1017     priv = GET_PRIVATE (greeter);
1018
1019     if (priv->login_timeout)
1020        g_source_remove (priv->login_timeout);
1021     priv->login_timeout = 0;
1022 }
1023
1024 /**
1025  * lightdm_greeter_login:
1026  * @greeter: A #LightDMGreeter
1027  * @username: (allow-none): A username or #NULL to prompt for a username.
1028  *
1029  * Starts the authentication procedure for a user.
1030  **/
1031 void
1032 lightdm_greeter_login (LightDMGreeter *greeter, const char *username)
1033 {
1034     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1035     guint8 message[MAX_MESSAGE_LENGTH];
1036     gsize offset = 0;
1037
1038     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1039
1040     if (!username)
1041         username = "";
1042
1043     priv->cancelling_authentication = FALSE;
1044     priv->authenticate_sequence_number++;
1045     priv->in_authentication = TRUE;  
1046     priv->is_authenticated = FALSE;
1047     g_free (priv->authentication_user);
1048     priv->authentication_user = g_strdup (username);
1049
1050     g_debug ("Starting authentication for user %s...", username);
1051     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_LOGIN, int_length () + string_length (username), &offset);
1052     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1053     write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
1054     write_message (greeter, message, offset);
1055 }
1056
1057 /**
1058  * lightdm_greeter_login_with_user_prompt:
1059  * @greeter: A #LightDMGreeter
1060  *
1061  * Starts the authentication procedure, prompting the greeter for a username.
1062  **/
1063 void
1064 lightdm_greeter_login_with_user_prompt (LightDMGreeter *greeter)
1065 {
1066     lightdm_greeter_login (greeter, NULL);
1067 }
1068
1069 /**
1070  * lightdm_greeter_login_as_guest:
1071  * @greeter: A #LightDMGreeter
1072  *
1073  * Starts the authentication procedure for the guest user.
1074  **/
1075 void
1076 lightdm_greeter_login_as_guest (LightDMGreeter *greeter)
1077 {
1078     LightDMGreeterPrivate *priv;
1079     guint8 message[MAX_MESSAGE_LENGTH];
1080     gsize offset = 0;
1081
1082     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1083
1084     priv = GET_PRIVATE (greeter);
1085
1086     priv->cancelling_authentication = FALSE;
1087     priv->authenticate_sequence_number++;
1088     priv->in_authentication = TRUE;
1089     priv->is_authenticated = FALSE;
1090     g_free (priv->authentication_user);
1091     priv->authentication_user = NULL;
1092
1093     g_debug ("Starting authentication for guest account...");
1094     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_LOGIN_AS_GUEST, int_length (), &offset);
1095     write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
1096     write_message (greeter, message, offset);
1097 }
1098
1099 /**
1100  * lightdm_greeter_respond:
1101  * @greeter: A #LightDMGreeter
1102  * @response: Response to a prompt
1103  *
1104  * Provide response to a prompt.
1105  **/
1106 void
1107 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
1108 {
1109     guint8 message[MAX_MESSAGE_LENGTH];
1110     gsize offset = 0;
1111
1112     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1113     g_return_if_fail (response != NULL);
1114
1115     g_debug ("Providing response to display manager");
1116     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, int_length () + string_length (response), &offset);
1117     // FIXME: Could be multiple responses required
1118     write_int (message, MAX_MESSAGE_LENGTH, 1, &offset);
1119     write_string (message, MAX_MESSAGE_LENGTH, response, &offset);
1120     write_message (greeter, message, offset);
1121 }
1122
1123 /**
1124  * lightdm_greeter_cancel_authentication:
1125  * @greeter: A #LightDMGreeter
1126  *
1127  * Cancel the current user authentication.
1128  **/
1129 void
1130 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
1131 {
1132     LightDMGreeterPrivate *priv;
1133     guint8 message[MAX_MESSAGE_LENGTH];
1134     gsize offset = 0;
1135
1136     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1137
1138     priv = GET_PRIVATE (greeter);
1139
1140     priv->cancelling_authentication = TRUE;
1141     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
1142     write_message (greeter, message, offset);
1143 }
1144
1145 /**
1146  * lightdm_greeter_get_in_authentication:
1147  * @greeter: A #LightDMGreeter
1148  *
1149  * Checks if the greeter is in the process of authenticating.
1150  *
1151  * Return value: #TRUE if the greeter is authenticating a user.
1152  **/
1153 gboolean
1154 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1155 {
1156     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1157     return GET_PRIVATE (greeter)->in_authentication;
1158 }
1159
1160 /**
1161  * lightdm_greeter_get_is_authenticated:
1162  * @greeter: A #LightDMGreeter
1163  *
1164  * Checks if the greeter has successfully authenticated.
1165  *
1166  * Return value: #TRUE if the greeter is authenticated for login.
1167  **/
1168 gboolean
1169 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1170 {
1171     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1172     return GET_PRIVATE (greeter)->is_authenticated;
1173 }
1174
1175 /**
1176  * lightdm_greeter_get_authentication_user:
1177  * @greeter: A #LightDMGreeter
1178  *
1179  * Get the user that is being authenticated.
1180  *
1181  * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
1182  */
1183 const gchar *
1184 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1185 {
1186     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1187     return GET_PRIVATE (greeter)->authentication_user;
1188 }
1189
1190 /**
1191  * lightdm_greeter_start_session:
1192  * @greeter: A #LightDMGreeter
1193  * @session: (allow-none): The session to log into or #NULL to use the default
1194  *
1195  * Start a session for the logged in user.
1196  **/
1197 void
1198 lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session)
1199 {
1200     guint8 message[MAX_MESSAGE_LENGTH];
1201     gsize offset = 0;
1202
1203     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1204   
1205     if (!session)
1206         session = "";
1207
1208     g_debug ("Starting session %s", session);
1209     write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
1210     write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
1211     write_message (greeter, message, offset);
1212 }
1213
1214 /**
1215  * lightdm_greeter_start_session_with_defaults:
1216  * @greeter: A #LightDMGreeter
1217  *
1218  * Login a user to a session using default settings for that user.
1219  **/
1220 void
1221 lightdm_greeter_start_default_session (LightDMGreeter *greeter)
1222 {
1223     lightdm_greeter_start_session (greeter, NULL);
1224 }
1225
1226 static gboolean
1227 upower_call_function (LightDMGreeter *greeter, const gchar *function, gboolean has_result)
1228 {
1229     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1230     GDBusProxy *proxy;
1231     GVariant *result;
1232     GError *error = NULL;
1233     gboolean function_result = FALSE;
1234   
1235     if (!priv->system_bus)
1236         return FALSE;
1237
1238     proxy = g_dbus_proxy_new_sync (priv->system_bus,
1239                                    G_DBUS_PROXY_FLAGS_NONE,
1240                                    NULL,
1241                                    "org.freedesktop.UPower",
1242                                    "/org/freedesktop/UPower",
1243                                    "org.freedesktop.UPower",
1244                                    NULL, NULL);
1245     result = g_dbus_proxy_call_sync (proxy,
1246                                      function,
1247                                      NULL,
1248                                      G_DBUS_CALL_FLAGS_NONE,
1249                                      -1,
1250                                      NULL,
1251                                      &error);
1252     g_object_unref (proxy);
1253
1254     if (!result)
1255         g_warning ("Error calling UPower function %s: %s", function, error->message);
1256     g_clear_error (&error);
1257     if (!result)
1258         return FALSE;
1259
1260     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1261         g_variant_get (result, "(b)", &function_result);
1262
1263     g_variant_unref (result);
1264     return function_result;
1265 }
1266
1267 /**
1268  * lightdm_greeter_get_can_suspend:
1269  * @greeter: A #LightDMGreeter
1270  *
1271  * Checks if the greeter is authorized to do a system suspend.
1272  *
1273  * Return value: #TRUE if the greeter can suspend the system
1274  **/
1275 gboolean
1276 lightdm_greeter_get_can_suspend (LightDMGreeter *greeter)
1277 {
1278     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1279     return upower_call_function (greeter, "SuspendAllowed", TRUE);
1280 }
1281
1282 /**
1283  * lightdm_greeter_suspend:
1284  * @greeter: A #LightDMGreeter
1285  *
1286  * Triggers a system suspend.
1287  **/
1288 void
1289 lightdm_greeter_suspend (LightDMGreeter *greeter)
1290 {
1291     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1292     upower_call_function (greeter, "Suspend", FALSE);
1293 }
1294
1295 /**
1296  * lightdm_greeter_get_can_hibernate:
1297  * @greeter: A #LightDMGreeter
1298  *
1299  * Checks if the greeter is authorized to do a system hibernate.
1300  *
1301  * Return value: #TRUE if the greeter can hibernate the system
1302  **/
1303 gboolean
1304 lightdm_greeter_get_can_hibernate (LightDMGreeter *greeter)
1305 {
1306     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1307     return upower_call_function (greeter, "HibernateAllowed", TRUE);
1308 }
1309
1310 /**
1311  * lightdm_greeter_hibernate:
1312  * @greeter: A #LightDMGreeter
1313  *
1314  * Triggers a system hibernate.
1315  **/
1316 void
1317 lightdm_greeter_hibernate (LightDMGreeter *greeter)
1318 {
1319     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1320     upower_call_function (greeter, "Hibernate", FALSE);
1321 }
1322
1323 static gboolean
1324 ck_call_function (LightDMGreeter *greeter, const gchar *function, gboolean has_result)
1325 {
1326     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1327     GDBusProxy *proxy;
1328     GVariant *result;
1329     GError *error = NULL;
1330     gboolean function_result = FALSE;
1331
1332     if (!priv->system_bus)
1333         return FALSE;
1334
1335     proxy = g_dbus_proxy_new_sync (priv->system_bus,
1336                                    G_DBUS_PROXY_FLAGS_NONE,
1337                                    NULL,
1338                                    "org.freedesktop.ConsoleKit",
1339                                    "/org/freedesktop/ConsoleKit/Manager",
1340                                    "org.freedesktop.ConsoleKit.Manager",
1341                                    NULL, NULL);
1342     result = g_dbus_proxy_call_sync (proxy,
1343                                      function,
1344                                      NULL,
1345                                      G_DBUS_CALL_FLAGS_NONE,
1346                                      -1,
1347                                      NULL,
1348                                      &error);
1349     g_object_unref (proxy);
1350
1351     if (!result)
1352         g_warning ("Error calling ConsoleKit function %s: %s", function, error->message);
1353     g_clear_error (&error);
1354     if (!result)
1355         return FALSE;
1356
1357     if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
1358         g_variant_get (result, "(b)", &function_result);
1359
1360     g_variant_unref (result);
1361     return function_result;
1362 }
1363
1364 /**
1365  * lightdm_greeter_get_can_restart:
1366  * @greeter: A #LightDMGreeter
1367  *
1368  * Checks if the greeter is authorized to do a system restart.
1369  *
1370  * Return value: #TRUE if the greeter can restart the system
1371  **/
1372 gboolean
1373 lightdm_greeter_get_can_restart (LightDMGreeter *greeter)
1374 {
1375     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1376     return ck_call_function (greeter, "CanRestart", TRUE);
1377 }
1378
1379 /**
1380  * lightdm_greeter_restart:
1381  * @greeter: A #LightDMGreeter
1382  *
1383  * Triggers a system restart.
1384  **/
1385 void
1386 lightdm_greeter_restart (LightDMGreeter *greeter)
1387 {
1388     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1389     ck_call_function (greeter, "Restart", FALSE);
1390 }
1391
1392 /**
1393  * lightdm_greeter_get_can_shutdown:
1394  * @greeter: A #LightDMGreeter
1395  *
1396  * Checks if the greeter is authorized to do a system shutdown.
1397  *
1398  * Return value: #TRUE if the greeter can shutdown the system
1399  **/
1400 gboolean
1401 lightdm_greeter_get_can_shutdown (LightDMGreeter *greeter)
1402 {
1403     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1404     return ck_call_function (greeter, "CanStop", TRUE);
1405 }
1406
1407 /**
1408  * lightdm_greeter_shutdown:
1409  * @greeter: A #LightDMGreeter
1410  *
1411  * Triggers a system shutdown.
1412  **/
1413 void
1414 lightdm_greeter_shutdown (LightDMGreeter *greeter)
1415 {
1416     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1417     ck_call_function (greeter, "Stop", FALSE);
1418 }
1419
1420 static void
1421 lightdm_greeter_init (LightDMGreeter *greeter)
1422 {
1423     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1424
1425     priv->read_buffer = g_malloc (HEADER_SIZE);
1426     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1427 }
1428
1429 static void
1430 lightdm_greeter_set_property (GObject      *object,
1431                           guint         prop_id,
1432                           const GValue *value,
1433                           GParamSpec   *pspec)
1434 {
1435     LightDMGreeter *self;
1436
1437     self = LIGHTDM_GREETER (object);
1438
1439     switch (prop_id) {
1440     case PROP_LAYOUT:
1441         lightdm_greeter_set_layout(self, g_value_get_string (value));
1442         break;
1443     default:
1444         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1445         break;
1446     }
1447 }
1448
1449 static void
1450 lightdm_greeter_get_property (GObject    *object,
1451                           guint       prop_id,
1452                           GValue     *value,
1453                           GParamSpec *pspec)
1454 {
1455     LightDMGreeter *self;
1456
1457     self = LIGHTDM_GREETER (object);
1458
1459     switch (prop_id) {
1460     case PROP_HOSTNAME:
1461         g_value_set_string (value, lightdm_greeter_get_hostname (self));
1462         break;
1463     case PROP_DEFAULT_LANGUAGE:
1464         g_value_set_string (value, lightdm_greeter_get_default_language (self));
1465         break;
1466     case PROP_LAYOUTS:
1467         break;
1468     case PROP_LAYOUT:
1469         g_value_set_string (value, lightdm_greeter_get_layout (self));
1470         break;
1471     case PROP_SESSIONS:
1472         break;
1473     case PROP_DEFAULT_SESSION_HINT:
1474         g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1475         break;
1476     case PROP_HIDE_USERS_HINT:
1477         g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1478         break;
1479     case PROP_HAS_GUEST_ACCOUNT_HINT:
1480         g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1481         break;
1482     case PROP_SELECT_USER_HINT:
1483         g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1484         break;
1485     case PROP_SELECT_GUEST_HINT:
1486         g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1487         break;
1488     case PROP_AUTOLOGIN_USER_HINT:
1489         g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1490         break;
1491     case PROP_AUTOLOGIN_GUEST_HINT:
1492         g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1493         break;
1494     case PROP_AUTOLOGIN_TIMEOUT_HINT:
1495         g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1496         break;
1497     case PROP_AUTHENTICATION_USER:
1498         g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1499         break;
1500     case PROP_IN_AUTHENTICATION:
1501         g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1502         break;
1503     case PROP_IS_AUTHENTICATED:
1504         g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1505         break;
1506     case PROP_CAN_SUSPEND:
1507         g_value_set_boolean (value, lightdm_greeter_get_can_suspend (self));
1508         break;
1509     case PROP_CAN_HIBERNATE:
1510         g_value_set_boolean (value, lightdm_greeter_get_can_hibernate (self));
1511         break;
1512     case PROP_CAN_RESTART:
1513         g_value_set_boolean (value, lightdm_greeter_get_can_restart (self));
1514         break;
1515     case PROP_CAN_SHUTDOWN:
1516         g_value_set_boolean (value, lightdm_greeter_get_can_shutdown (self));
1517         break;
1518     default:
1519         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1520         break;
1521     }
1522 }
1523
1524 static void
1525 marshal_VOID__STRING_INT (GClosure     *closure,
1526                           GValue       *return_value G_GNUC_UNUSED,
1527                           guint         n_param_values,
1528                           const GValue *param_values,
1529                           gpointer      invocation_hint G_GNUC_UNUSED,
1530                           gpointer      marshal_data)
1531 {
1532     typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer     data1,
1533                                                    gpointer     arg_1,
1534                                                    gint         arg_2,
1535                                                    gpointer     data2);
1536     register GMarshalFunc_VOID__STRING_INT callback;
1537     register GCClosure *cc = (GCClosure*) closure;
1538     register gpointer data1, data2;
1539
1540     g_return_if_fail (n_param_values == 3);
1541
1542     if (G_CCLOSURE_SWAP_DATA (closure))
1543     {
1544         data1 = closure->data;
1545         data2 = g_value_peek_pointer (param_values + 0);
1546     }
1547     else
1548     {
1549         data1 = g_value_peek_pointer (param_values + 0);
1550         data2 = closure->data;
1551     }
1552     callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback);
1553
1554     callback (data1,
1555               (param_values + 1)->data[0].v_pointer,
1556               (param_values + 2)->data[0].v_int,
1557               data2);
1558 }
1559
1560 static void
1561 lightdm_greeter_finalize (GObject *object)
1562 {
1563     LightDMGreeter *self = LIGHTDM_GREETER (object);
1564     LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1565
1566     if (priv->system_bus)
1567         g_object_unref (priv->system_bus);
1568     if (priv->to_server_channel)
1569         g_io_channel_unref (priv->to_server_channel);
1570     if (priv->from_server_channel)
1571         g_io_channel_unref (priv->from_server_channel);
1572     if (priv->display)
1573         XCloseDisplay (priv->display);
1574     g_free (priv->hostname);
1575     if (priv->user_list)
1576         g_object_unref (priv->user_list);
1577     g_list_free_full (priv->languages, g_object_unref);
1578     if (priv->xkl_engine)
1579         g_object_unref (priv->xkl_engine);
1580     if (priv->xkl_config)
1581         g_object_unref (priv->xkl_config);
1582     g_list_free_full (priv->layouts, g_object_unref);
1583     g_free (priv->layout);
1584     g_list_free_full (priv->sessions, g_object_unref);
1585     g_free (priv->authentication_user);
1586     g_hash_table_unref (priv->hints);
1587
1588     G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1589 }
1590
1591 static void
1592 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1593 {
1594     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1595
1596     g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
1597
1598     object_class->set_property = lightdm_greeter_set_property;
1599     object_class->get_property = lightdm_greeter_get_property;
1600     object_class->finalize = lightdm_greeter_finalize;
1601
1602     g_object_class_install_property (object_class,
1603                                      PROP_HOSTNAME,
1604                                      g_param_spec_string ("hostname",
1605                                                           "hostname",
1606                                                           "Hostname displaying greeter for",
1607                                                           NULL,
1608                                                           G_PARAM_READABLE));
1609     g_object_class_install_property (object_class,
1610                                      PROP_DEFAULT_LANGUAGE,
1611                                      g_param_spec_string ("default-language",
1612                                                           "default-language",
1613                                                           "Default language",
1614                                                           NULL,
1615                                                           G_PARAM_READWRITE));
1616     /*g_object_class_install_property (object_class,
1617                                      PROP_LAYOUTS,
1618                                      g_param_spec_list ("layouts",
1619                                                         "layouts",
1620                                                         "Available keyboard layouts"));*/
1621     g_object_class_install_property (object_class,
1622                                      PROP_LAYOUT,
1623                                      g_param_spec_string ("layout",
1624                                                           "layout",
1625                                                           "Current keyboard layout",
1626                                                           NULL,
1627                                                           G_PARAM_READWRITE));
1628     /*g_object_class_install_property (object_class,
1629                                      PROP_SESSIONS,
1630                                      g_param_spec_list ("sessions",
1631                                                         "sessions",
1632                                                         "Available sessions"));*/
1633     g_object_class_install_property (object_class,
1634                                      PROP_DEFAULT_SESSION_HINT,
1635                                      g_param_spec_string ("default-session-hint",
1636                                                           "default-session-hint",
1637                                                           "Default session hint",
1638                                                           NULL,
1639                                                           G_PARAM_READWRITE));
1640
1641     g_object_class_install_property (object_class,
1642                                      PROP_HIDE_USERS_HINT,
1643                                      g_param_spec_boolean ("hide-users-hint",
1644                                                            "hide-users-hint",
1645                                                            "hide users hint",
1646                                                            FALSE,
1647                                                            G_PARAM_READABLE));
1648
1649     g_object_class_install_property (object_class,
1650                                      PROP_HAS_GUEST_ACCOUNT_HINT,
1651                                      g_param_spec_boolean ("has-guest-account-hint",
1652                                                            "has-guest-account-hint",
1653                                                            "Has guest account hint",
1654                                                            FALSE,
1655                                                            G_PARAM_READABLE));
1656
1657     g_object_class_install_property (object_class,
1658                                      PROP_SELECT_USER_HINT,
1659                                      g_param_spec_string ("select-user-hint",
1660                                                           "select-user-hint",
1661                                                           "Select user hint",
1662                                                           NULL,
1663                                                           G_PARAM_READABLE));
1664
1665     g_object_class_install_property (object_class,
1666                                      PROP_SELECT_GUEST_HINT,
1667                                      g_param_spec_boolean ("select-guest-hint",
1668                                                            "select-guest-hint",
1669                                                            "Select guest account hint",
1670                                                            FALSE,
1671                                                            G_PARAM_READABLE));
1672
1673     g_object_class_install_property (object_class,
1674                                      PROP_AUTOLOGIN_USER_HINT,
1675                                      g_param_spec_string ("autologin-user-hint",
1676                                                           "autologin-user-hint",
1677                                                           "Autologin user hint",
1678                                                           NULL,
1679                                                           G_PARAM_READABLE));
1680
1681     g_object_class_install_property (object_class,
1682                                      PROP_AUTOLOGIN_GUEST_HINT,
1683                                      g_param_spec_boolean ("autologin-guest-hint",
1684                                                            "autologin-guest-hint",
1685                                                            "Autologin guest account hint",
1686                                                            FALSE,
1687                                                            G_PARAM_READABLE));
1688
1689     g_object_class_install_property (object_class,
1690                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
1691                                      g_param_spec_int ("autologin-timeout-hint",
1692                                                        "autologin-timeout-hint",
1693                                                        "Autologin timeout hint",
1694                                                        0, G_MAXINT, 0,
1695                                                        G_PARAM_READABLE));
1696
1697     g_object_class_install_property (object_class,
1698                                      PROP_AUTHENTICATION_USER,
1699                                      g_param_spec_string ("authentication-user",
1700                                                           "authentication-user",
1701                                                           "The user being authenticated",
1702                                                           NULL,
1703                                                           G_PARAM_READABLE));
1704     g_object_class_install_property (object_class,
1705                                      PROP_IN_AUTHENTICATION,
1706                                      g_param_spec_boolean ("in-authentication",
1707                                                            "in-authentication",
1708                                                            "TRUE if a user is being authenticated",
1709                                                            FALSE,
1710                                                            G_PARAM_READABLE));
1711     g_object_class_install_property (object_class,
1712                                      PROP_IS_AUTHENTICATED,
1713                                      g_param_spec_boolean ("is-authenticated",
1714                                                            "is-authenticated",
1715                                                            "TRUE if the selected user is authenticated",
1716                                                            FALSE,
1717                                                            G_PARAM_READABLE));
1718     g_object_class_install_property (object_class,
1719                                      PROP_CAN_SUSPEND,
1720                                      g_param_spec_boolean ("can-suspend",
1721                                                            "can-suspend",
1722                                                            "TRUE if allowed to suspend the system",
1723                                                            FALSE,
1724                                                            G_PARAM_READABLE));
1725     g_object_class_install_property (object_class,
1726                                      PROP_CAN_HIBERNATE,
1727                                      g_param_spec_boolean ("can-hibernate",
1728                                                            "can-hibernate",
1729                                                            "TRUE if allowed to hibernate the system",
1730                                                            FALSE,
1731                                                            G_PARAM_READABLE));
1732     g_object_class_install_property (object_class,
1733                                      PROP_CAN_RESTART,
1734                                      g_param_spec_boolean ("can-restart",
1735                                                            "can-restart",
1736                                                            "TRUE if allowed to restart the system",
1737                                                            FALSE,
1738                                                            G_PARAM_READABLE));
1739     g_object_class_install_property (object_class,
1740                                      PROP_CAN_SHUTDOWN,
1741                                      g_param_spec_boolean ("can-shutdown",
1742                                                            "can-shutdown",
1743                                                            "TRUE if allowed to shutdown the system",
1744                                                            FALSE,
1745                                                            G_PARAM_READABLE));
1746
1747     /**
1748      * LightDMGreeter::connected:
1749      * @greeter: A #LightDMGreeter
1750      *
1751      * The ::connected signal gets emitted when the greeter connects to the
1752      * LightDM server.
1753      **/
1754     signals[CONNECTED] =
1755         g_signal_new ("connected",
1756                       G_TYPE_FROM_CLASS (klass),
1757                       G_SIGNAL_RUN_LAST,
1758                       G_STRUCT_OFFSET (LightDMGreeterClass, connected),
1759                       NULL, NULL,
1760                       g_cclosure_marshal_VOID__VOID,
1761                       G_TYPE_NONE, 0);
1762
1763     /**
1764      * LightDMGreeter::show-prompt:
1765      * @greeter: A #LightDMGreeter
1766      * @text: Prompt text
1767      * @type: Prompt type
1768      *
1769      * The ::show-prompt signal gets emitted when the greeter should show a
1770      * prompt to the user.  The given text should be displayed and an input
1771      * field for the user to provide a response.
1772      *
1773      * Call lightdm_greeter_respond() with the resultant input or
1774      * lightdm_greeter_cancel_authentication() to abort the authentication.
1775      **/
1776     signals[SHOW_PROMPT] =
1777         g_signal_new ("show-prompt",
1778                       G_TYPE_FROM_CLASS (klass),
1779                       G_SIGNAL_RUN_LAST,
1780                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
1781                       NULL, NULL,
1782                       marshal_VOID__STRING_INT,
1783                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1784
1785     /**
1786      * LightDMGreeter::show-message:
1787      * @greeter: A #LightDMGreeter
1788      * @text: Message text
1789      * @type: Message type
1790      *
1791      * The ::show-message signal gets emitted when the greeter
1792      * should show a message to the user.
1793      **/
1794     signals[SHOW_MESSAGE] =
1795         g_signal_new ("show-message",
1796                       G_TYPE_FROM_CLASS (klass),
1797                       G_SIGNAL_RUN_LAST,
1798                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
1799                       NULL, NULL,
1800                       marshal_VOID__STRING_INT,
1801                       G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
1802
1803     /**
1804      * LightDMGreeter::authentication-complete:
1805      * @greeter: A #LightDMGreeter
1806      *
1807      * The ::authentication-complete signal gets emitted when the greeter
1808      * has completed authentication.
1809      *
1810      * Call lightdm_greeter_get_is_authenticated() to check if the authentication
1811      * was successful.
1812      **/
1813     signals[AUTHENTICATION_COMPLETE] =
1814         g_signal_new ("authentication-complete",
1815                       G_TYPE_FROM_CLASS (klass),
1816                       G_SIGNAL_RUN_LAST,
1817                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
1818                       NULL, NULL,
1819                       g_cclosure_marshal_VOID__VOID,
1820                       G_TYPE_NONE, 0);
1821
1822     /**
1823      * LightDMGreeter::session-failed:
1824      * @greeter: A #LightDMGreeter
1825      *
1826      * The ::session-failed signal gets emitted when the deamon has failed
1827      * to start the requested session.
1828      **/
1829     signals[SESSION_FAILED] =
1830         g_signal_new ("session-failed",
1831                       G_TYPE_FROM_CLASS (klass),
1832                       G_SIGNAL_RUN_LAST,
1833                       G_STRUCT_OFFSET (LightDMGreeterClass, session_failed),
1834                       NULL, NULL,
1835                       g_cclosure_marshal_VOID__VOID,
1836                       G_TYPE_NONE, 0);
1837
1838     /**
1839      * LightDMGreeter::autologin-timer-expired:
1840      * @greeter: A #LightDMGreeter
1841      *
1842      * The ::timed-login signal gets emitted when the automatic login timer has expired.
1843      * The application should then call lightdm_greeter_login().
1844      **/
1845     signals[AUTOLOGIN_TIMER_EXPIRED] =
1846         g_signal_new ("autologin-timer-expired",
1847                       G_TYPE_FROM_CLASS (klass),
1848                       G_SIGNAL_RUN_LAST,
1849                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
1850                       NULL, NULL,
1851                       g_cclosure_marshal_VOID__VOID,
1852                       G_TYPE_NONE, 0);
1853
1854     /**
1855      * LightDMGreeter::quit:
1856      * @greeter: A #LightDMGreeter
1857      *
1858      * The ::quit signal gets emitted when the greeter should exit.
1859      **/
1860     signals[QUIT] =
1861         g_signal_new ("quit",
1862                       G_TYPE_FROM_CLASS (klass),
1863                       G_SIGNAL_RUN_LAST,
1864                       G_STRUCT_OFFSET (LightDMGreeterClass, quit),
1865                       NULL, NULL,
1866                       g_cclosure_marshal_VOID__VOID,
1867                       G_TYPE_NONE, 0);
1868 }