]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - libldmgreeter/greeter.c
cc9e786ac0ebec6a84996161665d6e69e2c10d73
[sojka/lightdm.git] / libldmgreeter / greeter.c
1 /*
2  * Copyright (C) 2010 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <locale.h>
15
16 #include <gio/gdesktopappinfo.h>
17 #include <dbus/dbus-glib.h>
18 #include <security/pam_appl.h>
19 #include <libxklavier/xklavier.h>
20
21 #include "greeter.h"
22
23 enum {
24     PROP_0,
25     PROP_NUM_USERS,
26     PROP_USERS,
27     PROP_LAYOUTS,
28     PROP_LAYOUT,
29     PROP_SESSIONS,
30     PROP_SESSION,
31     PROP_TIMED_LOGIN_USER,
32     PROP_TIMED_LOGIN_DELAY,
33     PROP_IS_AUTHENTICATED,
34     PROP_CAN_SUSPEND,
35     PROP_CAN_HIBERNATE,
36     PROP_CAN_RESTART,
37     PROP_CAN_SHUTDOWN
38 };
39
40 enum {
41     SHOW_PROMPT,
42     SHOW_MESSAGE,
43     SHOW_ERROR,
44     AUTHENTICATION_COMPLETE,
45     TIMED_LOGIN,
46     QUIT,
47     LAST_SIGNAL
48 };
49 static guint signals[LAST_SIGNAL] = { 0 };
50
51 struct _LdmGreeterPrivate
52 {
53     DBusGConnection *lightdm_bus;
54
55     DBusGConnection *system_bus;
56
57     DBusGProxy *display_proxy, *session_proxy, *user_proxy;
58
59     Display *display;
60
61     gboolean have_users;
62     GList *users;
63   
64     gboolean have_languages;
65     GList *languages;
66
67     XklEngine *xkl_engine;
68     XklConfigRec *xkl_config;
69     gboolean have_layouts;
70     GList *layouts;
71     gchar *layout;
72
73     gboolean have_sessions;
74     GList *sessions;
75     gchar *session;
76
77     gboolean is_authenticated;
78
79     gchar *timed_user;
80     gint login_delay;
81     guint login_timeout;
82 };
83
84 G_DEFINE_TYPE (LdmGreeter, ldm_greeter, G_TYPE_OBJECT);
85
86 /**
87  * ldm_greeter_new:
88  * 
89  * Create a new greeter.
90  * 
91  * Return value: the new #LdmGreeter
92  **/
93 LdmGreeter *
94 ldm_greeter_new ()
95 {
96     return g_object_new (LDM_TYPE_GREETER, NULL);
97 }
98
99 static gboolean
100 timed_login_cb (gpointer data)
101 {
102     LdmGreeter *greeter = data;
103
104     g_signal_emit (G_OBJECT (greeter), signals[TIMED_LOGIN], 0, greeter->priv->timed_user);
105
106     return TRUE;
107 }
108
109 /**
110  * ldm_greeter_connect:
111  * @greeter: The greeter to connect
112  *
113  * Connects the greeter to the display manager.
114  * 
115  * Return value: TRUE if successfully connected
116  **/
117 gboolean
118 ldm_greeter_connect (LdmGreeter *greeter)
119 {
120     gboolean result;
121     GError *error = NULL;
122
123     result = dbus_g_proxy_call (greeter->priv->display_proxy, "Connect", &error,
124                                 G_TYPE_INVALID,
125                                 G_TYPE_STRING, &greeter->priv->session,                                
126                                 G_TYPE_STRING, &greeter->priv->timed_user,
127                                 G_TYPE_INT, &greeter->priv->login_delay,
128                                 G_TYPE_INVALID);
129
130     if (!result)
131         g_warning ("Failed to connect to display manager: %s", error->message);
132     g_clear_error (&error);
133     if (!result)
134         return FALSE;
135
136     /* Set timeout for default login */
137     if (greeter->priv->timed_user[0] != '\0' && greeter->priv->login_delay > 0)
138     {
139         g_debug ("Logging in as %s in %d seconds", greeter->priv->timed_user, greeter->priv->login_delay);
140         greeter->priv->login_timeout = g_timeout_add (greeter->priv->login_delay * 1000, timed_login_cb, greeter);
141     }
142
143     return result;
144 }
145
146 #define TYPE_USER dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID)
147 #define TYPE_USER_LIST dbus_g_type_get_collection ("GPtrArray", TYPE_USER)
148
149 static void
150 update_users (LdmGreeter *greeter)
151 {
152     GPtrArray *users;
153     gboolean result;
154     gint i;
155     GError *error = NULL;
156
157     if (greeter->priv->have_users)
158         return;
159
160     result = dbus_g_proxy_call (greeter->priv->user_proxy, "GetUsers", &error,
161                                 G_TYPE_INVALID,
162                                 TYPE_USER_LIST, &users,
163                                 G_TYPE_INVALID);
164     if (!result)
165         g_warning ("Failed to get users: %s", error->message);
166     g_clear_error (&error);
167   
168     if (!result)
169         return;
170   
171     for (i = 0; i < users->len; i++)
172     {
173         GValue value = { 0 };
174         LdmUser *user;
175         gchar *name, *real_name, *image;
176         gboolean logged_in;
177
178         g_value_init (&value, TYPE_USER);
179         g_value_set_static_boxed (&value, users->pdata[i]);
180         dbus_g_type_struct_get (&value, 0, &name, 1, &real_name, 2, &image, 3, &logged_in, G_MAXUINT);
181         g_value_unset (&value);
182
183         user = ldm_user_new (name, real_name, image, logged_in);
184         g_free (name);
185         g_free (real_name);
186         g_free (image);
187
188         greeter->priv->users = g_list_append (greeter->priv->users, user);
189     }
190
191     g_ptr_array_free (users, TRUE);
192
193     greeter->priv->have_users = TRUE;
194 }
195
196 /**
197  * ldm_greeter_get_num_users:
198  * @greeter: a #LdmGreeter
199  *
200  * Return value: The number of users able to log in
201  **/
202 gint
203 ldm_greeter_get_num_users (LdmGreeter *greeter)
204 {
205     update_users (greeter);
206     return g_list_length (greeter->priv->users);
207 }
208
209 /**
210  * ldm_greeter_get_users:
211  * @greeter: A #LdmGreeter
212  * 
213  * Get a list of users to present to the user.  This list may be a subset of the
214  * available users and may be empty depending on the server configuration.
215  * 
216  * Return value: A list of #LdmUser that should be presented to the user.
217  **/
218 const GList *
219 ldm_greeter_get_users (LdmGreeter *greeter)
220 {
221     update_users (greeter);
222     return greeter->priv->users;
223 }
224
225 static void
226 update_languages (LdmGreeter *greeter)
227 {
228     gchar *stdout_text = NULL, *stderr_text = NULL;
229     gint exit_status;
230     gboolean result;
231     GError *error = NULL;
232
233     if (greeter->priv->have_languages)
234         return;
235
236     result = g_spawn_command_line_sync ("locale -a", &stdout_text, &stderr_text, &exit_status, &error);
237     if (!result || exit_status != 0)
238         g_warning ("Failed to get languages, locale -a returned %d: %s", exit_status, error->message);
239     else
240     {
241         gchar **tokens;
242         int i;
243
244         tokens = g_strsplit_set (stdout_text, "\n\r", -1);
245         for (i = 0; tokens[i]; i++)
246         {
247             LdmLanguage *language;
248             gchar *code;
249
250             code = g_strchug (tokens[i]);
251             if (code[0] == '\0')
252                 continue;
253
254             language = ldm_language_new (code);
255             greeter->priv->languages = g_list_append (greeter->priv->languages, language);
256         }
257
258         g_strfreev (tokens);
259     }
260
261     g_clear_error (&error);
262     g_free (stdout_text);
263     g_free (stderr_text);
264
265     greeter->priv->have_languages = TRUE;
266 }
267
268 /**
269  * ldm_greeter_get_languages:
270  * @greeter: A #LdmGreeter
271  * 
272  * Get a list of languages to present to the user.
273  * 
274  * Return value: A list of #LdmLanguage that should be presented to the user.
275  **/
276 const GList *
277 ldm_greeter_get_languages (LdmGreeter *greeter)
278 {
279     update_languages (greeter);
280     return greeter->priv->languages;
281 }
282
283 /**
284  * ldm_greeter_get_language:
285  * @greeter: A #LdmGreeter
286  * 
287  * Get the current language.
288  * 
289  * Return value: The current language.
290  **/
291 const gchar *
292 ldm_greeter_get_language (LdmGreeter *greeter)
293 {
294     return setlocale (LC_ALL, NULL);
295 }
296
297 static void
298 layout_cb (XklConfigRegistry *config,
299            const XklConfigItem *item,
300            gpointer data)
301 {
302     LdmGreeter *greeter = data;
303     LdmLayout *layout;
304   
305     layout = ldm_layout_new (item->name, item->short_description, item->description);
306     greeter->priv->layouts = g_list_append (greeter->priv->layouts, layout);
307 }
308
309 static void
310 setup_display (LdmGreeter *greeter)
311 {
312     if (!greeter->priv->display)
313         greeter->priv->display = XOpenDisplay (NULL);
314 }
315
316 static void
317 setup_xkl (LdmGreeter *greeter)
318 {
319     setup_display (greeter);
320     greeter->priv->xkl_engine = xkl_engine_get_instance (greeter->priv->display);
321     greeter->priv->xkl_config = xkl_config_rec_new ();
322     if (!xkl_config_rec_get_from_server (greeter->priv->xkl_config, greeter->priv->xkl_engine))
323         g_warning ("Failed to get Xkl configuration from server");
324     greeter->priv->layout = g_strdup (greeter->priv->xkl_config->layouts[0]);
325 }
326
327 /**
328  * ldm_greeter_get_layouts:
329  * @greeter: A #LdmGreeter
330  * 
331  * Get a list of keyboard layouts to present to the user.
332  * 
333  * Return value: A list of #LdmLayout that should be presented to the user.
334  **/
335 const GList *
336 ldm_greeter_get_layouts (LdmGreeter *greeter)
337 {
338     XklConfigRegistry *registry;
339
340     if (greeter->priv->have_layouts)
341         return greeter->priv->layouts;
342
343     setup_xkl (greeter);
344
345     registry = xkl_config_registry_get_instance (greeter->priv->xkl_engine);
346     xkl_config_registry_load (registry, FALSE);
347     xkl_config_registry_foreach_layout (registry, layout_cb, greeter);
348     g_object_unref (registry);
349     greeter->priv->have_layouts = TRUE;
350
351     return greeter->priv->layouts;
352 }
353
354 /**
355  * ldm_greeter_set_layout:
356  * @greeter: A #LdmGreeter
357  * @layout: The layout to use
358  * 
359  * Set the layout for this session.
360  **/
361 void
362 ldm_greeter_set_layout (LdmGreeter *greeter, const gchar *layout)
363 {
364     XklConfigRec *config;
365
366     setup_xkl (greeter);
367
368     config = xkl_config_rec_new ();
369     config->layouts = g_malloc (sizeof (gchar *) * 2);
370     config->model = g_strdup (greeter->priv->xkl_config->model);
371     config->layouts[0] = g_strdup (layout);
372     config->layouts[1] = NULL;
373     if (!xkl_config_rec_activate (config, greeter->priv->xkl_engine))
374         g_warning ("Failed to activate XKL config");
375     else
376         greeter->priv->layout = g_strdup (layout);
377     g_object_unref (config);
378 }
379
380 /**
381  * ldm_greeter_get_layout:
382  * @greeter: A #LdmGreeter
383  * 
384  * Get the current keyboard layout.
385  * 
386  * Return value: The currently active layout for this user.
387  **/
388 const gchar *
389 ldm_greeter_get_layout (LdmGreeter *greeter)
390 {
391     setup_xkl (greeter);
392     return greeter->priv->layout;
393 }
394
395 static void
396 update_sessions (LdmGreeter *greeter)
397 {
398     GDir *directory;
399     GError *error = NULL;
400     GKeyFile *key_file;
401
402     if (greeter->priv->have_sessions)
403         return;
404
405     directory = g_dir_open (XSESSIONS_DIR, 0, &error);
406     if (!directory)
407         g_warning ("Failed to open sessions directory: %s", error->message);
408     g_clear_error (&error);
409     if (!directory)
410         return;
411
412     key_file = g_key_file_new ();
413     while (TRUE)
414     {
415         const gchar *filename;
416         gchar *key, *path;
417         gboolean result;
418
419         filename = g_dir_read_name (directory);
420         if (filename == NULL)
421             break;
422
423         if (!g_str_has_suffix (filename, ".desktop"))
424             continue;
425
426         key = g_strndup (filename, strlen (filename) - strlen (".desktop"));
427         path = g_build_filename (XSESSIONS_DIR, filename, NULL);
428         g_debug ("Loading session %s", path);
429
430         result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
431         if (!result)
432             g_warning ("Failed to load session file %s: %s:", path, error->message);
433         g_clear_error (&error);
434
435         if (result)
436         {
437             GDesktopAppInfo *desktop_file;
438
439             desktop_file = g_desktop_app_info_new_from_keyfile (key_file);
440
441             if (desktop_file && g_app_info_should_show (G_APP_INFO (desktop_file)))
442             {
443                 const gchar *name, *comment;
444
445                 name = g_app_info_get_name (G_APP_INFO (desktop_file));
446                 comment = g_app_info_get_display_name (G_APP_INFO (desktop_file));
447                 if (name && comment)
448                 {
449                     g_debug ("Loaded session %s (%s, %s)", key, name, comment);
450                     greeter->priv->sessions = g_list_append (greeter->priv->sessions, ldm_session_new (key, name, comment));
451                 }
452                 else
453                     g_warning ("Invalid session %s: %s", path, error->message);
454                 g_clear_error (&error);
455             }
456
457             if (desktop_file)
458                 g_object_unref (desktop_file);
459         }
460
461         g_free (key);
462         g_free (path);
463     }
464
465     g_dir_close (directory);
466     g_key_file_free (key_file);
467
468     greeter->priv->have_sessions = TRUE;
469 }
470
471 /**
472  * ldm_greeter_get_sessions:
473  * @greeter: A #LdmGreeter
474  *
475  * Get the available sessions.
476  *
477  * Return value: A list of #LdmSession
478  **/
479 const GList *
480 ldm_greeter_get_sessions (LdmGreeter *greeter)
481 {
482     update_sessions (greeter);
483     return greeter->priv->sessions;
484 }
485
486 /**
487  * ldm_greeter_set_session:
488  * @greeter: A #LdmGreeter
489  * @session: A session name.
490  * 
491  * Set the session to log into.
492  **/
493 void
494 ldm_greeter_set_session (LdmGreeter *greeter, const gchar *session)
495 {
496     GError *error = NULL;
497
498     if (!dbus_g_proxy_call (greeter->priv->display_proxy, "SetSession", &error,
499                             G_TYPE_STRING, session,
500                             G_TYPE_INVALID,
501                             G_TYPE_INVALID))
502         g_warning ("Failed to set session: %s", error->message);
503     else
504     {
505         g_free (greeter->priv->session);
506         greeter->priv->session = g_strdup (session);
507     }
508     g_clear_error (&error);
509 }
510
511 /**
512  * ldm_greeter_get_session:
513  * @greeter: A #LdmGreeter
514  *
515  * Get the session that will be logged into.
516  *
517  * Return value: The session name
518  **/
519 const gchar *
520 ldm_greeter_get_session (LdmGreeter *greeter)
521 {
522     return greeter->priv->session;
523 }
524
525 /**
526  * ldm_greeter_get_timed_login_user:
527  * @greeter: A #LdmGreeter
528  *
529  * Get the user to log in by as default.
530  *
531  * Return value: A username
532  */
533 const gchar *
534 ldm_greeter_get_timed_login_user (LdmGreeter *greeter)
535 {
536     return greeter->priv->timed_user;
537 }
538
539 /**
540  * ldm_greeter_get_timed_login_delay:
541  * @greeter: A #LdmGreeter
542  *
543  * Get the number of seconds to wait until logging in as the default user.
544  *
545  * Return value: The number of seconds before logging in as the default user
546  */
547 gint
548 ldm_greeter_get_timed_login_delay (LdmGreeter *greeter)
549 {
550     return greeter->priv->login_delay;
551 }
552
553 /**
554  * ldm_greeter_cancel_timed_login:
555  * @greeter: A #LdmGreeter
556  *
557  * Cancel the login as the default user.
558  */
559 void
560 ldm_greeter_cancel_timed_login (LdmGreeter *greeter)
561 {
562     if (greeter->priv->login_timeout)
563        g_source_remove (greeter->priv->login_timeout);
564     greeter->priv->login_timeout = 0;
565 }
566
567 #define TYPE_MESSAGE dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID)
568 #define TYPE_MESSAGE_LIST dbus_g_type_get_collection ("GPtrArray", TYPE_MESSAGE)
569
570 static void
571 auth_response_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer userdata)
572 {
573     LdmGreeter *greeter = userdata;
574     gboolean result;
575     GError *error = NULL;
576     gint return_code;
577     GPtrArray *array;
578     int i;
579
580     result = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &return_code, TYPE_MESSAGE_LIST, &array, G_TYPE_INVALID);
581     if (!result)
582         g_warning ("Failed to complete D-Bus call: %s", error->message);
583     g_clear_error (&error);
584     if (!result)
585         return;
586
587     for (i = 0; i < array->len; i++)
588     {
589         GValue value = { 0 };
590         gint msg_style;
591         gchar *msg;
592       
593         g_value_init (&value, TYPE_MESSAGE);
594         g_value_set_static_boxed (&value, array->pdata[i]);
595         dbus_g_type_struct_get (&value, 0, &msg_style, 1, &msg, G_MAXUINT);
596
597         // FIXME: Should stop on prompts?
598         switch (msg_style)
599         {
600         case PAM_PROMPT_ECHO_OFF:
601         case PAM_PROMPT_ECHO_ON:
602             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg);
603             break;
604         case PAM_ERROR_MSG:
605             g_signal_emit (G_OBJECT (greeter), signals[SHOW_ERROR], 0, msg);
606             break;
607         case PAM_TEXT_INFO:
608             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg);
609             break;
610         }
611
612         g_free (msg);
613
614         g_value_unset (&value);
615     }
616
617     if (array->len == 0)
618     {
619         greeter->priv->is_authenticated = (return_code == 0);
620         g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
621     }
622
623     g_ptr_array_unref (array);
624 }
625
626 /**
627  * ldm_greeter_start_authentication:
628  * @greeter: A #LdmGreeter
629  * @username: A username
630  *
631  * Starts the authentication procedure for a user.
632  **/
633 void
634 ldm_greeter_start_authentication (LdmGreeter *greeter, const char *username)
635 {
636     dbus_g_proxy_begin_call (greeter->priv->display_proxy, "StartAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRING, username, G_TYPE_INVALID);
637 }
638
639 /**
640  * ldm_greeter_provide_secret:
641  * @greeter: A #LdmGreeter
642  * @secret: Response to a prompt
643  *
644  * Provide secret information from a prompt.
645  **/
646 void
647 ldm_greeter_provide_secret (LdmGreeter *greeter, const gchar *secret)
648 {
649     gchar **secrets;
650
651     // FIXME: Could be multiple secrets required
652     secrets = g_malloc (sizeof (char *) * 2);
653     secrets[0] = g_strdup (secret);
654     secrets[1] = NULL;
655     dbus_g_proxy_begin_call (greeter->priv->display_proxy, "ContinueAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRV, secrets, G_TYPE_INVALID);
656 }
657
658 /**
659  * ldm_greeter_cancel_authentication:
660  * @greeter: A #LdmGreeter
661  * 
662  * Cancel the current user authentication.
663  **/
664 void
665 ldm_greeter_cancel_authentication (LdmGreeter *greeter)
666 {
667 }
668
669 /**
670  * ldm_greeter_get_is_authenticated:
671  * @greeter: A #LdmGreeter
672  * 
673  * Checks if the greeter has successfully authenticated.
674  *
675  * Return value: TRUE if the greeter is authenticated for login.
676  **/
677 gboolean
678 ldm_greeter_get_is_authenticated (LdmGreeter *greeter)
679 {
680     return greeter->priv->is_authenticated;
681 }
682
683 /**
684  * ldm_greeter_login:
685  * @greeter: A #LdmGreeter
686  * 
687  * Login with the currently authenticated user.
688  **/
689 void
690 ldm_greeter_login (LdmGreeter *greeter)
691 {
692     /* Quitting the greeter will cause the login to occur */
693     g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
694 }
695
696 /**
697  * ldm_greeter_get_can_suspend:
698  * @greeter: A #LdmGreeter
699  * 
700  * Checks if the greeter is authorized to do a system suspend.
701  *
702  * Return value: TRUE if the greeter can suspend the system
703  **/
704 gboolean
705 ldm_greeter_get_can_suspend (LdmGreeter *greeter)
706 {
707     DBusGProxy *proxy;
708     gboolean result = FALSE;
709     GError *error = NULL;
710
711     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
712                                        "org.freedesktop.UPower",
713                                        "/org/freedesktop/UPower",
714                                        "org.freedesktop.UPower");
715     if (!dbus_g_proxy_call (proxy, "SuspendAllowed", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
716         g_warning ("Error checking for suspend authority: %s", error->message);
717     g_clear_error (&error);
718
719     g_object_unref (proxy);
720
721     return result;
722 }
723
724 /**
725  * ldm_greeter_suspend:
726  * @greeter: A #LdmGreeter
727  * 
728  * Triggers a system suspend.
729  **/
730 void
731 ldm_greeter_suspend (LdmGreeter *greeter)
732 {
733     DBusGProxy *proxy;
734     GError *error = NULL;
735
736     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
737                                        "org.freedesktop.UPower",
738                                        "/org/freedesktop/UPower",
739                                        "org.freedesktop.UPower");
740     if (!dbus_g_proxy_call (proxy, "Suspend", &error, G_TYPE_INVALID, G_TYPE_INVALID))
741         g_warning ("Failed to hibernate: %s", error->message);
742     g_clear_error (&error);
743
744     g_object_unref (proxy);
745 }
746
747 /**
748  * ldm_greeter_get_can_hibernate:
749  * @greeter: A #LdmGreeter
750  * 
751  * Checks if the greeter is authorized to do a system hibernate.
752  *
753  * Return value: TRUE if the greeter can hibernate the system
754  **/
755 gboolean
756 ldm_greeter_get_can_hibernate (LdmGreeter *greeter)
757 {
758     DBusGProxy *proxy;
759     gboolean result = FALSE;
760     GError *error = NULL;
761
762     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
763                                        "org.freedesktop.UPower",
764                                        "/org/freedesktop/UPower",
765                                        "org.freedesktop.UPower");
766     if (!dbus_g_proxy_call (proxy, "HibernateAllowed", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
767         g_warning ("Error checking for hibernate authority: %s", error->message);
768     g_clear_error (&error);
769
770     g_object_unref (proxy);
771
772     return result;
773 }
774
775 /**
776  * ldm_greeter_hibernate:
777  * @greeter: A #LdmGreeter
778  * 
779  * Triggers a system hibernate.
780  **/
781 void
782 ldm_greeter_hibernate (LdmGreeter *greeter)
783 {
784     DBusGProxy *proxy;
785     GError *error = NULL;
786
787     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
788                                        "org.freedesktop.UPower",
789                                        "/org/freedesktop/UPower",
790                                        "org.freedesktop.UPower");
791     if (!dbus_g_proxy_call (proxy, "Hibernate", &error, G_TYPE_INVALID, G_TYPE_INVALID))
792         g_warning ("Failed to hibernate: %s", error->message);
793     g_clear_error (&error);
794
795     g_object_unref (proxy);
796 }
797
798 /**
799  * ldm_greeter_get_can_restart:
800  * @greeter: A #LdmGreeter
801  * 
802  * Checks if the greeter is authorized to do a system restart.
803  *
804  * Return value: TRUE if the greeter can restart the system
805  **/
806 gboolean
807 ldm_greeter_get_can_restart (LdmGreeter *greeter)
808 {
809     DBusGProxy *proxy;
810     gboolean result = FALSE;
811     GError *error = NULL;
812
813     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
814                                        "org.freedesktop.ConsoleKit",
815                                        "/org/freedesktop/ConsoleKit/Manager",
816                                        "org.freedesktop.ConsoleKit.Manager");
817     if (!dbus_g_proxy_call (proxy, "CanRestart", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
818         g_warning ("Error checking for restart authority: %s", error->message);
819     g_clear_error (&error);
820
821     g_object_unref (proxy);
822
823     return result; 
824 }
825
826 /**
827  * ldm_greeter_restart:
828  * @greeter: A #LdmGreeter
829  * 
830  * Triggers a system restart.
831  **/
832 void
833 ldm_greeter_restart (LdmGreeter *greeter)
834 {
835     DBusGProxy *proxy;
836     GError *error = NULL;
837
838     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
839                                        "org.freedesktop.ConsoleKit",
840                                        "/org/freedesktop/ConsoleKit/Manager",
841                                        "org.freedesktop.ConsoleKit.Manager");
842     if (!dbus_g_proxy_call (proxy, "Restart", &error, G_TYPE_INVALID, G_TYPE_INVALID))
843         g_warning ("Failed to restart: %s", error->message);
844     g_clear_error (&error);
845
846     g_object_unref (proxy);
847 }
848
849 /**
850  * ldm_greeter_get_can_shutdown:
851  * @greeter: A #LdmGreeter
852  * 
853  * Checks if the greeter is authorized to do a system shutdown.
854  *
855  * Return value: TRUE if the greeter can shutdown the system
856  **/
857 gboolean
858 ldm_greeter_get_can_shutdown (LdmGreeter *greeter)
859 {
860     DBusGProxy *proxy;
861     gboolean result = FALSE;
862     GError *error = NULL;
863
864     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
865                                        "org.freedesktop.ConsoleKit",
866                                        "/org/freedesktop/ConsoleKit/Manager",
867                                        "org.freedesktop.ConsoleKit.Manager");
868     if (!dbus_g_proxy_call (proxy, "CanStop", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
869         g_warning ("Error checking for shutdown authority: %s", error->message);
870     g_clear_error (&error);
871
872     g_object_unref (proxy);
873
874     return result; 
875 }
876
877 /**
878  * ldm_greeter_shutdown:
879  * @greeter: A #LdmGreeter
880  * 
881  * Triggers a system shutdown.
882  **/
883 void
884 ldm_greeter_shutdown (LdmGreeter *greeter)
885 {
886     DBusGProxy *proxy;
887     GError *error = NULL;
888
889     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
890                                        "org.freedesktop.ConsoleKit",
891                                        "/org/freedesktop/ConsoleKit/Manager",
892                                        "org.freedesktop.ConsoleKit.Manager");
893     if (!dbus_g_proxy_call (proxy, "Stop", &error, G_TYPE_INVALID, G_TYPE_INVALID))
894         g_warning ("Failed to shutdown: %s", error->message);
895     g_clear_error (&error);
896
897     g_object_unref (proxy);
898 }
899
900 static void
901 ldm_greeter_init (LdmGreeter *greeter)
902 {
903     GError *error = NULL;
904     const gchar *bus_address, *object;
905     DBusBusType bus_type = DBUS_BUS_SYSTEM;
906
907     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, LDM_TYPE_GREETER, LdmGreeterPrivate);
908
909     greeter->priv->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
910     if (!greeter->priv->system_bus)
911         g_error ("Failed to connect to system bus: %s", error->message);
912     g_clear_error (&error);
913
914     bus_address = getenv ("LDM_BUS");
915     if (bus_address && strcmp (bus_address, "SESSION") == 0)
916         bus_type = DBUS_BUS_SESSION;
917
918     greeter->priv->lightdm_bus = dbus_g_bus_get (bus_type, &error);
919     if (!greeter->priv->lightdm_bus)
920         g_error ("Failed to connect to LightDM bus: %s", error->message);
921     g_clear_error (&error);
922
923     object = getenv ("LDM_DISPLAY");
924     if (!object)
925         g_error ("No LDM_DISPLAY enviroment variable");
926
927     greeter->priv->display_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
928                                                               "org.gnome.LightDisplayManager",
929                                                               object,
930                                                               "org.gnome.LightDisplayManager.Greeter");
931     greeter->priv->session_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
932                                                               "org.gnome.LightDisplayManager",
933                                                               "/org/gnome/LightDisplayManager/Session",
934                                                               "org.gnome.LightDisplayManager.Session");
935     greeter->priv->user_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
936                                                            "org.gnome.LightDisplayManager",
937                                                            "/org/gnome/LightDisplayManager/Users",
938                                                            "org.gnome.LightDisplayManager.Users");
939 }
940
941 static void
942 ldm_greeter_set_property(GObject      *object,
943                          guint         prop_id,
944                          const GValue *value,
945                          GParamSpec   *pspec)
946 {
947     LdmGreeter *self;
948     gint i, n_pages;
949
950     self = LDM_GREETER (object);
951
952     switch (prop_id) {
953     case PROP_LAYOUT:
954         ldm_greeter_set_layout(self, g_value_get_string (value));
955         break;
956     case PROP_SESSION:
957         ldm_greeter_set_session(self, g_value_get_string (value));
958         break;
959     default:
960         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
961         break;
962     }
963 }
964
965 static void
966 ldm_greeter_get_property(GObject    *object,
967                          guint       prop_id,
968                          GValue     *value,
969                          GParamSpec *pspec)
970 {
971     LdmGreeter *self;
972
973     self = LDM_GREETER (object);
974
975     switch (prop_id) {
976     case PROP_NUM_USERS:
977         g_value_set_int (value, ldm_greeter_get_num_users (self));
978         break;
979     case PROP_USERS:
980         break;
981     case PROP_LAYOUTS:
982         break;
983     case PROP_LAYOUT:
984         g_value_set_string (value, ldm_greeter_get_layout (self));
985         break;      
986     case PROP_SESSIONS:
987         break;
988     case PROP_SESSION:
989         g_value_set_string (value, ldm_greeter_get_session (self));
990         break;
991     case PROP_TIMED_LOGIN_USER:
992         g_value_set_string (value, ldm_greeter_get_timed_login_user (self));
993         break;
994     case PROP_TIMED_LOGIN_DELAY:
995         g_value_set_int (value, ldm_greeter_get_timed_login_delay (self));
996         break;
997     case PROP_IS_AUTHENTICATED:
998         g_value_set_boolean (value, ldm_greeter_get_is_authenticated (self));
999         break;
1000     case PROP_CAN_SUSPEND:
1001         g_value_set_boolean (value, ldm_greeter_get_can_suspend (self));
1002         break;
1003     case PROP_CAN_HIBERNATE:
1004         g_value_set_boolean (value, ldm_greeter_get_can_hibernate (self));
1005         break;
1006     case PROP_CAN_RESTART:
1007         g_value_set_boolean (value, ldm_greeter_get_can_restart (self));
1008         break;
1009     case PROP_CAN_SHUTDOWN:
1010         g_value_set_boolean (value, ldm_greeter_get_can_shutdown (self));
1011         break;
1012     default:
1013         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1014         break;
1015     }
1016 }
1017
1018 static void
1019 ldm_greeter_class_init (LdmGreeterClass *klass)
1020 {
1021     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1022   
1023     g_type_class_add_private (klass, sizeof (LdmGreeterPrivate));
1024
1025     object_class->set_property = ldm_greeter_set_property;
1026     object_class->get_property = ldm_greeter_get_property;
1027
1028     g_object_class_install_property(object_class,
1029                                     PROP_NUM_USERS,
1030                                     g_param_spec_int("num-users",
1031                                                      "num- users",
1032                                                      "Number of login users",
1033                                                      0, G_MAXINT, 0,
1034                                                      G_PARAM_READABLE));
1035     /*g_object_class_install_property(object_class,
1036                                     PROP_USERS,
1037                                     g_param_spec_list("users",
1038                                                       "users",
1039                                                       "Users that can login"));
1040     g_object_class_install_property(object_class,
1041                                     PROP_LAYOUTS,
1042                                     g_param_spec_list("layouts",
1043                                                       "layouts",
1044                                                       "Available keyboard layouts"));*/
1045     g_object_class_install_property(object_class,
1046                                     PROP_LAYOUT,
1047                                     g_param_spec_string("layout",
1048                                                         "layout",
1049                                                         "Current keyboard layout",
1050                                                         NULL,
1051                                                         G_PARAM_READWRITE));
1052     /*g_object_class_install_property(object_class,
1053                                     PROP_SESSIONS,
1054                                     g_param_spec_list("sessions",
1055                                                       "sessions",
1056                                                       "Available sessions"));*/
1057     g_object_class_install_property(object_class,
1058                                     PROP_SESSION,
1059                                     g_param_spec_string("session",
1060                                                         "session",
1061                                                         "Selected session",
1062                                                         NULL,
1063                                                         G_PARAM_READWRITE));
1064     g_object_class_install_property(object_class,
1065                                     PROP_TIMED_LOGIN_USER,
1066                                     g_param_spec_string("timed-login-user",
1067                                                         "timed-login-user",
1068                                                         "User to login as when timed expires",
1069                                                         NULL,
1070                                                         G_PARAM_READABLE));
1071     g_object_class_install_property(object_class,
1072                                     PROP_TIMED_LOGIN_DELAY,
1073                                     g_param_spec_int("login-delay",
1074                                                      "login-delay",
1075                                                      "Number of seconds until logging in as default user",
1076                                                      G_MININT, G_MAXINT, 0,
1077                                                      G_PARAM_READABLE));
1078     g_object_class_install_property(object_class,
1079                                     PROP_IS_AUTHENTICATED,
1080                                     g_param_spec_boolean("is-authenticated",
1081                                                          "is-authenticated",
1082                                                          "TRUE if the selected user is authenticated",
1083                                                          FALSE,
1084                                                          G_PARAM_READABLE));
1085     g_object_class_install_property(object_class,
1086                                     PROP_CAN_SUSPEND,
1087                                     g_param_spec_boolean("can-suspend",
1088                                                          "can-suspend",
1089                                                          "TRUE if allowed to suspend the system",
1090                                                          FALSE,
1091                                                          G_PARAM_READABLE));
1092     g_object_class_install_property(object_class,
1093                                     PROP_CAN_HIBERNATE,
1094                                     g_param_spec_boolean("can-hibernate",
1095                                                          "can-hibernate",
1096                                                          "TRUE if allowed to hibernate the system",
1097                                                          FALSE,
1098                                                          G_PARAM_READABLE));
1099     g_object_class_install_property(object_class,
1100                                     PROP_CAN_RESTART,
1101                                     g_param_spec_boolean("can-restart",
1102                                                          "can-restart",
1103                                                          "TRUE if allowed to restart the system",
1104                                                          FALSE,
1105                                                          G_PARAM_READABLE));
1106     g_object_class_install_property(object_class,
1107                                     PROP_CAN_SHUTDOWN,
1108                                     g_param_spec_boolean("can-shutdown",
1109                                                          "can-shutdown",
1110                                                          "TRUE if allowed to shutdown the system",
1111                                                          FALSE,
1112                                                          G_PARAM_READABLE));
1113
1114     /**
1115      * LdmGreeter::show-prompt:
1116      * @greeter: A #LdmGreeter
1117      * @text: Prompt text
1118      * 
1119      * The ::show-prompt signal gets emitted when the greeter should show a
1120      * prompt to the user.  The given text should be displayed and an input
1121      * field for the user to provide a response.
1122      * 
1123      * Call ldm_greeter_provide_secret() with the resultant input or
1124      * ldm_greeter_cancel_authentication() to abort the authentication.
1125      **/
1126     signals[SHOW_PROMPT] =
1127         g_signal_new ("show-prompt",
1128                       G_TYPE_FROM_CLASS (klass),
1129                       G_SIGNAL_RUN_LAST,
1130                       G_STRUCT_OFFSET (LdmGreeterClass, show_prompt),
1131                       NULL, NULL,
1132                       g_cclosure_marshal_VOID__STRING,
1133                       G_TYPE_NONE, 1, G_TYPE_STRING);
1134
1135     /**
1136      * LdmGreeter::show-message:
1137      * @greeter: A #LdmGreeter
1138      * @text: Message text
1139      *
1140      * The ::show-message signal gets emitted when the greeter
1141      * should show an informational message to the user.
1142      **/
1143     signals[SHOW_MESSAGE] =
1144         g_signal_new ("show-message",
1145                       G_TYPE_FROM_CLASS (klass),
1146                       G_SIGNAL_RUN_LAST,
1147                       G_STRUCT_OFFSET (LdmGreeterClass, show_message),
1148                       NULL, NULL,
1149                       g_cclosure_marshal_VOID__STRING,
1150                       G_TYPE_NONE, 1, G_TYPE_STRING);
1151
1152     /**
1153      * LdmGreeter::show-error:
1154      * @greeter: A #LdmGreeter
1155      * @text: Message text
1156      *
1157      * The ::show-error signal gets emitted when the greeter
1158      * should show an error message to the user.
1159      **/
1160     signals[SHOW_ERROR] =
1161         g_signal_new ("show-error",
1162                       G_TYPE_FROM_CLASS (klass),
1163                       G_SIGNAL_RUN_LAST,
1164                       G_STRUCT_OFFSET (LdmGreeterClass, show_error),
1165                       NULL, NULL,
1166                       g_cclosure_marshal_VOID__STRING,
1167                       G_TYPE_NONE, 1, G_TYPE_STRING);
1168
1169     /**
1170      * LdmGreeter::authentication-complete:
1171      * @greeter: A #LdmGreeter
1172      *
1173      * The ::authentication-complete signal gets emitted when the greeter
1174      * has completed authentication.
1175      * 
1176      * Call ldm_greeter_get_is_authenticated() to check if the authentication
1177      * was successful.
1178      **/
1179     signals[AUTHENTICATION_COMPLETE] =
1180         g_signal_new ("authentication-complete",
1181                       G_TYPE_FROM_CLASS (klass),
1182                       G_SIGNAL_RUN_LAST,
1183                       G_STRUCT_OFFSET (LdmGreeterClass, authentication_complete),
1184                       NULL, NULL,
1185                       g_cclosure_marshal_VOID__VOID,
1186                       G_TYPE_NONE, 0);
1187
1188     /**
1189      * LdmGreeter::timed-login:
1190      * @greeter: A #LdmGreeter
1191      * @username: A username
1192      *
1193      * The ::timed-login signal gets emitted when the default user timer
1194      * has expired.
1195      **/
1196     signals[TIMED_LOGIN] =
1197         g_signal_new ("timed-login",
1198                       G_TYPE_FROM_CLASS (klass),
1199                       G_SIGNAL_RUN_LAST,
1200                       G_STRUCT_OFFSET (LdmGreeterClass, timed_login),
1201                       NULL, NULL,
1202                       g_cclosure_marshal_VOID__STRING,
1203                       G_TYPE_NONE, 1, G_TYPE_STRING);
1204
1205     /**
1206      * LdmGreeter::quit:
1207      * @greeter: A #LdmGreeter
1208      *
1209      * The ::quit signal gets emitted when the greeter should exit.
1210      **/
1211     signals[QUIT] =
1212         g_signal_new ("quit",
1213                       G_TYPE_FROM_CLASS (klass),
1214                       G_SIGNAL_RUN_LAST,
1215                       G_STRUCT_OFFSET (LdmGreeterClass, quit),
1216                       NULL, NULL,
1217                       g_cclosure_marshal_VOID__VOID,
1218                       G_TYPE_NONE, 0);
1219 }