]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - libldmgreeter-gobject/greeter.c
ae15874ad9c7155c4d220423b3e450bd92342af0
[sojka/lightdm.git] / libldmgreeter-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 <stdlib.h>
13 #include <string.h>
14 #include <locale.h>
15 #include <sys/utsname.h>
16
17 #include <gio/gdesktopappinfo.h>
18 #include <dbus/dbus-glib.h>
19 #include <security/pam_appl.h>
20 #include <libxklavier/xklavier.h>
21
22 #include "greeter.h"
23
24 enum {
25     PROP_0,
26     PROP_HOSTNAME,  
27     PROP_NUM_USERS,
28     PROP_USERS,
29     PROP_DEFAULT_LANGUAGE,
30     PROP_LAYOUTS,
31     PROP_LAYOUT,
32     PROP_SESSIONS,
33     PROP_DEFAULT_SESSION,
34     PROP_TIMED_LOGIN_USER,
35     PROP_TIMED_LOGIN_DELAY,
36     PROP_AUTHENTICATION_USER,
37     PROP_IS_AUTHENTICATED,
38     PROP_CAN_SUSPEND,
39     PROP_CAN_HIBERNATE,
40     PROP_CAN_RESTART,
41     PROP_CAN_SHUTDOWN
42 };
43
44 enum {
45     SHOW_PROMPT,
46     SHOW_MESSAGE,
47     SHOW_ERROR,
48     AUTHENTICATION_COMPLETE,
49     TIMED_LOGIN,
50     QUIT,
51     LAST_SIGNAL
52 };
53 static guint signals[LAST_SIGNAL] = { 0 };
54
55 struct _LdmGreeterPrivate
56 {
57     DBusGConnection *lightdm_bus;
58
59     DBusGConnection *system_bus;
60
61     DBusGProxy *display_proxy, *session_proxy, *user_proxy;
62
63     Display *display;
64
65     gchar *hostname;
66
67     gchar *theme;
68     GKeyFile *theme_file;
69
70     gboolean have_users;
71     GList *users;
72
73     gchar *default_language;  
74     gboolean have_languages;
75     GList *languages;
76
77     gchar *default_layout;
78     XklEngine *xkl_engine;
79     XklConfigRec *xkl_config;
80     gboolean have_layouts;
81     GList *layouts;
82     gchar *layout;
83
84     gboolean have_sessions;
85     GList *sessions;
86     gchar *default_session;
87
88     gchar *authentication_user;
89     gboolean is_authenticated;
90
91     gchar *timed_user;
92     gint login_delay;
93     guint login_timeout;
94 };
95
96 G_DEFINE_TYPE (LdmGreeter, ldm_greeter, G_TYPE_OBJECT);
97
98 /**
99  * ldm_greeter_new:
100  * 
101  * Create a new greeter.
102  * 
103  * Return value: the new #LdmGreeter
104  **/
105 LdmGreeter *
106 ldm_greeter_new ()
107 {
108     return g_object_new (LDM_TYPE_GREETER, NULL);
109 }
110
111 static gboolean
112 timed_login_cb (gpointer data)
113 {
114     LdmGreeter *greeter = data;
115
116     greeter->priv->login_timeout = 0;
117     g_signal_emit (G_OBJECT (greeter), signals[TIMED_LOGIN], 0, greeter->priv->timed_user);
118
119     return FALSE;
120 }
121
122 static void
123 quit_cb (DBusGProxy *proxy, LdmGreeter *greeter)
124 {
125     g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
126 }
127
128 /**
129  * ldm_greeter_connect:
130  * @greeter: The greeter to connect
131  *
132  * Connects the greeter to the display manager.
133  * 
134  * Return value: TRUE if successfully connected
135  **/
136 gboolean
137 ldm_greeter_connect (LdmGreeter *greeter)
138 {
139     GError *error = NULL;
140     const gchar *bus_address, *object;
141     DBusBusType bus_type = DBUS_BUS_SYSTEM;
142     gboolean result;
143
144     g_return_val_if_fail (greeter != NULL, FALSE);
145
146     greeter->priv->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
147     if (!greeter->priv->system_bus)
148         g_warning ("Failed to connect to system bus: %s", error->message);
149     g_clear_error (&error);
150     if (!greeter->priv->system_bus)
151         return FALSE;
152
153     bus_address = getenv ("LDM_BUS");
154     if (bus_address && strcmp (bus_address, "SESSION") == 0)
155         bus_type = DBUS_BUS_SESSION;
156
157     greeter->priv->lightdm_bus = dbus_g_bus_get (bus_type, &error);
158     if (!greeter->priv->lightdm_bus)
159         g_warning ("Failed to connect to LightDM bus: %s", error->message);
160     g_clear_error (&error);
161     if (!greeter->priv->lightdm_bus)
162         return FALSE;
163
164     object = getenv ("LDM_DISPLAY");
165     if (!object)
166     {
167         g_warning ("No LDM_DISPLAY enviroment variable");
168         return FALSE;
169     }
170
171     greeter->priv->display_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
172                                                               "org.lightdm.LightDisplayManager",
173                                                               object,
174                                                               "org.lightdm.LightDisplayManager.Greeter");
175     dbus_g_proxy_add_signal (greeter->priv->display_proxy, "QuitGreeter", G_TYPE_INVALID);
176     dbus_g_proxy_connect_signal (greeter->priv->display_proxy, "QuitGreeter", G_CALLBACK (quit_cb), greeter, NULL);
177     greeter->priv->session_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
178                                                               "org.lightdm.LightDisplayManager",
179                                                               "/org/lightdm/LightDisplayManager/Session",
180                                                               "org.lightdm.LightDisplayManager.Session");
181     greeter->priv->user_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
182                                                            "org.lightdm.LightDisplayManager",
183                                                            "/org/lightdm/LightDisplayManager/Users",
184                                                            "org.lightdm.LightDisplayManager.Users");
185
186     g_debug ("Connecting to display manager...");
187     result = dbus_g_proxy_call (greeter->priv->display_proxy, "Connect", &error,
188                                 G_TYPE_INVALID,
189                                 G_TYPE_STRING, &greeter->priv->theme,
190                                 G_TYPE_STRING, &greeter->priv->default_language,
191                                 G_TYPE_STRING, &greeter->priv->default_layout,
192                                 G_TYPE_STRING, &greeter->priv->default_session,
193                                 G_TYPE_STRING, &greeter->priv->timed_user,
194                                 G_TYPE_INT, &greeter->priv->login_delay,
195                                 G_TYPE_INVALID);
196
197     if (result)
198         g_debug ("Connected theme=%s default-language=%s default-layout=%s default-session=%s timed-user=%s login-delay=%d",
199                  greeter->priv->theme,
200                  greeter->priv->default_language, greeter->priv->default_layout, greeter->priv->default_session,
201                  greeter->priv->timed_user, greeter->priv->login_delay);
202     else
203         g_warning ("Failed to connect to display manager: %s", error->message);
204     g_clear_error (&error);
205     if (!result)
206         return FALSE;
207
208     /* Set timeout for default login */
209     if (greeter->priv->timed_user[0] != '\0' && greeter->priv->login_delay > 0)
210     {
211         g_debug ("Logging in as %s in %d seconds", greeter->priv->timed_user, greeter->priv->login_delay);
212         greeter->priv->login_timeout = g_timeout_add (greeter->priv->login_delay * 1000, timed_login_cb, greeter);
213     }
214
215     return result;
216 }
217
218 /**
219  * ldm_greeter_get_hostname:
220  * @greeter: a #LdmGreeter
221  *
222  * Return value: The host this greeter is displaying
223  **/
224 const gchar *
225 ldm_greeter_get_hostname (LdmGreeter *greeter)
226 {
227     g_return_val_if_fail (greeter != NULL, NULL);
228
229     if (!greeter->priv->hostname)
230     {
231         struct utsname info;
232         uname (&info);
233         greeter->priv->hostname = g_strdup (info.nodename);
234     }
235
236     return greeter->priv->hostname;
237 }
238
239 /**
240  * ldm_greeter_get_theme:
241  * @greeter: a #LdmGreeter
242  *
243  * Return value: The theme this greeter is using
244  **/
245 const gchar *
246 ldm_greeter_get_theme (LdmGreeter *greeter)
247 {
248     g_return_val_if_fail (greeter != NULL, NULL);
249     return greeter->priv->theme;
250 }
251
252 static void
253 load_theme (LdmGreeter *greeter)
254 {
255     GError *error = NULL;
256   
257     if (greeter->priv->theme_file)
258         return;
259
260     greeter->priv->theme_file = g_key_file_new ();
261     if (!g_key_file_load_from_file (greeter->priv->theme_file, greeter->priv->theme, G_KEY_FILE_NONE, &error))
262         g_warning ("Failed to read theme file: %s", error->message);
263     g_clear_error (&error);
264 }
265
266 /**
267  * ldm_greeter_get_string_property:
268  * @greeter: a #LdmGreeter
269  * @name: the name of the property to get
270  *
271  * Return value: The value of this property or NULL if it is not defined
272  **/
273 gchar *
274 ldm_greeter_get_string_property (LdmGreeter *greeter, const gchar *name)
275 {
276     GError *error = NULL;
277     gchar *result;
278
279     g_return_val_if_fail (greeter != NULL, NULL);
280
281     load_theme (greeter);
282
283     result = g_key_file_get_string (greeter->priv->theme_file, "theme", name, &error);
284     if (!result)
285         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
286     g_clear_error (&error);
287
288     return result;
289 }
290
291 /**
292  * ldm_greeter_get_integer_property:
293  * @greeter: a #LdmGreeter
294  * @name: the name of the property to get
295  *
296  * Return value: The value of this property or 0 if it is not defined
297  **/
298 gint
299 ldm_greeter_get_integer_property (LdmGreeter *greeter, const gchar *name)
300 {
301     GError *error = NULL;
302     gint result;
303
304     g_return_val_if_fail (greeter != NULL, 0);
305
306     load_theme (greeter);
307
308     result = g_key_file_get_integer (greeter->priv->theme_file, "theme", name, &error);
309     if (!result)
310         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
311     g_clear_error (&error);
312
313     return result;
314 }
315
316 /**
317  * ldm_greeter_get_boolean_property:
318  * @greeter: a #LdmGreeter
319  * @name: the name of the property to get
320  *
321  * Return value: The value of this property or FALSE if it is not defined
322  **/
323 gboolean
324 ldm_greeter_get_boolean_property (LdmGreeter *greeter, const gchar *name)
325 {
326     GError *error = NULL;
327     gboolean result;
328
329     g_return_val_if_fail (greeter != NULL, FALSE);
330
331     load_theme (greeter);
332
333     result = g_key_file_get_boolean (greeter->priv->theme_file, "theme", name, &error);
334     if (!result)
335         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
336     g_clear_error (&error);
337
338     return result;
339 }
340
341 #define TYPE_USER dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID)
342 #define TYPE_USER_LIST dbus_g_type_get_collection ("GPtrArray", TYPE_USER)
343
344 static void
345 update_users (LdmGreeter *greeter)
346 {
347     GPtrArray *users;
348     gboolean result;
349     gint i;
350     GError *error = NULL;
351
352     if (greeter->priv->have_users)
353         return;
354
355     g_debug ("Getting user list...");
356     result = dbus_g_proxy_call (greeter->priv->user_proxy, "GetUsers", &error,
357                                 G_TYPE_INVALID,
358                                 TYPE_USER_LIST, &users,
359                                 G_TYPE_INVALID);
360     if (!result)
361         g_warning ("Failed to get users: %s", error->message);
362     g_clear_error (&error);
363   
364     if (!result)
365         return;
366
367     g_debug ("Got %d users", users->len);
368     for (i = 0; i < users->len; i++)
369     {
370         GValue value = { 0 };
371         LdmUser *user;
372         gchar *name, *real_name, *image;
373         gboolean logged_in;
374
375         g_value_init (&value, TYPE_USER);
376         g_value_set_static_boxed (&value, users->pdata[i]);
377         dbus_g_type_struct_get (&value, 0, &name, 1, &real_name, 2, &image, 3, &logged_in, G_MAXUINT);
378         g_value_unset (&value);
379
380         user = ldm_user_new (greeter, name, real_name, image, logged_in);
381         g_free (name);
382         g_free (real_name);
383         g_free (image);
384
385         greeter->priv->users = g_list_append (greeter->priv->users, user);
386     }
387
388     g_ptr_array_free (users, TRUE);
389
390     greeter->priv->have_users = TRUE;
391 }
392
393 /**
394  * ldm_greeter_get_num_users:
395  * @greeter: a #LdmGreeter
396  *
397  * Return value: The number of users able to log in
398  **/
399 gint
400 ldm_greeter_get_num_users (LdmGreeter *greeter)
401 {
402     g_return_val_if_fail (greeter != NULL, 0);
403     update_users (greeter);
404     return g_list_length (greeter->priv->users);
405 }
406
407 /**
408  * ldm_greeter_get_users:
409  * @greeter: A #LdmGreeter
410  * 
411  * Get a list of users to present to the user.  This list may be a subset of the
412  * available users and may be empty depending on the server configuration.
413  * 
414  * Return value: A list of #LdmUser that should be presented to the user.
415  **/
416 const GList *
417 ldm_greeter_get_users (LdmGreeter *greeter)
418 {
419     g_return_val_if_fail (greeter != NULL, NULL);
420     update_users (greeter);
421     return greeter->priv->users;
422 }
423
424 static void
425 update_languages (LdmGreeter *greeter)
426 {
427     gchar *stdout_text = NULL, *stderr_text = NULL;
428     gint exit_status;
429     gboolean result;
430     GError *error = NULL;
431
432     if (greeter->priv->have_languages)
433         return;
434
435     result = g_spawn_command_line_sync ("locale -a", &stdout_text, &stderr_text, &exit_status, &error);
436     if (!result || exit_status != 0)
437         g_warning ("Failed to get languages, locale -a returned %d: %s", exit_status, error->message);
438     else
439     {
440         gchar **tokens;
441         int i;
442
443         tokens = g_strsplit_set (stdout_text, "\n\r", -1);
444         for (i = 0; tokens[i]; i++)
445         {
446             LdmLanguage *language;
447             gchar *code;
448
449             code = g_strchug (tokens[i]);
450             if (code[0] == '\0')
451                 continue;
452
453             /* Ignore the non-interesting languages */
454             if (strcmp (code, "C") == 0 || strcmp (code, "POSIX") == 0)
455                 continue;
456
457             language = ldm_language_new (code);
458             greeter->priv->languages = g_list_append (greeter->priv->languages, language);
459         }
460
461         g_strfreev (tokens);
462     }
463
464     g_clear_error (&error);
465     g_free (stdout_text);
466     g_free (stderr_text);
467
468     greeter->priv->have_languages = TRUE;
469 }
470
471 /**
472  * ldm_greeter_get_default_language:
473  * @greeter: A #LdmGreeter
474  * 
475  * Get the default language.
476  * 
477  * Return value: The default language.
478  **/
479 const gchar *
480 ldm_greeter_get_default_language (LdmGreeter *greeter)
481 {
482     g_return_val_if_fail (greeter != NULL, NULL);
483     return greeter->priv->default_language;
484 }
485
486 /**
487  * ldm_greeter_get_languages:
488  * @greeter: A #LdmGreeter
489  * 
490  * Get a list of languages to present to the user.
491  * 
492  * Return value: A list of #LdmLanguage that should be presented to the user.
493  **/
494 const GList *
495 ldm_greeter_get_languages (LdmGreeter *greeter)
496 {
497     g_return_val_if_fail (greeter != NULL, NULL);
498     update_languages (greeter);
499     return greeter->priv->languages;
500 }
501
502 const gchar *
503 ldm_greeter_get_default_layout (LdmGreeter *greeter)
504 {
505     g_return_val_if_fail (greeter != NULL, NULL);
506     return greeter->priv->default_layout;
507 }
508
509 static void
510 layout_cb (XklConfigRegistry *config,
511            const XklConfigItem *item,
512            gpointer data)
513 {
514     LdmGreeter *greeter = data;
515     LdmLayout *layout;
516   
517     layout = ldm_layout_new (item->name, item->short_description, item->description);
518     greeter->priv->layouts = g_list_append (greeter->priv->layouts, layout);
519 }
520
521 static void
522 setup_display (LdmGreeter *greeter)
523 {
524     if (!greeter->priv->display)
525         greeter->priv->display = XOpenDisplay (NULL);
526 }
527
528 static void
529 setup_xkl (LdmGreeter *greeter)
530 {
531     setup_display (greeter);
532     greeter->priv->xkl_engine = xkl_engine_get_instance (greeter->priv->display);
533     greeter->priv->xkl_config = xkl_config_rec_new ();
534     if (!xkl_config_rec_get_from_server (greeter->priv->xkl_config, greeter->priv->xkl_engine))
535         g_warning ("Failed to get Xkl configuration from server");
536     greeter->priv->layout = g_strdup (greeter->priv->xkl_config->layouts[0]);
537 }
538
539 /**
540  * ldm_greeter_get_layouts:
541  * @greeter: A #LdmGreeter
542  * 
543  * Get a list of keyboard layouts to present to the user.
544  * 
545  * Return value: A list of #LdmLayout that should be presented to the user.
546  **/
547 const GList *
548 ldm_greeter_get_layouts (LdmGreeter *greeter)
549 {
550     XklConfigRegistry *registry;
551
552     g_return_val_if_fail (greeter != NULL, NULL);
553
554     if (greeter->priv->have_layouts)
555         return greeter->priv->layouts;
556
557     setup_xkl (greeter);
558
559     registry = xkl_config_registry_get_instance (greeter->priv->xkl_engine);
560     xkl_config_registry_load (registry, FALSE);
561     xkl_config_registry_foreach_layout (registry, layout_cb, greeter);
562     g_object_unref (registry);
563     greeter->priv->have_layouts = TRUE;
564
565     return greeter->priv->layouts;
566 }
567
568 /**
569  * ldm_greeter_set_layout:
570  * @greeter: A #LdmGreeter
571  * @layout: The layout to use
572  * 
573  * Set the layout for this session.
574  **/
575 void
576 ldm_greeter_set_layout (LdmGreeter *greeter, const gchar *layout)
577 {
578     XklConfigRec *config;
579
580     g_return_if_fail (LDM_IS_GREETER (greeter));
581     g_return_if_fail (layout != NULL);
582
583     g_debug ("Setting keyboard layout to %s", layout);
584   
585     setup_xkl (greeter);
586
587     config = xkl_config_rec_new ();
588     config->layouts = g_malloc (sizeof (gchar *) * 2);
589     config->model = g_strdup (greeter->priv->xkl_config->model);
590     config->layouts[0] = g_strdup (layout);
591     config->layouts[1] = NULL;
592     if (!xkl_config_rec_activate (config, greeter->priv->xkl_engine))
593         g_warning ("Failed to activate XKL config");
594     else
595         greeter->priv->layout = g_strdup (layout);
596     g_object_unref (config);
597 }
598
599 /**
600  * ldm_greeter_get_layout:
601  * @greeter: A #LdmGreeter
602  * 
603  * Get the current keyboard layout.
604  * 
605  * Return value: The currently active layout for this user.
606  **/
607 const gchar *
608 ldm_greeter_get_layout (LdmGreeter *greeter)
609 {
610     g_return_val_if_fail (greeter != NULL, NULL);
611     setup_xkl (greeter);
612     return greeter->priv->layout;
613 }
614
615 static void
616 update_sessions (LdmGreeter *greeter)
617 {
618     GDir *directory;
619     GError *error = NULL;
620
621     if (greeter->priv->have_sessions)
622         return;
623
624     directory = g_dir_open (XSESSIONS_DIR, 0, &error);
625     if (!directory)
626         g_warning ("Failed to open sessions directory: %s", error->message);
627     g_clear_error (&error);
628     if (!directory)
629         return;
630
631     while (TRUE)
632     {
633         const gchar *filename;
634         GKeyFile *key_file;
635         gchar *key, *path;
636         gboolean result;
637
638         filename = g_dir_read_name (directory);
639         if (filename == NULL)
640             break;
641
642         if (!g_str_has_suffix (filename, ".desktop"))
643             continue;
644
645         key = g_strndup (filename, strlen (filename) - strlen (".desktop"));
646         path = g_build_filename (XSESSIONS_DIR, filename, NULL);
647         g_debug ("Loading session %s", path);
648
649         key_file = g_key_file_new ();
650         result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
651         if (!result)
652             g_warning ("Failed to load session file %s: %s:", path, error->message);
653         g_clear_error (&error);
654
655         if (result && !g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL))
656         {
657             gchar *domain, *name, *comment;
658
659 #ifdef G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN
660             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN, NULL);
661 #else
662             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL);
663 #endif          
664             name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, domain, NULL);
665             comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, domain, NULL);
666             if (!comment)
667                 comment = g_strdup ("");
668             if (name)
669             {
670                 g_debug ("Loaded session %s (%s, %s)", key, name, comment);
671                 greeter->priv->sessions = g_list_append (greeter->priv->sessions, ldm_session_new (key, name, comment));
672             }
673             else
674                 g_warning ("Invalid session %s: %s", path, error->message);
675             g_clear_error (&error);
676             g_free (domain);
677             g_free (name);
678             g_free (comment);
679         }
680
681         g_free (key);
682         g_free (path);
683         g_key_file_free (key_file);
684     }
685
686     g_dir_close (directory);
687
688     greeter->priv->have_sessions = TRUE;
689 }
690
691 /**
692  * ldm_greeter_get_sessions:
693  * @greeter: A #LdmGreeter
694  *
695  * Get the available sessions.
696  *
697  * Return value: A list of #LdmSession
698  **/
699 const GList *
700 ldm_greeter_get_sessions (LdmGreeter *greeter)
701 {
702     g_return_val_if_fail (greeter != NULL, NULL);
703     update_sessions (greeter);
704     return greeter->priv->sessions;
705 }
706
707 /**
708  * ldm_greeter_get_default_session:
709  * @greeter: A #LdmGreeter
710  *
711  * Get the default session to use.
712  *
713  * Return value: The session name
714  **/
715 const gchar *
716 ldm_greeter_get_default_session (LdmGreeter *greeter)
717 {
718     g_return_val_if_fail (greeter != NULL, NULL);
719     return greeter->priv->default_session;
720 }
721
722 /**
723  * ldm_greeter_get_timed_login_user:
724  * @greeter: A #LdmGreeter
725  *
726  * Get the user to log in by as default.
727  *
728  * Return value: A username
729  */
730 const gchar *
731 ldm_greeter_get_timed_login_user (LdmGreeter *greeter)
732 {
733     g_return_val_if_fail (greeter != NULL, NULL);
734     return greeter->priv->timed_user;
735 }
736
737 /**
738  * ldm_greeter_get_timed_login_delay:
739  * @greeter: A #LdmGreeter
740  *
741  * Get the number of seconds to wait until logging in as the default user.
742  *
743  * Return value: The number of seconds before logging in as the default user
744  */
745 gint
746 ldm_greeter_get_timed_login_delay (LdmGreeter *greeter)
747 {
748     g_return_val_if_fail (greeter != NULL, 0);
749     return greeter->priv->login_delay;
750 }
751
752 /**
753  * ldm_greeter_cancel_timed_login:
754  * @greeter: A #LdmGreeter
755  *
756  * Cancel the login as the default user.
757  */
758 void
759 ldm_greeter_cancel_timed_login (LdmGreeter *greeter)
760 {
761     g_return_if_fail (LDM_IS_GREETER (greeter));
762   
763     if (greeter->priv->login_timeout)
764        g_source_remove (greeter->priv->login_timeout);
765     greeter->priv->login_timeout = 0;
766 }
767
768 #define TYPE_MESSAGE dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID)
769 #define TYPE_MESSAGE_LIST dbus_g_type_get_collection ("GPtrArray", TYPE_MESSAGE)
770
771 static void
772 auth_response_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer userdata)
773 {
774     LdmGreeter *greeter = userdata;
775     gboolean result;
776     GError *error = NULL;
777     gint return_code;
778     GPtrArray *array;
779     int i;
780
781     result = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &return_code, TYPE_MESSAGE_LIST, &array, G_TYPE_INVALID);
782     if (!result)
783         g_warning ("Failed to complete StartAuthentication(): %s", error->message);
784     g_clear_error (&error);
785     if (!result)
786         return;
787
788     if (array->len > 0)
789         g_debug ("Authentication continues with %d messages", array->len);
790     else
791         g_debug ("Authentication complete with return code %d", return_code);
792
793     for (i = 0; i < array->len; i++)
794     {
795         GValue value = { 0 };
796         gint msg_style;
797         gchar *msg;
798       
799         g_value_init (&value, TYPE_MESSAGE);
800         g_value_set_static_boxed (&value, array->pdata[i]);
801         dbus_g_type_struct_get (&value, 0, &msg_style, 1, &msg, G_MAXUINT);
802
803         // FIXME: Should stop on prompts?
804         switch (msg_style)
805         {
806         case PAM_PROMPT_ECHO_OFF:
807         case PAM_PROMPT_ECHO_ON:
808             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg);
809             break;
810         case PAM_ERROR_MSG:
811             g_signal_emit (G_OBJECT (greeter), signals[SHOW_ERROR], 0, msg);
812             break;
813         case PAM_TEXT_INFO:
814             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg);
815             break;
816         }
817
818         g_free (msg);
819
820         g_value_unset (&value);
821     }
822
823     if (array->len == 0)
824     {
825         greeter->priv->is_authenticated = (return_code == 0);
826         if (!greeter->priv->is_authenticated)
827         {
828             g_free (greeter->priv->authentication_user);
829             greeter->priv->authentication_user = NULL;
830         }
831         g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
832     }
833
834     g_ptr_array_unref (array);
835 }
836
837 /**
838  * ldm_greeter_start_authentication:
839  * @greeter: A #LdmGreeter
840  * @username: A username
841  *
842  * Starts the authentication procedure for a user.
843  **/
844 void
845 ldm_greeter_start_authentication (LdmGreeter *greeter, const char *username)
846 {
847     g_return_if_fail (LDM_IS_GREETER (greeter));
848     g_return_if_fail (username != NULL);
849
850     greeter->priv->is_authenticated = FALSE;
851     g_free (greeter->priv->authentication_user);
852     greeter->priv->authentication_user = g_strdup (username);
853     g_debug ("Starting authentication for user %s...", username);
854     dbus_g_proxy_begin_call (greeter->priv->display_proxy, "StartAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRING, username, G_TYPE_INVALID);
855 }
856
857 /**
858  * ldm_greeter_provide_secret:
859  * @greeter: A #LdmGreeter
860  * @secret: Response to a prompt
861  *
862  * Provide secret information from a prompt.
863  **/
864 void
865 ldm_greeter_provide_secret (LdmGreeter *greeter, const gchar *secret)
866 {
867     gchar **secrets;
868
869     g_return_if_fail (LDM_IS_GREETER (greeter));
870     g_return_if_fail (secret != NULL);
871
872     // FIXME: Could be multiple secrets required
873     secrets = g_malloc (sizeof (char *) * 2);
874     secrets[0] = g_strdup (secret);
875     secrets[1] = NULL;
876     g_debug ("Providing secret to display manager");  
877     dbus_g_proxy_begin_call (greeter->priv->display_proxy, "ContinueAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRV, secrets, G_TYPE_INVALID);
878 }
879
880 /**
881  * ldm_greeter_cancel_authentication:
882  * @greeter: A #LdmGreeter
883  * 
884  * Cancel the current user authentication.
885  **/
886 void
887 ldm_greeter_cancel_authentication (LdmGreeter *greeter)
888 {
889     g_return_if_fail (LDM_IS_GREETER (greeter));
890 }
891
892 /**
893  * ldm_greeter_get_is_authenticated:
894  * @greeter: A #LdmGreeter
895  * 
896  * Checks if the greeter has successfully authenticated.
897  *
898  * Return value: TRUE if the greeter is authenticated for login.
899  **/
900 gboolean
901 ldm_greeter_get_is_authenticated (LdmGreeter *greeter)
902 {
903     g_return_val_if_fail (greeter != NULL, FALSE);
904     return greeter->priv->is_authenticated;
905 }
906
907 /**
908  * ldm_greeter_get_authentication_user:
909  * @greeter: A #LdmGreeter
910  * 
911  * Get the user that is being authenticated.
912  * 
913  * Return value: The username of the authentication user being authenticated or NULL if no authentication in progress.
914  */
915 const gchar *
916 ldm_greeter_get_authentication_user (LdmGreeter *greeter)
917 {
918     g_return_val_if_fail (greeter != NULL, NULL);
919     return greeter->priv->authentication_user;
920 }
921
922 /**
923  * ldm_greeter_login:
924  * @greeter: A #LdmGreeter
925  * @username: The user to log in as
926  * @session: The session to log into or NULL to use the default
927  * @language: The language to use or NULL to use the default
928  *
929  * Login a user to a session
930  **/
931 void
932 ldm_greeter_login (LdmGreeter *greeter, const gchar *username, const gchar *session, const gchar *language)
933 {
934     GError *error = NULL;
935
936     g_return_if_fail (LDM_IS_GREETER (greeter));
937     g_return_if_fail (username != NULL);
938
939     g_debug ("Logging in");
940     if (!dbus_g_proxy_call (greeter->priv->display_proxy, "Login", &error,
941                             G_TYPE_STRING, username,
942                             G_TYPE_STRING, session ? session : "",
943                             G_TYPE_STRING, language ? language : "",
944                             G_TYPE_INVALID,
945                             G_TYPE_INVALID))
946         g_warning ("Failed to login: %s", error->message);
947     g_clear_error (&error);
948 }
949
950 /**
951  * ldm_greeter_get_can_suspend:
952  * @greeter: A #LdmGreeter
953  * 
954  * Checks if the greeter is authorized to do a system suspend.
955  *
956  * Return value: TRUE if the greeter can suspend the system
957  **/
958 gboolean
959 ldm_greeter_get_can_suspend (LdmGreeter *greeter)
960 {
961     DBusGProxy *proxy;
962     gboolean result = TRUE;
963     GError *error = NULL;
964
965     g_return_val_if_fail (greeter != NULL, FALSE);
966
967     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
968                                        "org.freedesktop.UPower",
969                                        "/org/freedesktop/UPower",
970                                        "org.freedesktop.UPower");
971     if (!dbus_g_proxy_call (proxy, "SuspendAllowed", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
972         g_warning ("Error checking for suspend authority: %s", error->message);
973     g_clear_error (&error);
974
975     g_object_unref (proxy);
976
977     return result;
978 }
979
980 /**
981  * ldm_greeter_suspend:
982  * @greeter: A #LdmGreeter
983  * 
984  * Triggers a system suspend.
985  **/
986 void
987 ldm_greeter_suspend (LdmGreeter *greeter)
988 {
989     DBusGProxy *proxy;
990     GError *error = NULL;
991
992     g_return_if_fail (LDM_IS_GREETER (greeter));
993
994     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
995                                        "org.freedesktop.UPower",
996                                        "/org/freedesktop/UPower",
997                                        "org.freedesktop.UPower");
998     if (!dbus_g_proxy_call (proxy, "Suspend", &error, G_TYPE_INVALID, G_TYPE_INVALID))
999         g_warning ("Failed to hibernate: %s", error->message);
1000     g_clear_error (&error);
1001
1002     g_object_unref (proxy);
1003 }
1004
1005 /**
1006  * ldm_greeter_get_can_hibernate:
1007  * @greeter: A #LdmGreeter
1008  * 
1009  * Checks if the greeter is authorized to do a system hibernate.
1010  *
1011  * Return value: TRUE if the greeter can hibernate the system
1012  **/
1013 gboolean
1014 ldm_greeter_get_can_hibernate (LdmGreeter *greeter)
1015 {
1016     DBusGProxy *proxy;
1017     gboolean result = FALSE;
1018     GError *error = NULL;
1019
1020     g_return_val_if_fail (greeter != NULL, FALSE);
1021
1022     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1023                                        "org.freedesktop.UPower",
1024                                        "/org/freedesktop/UPower",
1025                                        "org.freedesktop.UPower");
1026     if (!dbus_g_proxy_call (proxy, "HibernateAllowed", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
1027         g_warning ("Error checking for hibernate authority: %s", error->message);
1028     g_clear_error (&error);
1029
1030     g_object_unref (proxy);
1031
1032     return result;
1033 }
1034
1035 /**
1036  * ldm_greeter_hibernate:
1037  * @greeter: A #LdmGreeter
1038  * 
1039  * Triggers a system hibernate.
1040  **/
1041 void
1042 ldm_greeter_hibernate (LdmGreeter *greeter)
1043 {
1044     DBusGProxy *proxy;
1045     GError *error = NULL;
1046
1047     g_return_if_fail (LDM_IS_GREETER (greeter));
1048
1049     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1050                                        "org.freedesktop.UPower",
1051                                        "/org/freedesktop/UPower",
1052                                        "org.freedesktop.UPower");
1053     if (!dbus_g_proxy_call (proxy, "Hibernate", &error, G_TYPE_INVALID, G_TYPE_INVALID))
1054         g_warning ("Failed to hibernate: %s", error->message);
1055     g_clear_error (&error);
1056
1057     g_object_unref (proxy);
1058 }
1059
1060 /**
1061  * ldm_greeter_get_can_restart:
1062  * @greeter: A #LdmGreeter
1063  * 
1064  * Checks if the greeter is authorized to do a system restart.
1065  *
1066  * Return value: TRUE if the greeter can restart the system
1067  **/
1068 gboolean
1069 ldm_greeter_get_can_restart (LdmGreeter *greeter)
1070 {
1071     DBusGProxy *proxy;
1072     gboolean result = FALSE;
1073     GError *error = NULL;
1074
1075     g_return_val_if_fail (greeter != NULL, FALSE);
1076
1077     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1078                                        "org.freedesktop.ConsoleKit",
1079                                        "/org/freedesktop/ConsoleKit/Manager",
1080                                        "org.freedesktop.ConsoleKit.Manager");
1081     if (!dbus_g_proxy_call (proxy, "CanRestart", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
1082         g_warning ("Error checking for restart authority: %s", error->message);
1083     g_clear_error (&error);
1084
1085     g_object_unref (proxy);
1086
1087     return result; 
1088 }
1089
1090 /**
1091  * ldm_greeter_restart:
1092  * @greeter: A #LdmGreeter
1093  * 
1094  * Triggers a system restart.
1095  **/
1096 void
1097 ldm_greeter_restart (LdmGreeter *greeter)
1098 {
1099     DBusGProxy *proxy;
1100     GError *error = NULL;
1101
1102     g_return_if_fail (LDM_IS_GREETER (greeter));
1103
1104     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1105                                        "org.freedesktop.ConsoleKit",
1106                                        "/org/freedesktop/ConsoleKit/Manager",
1107                                        "org.freedesktop.ConsoleKit.Manager");
1108     if (!dbus_g_proxy_call (proxy, "Restart", &error, G_TYPE_INVALID, G_TYPE_INVALID))
1109         g_warning ("Failed to restart: %s", error->message);
1110     g_clear_error (&error);
1111
1112     g_object_unref (proxy);
1113 }
1114
1115 /**
1116  * ldm_greeter_get_can_shutdown:
1117  * @greeter: A #LdmGreeter
1118  * 
1119  * Checks if the greeter is authorized to do a system shutdown.
1120  *
1121  * Return value: TRUE if the greeter can shutdown the system
1122  **/
1123 gboolean
1124 ldm_greeter_get_can_shutdown (LdmGreeter *greeter)
1125 {
1126     DBusGProxy *proxy;
1127     gboolean result = FALSE;
1128     GError *error = NULL;
1129
1130     g_return_val_if_fail (greeter != NULL, FALSE);
1131
1132     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1133                                        "org.freedesktop.ConsoleKit",
1134                                        "/org/freedesktop/ConsoleKit/Manager",
1135                                        "org.freedesktop.ConsoleKit.Manager");
1136     if (!dbus_g_proxy_call (proxy, "CanStop", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
1137         g_warning ("Error checking for shutdown authority: %s", error->message);
1138     g_clear_error (&error);
1139
1140     g_object_unref (proxy);
1141
1142     return result; 
1143 }
1144
1145 /**
1146  * ldm_greeter_shutdown:
1147  * @greeter: A #LdmGreeter
1148  * 
1149  * Triggers a system shutdown.
1150  **/
1151 void
1152 ldm_greeter_shutdown (LdmGreeter *greeter)
1153 {
1154     DBusGProxy *proxy;
1155     GError *error = NULL;
1156
1157     g_return_if_fail (LDM_IS_GREETER (greeter));
1158
1159     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1160                                        "org.freedesktop.ConsoleKit",
1161                                        "/org/freedesktop/ConsoleKit/Manager",
1162                                        "org.freedesktop.ConsoleKit.Manager");
1163     if (!dbus_g_proxy_call (proxy, "Stop", &error, G_TYPE_INVALID, G_TYPE_INVALID))
1164         g_warning ("Failed to shutdown: %s", error->message);
1165     g_clear_error (&error);
1166
1167     g_object_unref (proxy);
1168 }
1169
1170 gboolean
1171 ldm_greeter_get_user_defaults (LdmGreeter *greeter, const gchar *username, gchar **language, gchar **layout, gchar **session)
1172 {
1173     GError *error = NULL;
1174     gboolean result;
1175
1176     result = dbus_g_proxy_call (greeter->priv->user_proxy, "GetUserDefaults", &error,
1177                                 G_TYPE_STRING, username,
1178                                 G_TYPE_INVALID,
1179                                 G_TYPE_STRING, language,
1180                                 G_TYPE_STRING, layout,
1181                                 G_TYPE_STRING, session,
1182                                 G_TYPE_INVALID);
1183   
1184     if (!result)
1185         g_warning ("Failed to get user defaults: %s", error->message);
1186     g_clear_error (&error);
1187
1188     return result;
1189 }
1190
1191 static void
1192 ldm_greeter_init (LdmGreeter *greeter)
1193 {
1194     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, LDM_TYPE_GREETER, LdmGreeterPrivate);
1195 }
1196
1197 static void
1198 ldm_greeter_set_property (GObject      *object,
1199                           guint         prop_id,
1200                           const GValue *value,
1201                           GParamSpec   *pspec)
1202 {
1203     LdmGreeter *self;
1204     gint i, n_pages;
1205
1206     self = LDM_GREETER (object);
1207
1208     switch (prop_id) {
1209     case PROP_LAYOUT:
1210         ldm_greeter_set_layout(self, g_value_get_string (value));
1211         break;
1212     default:
1213         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1214         break;
1215     }
1216 }
1217
1218 static void
1219 ldm_greeter_get_property (GObject    *object,
1220                           guint       prop_id,
1221                           GValue     *value,
1222                           GParamSpec *pspec)
1223 {
1224     LdmGreeter *self;
1225
1226     self = LDM_GREETER (object);
1227
1228     switch (prop_id) {
1229     case PROP_HOSTNAME:
1230         g_value_set_string (value, ldm_greeter_get_hostname (self));
1231         break;
1232     case PROP_NUM_USERS:
1233         g_value_set_int (value, ldm_greeter_get_num_users (self));
1234         break;
1235     case PROP_USERS:
1236         break;
1237     case PROP_DEFAULT_LANGUAGE:
1238         g_value_set_string (value, ldm_greeter_get_default_language (self));
1239         break;
1240     case PROP_LAYOUTS:
1241         break;
1242     case PROP_LAYOUT:
1243         g_value_set_string (value, ldm_greeter_get_layout (self));
1244         break;      
1245     case PROP_SESSIONS:
1246         break;
1247     case PROP_DEFAULT_SESSION:
1248         g_value_set_string (value, ldm_greeter_get_default_session (self));
1249         break;
1250     case PROP_TIMED_LOGIN_USER:
1251         g_value_set_string (value, ldm_greeter_get_timed_login_user (self));
1252         break;
1253     case PROP_TIMED_LOGIN_DELAY:
1254         g_value_set_int (value, ldm_greeter_get_timed_login_delay (self));
1255         break;
1256     case PROP_AUTHENTICATION_USER:
1257         g_value_set_string (value, ldm_greeter_get_authentication_user (self));
1258         break;
1259     case PROP_IS_AUTHENTICATED:
1260         g_value_set_boolean (value, ldm_greeter_get_is_authenticated (self));
1261         break;
1262     case PROP_CAN_SUSPEND:
1263         g_value_set_boolean (value, ldm_greeter_get_can_suspend (self));
1264         break;
1265     case PROP_CAN_HIBERNATE:
1266         g_value_set_boolean (value, ldm_greeter_get_can_hibernate (self));
1267         break;
1268     case PROP_CAN_RESTART:
1269         g_value_set_boolean (value, ldm_greeter_get_can_restart (self));
1270         break;
1271     case PROP_CAN_SHUTDOWN:
1272         g_value_set_boolean (value, ldm_greeter_get_can_shutdown (self));
1273         break;
1274     default:
1275         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1276         break;
1277     }
1278 }
1279
1280 static void
1281 ldm_greeter_class_init (LdmGreeterClass *klass)
1282 {
1283     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1284   
1285     g_type_class_add_private (klass, sizeof (LdmGreeterPrivate));
1286
1287     object_class->set_property = ldm_greeter_set_property;
1288     object_class->get_property = ldm_greeter_get_property;
1289
1290     g_object_class_install_property (object_class,
1291                                      PROP_NUM_USERS,
1292                                      g_param_spec_string ("hostname",
1293                                                           "hostname",
1294                                                           "Hostname displaying greeter for",
1295                                                           NULL,
1296                                                           G_PARAM_READABLE));
1297     g_object_class_install_property (object_class,
1298                                      PROP_NUM_USERS,
1299                                      g_param_spec_int ("num-users",
1300                                                        "num-users",
1301                                                        "Number of login users",
1302                                                        0, G_MAXINT, 0,
1303                                                        G_PARAM_READABLE));
1304     /*g_object_class_install_property (object_class,
1305                                      PROP_USERS,
1306                                      g_param_spec_list ("users",
1307                                                         "users",
1308                                                         "Users that can login"));
1309     g_object_class_install_property (object_class,
1310                                      PROP_DEFAULT_LANGUAGE,
1311                                      g_param_spec_string ("default-language",
1312                                                           "default-language",
1313                                                           "Default language",
1314                                                           NULL,
1315                                                           G_PARAM_READWRITE));
1316     g_object_class_install_property (object_class,
1317                                      PROP_LAYOUTS,
1318                                      g_param_spec_list ("layouts",
1319                                                         "layouts",
1320                                                         "Available keyboard layouts"));*/
1321     g_object_class_install_property (object_class,
1322                                      PROP_LAYOUT,
1323                                      g_param_spec_string ("layout",
1324                                                           "layout",
1325                                                           "Current keyboard layout",
1326                                                           NULL,
1327                                                           G_PARAM_READWRITE));
1328     /*g_object_class_install_property (object_class,
1329                                      PROP_SESSIONS,
1330                                      g_param_spec_list ("sessions",
1331                                                         "sessions",
1332                                                         "Available sessions"));*/
1333     g_object_class_install_property (object_class,
1334                                      PROP_DEFAULT_SESSION,
1335                                      g_param_spec_string ("default-session",
1336                                                           "default-session",
1337                                                           "Default session",
1338                                                           NULL,
1339                                                           G_PARAM_READWRITE));
1340     g_object_class_install_property (object_class,
1341                                      PROP_TIMED_LOGIN_USER,
1342                                      g_param_spec_string ("timed-login-user",
1343                                                           "timed-login-user",
1344                                                           "User to login as when timed expires",
1345                                                           NULL,
1346                                                           G_PARAM_READABLE));
1347     g_object_class_install_property (object_class,
1348                                      PROP_TIMED_LOGIN_DELAY,
1349                                      g_param_spec_int ("login-delay",
1350                                                        "login-delay",
1351                                                        "Number of seconds until logging in as default user",
1352                                                        G_MININT, G_MAXINT, 0,
1353                                                        G_PARAM_READABLE));
1354     g_object_class_install_property (object_class,
1355                                      PROP_AUTHENTICATION_USER,
1356                                      g_param_spec_string ("authentication-user",
1357                                                           "authentication-user",
1358                                                           "The user being authenticated",
1359                                                           NULL,
1360                                                           G_PARAM_READABLE));
1361     g_object_class_install_property (object_class,
1362                                      PROP_IS_AUTHENTICATED,
1363                                      g_param_spec_boolean ("is-authenticated",
1364                                                            "is-authenticated",
1365                                                            "TRUE if the selected user is authenticated",
1366                                                            FALSE,
1367                                                            G_PARAM_READABLE));
1368     g_object_class_install_property (object_class,
1369                                      PROP_CAN_SUSPEND,
1370                                      g_param_spec_boolean ("can-suspend",
1371                                                            "can-suspend",
1372                                                            "TRUE if allowed to suspend the system",
1373                                                            FALSE,
1374                                                            G_PARAM_READABLE));
1375     g_object_class_install_property (object_class,
1376                                      PROP_CAN_HIBERNATE,
1377                                      g_param_spec_boolean ("can-hibernate",
1378                                                            "can-hibernate",
1379                                                            "TRUE if allowed to hibernate the system",
1380                                                            FALSE,
1381                                                            G_PARAM_READABLE));
1382     g_object_class_install_property (object_class,
1383                                      PROP_CAN_RESTART,
1384                                      g_param_spec_boolean ("can-restart",
1385                                                            "can-restart",
1386                                                            "TRUE if allowed to restart the system",
1387                                                            FALSE,
1388                                                            G_PARAM_READABLE));
1389     g_object_class_install_property (object_class,
1390                                      PROP_CAN_SHUTDOWN,
1391                                      g_param_spec_boolean ("can-shutdown",
1392                                                            "can-shutdown",
1393                                                            "TRUE if allowed to shutdown the system",
1394                                                            FALSE,
1395                                                            G_PARAM_READABLE));
1396
1397     /**
1398      * LdmGreeter::show-prompt:
1399      * @greeter: A #LdmGreeter
1400      * @text: Prompt text
1401      * 
1402      * The ::show-prompt signal gets emitted when the greeter should show a
1403      * prompt to the user.  The given text should be displayed and an input
1404      * field for the user to provide a response.
1405      * 
1406      * Call ldm_greeter_provide_secret() with the resultant input or
1407      * ldm_greeter_cancel_authentication() to abort the authentication.
1408      **/
1409     signals[SHOW_PROMPT] =
1410         g_signal_new ("show-prompt",
1411                       G_TYPE_FROM_CLASS (klass),
1412                       G_SIGNAL_RUN_LAST,
1413                       G_STRUCT_OFFSET (LdmGreeterClass, show_prompt),
1414                       NULL, NULL,
1415                       g_cclosure_marshal_VOID__STRING,
1416                       G_TYPE_NONE, 1, G_TYPE_STRING);
1417
1418     /**
1419      * LdmGreeter::show-message:
1420      * @greeter: A #LdmGreeter
1421      * @text: Message text
1422      *
1423      * The ::show-message signal gets emitted when the greeter
1424      * should show an informational message to the user.
1425      **/
1426     signals[SHOW_MESSAGE] =
1427         g_signal_new ("show-message",
1428                       G_TYPE_FROM_CLASS (klass),
1429                       G_SIGNAL_RUN_LAST,
1430                       G_STRUCT_OFFSET (LdmGreeterClass, show_message),
1431                       NULL, NULL,
1432                       g_cclosure_marshal_VOID__STRING,
1433                       G_TYPE_NONE, 1, G_TYPE_STRING);
1434
1435     /**
1436      * LdmGreeter::show-error:
1437      * @greeter: A #LdmGreeter
1438      * @text: Message text
1439      *
1440      * The ::show-error signal gets emitted when the greeter
1441      * should show an error message to the user.
1442      **/
1443     signals[SHOW_ERROR] =
1444         g_signal_new ("show-error",
1445                       G_TYPE_FROM_CLASS (klass),
1446                       G_SIGNAL_RUN_LAST,
1447                       G_STRUCT_OFFSET (LdmGreeterClass, show_error),
1448                       NULL, NULL,
1449                       g_cclosure_marshal_VOID__STRING,
1450                       G_TYPE_NONE, 1, G_TYPE_STRING);
1451
1452     /**
1453      * LdmGreeter::authentication-complete:
1454      * @greeter: A #LdmGreeter
1455      *
1456      * The ::authentication-complete signal gets emitted when the greeter
1457      * has completed authentication.
1458      * 
1459      * Call ldm_greeter_get_is_authenticated() to check if the authentication
1460      * was successful.
1461      **/
1462     signals[AUTHENTICATION_COMPLETE] =
1463         g_signal_new ("authentication-complete",
1464                       G_TYPE_FROM_CLASS (klass),
1465                       G_SIGNAL_RUN_LAST,
1466                       G_STRUCT_OFFSET (LdmGreeterClass, authentication_complete),
1467                       NULL, NULL,
1468                       g_cclosure_marshal_VOID__VOID,
1469                       G_TYPE_NONE, 0);
1470
1471     /**
1472      * LdmGreeter::timed-login:
1473      * @greeter: A #LdmGreeter
1474      * @username: A username
1475      *
1476      * The ::timed-login signal gets emitted when the default user timer
1477      * has expired.
1478      **/
1479     signals[TIMED_LOGIN] =
1480         g_signal_new ("timed-login",
1481                       G_TYPE_FROM_CLASS (klass),
1482                       G_SIGNAL_RUN_LAST,
1483                       G_STRUCT_OFFSET (LdmGreeterClass, timed_login),
1484                       NULL, NULL,
1485                       g_cclosure_marshal_VOID__STRING,
1486                       G_TYPE_NONE, 1, G_TYPE_STRING);
1487
1488     /**
1489      * LdmGreeter::quit:
1490      * @greeter: A #LdmGreeter
1491      *
1492      * The ::quit signal gets emitted when the greeter should exit.
1493      **/
1494     signals[QUIT] =
1495         g_signal_new ("quit",
1496                       G_TYPE_FROM_CLASS (klass),
1497                       G_SIGNAL_RUN_LAST,
1498                       G_STRUCT_OFFSET (LdmGreeterClass, quit),
1499                       NULL, NULL,
1500                       g_cclosure_marshal_VOID__VOID,
1501                       G_TYPE_NONE, 0);
1502 }