Tizen 2.1 release
[platform/core/uifw/e17.git] / src / bin / e_desklock.c
1 #include "e.h"
2 #ifdef HAVE_PAM
3 # include <security/pam_appl.h>
4 # include <pwd.h>
5 #endif
6
7 #define E_DESKLOCK_STATE_DEFAULT  0
8 #define E_DESKLOCK_STATE_CHECKING 1
9 #define E_DESKLOCK_STATE_INVALID  2
10
11 #define ELOCK_POPUP_LAYER         10000
12 #define PASSWD_LEN                256
13
14 /**************************** private data ******************************/
15 typedef struct _E_Desklock_Data       E_Desklock_Data;
16 typedef struct _E_Desklock_Popup_Data E_Desklock_Popup_Data;
17 #ifdef HAVE_PAM
18 typedef struct _E_Desklock_Auth       E_Desklock_Auth;
19 #endif
20
21 typedef struct _E_Desklock_Run  E_Desklock_Run;
22
23 struct _E_Desklock_Popup_Data
24 {
25    E_Popup     *popup_wnd;
26    Evas_Object *bg_object;
27    Evas_Object *login_box;
28 };
29
30 struct _E_Desklock_Data
31 {
32    Eina_List     *elock_wnd_list;
33    Ecore_X_Window elock_wnd;
34    Eina_List     *handlers;
35    Ecore_Event_Handler *move_handler;
36    Ecore_X_Window elock_grab_break_wnd;
37    char           passwd[PASSWD_LEN];
38    int            state;
39    Eina_Bool     selected : 1;
40 };
41
42 struct _E_Desklock_Run
43 {
44    E_Order *desk_run;
45    int position;
46 };
47
48 #ifdef HAVE_PAM
49 struct _E_Desklock_Auth
50 {
51    struct
52    {
53       struct pam_conv conv;
54       pam_handle_t   *handle;
55    } pam;
56
57    char user[4096];
58    char passwd[4096];
59 };
60 #endif
61
62 static E_Desklock_Data *edd = NULL;
63 static E_Zone *last_active_zone = NULL;
64 #ifdef HAVE_PAM
65 static Ecore_Event_Handler *_e_desklock_exit_handler = NULL;
66 static pid_t _e_desklock_child_pid = -1;
67 #endif
68 static Ecore_Exe *_e_custom_desklock_exe = NULL;
69 static Ecore_Event_Handler *_e_custom_desklock_exe_handler = NULL;
70 static Ecore_Poller *_e_desklock_idle_poller = NULL;
71 static int _e_desklock_user_idle = 0;
72 static double _e_desklock_autolock_time = 0.0;
73 static E_Dialog *_e_desklock_ask_presentation_dia = NULL;
74 static int _e_desklock_ask_presentation_count = 0;
75
76 static Ecore_Event_Handler *_e_desklock_run_handler = NULL;
77 static Ecore_Job *job = NULL;
78 static Eina_List *tasks = NULL;
79
80
81 /***********************************************************************/
82
83 static Eina_Bool _e_desklock_cb_key_down(void *data, int type, void *event);
84 static Eina_Bool _e_desklock_cb_mouse_move(void *data, int type, void *event);
85 static Eina_Bool _e_desklock_cb_custom_desklock_exit(void *data, int type, void *event);
86 static Eina_Bool _e_desklock_cb_idle_poller(void *data);
87 static Eina_Bool _e_desklock_cb_window_stack(void *data, int type, void *event);
88 static Eina_Bool _e_desklock_cb_zone_add(void *data, int type, void *event);
89 static Eina_Bool _e_desklock_cb_zone_del(void *data, int type, void *event);
90 static Eina_Bool _e_desklock_cb_zone_move_resize(void *data, int type, void *event);
91
92 static Eina_Bool _e_desklock_cb_run(void *data, int type, void *event);
93
94 static void      _e_desklock_popup_free(E_Desklock_Popup_Data *edp);
95 static void      _e_desklock_popup_add(E_Zone *zone);
96 static void      _e_desklock_login_box_add(E_Desklock_Popup_Data *edp);
97 static void      _e_desklock_select(void);
98 static void      _e_desklock_unselect(void);
99 static void      _e_desklock_null(void);
100 static void      _e_desklock_passwd_update(void);
101 static void      _e_desklock_backspace(void);
102 static void      _e_desklock_delete(void);
103 static int       _e_desklock_zone_num_get(void);
104 static int       _e_desklock_check_auth(void);
105 static void      _e_desklock_state_set(int state);
106
107 static Eina_Bool _e_desklock_state = EINA_FALSE;
108 #ifdef HAVE_PAM
109 static Eina_Bool _e_desklock_cb_exit(void *data, int type, void *event);
110 static int       _desklock_auth(char *passwd);
111 static int       _desklock_pam_init(E_Desklock_Auth *da);
112 static int       _desklock_auth_pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr);
113 static char     *_desklock_auth_get_current_user(void);
114 static char     *_desklock_auth_get_current_host(void);
115 #endif
116
117 static void      _e_desklock_ask_presentation_mode(void);
118
119 EAPI int E_EVENT_DESKLOCK = 0;
120
121 EINTERN int
122 e_desklock_init(void)
123 {
124    /* A poller to tick every 256 ticks, watching for an idle user */
125    _e_desklock_idle_poller = ecore_poller_add(ECORE_POLLER_CORE, 256,
126                                               _e_desklock_cb_idle_poller, NULL);
127
128    if (e_config->desklock_background)
129      e_filereg_register(e_config->desklock_background);
130
131    E_EVENT_DESKLOCK = ecore_event_type_new();
132
133    _e_desklock_run_handler = ecore_event_handler_add(E_EVENT_DESKLOCK,
134                                                      _e_desklock_cb_run, NULL);
135
136    return 1;
137 }
138
139 EINTERN int
140 e_desklock_shutdown(void)
141 {
142    Eina_Bool waslocked = EINA_FALSE;
143    E_Desklock_Run *task;
144
145    if (edd) waslocked = EINA_TRUE;
146    if (!x_fatal)
147      e_desklock_hide();
148    if (e_config->desklock_background)
149      e_filereg_deregister(e_config->desklock_background);
150
151    if (waslocked) e_util_env_set("E_DESKLOCK_LOCKED", "locked");
152
153    ecore_event_handler_del(_e_desklock_run_handler);
154    _e_desklock_run_handler = NULL;
155
156    if (job) ecore_job_del(job);
157    job = NULL;
158
159    EINA_LIST_FREE(tasks, task)
160      {
161         e_object_del(E_OBJECT(task->desk_run));
162         free(task);
163      }
164
165    return 1;
166 }
167
168 static const char *
169 _user_wallpaper_get(void)
170 {
171    const E_Config_Desktop_Background *cdbg;
172    const Eina_List *l;
173
174    if (e_config->desktop_default_background)
175      return e_config->desktop_default_background;
176
177    EINA_LIST_FOREACH(e_config->desktop_backgrounds, l, cdbg)
178      if (cdbg->file) return cdbg->file;
179
180    return e_theme_edje_file_get("base/theme/desklock", "e/desklock/background");
181 }
182
183 EAPI int
184 e_desklock_show_autolocked(void)
185 {
186    if (e_util_fullscreen_curreny_any()) return 0;
187    if (_e_desklock_autolock_time < 1.0)
188      _e_desklock_autolock_time = ecore_loop_time_get();
189    return e_desklock_show(EINA_FALSE);
190 }
191
192 EAPI int
193 e_desklock_show(Eina_Bool suspend)
194 {
195    Eina_List *managers, *l, *l2, *l3;
196    E_Manager *man;
197    int total_zone_num;
198    E_Event_Desklock *ev;
199
200    if (_e_custom_desklock_exe) return 0;
201
202    if (e_config->desklock_use_custom_desklock && e_config->desklock_custom_desklock_cmd && e_config->desklock_custom_desklock_cmd[0])
203      {
204         _e_custom_desklock_exe_handler =
205           ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
206                                   _e_desklock_cb_custom_desklock_exit, NULL);
207         e_util_library_path_strip();
208         _e_custom_desklock_exe =
209           ecore_exe_run(e_config->desklock_custom_desklock_cmd, NULL);
210         e_util_library_path_restore();
211         _e_desklock_state = EINA_TRUE;
212         return 1;
213      }
214
215 #ifndef HAVE_PAM
216    e_util_dialog_show(_("Error - no PAM support"),
217                       _("No PAM support was built into Enlightenment, so<br>"
218                         "desk locking is disabled."));
219    return 0;
220 #endif
221
222    if (edd) return 0;
223
224 #ifdef HAVE_PAM
225    if (e_config->desklock_auth_method == 1)
226      {
227 #endif
228    if (!e_config->desklock_personal_passwd)
229      {
230         E_Zone *zone;
231
232         zone = e_util_zone_current_get(e_manager_current_get());
233         if (zone)
234           e_configure_registry_call("screen/screen_lock", zone->container, NULL);
235         return 0;
236      }
237 #ifdef HAVE_PAM
238 }
239
240 #endif
241
242    edd = E_NEW(E_Desklock_Data, 1);
243    if (!edd) return 0;
244    edd->elock_wnd = ecore_x_window_input_new(e_manager_current_get()->root, 0, 0, 1, 1);
245    ecore_x_window_show(edd->elock_wnd);
246    managers = e_manager_list();
247    if (!e_grabinput_get(edd->elock_wnd, 0, edd->elock_wnd))
248      {
249         EINA_LIST_FOREACH(managers, l, man)
250           {
251              Ecore_X_Window *windows;
252              int wnum;
253
254              windows = ecore_x_window_children_get(man->root, &wnum);
255              if (windows)
256                {
257                   int i;
258
259                   for (i = 0; i < wnum; i++)
260                     {
261                        Ecore_X_Window_Attributes att;
262
263                        memset(&att, 0, sizeof(Ecore_X_Window_Attributes));
264                        ecore_x_window_attributes_get(windows[i], &att);
265                        if (att.visible)
266                          {
267                             ecore_x_window_hide(windows[i]);
268                             if (e_grabinput_get(edd->elock_wnd, 0, edd->elock_wnd))
269                               {
270                                  edd->elock_grab_break_wnd = windows[i];
271                                  free(windows);
272                                  goto works;
273                               }
274                             ecore_x_window_show(windows[i]);
275                          }
276                     }
277                   free(windows);
278                }
279           }
280         /* everything failed - can't lock */
281         e_util_dialog_show(_("Lock Failed"),
282                            _("Locking the desktop failed because some application<br>"
283                              "has grabbed either the keyboard or the mouse or both<br>"
284                              "and their grab is unable to be broken."));
285         ecore_x_window_free(edd->elock_wnd);
286         E_FREE(edd);
287         return 0;
288      }
289 works:
290
291    total_zone_num = _e_desklock_zone_num_get();
292    EINA_LIST_FOREACH(managers, l, man)
293      {
294         E_Container *con;
295
296         EINA_LIST_FOREACH(man->containers, l2, con)
297           {
298              E_Zone *zone;
299              EINA_LIST_FOREACH(con->zones, l3, zone)
300                _e_desklock_popup_add(zone);
301           }
302      }
303
304    /* handlers */
305    edd->handlers =
306      eina_list_append(edd->handlers,
307                       ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
308                                               _e_desklock_cb_key_down, NULL));
309    edd->handlers =
310      eina_list_append(edd->handlers,
311                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_STACK,
312                                               _e_desklock_cb_window_stack, NULL));
313    edd->handlers =
314      eina_list_append(edd->handlers,
315                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CONFIGURE,
316                                               _e_desklock_cb_window_stack, NULL));
317    edd->handlers =
318      eina_list_append(edd->handlers,
319                       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CREATE,
320                                               _e_desklock_cb_window_stack, NULL));
321    edd->handlers =
322      eina_list_append(edd->handlers,
323                       ecore_event_handler_add(E_EVENT_ZONE_ADD,
324                                               _e_desklock_cb_zone_add, NULL));
325    edd->handlers =
326      eina_list_append(edd->handlers,
327                       ecore_event_handler_add(E_EVENT_ZONE_DEL,
328                                               _e_desklock_cb_zone_del, NULL));
329    edd->handlers =
330      eina_list_append(edd->handlers,
331                       ecore_event_handler_add(E_EVENT_ZONE_MOVE_RESIZE,
332                                               _e_desklock_cb_zone_move_resize, NULL));
333
334    if ((total_zone_num > 1) && (e_config->desklock_login_box_zone == -2))
335      edd->move_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _e_desklock_cb_mouse_move, NULL);
336
337    _e_desklock_passwd_update();
338
339    ev = E_NEW(E_Event_Desklock, 1);
340    ev->on = 1;
341    ev->suspend = suspend;
342    ecore_event_add(E_EVENT_DESKLOCK, ev, NULL, NULL);
343
344    e_util_env_set("E_DESKLOCK_LOCKED", "locked");
345    _e_desklock_state = EINA_TRUE;
346    return 1;
347 }
348
349 EAPI void
350 e_desklock_hide(void)
351 {
352    E_Desklock_Popup_Data *edp;
353    E_Event_Desklock *ev;
354
355    if ((!edd) && (!_e_custom_desklock_exe)) return;
356
357    _e_desklock_state = EINA_FALSE;
358    ev = E_NEW(E_Event_Desklock, 1);
359    ev->on = 0;
360    ev->suspend = 1;
361    ecore_event_add(E_EVENT_DESKLOCK, ev, NULL, NULL);
362
363    if (e_config->desklock_use_custom_desklock)
364      {
365         _e_custom_desklock_exe = NULL;
366         return;
367      }
368
369    if (!edd) return;
370    if (edd->elock_grab_break_wnd)
371      ecore_x_window_show(edd->elock_grab_break_wnd);
372
373    EINA_LIST_FREE(edd->elock_wnd_list, edp)
374      _e_desklock_popup_free(edp);
375
376    E_FREE_LIST(edd->handlers, ecore_event_handler_del);
377    if (edd->move_handler) ecore_event_handler_del(edd->move_handler);
378
379    e_grabinput_release(edd->elock_wnd, edd->elock_wnd);
380    ecore_x_window_free(edd->elock_wnd);
381
382    E_FREE(edd);
383    edd = NULL;
384
385    if (_e_desklock_autolock_time > 0.0)
386      {
387         if ((e_config->desklock_ask_presentation) &&
388             (e_config->desklock_ask_presentation_timeout > 0.0))
389           {
390              double max, now;
391
392              now = ecore_loop_time_get();
393              max = _e_desklock_autolock_time + e_config->desklock_ask_presentation_timeout;
394              if (now <= max)
395                _e_desklock_ask_presentation_mode();
396           }
397         else
398           _e_desklock_ask_presentation_count = 0;
399
400         _e_desklock_autolock_time = 0.0;
401      }
402    e_util_env_set("E_DESKLOCK_LOCKED", "freefreefree");
403 }
404
405 static void
406 _e_desklock_popup_add(E_Zone *zone)
407 {
408    E_Desklock_Popup_Data *edp;
409    E_Config_Desklock_Background *cbg;
410    const char *bg;
411
412    cbg = eina_list_nth(e_config->desklock_backgrounds, zone->num);
413    bg = cbg ? cbg->file : NULL;
414    edp = E_NEW(E_Desklock_Popup_Data, 1);
415    if (!edp)
416      {
417         CRI("DESKLOCK FAILED FOR ZONE %d!", zone->num);
418         return;
419      }
420
421    edp->popup_wnd = e_popup_new(zone, 0, 0, zone->w, zone->h);
422    evas_event_feed_mouse_move(edp->popup_wnd->evas, -1000000, -1000000,
423                               ecore_x_current_time_get(), NULL);
424
425    e_popup_layer_set(edp->popup_wnd, ELOCK_POPUP_LAYER);
426    ecore_evas_raise(edp->popup_wnd->ecore_evas);
427
428    evas_event_freeze(edp->popup_wnd->evas);
429    edp->bg_object = edje_object_add(edp->popup_wnd->evas);
430
431    if ((!bg) || (!strcmp(bg, "theme_desklock_background")))
432      {
433         e_theme_edje_object_set(edp->bg_object,
434                                 "base/theme/desklock",
435                                 "e/desklock/background");
436      }
437    else if (!strcmp(bg, "theme_background"))
438      {
439         e_theme_edje_object_set(edp->bg_object,
440                                 "base/theme/backgrounds",
441                                 "e/desktop/background");
442      }
443    else
444      {
445         const char *f;
446
447         if (!strcmp(bg, "user_background"))
448           f = _user_wallpaper_get();
449         else
450           f = bg;
451
452         if (e_util_edje_collection_exists(f, "e/desklock/background"))
453           {
454              edje_object_file_set(edp->bg_object, f, "e/desklock/background");
455           }
456         else
457           {
458              if (!edje_object_file_set(edp->bg_object,
459                                        f, "e/desktop/background"))
460                {
461                   edje_object_file_set(edp->bg_object,
462                                        e_theme_edje_file_get("base/theme/desklock",
463                                                              "e/desklock/background"),
464                                        "e/desklock/background");
465                }
466           }
467      }
468
469    evas_object_move(edp->bg_object, 0, 0);
470    evas_object_resize(edp->bg_object, zone->w, zone->h);
471    evas_object_show(edp->bg_object);
472
473    _e_desklock_login_box_add(edp);
474    e_popup_edje_bg_object_set(edp->popup_wnd, edp->bg_object);
475    evas_event_thaw(edp->popup_wnd->evas);
476
477    e_popup_show(edp->popup_wnd);
478
479    edd->elock_wnd_list = eina_list_append(edd->elock_wnd_list, edp);
480 }
481
482 static void
483 _e_desklock_login_box_add(E_Desklock_Popup_Data *edp)
484 {
485    int mw, mh;
486    E_Zone *zone = edp->popup_wnd->zone;
487    E_Zone *current_zone;
488    int total_zone_num;
489
490    last_active_zone = current_zone = e_zone_current_get(e_container_current_get(e_manager_current_get()));
491    total_zone_num = _e_desklock_zone_num_get();
492    if (total_zone_num > 1)
493      {
494         if ((e_config->desklock_login_box_zone == -2) && (zone != current_zone))
495           return;
496         if ((e_config->desklock_login_box_zone > -1) && (e_config->desklock_login_box_zone != (int)eina_list_count(edd->elock_wnd_list)))
497           return;
498      }
499
500    edp->login_box = edje_object_add(edp->popup_wnd->evas);
501    e_theme_edje_object_set(edp->login_box,
502                            "base/theme/desklock",
503                            "e/desklock/login_box");
504    edje_object_part_text_set(edp->login_box, "e.text.title",
505                              _("Please enter your unlock password"));
506    edje_object_size_min_calc(edp->login_box, &mw, &mh);
507    if (edje_object_part_exists(edp->bg_object, "e.swallow.login_box"))
508      {
509         edje_extern_object_min_size_set(edp->login_box, mw, mh);
510         edje_object_part_swallow(edp->bg_object, "e.swallow.login_box", edp->login_box);
511      }
512    else
513      {
514         evas_object_resize(edp->login_box, mw, mh);
515         evas_object_move(edp->login_box,
516                          ((zone->w - mw) / 2),
517                          ((zone->h - mh) / 2));
518      }
519    evas_object_show(edp->login_box);
520 }
521
522 static void
523 _e_desklock_popup_free(E_Desklock_Popup_Data *edp)
524 {
525    if (!edp) return;
526    e_popup_hide(edp->popup_wnd);
527
528    evas_event_freeze(edp->popup_wnd->evas);
529    evas_object_del(edp->bg_object);
530    evas_object_del(edp->login_box);
531    evas_event_thaw(edp->popup_wnd->evas);
532
533    e_util_defer_object_del(E_OBJECT(edp->popup_wnd));
534    E_FREE(edp);
535 }
536
537 static Eina_Bool
538 _e_desklock_cb_window_stack(void *data __UNUSED__,
539                             int type,
540                             void *event)
541 {
542    Ecore_X_Window win, win2 = 0;
543    E_Desklock_Popup_Data *edp;
544    Eina_List *l;
545    Eina_Bool raise_win = EINA_TRUE;
546
547    if (!edd) return ECORE_CALLBACK_PASS_ON;
548
549    if (type == ECORE_X_EVENT_WINDOW_STACK)
550      win = ((Ecore_X_Event_Window_Stack *)event)->event_win;
551    else if (type == ECORE_X_EVENT_WINDOW_CONFIGURE)
552      {
553         win = ((Ecore_X_Event_Window_Configure *)event)->event_win;
554         win2 = ((Ecore_X_Event_Window_Configure *)event)->win;
555      }
556    else if (type == ECORE_X_EVENT_WINDOW_CREATE)
557      win = ((Ecore_X_Event_Window_Create *)event)->win;
558    else
559      return ECORE_CALLBACK_PASS_ON;
560
561    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
562      {
563         if ((win == edp->popup_wnd->evas_win) ||
564             ((win2) && (win2 == edp->popup_wnd->evas_win)))
565           {
566              raise_win = EINA_FALSE;
567              break;
568           }
569      }
570
571    if (raise_win)
572      {
573         EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
574           ecore_evas_raise(edp->popup_wnd->ecore_evas);
575      }
576
577    return ECORE_CALLBACK_PASS_ON;
578 }
579
580 EAPI Eina_Bool
581 e_desklock_state_get(void)
582 {
583    return _e_desklock_state;
584 }
585
586 static Eina_List *
587 _e_desklock_popup_find(E_Zone *zone)
588 {
589    Eina_List *l;
590    E_Desklock_Popup_Data *edp;
591
592    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
593      if (edp->popup_wnd->zone == zone) return l;
594    return NULL;
595 }
596
597 static Eina_Bool
598 _e_desklock_cb_zone_add(void *data __UNUSED__,
599                         int type __UNUSED__,
600                         void *event)
601 {
602    E_Event_Zone_Add *ev = event;
603    if (!edd) return ECORE_CALLBACK_PASS_ON;
604    if ((!edd->move_handler) && (e_config->desklock_login_box_zone == -2))
605      edd->move_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _e_desklock_cb_mouse_move, NULL);
606    if (!_e_desklock_popup_find(ev->zone)) _e_desklock_popup_add(ev->zone);
607    return ECORE_CALLBACK_PASS_ON;
608 }
609
610 static Eina_Bool
611 _e_desklock_cb_zone_del(void *data __UNUSED__,
612                         int type __UNUSED__,
613                         void *event)
614 {
615    E_Event_Zone_Del *ev = event;
616    Eina_List *l;
617    if (!edd) return ECORE_CALLBACK_PASS_ON;
618    if ((eina_list_count(e_container_current_get(e_manager_current_get())->zones) == 1) && (e_config->desklock_login_box_zone == -2))
619      edd->move_handler = ecore_event_handler_del(edd->move_handler);
620         
621    l = _e_desklock_popup_find(ev->zone);
622    if (l)
623      {
624         _e_desklock_popup_free(l->data);
625         edd->elock_wnd_list = eina_list_remove_list(edd->elock_wnd_list, l);
626      }
627    return ECORE_CALLBACK_PASS_ON;
628 }
629
630 static Eina_Bool
631 _e_desklock_cb_zone_move_resize(void *data __UNUSED__,
632                                 int type __UNUSED__,
633                                 void *event)
634 {
635    E_Desklock_Popup_Data *edp;
636    Eina_List *l;
637    E_Event_Zone_Move_Resize *ev = event;
638
639    if (!edd) return ECORE_CALLBACK_PASS_ON;
640    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
641      if (edp->popup_wnd->zone == ev->zone)
642        {
643           e_popup_move_resize(edp->popup_wnd, 0, 0, ev->zone->w, ev->zone->h);
644           evas_object_resize(edp->bg_object, ev->zone->w, ev->zone->h);
645           break;
646        }
647    return ECORE_CALLBACK_PASS_ON;
648 }
649
650 static Eina_Bool
651 _e_desklock_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
652 {
653    Ecore_Event_Key *ev = event;
654
655    if ((ev->window != edd->elock_wnd) ||
656        (edd->state == E_DESKLOCK_STATE_CHECKING)) return 1;
657
658    if (!strcmp(ev->key, "Escape"))
659      {
660         if (edd->selected)
661           {
662              _e_desklock_unselect();
663              return ECORE_CALLBACK_RENEW;
664           }
665      }
666    else if (!strcmp(ev->key, "KP_Enter"))
667      _e_desklock_check_auth();
668    else if (!strcmp(ev->key, "Return"))
669      _e_desklock_check_auth();
670    else if (!strcmp(ev->key, "BackSpace"))
671      {
672         if (edd->selected)
673           {
674              _e_desklock_null();
675              _e_desklock_unselect();
676              return ECORE_CALLBACK_RENEW;
677           }
678         _e_desklock_backspace();
679      }
680    else if (!strcmp(ev->key, "Delete"))
681      {
682         if (edd->selected)
683           {
684              _e_desklock_null();
685              _e_desklock_unselect();
686              return ECORE_CALLBACK_RENEW;
687           }
688         _e_desklock_delete();
689      }
690    else if ((!strcmp(ev->key, "u") &&
691              (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)))
692      _e_desklock_null();
693    else if ((!strcmp(ev->key, "a") &&
694              (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)))
695      _e_desklock_select();
696    else
697      {
698         /* here we have to grab a password */
699         if (ev->compose)
700           {
701              if (edd->selected)
702                {
703                   _e_desklock_null();
704                   _e_desklock_unselect();
705                }
706              if ((strlen(edd->passwd) < (PASSWD_LEN - strlen(ev->compose))))
707                {
708                   strcat(edd->passwd, ev->compose);
709                   _e_desklock_passwd_update();
710                }
711           }
712      }
713
714    return ECORE_CALLBACK_PASS_ON;
715 }
716
717 static Eina_Bool
718 _e_desklock_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__)
719 {
720    E_Desklock_Popup_Data *edp;
721    E_Zone *current_zone;
722    Eina_List *l;
723
724    current_zone = e_zone_current_get(e_container_current_get(e_manager_current_get()));
725
726    if (current_zone == last_active_zone)
727      return ECORE_CALLBACK_PASS_ON;
728
729    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
730      {
731         if (!edp) continue;
732
733         if (edp->popup_wnd->zone != current_zone)
734           {
735              if (edp->login_box) evas_object_hide(edp->login_box);
736              continue;
737           }
738         if (edp->login_box)
739           evas_object_show(edp->login_box);
740         else
741           _e_desklock_login_box_add(edp);
742      }
743    _e_desklock_passwd_update();
744    last_active_zone = current_zone;
745    return ECORE_CALLBACK_PASS_ON;
746 }
747
748 static void
749 _e_desklock_passwd_update(void)
750 {
751    int len, i;
752    char passwd_hidden[PASSWD_LEN] = "", *pp;
753    E_Desklock_Popup_Data *edp;
754    Eina_List *l;
755
756    if (!edd) return;
757
758    len = eina_unicode_utf8_get_len(edd->passwd);
759    for (i = 0, pp = passwd_hidden; i < len; i++, pp++)
760      *pp = '*';
761    *pp = 0;
762
763    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
764      if (edp->login_box) edje_object_part_text_set(edp->login_box, "e.text.password",
765                                passwd_hidden);
766 }
767
768 static void
769 _e_desklock_select(void)
770 {
771    E_Desklock_Popup_Data *edp;
772    Eina_List *l;
773    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
774      if (edp->login_box)
775        edje_object_signal_emit(edp->login_box, "e,state,selected", "e");
776    edd->selected = EINA_TRUE;
777 }
778
779 static void
780 _e_desklock_unselect(void)
781 {
782    E_Desklock_Popup_Data *edp;
783    Eina_List *l;
784    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
785      if (edp->login_box)
786        edje_object_signal_emit(edp->login_box, "e,state,unselected", "e");
787    edd->selected = EINA_FALSE;
788 }
789
790 static void
791 _e_desklock_null(void)
792 {
793    memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
794    _e_desklock_passwd_update();
795 }
796
797 static void
798 _e_desklock_backspace(void)
799 {
800    int len, val, pos;
801
802    if (!edd) return;
803
804    len = strlen(edd->passwd);
805    if (len > 0)
806      {
807         pos = evas_string_char_prev_get(edd->passwd, len, &val);
808         if ((pos < len) && (pos >= 0))
809           {
810              edd->passwd[pos] = 0;
811              _e_desklock_passwd_update();
812           }
813      }
814 }
815
816 static void
817 _e_desklock_delete(void)
818 {
819    _e_desklock_backspace();
820 }
821
822 static int
823 _e_desklock_zone_num_get(void)
824 {
825    int num;
826    Eina_List *l, *l2;
827    E_Manager *man;
828
829    num = 0;
830    EINA_LIST_FOREACH(e_manager_list(), l, man)
831      {
832         E_Container *con;
833         EINA_LIST_FOREACH(man->containers, l2, con)
834           num += eina_list_count(con->zones);
835      }
836
837    return num;
838 }
839
840 static int
841 _e_desklock_check_auth(void)
842 {
843    if (!edd) return 0;
844 #ifdef HAVE_PAM
845    if (e_config->desklock_auth_method == 0)
846      {
847         int ret;
848         
849         ret = _desklock_auth(edd->passwd);
850         // passwd off in child proc now - null out from parent
851         memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
852         return ret;
853      }
854    else if (e_config->desklock_auth_method == 1)
855      {
856 #endif
857         if ((e_config->desklock_personal_passwd) &&
858             (!strcmp(!edd->passwd ? "" : edd->passwd,
859                      !e_config->desklock_personal_passwd ? "" :
860                      e_config->desklock_personal_passwd)))
861           {
862              /* password ok */
863              /* security - null out passwd string once we are done with it */
864              memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
865              e_desklock_hide();
866              return 1;
867           }
868 #ifdef HAVE_PAM
869      }
870    
871 #endif
872    /* password is definitely wrong */
873    _e_desklock_state_set(E_DESKLOCK_STATE_INVALID);
874    _e_desklock_null();
875    return 0;
876 }
877
878 static void
879 _e_desklock_state_set(int state)
880 {
881    Eina_List *l;
882    E_Desklock_Popup_Data *edp;
883    const char *signal_desklock, *text;
884    if (!edd) return;
885
886    edd->state = state;
887    if (state == E_DESKLOCK_STATE_CHECKING)
888      {
889         signal_desklock = "e,state,checking";
890         text = "Authenticating...";
891      }
892    else if (state == E_DESKLOCK_STATE_INVALID)
893      {
894         signal_desklock = "e,state,invalid";
895         text = "The password you entered is invalid. Try again.";
896      }
897    else
898      return;
899
900    EINA_LIST_FOREACH(edd->elock_wnd_list, l, edp)
901      {
902         edje_object_signal_emit(edp->login_box, signal_desklock, "e.desklock");
903         edje_object_signal_emit(edp->bg_object, signal_desklock, "e.desklock");
904         edje_object_part_text_set(edp->login_box, "e.text.title", text);
905      }
906 }
907
908 #ifdef HAVE_PAM
909 static Eina_Bool
910 _e_desklock_cb_exit(void *data __UNUSED__, int type __UNUSED__, void *event)
911 {
912    Ecore_Exe_Event_Del *ev = event;
913
914    if (ev->pid == _e_desklock_child_pid)
915      {
916         _e_desklock_child_pid = -1;
917         /* ok */
918         if (ev->exit_code == 0)
919           {
920              /* security - null out passwd string once we are done with it */
921              memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
922              e_desklock_hide();
923           }
924         /* error */
925         else if (ev->exit_code < 128)
926           {
927              /* security - null out passwd string once we are done with it */
928              memset(edd->passwd, 0, sizeof(char) * PASSWD_LEN);
929              e_desklock_hide();
930              e_util_dialog_show(_("Authentication System Error"),
931                                 _("Authentication via PAM had errors setting up the<br>"
932                                   "authentication session. The error code was <hilight>%i</hilight>.<br>"
933                                   "This is bad and should not be happening. Please report this bug.")
934                                 , ev->exit_code);
935           }
936         /* failed auth */
937         else
938           {
939              _e_desklock_state_set(E_DESKLOCK_STATE_INVALID);
940              /* security - null out passwd string once we are done with it */
941              _e_desklock_null();
942           }
943         if (_e_desklock_exit_handler)
944           ecore_event_handler_del(_e_desklock_exit_handler);
945         _e_desklock_exit_handler = NULL;
946      }
947    return ECORE_CALLBACK_PASS_ON;
948 }
949
950 static int
951 _desklock_auth(char *passwd)
952 {
953    _e_desklock_state_set(E_DESKLOCK_STATE_CHECKING);
954    _e_desklock_child_pid = fork();
955    if (_e_desklock_child_pid > 0)
956      {
957         /* parent */
958         _e_desklock_exit_handler =
959           ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _e_desklock_cb_exit,
960                                   NULL);
961      }
962    else if (_e_desklock_child_pid == 0)
963      {
964         /* child */
965         int pamerr;
966         E_Desklock_Auth da;
967         char *current_user, *p;
968         struct sigaction action;
969
970         action.sa_handler = SIG_DFL;
971         action.sa_flags = SA_ONSTACK | SA_NODEFER | SA_RESETHAND | SA_SIGINFO;
972         sigemptyset(&action.sa_mask);
973         sigaction(SIGSEGV, &action, NULL);
974         sigaction(SIGILL, &action, NULL);
975         sigaction(SIGFPE, &action, NULL);
976         sigaction(SIGBUS, &action, NULL);
977         sigaction(SIGABRT, &action, NULL);
978
979         current_user = _desklock_auth_get_current_user();
980         eina_strlcpy(da.user, current_user, sizeof(da.user));
981         eina_strlcpy(da.passwd, passwd, sizeof(da.passwd));
982         /* security - null out passwd string once we are done with it */
983         for (p = passwd; *p; p++)
984           *p = 0;
985         da.pam.handle = NULL;
986         da.pam.conv.conv = NULL;
987         da.pam.conv.appdata_ptr = NULL;
988
989         pamerr = _desklock_pam_init(&da);
990         if (pamerr != PAM_SUCCESS)
991           {
992              free(current_user);
993              exit(1);
994           }
995         pamerr = pam_authenticate(da.pam.handle, 0);
996         pam_end(da.pam.handle, pamerr);
997         /* security - null out passwd string once we are done with it */
998         memset(da.passwd, 0, sizeof(da.passwd));
999         if (pamerr == PAM_SUCCESS)
1000           {
1001              free(current_user);
1002              exit(0);
1003           }
1004         free(current_user);
1005         exit(-1);
1006      }
1007    else
1008      {
1009         _e_desklock_state_set(E_DESKLOCK_STATE_INVALID);
1010         return 0;
1011      }
1012    return 1;
1013 }
1014
1015 static char *
1016 _desklock_auth_get_current_user(void)
1017 {
1018    char *user;
1019    struct passwd *pwent = NULL;
1020
1021    pwent = getpwuid(getuid());
1022    user = strdup(pwent->pw_name);
1023    return user;
1024 }
1025
1026 static int
1027 _desklock_pam_init(E_Desklock_Auth *da)
1028 {
1029    int pamerr;
1030    const char *pam_prof;
1031    char *current_host;
1032    char *current_user;
1033
1034    if (!da) return -1;
1035
1036    da->pam.conv.conv = _desklock_auth_pam_conv;
1037    da->pam.conv.appdata_ptr = da;
1038    da->pam.handle = NULL;
1039
1040    /* try other pam profiles - and system-auth (login for fbsd users) is a fallback */
1041    pam_prof = "login";
1042    if (ecore_file_exists("/etc/pam.d/enlightenment"))
1043      pam_prof = "enlightenment";
1044    else if (ecore_file_exists("/etc/pam.d/xscreensaver"))
1045      pam_prof = "xscreensaver";
1046    else if (ecore_file_exists("/etc/pam.d/kscreensaver"))
1047      pam_prof = "kscreensaver";
1048    else if (ecore_file_exists("/etc/pam.d/system-auth"))
1049      pam_prof = "system-auth";
1050    else if (ecore_file_exists("/etc/pam.d/system"))
1051      pam_prof = "system";
1052    else if (ecore_file_exists("/etc/pam.d/xdm"))
1053      pam_prof = "xdm";
1054    else if (ecore_file_exists("/etc/pam.d/gdm"))
1055      pam_prof = "gdm";
1056    else if (ecore_file_exists("/etc/pam.d/kdm"))
1057      pam_prof = "kdm";
1058
1059    if ((pamerr = pam_start(pam_prof, da->user, &(da->pam.conv),
1060                            &(da->pam.handle))) != PAM_SUCCESS)
1061      return pamerr;
1062
1063    current_user = _desklock_auth_get_current_user();
1064
1065    if ((pamerr = pam_set_item(da->pam.handle, PAM_USER, current_user)) != PAM_SUCCESS)
1066      {
1067         free(current_user);
1068         return pamerr;
1069      }
1070
1071    current_host = _desklock_auth_get_current_host();
1072    if ((pamerr = pam_set_item(da->pam.handle, PAM_RHOST, current_host)) != PAM_SUCCESS)
1073      {
1074         free(current_user);
1075         free(current_host);
1076         return pamerr;
1077      }
1078
1079    free(current_user);
1080    free(current_host);
1081    return 0;
1082 }
1083
1084 static int
1085 _desklock_auth_pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
1086 {
1087    int replies = 0;
1088    E_Desklock_Auth *da = (E_Desklock_Auth *)appdata_ptr;
1089    struct pam_response *reply = NULL;
1090
1091    reply = (struct pam_response *)malloc(sizeof(struct pam_response) * num_msg);
1092
1093    if (!reply) return PAM_CONV_ERR;
1094
1095    for (replies = 0; replies < num_msg; replies++)
1096      {
1097         switch (msg[replies]->msg_style)
1098           {
1099            case PAM_PROMPT_ECHO_ON:
1100              reply[replies].resp_retcode = PAM_SUCCESS;
1101              reply[replies].resp = strdup(da->user);
1102              break;
1103
1104            case PAM_PROMPT_ECHO_OFF:
1105              reply[replies].resp_retcode = PAM_SUCCESS;
1106              reply[replies].resp = strdup(da->passwd);
1107              break;
1108
1109            case PAM_ERROR_MSG:
1110            case PAM_TEXT_INFO:
1111              reply[replies].resp_retcode = PAM_SUCCESS;
1112              reply[replies].resp = NULL;
1113              break;
1114
1115            default:
1116              free(reply);
1117              return PAM_CONV_ERR;
1118           }
1119      }
1120    *resp = reply;
1121    return PAM_SUCCESS;
1122 }
1123
1124 static char *
1125 _desklock_auth_get_current_host(void)
1126 {
1127    return strdup("localhost");
1128 }
1129
1130 #endif
1131
1132 static Eina_Bool
1133 _e_desklock_cb_custom_desklock_exit(void *data __UNUSED__, int type __UNUSED__, void *event)
1134 {
1135    Ecore_Exe_Event_Del *ev = event;
1136
1137    if (ev->exe != _e_custom_desklock_exe) return ECORE_CALLBACK_PASS_ON;
1138
1139    if (ev->exit_code != 0)
1140      {
1141         /* do something profound here... like notify someone */
1142      }
1143
1144    e_desklock_hide();
1145
1146    return ECORE_CALLBACK_DONE;
1147 }
1148
1149 static Eina_Bool
1150 _e_desklock_cb_idle_poller(void *data __UNUSED__)
1151 {
1152    if ((e_config->desklock_autolock_idle) && (!e_config->mode.presentation) &&
1153        (!e_util_fullscreen_curreny_any()))
1154      {
1155         double idle, max;
1156
1157         /* If a desklock is already up, bail */
1158         if ((_e_custom_desklock_exe) || (edd)) return ECORE_CALLBACK_RENEW;
1159
1160         idle = ecore_x_screensaver_idle_time_get();
1161         max = e_config->desklock_autolock_idle_timeout;
1162         if (_e_desklock_ask_presentation_count > 0)
1163           max *= (1 + _e_desklock_ask_presentation_count);
1164
1165         /* If we have exceeded our idle time... */
1166         if (idle >= max)
1167           {
1168              /*
1169               * Unfortunately, not all "desklocks" stay up for as long as
1170               * the user is idle or until it is unlocked.
1171               *
1172               * 'xscreensaver-command -lock' for example sends a command
1173               * to xscreensaver and then terminates.  So, we have another
1174               * check (_e_desklock_user_idle) which lets us know that we
1175               * have locked the screen due to idleness.
1176               */
1177              if (!_e_desklock_user_idle)
1178                {
1179                   _e_desklock_user_idle = 1;
1180                   e_desklock_show_autolocked();
1181                }
1182           }
1183         else
1184           _e_desklock_user_idle = 0;
1185      }
1186
1187    /* Make sure our poller persists. */
1188    return ECORE_CALLBACK_RENEW;
1189 }
1190
1191 static void
1192 _e_desklock_ask_presentation_del(void *data)
1193 {
1194    if (_e_desklock_ask_presentation_dia == data)
1195      _e_desklock_ask_presentation_dia = NULL;
1196 }
1197
1198 static void
1199 _e_desklock_ask_presentation_yes(void *data __UNUSED__, E_Dialog *dia)
1200 {
1201    e_config->mode.presentation = 1;
1202    e_config_mode_changed();
1203    e_config_save_queue();
1204    e_object_del(E_OBJECT(dia));
1205    _e_desklock_ask_presentation_count = 0;
1206 }
1207
1208 static void
1209 _e_desklock_ask_presentation_no(void *data __UNUSED__, E_Dialog *dia)
1210 {
1211    e_object_del(E_OBJECT(dia));
1212    _e_desklock_ask_presentation_count = 0;
1213 }
1214
1215 static void
1216 _e_desklock_ask_presentation_no_increase(void *data __UNUSED__, E_Dialog *dia)
1217 {
1218    int timeout, interval, blanking, expose;
1219
1220    _e_desklock_ask_presentation_count++;
1221    timeout = e_config->screensaver_timeout * _e_desklock_ask_presentation_count;
1222    interval = e_config->screensaver_interval;
1223    blanking = e_config->screensaver_blanking;
1224    expose = e_config->screensaver_expose;
1225
1226    ecore_x_screensaver_set(timeout, interval, blanking, expose);
1227    e_object_del(E_OBJECT(dia));
1228 }
1229
1230 static void
1231 _e_desklock_ask_presentation_no_forever(void *data __UNUSED__, E_Dialog *dia)
1232 {
1233    e_config->desklock_ask_presentation = 0;
1234    e_config_save_queue();
1235    e_object_del(E_OBJECT(dia));
1236    _e_desklock_ask_presentation_count = 0;
1237 }
1238
1239 static void
1240 _e_desklock_ask_presentation_key_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event)
1241 {
1242    Evas_Event_Key_Down *ev = event;
1243    E_Dialog *dia = data;
1244
1245    if (strcmp(ev->keyname, "Return") == 0)
1246      _e_desklock_ask_presentation_yes(NULL, dia);
1247    else if (strcmp(ev->keyname, "Escape") == 0)
1248      _e_desklock_ask_presentation_no(NULL, dia);
1249 }
1250
1251 static void
1252 _e_desklock_ask_presentation_mode(void)
1253 {
1254    E_Manager *man;
1255    E_Container *con;
1256    E_Dialog *dia;
1257
1258    if (_e_desklock_ask_presentation_dia) return;
1259
1260    if (!(man = e_manager_current_get())) return;
1261    if (!(con = e_container_current_get(man))) return;
1262    if (!(dia = e_dialog_new(con, "E", "_desklock_ask_presentation"))) return;
1263
1264    e_dialog_title_set(dia, _("Activate Presentation Mode?"));
1265    e_dialog_icon_set(dia, "dialog-ask", 64);
1266    e_dialog_text_set(dia,
1267                      _("You unlocked desktop too fast.<br><br>"
1268                        "Would you like to enable <b>presentation</b> mode and "
1269                        "temporarily disable screen saver, lock and power saving?"));
1270
1271    e_object_del_attach_func_set(E_OBJECT(dia),
1272                                 _e_desklock_ask_presentation_del);
1273    e_dialog_button_add(dia, _("Yes"), NULL,
1274                        _e_desklock_ask_presentation_yes, NULL);
1275    e_dialog_button_add(dia, _("No"), NULL,
1276                        _e_desklock_ask_presentation_no, NULL);
1277    e_dialog_button_add(dia, _("No, but increase timeout"), NULL,
1278                        _e_desklock_ask_presentation_no_increase, NULL);
1279    e_dialog_button_add(dia, _("No, and stop asking"), NULL,
1280                        _e_desklock_ask_presentation_no_forever, NULL);
1281
1282    e_dialog_button_focus_num(dia, 0);
1283    e_widget_list_homogeneous_set(dia->box_object, 0);
1284    e_win_centered_set(dia->win, 1);
1285    e_dialog_show(dia);
1286
1287    evas_object_event_callback_add(dia->bg_object, EVAS_CALLBACK_KEY_DOWN,
1288                                   _e_desklock_ask_presentation_key_down, dia);
1289
1290    _e_desklock_ask_presentation_dia = dia;
1291 }
1292
1293 static Eina_Bool
1294 _e_desklock_run(E_Desklock_Run *task)
1295 {
1296    Efreet_Desktop *desktop;
1297
1298    desktop = eina_list_nth(task->desk_run->desktops, task->position++);
1299    if (!desktop)
1300      {
1301         e_object_del(E_OBJECT(task->desk_run));
1302         free(task);
1303         return EINA_FALSE;
1304      }
1305
1306    e_exec(NULL, desktop, NULL, NULL, NULL);
1307    return EINA_TRUE;
1308 }
1309
1310 static void
1311 _e_desklock_job(void *data __UNUSED__)
1312 {
1313    E_Desklock_Run *task;
1314
1315    job = NULL;
1316    if (!tasks) return ;
1317
1318    task = eina_list_data_get(tasks);
1319    if (!_e_desklock_run(task))
1320      tasks = eina_list_remove_list(tasks, tasks);
1321
1322    if (tasks) job = ecore_job_add(_e_desklock_job, NULL);
1323 }
1324
1325 static Eina_Bool
1326 _e_desklock_cb_run(void *data __UNUSED__, int type __UNUSED__, void *event)
1327 {
1328    E_Desklock_Run *task;
1329    E_Event_Desklock *ev = event;
1330    E_Order *desk_run;
1331    char buf[PATH_MAX];
1332
1333    if (!ev->suspend) return ECORE_CALLBACK_PASS_ON;
1334
1335    if (ev->on)
1336      {
1337         e_user_dir_concat_static(buf, "applications/desk-lock/.order");
1338         if (!ecore_file_exists(buf))
1339           e_prefix_data_concat_static(buf, "applications/desk-lock/.order");
1340      }
1341    else
1342      {
1343         e_user_dir_concat_static(buf, "applications/desk-unlock/.order");
1344         if (!ecore_file_exists(buf))
1345           e_prefix_data_concat_static(buf, "applications/desk-unlock/.order");
1346      }
1347
1348    desk_run = e_order_new(buf);
1349    if (!desk_run) return ECORE_CALLBACK_PASS_ON;
1350
1351    task = calloc(1, sizeof (E_Desklock_Run));
1352    if (!task)
1353      {
1354         e_object_del(E_OBJECT(desk_run));
1355         return ECORE_CALLBACK_PASS_ON;
1356      }
1357
1358    task->desk_run = desk_run;
1359    tasks = eina_list_append(tasks, task);
1360
1361    if (!job) ecore_job_add(_e_desklock_job, NULL);
1362
1363    return ECORE_CALLBACK_PASS_ON;
1364 }
1365