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