http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / driver / lock.c
1 /* lock.c --- handling the password dialog for locking-mode.
2  * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 /* Athena locking code contributed by Jon A. Christopher <jac8782@tamu.edu> */
14 /* Copyright 1997, with the same permissions as above. */
15
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
19
20 #include <X11/Intrinsic.h>
21 #include <X11/Xos.h>            /* for time() */
22 #include <time.h>
23 #include <sys/time.h>
24 #include "xscreensaver.h"
25 #include "resources.h"
26
27 #ifndef NO_LOCKING              /* (mostly) whole file */
28
29 #ifdef HAVE_SYSLOG
30 # include <syslog.h>
31 #endif /* HAVE_SYSLOG */
32
33 #ifdef HAVE_XHPDISABLERESET
34 # include <X11/XHPlib.h>
35   static void hp_lock_reset (saver_info *si, Bool lock_p);
36 #endif /* HAVE_XHPDISABLERESET */
37
38 #ifdef HAVE_VT_LOCKSWITCH
39 # include <fcntl.h>
40 # include <sys/ioctl.h>
41 # include <sys/vt.h>
42   static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
43 #endif /* HAVE_VT_LOCKSWITCH */
44
45 #ifdef HAVE_XF86VMODE
46 # include <X11/extensions/xf86vmode.h>
47   static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
48 #endif /* HAVE_XF86VMODE */
49
50
51 #ifdef _VROOT_H_
52 ERROR!  You must not include vroot.h in this file.
53 #endif
54
55 #ifndef VMS
56 # include <pwd.h>
57 #else /* VMS */
58
59 extern char *getenv(const char *name);
60 extern int validate_user(char *name, char *password);
61
62 static Bool
63 vms_passwd_valid_p(char *pw, Bool verbose_p)
64 {
65   return (validate_user (getenv("USER"), typed_passwd) == 1);
66 }
67 # undef passwd_valid_p
68 # define passwd_valid_p vms_passwd_valid_p
69
70 #endif /* VMS */
71
72
73 #undef MAX
74 #define MAX(a,b) ((a)>(b)?(a):(b))
75
76 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
77
78 struct passwd_dialog_data {
79
80   saver_screen_info *prompt_screen;
81   int previous_mouse_x, previous_mouse_y;
82
83   enum passwd_state state;
84   char typed_passwd [80];
85   XtIntervalId timer;
86   int i_beam;
87
88   float ratio;
89   Position x, y;
90   Dimension width;
91   Dimension height;
92   Dimension border_width;
93
94   char *heading_label;
95   char *body_label;
96   char *user_label;
97   char *passwd_label;
98   char *date_label;
99   char *user_string;
100   char *passwd_string;
101
102   XFontStruct *heading_font;
103   XFontStruct *body_font;
104   XFontStruct *label_font;
105   XFontStruct *passwd_font;
106   XFontStruct *date_font;
107
108   Pixel foreground;
109   Pixel background;
110   Pixel passwd_foreground;
111   Pixel passwd_background;
112   Pixel thermo_foreground;
113   Pixel thermo_background;
114   Pixel shadow_top;
115   Pixel shadow_bottom;
116
117   Dimension logo_width;
118   Dimension logo_height;
119   Dimension thermo_width;
120   Dimension internal_border;
121   Dimension shadow_width;
122
123   Dimension passwd_field_x, passwd_field_y;
124   Dimension passwd_field_width, passwd_field_height;
125
126   Dimension thermo_field_x, thermo_field_y;
127   Dimension thermo_field_height;
128
129   Pixmap logo_pixmap;
130   int logo_npixels;
131   unsigned long *logo_pixels;
132
133   Pixmap save_under;
134 };
135
136 static void draw_passwd_window (saver_info *si);
137 static void update_passwd_window (saver_info *si, const char *printed_passwd,
138                                   float ratio);
139 static void destroy_passwd_window (saver_info *si);
140 static void undo_vp_motion (saver_info *si);
141
142
143 static void
144 make_passwd_window (saver_info *si)
145 {
146   struct passwd *p = getpwuid (getuid ());
147   XSetWindowAttributes attrs;
148   unsigned long attrmask = 0;
149   passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
150   Screen *screen;
151   Colormap cmap;
152   char *f;
153
154   pw->prompt_screen = &si->screens [mouse_screen (si)];
155   if (si->prefs.verbose_p)
156     fprintf (stderr, "%s: %d: creating password dialog.\n",
157              blurb(), pw->prompt_screen->number);
158
159   screen = pw->prompt_screen->screen;
160   cmap = DefaultColormapOfScreen (screen);
161
162   pw->ratio = 1.0;
163
164   pw->heading_label = get_string_resource ("passwd.heading.label",
165                                            "Dialog.Label.Label");
166   pw->body_label = get_string_resource ("passwd.body.label",
167                                         "Dialog.Label.Label");
168   pw->user_label = get_string_resource ("passwd.user.label",
169                                         "Dialog.Label.Label");
170   pw->passwd_label = get_string_resource ("passwd.passwd.label",
171                                           "Dialog.Label.Label");
172   pw->date_label = get_string_resource ("dateFormat", "DateFormat");
173
174   if (!pw->heading_label)
175     pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
176   if (!pw->body_label)
177     pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
178   if (!pw->user_label) pw->user_label = strdup("ERROR");
179   if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
180   if (!pw->date_label) pw->date_label = strdup("ERROR");
181
182   /* Put the version number in the label. */
183   {
184     char *s = (char *) malloc (strlen(pw->heading_label) + 20);
185     sprintf(s, pw->heading_label, si->version);
186     free (pw->heading_label);
187     pw->heading_label = s;
188   }
189
190   pw->user_string = (p && p->pw_name ? p->pw_name : "???");
191   pw->passwd_string = strdup("");
192
193   f = get_string_resource ("passwd.headingFont", "Dialog.Font");
194   pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
195   if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
196   if (f) free (f);
197
198   f = get_string_resource("passwd.bodyFont", "Dialog.Font");
199   pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
200   if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
201   if (f) free (f);
202
203   f = get_string_resource("passwd.labelFont", "Dialog.Font");
204   pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
205   if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
206   if (f) free (f);
207
208   f = get_string_resource("passwd.passwdFont", "Dialog.Font");
209   pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
210   if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
211   if (f) free (f);
212
213   f = get_string_resource("passwd.dateFont", "Dialog.Font");
214   pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
215   if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
216   if (f) free (f);
217
218   pw->foreground = get_pixel_resource ("passwd.foreground",
219                                        "Dialog.Foreground",
220                                        si->dpy, cmap);
221   pw->background = get_pixel_resource ("passwd.background",
222                                        "Dialog.Background",
223                                        si->dpy, cmap);
224
225   if (pw->foreground == pw->background)
226     {
227       /* Make sure the error messages show up. */
228       pw->foreground = BlackPixelOfScreen (screen);
229       pw->background = WhitePixelOfScreen (screen);
230     }
231
232   pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
233                                               "Dialog.Text.Foreground",
234                                               si->dpy, cmap);
235   pw->passwd_background = get_pixel_resource ("passwd.text.background",
236                                               "Dialog.Text.Background",
237                                               si->dpy, cmap);
238   pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
239                                               "Dialog.Thermometer.Foreground",
240                                               si->dpy, cmap);
241   pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
242                                               "Dialog.Thermometer.Background",
243                                               si->dpy, cmap);
244   pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
245                                        "Dialog.Foreground",
246                                        si->dpy, cmap);
247   pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
248                                           "Dialog.Background",
249                                           si->dpy, cmap);
250
251   pw->logo_width = get_integer_resource ("passwd.logo.width",
252                                          "Dialog.Logo.Width");
253   pw->logo_height = get_integer_resource ("passwd.logo.height",
254                                           "Dialog.Logo.Height");
255   pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
256                                            "Dialog.Thermometer.Width");
257   pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
258                                               "Dialog.InternalBorderWidth");
259   pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
260                                            "Dialog.ShadowThickness");
261
262   if (pw->logo_width == 0)  pw->logo_width = 150;
263   if (pw->logo_height == 0) pw->logo_height = 150;
264   if (pw->internal_border == 0) pw->internal_border = 15;
265   if (pw->shadow_width == 0) pw->shadow_width = 4;
266   if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
267
268   {
269     int direction, ascent, descent;
270     XCharStruct overall;
271
272     pw->width = 0;
273     pw->height = 0;
274
275     /* Measure the heading_label. */
276     XTextExtents (pw->heading_font,
277                   pw->heading_label, strlen(pw->heading_label),
278                   &direction, &ascent, &descent, &overall);
279     if (overall.width > pw->width) pw->width = overall.width;
280     pw->height += ascent + descent;
281
282     /* Measure the body_label. */
283     XTextExtents (pw->body_font,
284                   pw->body_label, strlen(pw->body_label),
285                   &direction, &ascent, &descent, &overall);
286     if (overall.width > pw->width) pw->width = overall.width;
287     pw->height += ascent + descent;
288
289     {
290       Dimension w2 = 0, w3 = 0;
291       Dimension h2 = 0, h3 = 0;
292       const char *passwd_string = "MMMMMMMMMMMM";
293
294       /* Measure the user_label. */
295       XTextExtents (pw->label_font,
296                     pw->user_label, strlen(pw->user_label),
297                     &direction, &ascent, &descent, &overall);
298       if (overall.width > w2)  w2 = overall.width;
299       h2 += ascent + descent;
300
301       /* Measure the passwd_label. */
302       XTextExtents (pw->label_font,
303                     pw->passwd_label, strlen(pw->passwd_label),
304                     &direction, &ascent, &descent, &overall);
305       if (overall.width > w2)  w2 = overall.width;
306       h2 += ascent + descent;
307
308       /* Measure the user_string. */
309       XTextExtents (pw->passwd_font,
310                     pw->user_string, strlen(pw->user_string),
311                     &direction, &ascent, &descent, &overall);
312       overall.width += (pw->shadow_width * 4);
313       ascent += (pw->shadow_width * 4);
314       if (overall.width > w3)  w3 = overall.width;
315       h3 += ascent + descent;
316
317       /* Measure the (maximally-sized, dummy) passwd_string. */
318       XTextExtents (pw->passwd_font,
319                     passwd_string, strlen(passwd_string),
320                     &direction, &ascent, &descent, &overall);
321       overall.width += (pw->shadow_width * 4);
322       ascent += (pw->shadow_width * 4);
323       if (overall.width > w3)  w3 = overall.width;
324       h3 += ascent + descent;
325
326       w2 = w2 + w3 + (pw->shadow_width * 2);
327       h2 = MAX (h2, h3);
328
329       if (w2 > pw->width)  pw->width  = w2;
330       pw->height += h2;
331     }
332
333     pw->width  += (pw->internal_border * 2);
334     pw->height += (pw->internal_border * 4);
335
336     pw->width += pw->thermo_width + (pw->shadow_width * 3);
337
338     if (pw->logo_height > pw->height)
339       pw->height = pw->logo_height;
340     else if (pw->height > pw->logo_height)
341       pw->logo_height = pw->height;
342
343     pw->logo_width = pw->logo_height;
344
345     pw->width += pw->logo_width;
346   }
347
348   attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
349   attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
350
351   /* We need to remember the mouse position and restore it afterward, or
352      sometimes (perhaps only with Xinerama?) the mouse gets warped to
353      inside the bounds of the lock dialog window.
354    */
355   {
356     Window pointer_root, pointer_child;
357     int root_x, root_y, win_x, win_y;
358     unsigned int mask;
359     pw->previous_mouse_x = 0;
360     pw->previous_mouse_y = 0;
361     if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
362                        &pointer_root, &pointer_child,
363                        &root_x, &root_y, &win_x, &win_y, &mask))
364       {
365         pw->previous_mouse_x = root_x;
366         pw->previous_mouse_y = root_y;
367         if (si->prefs.verbose_p)
368           fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
369                    blurb(), pw->prompt_screen->number,
370                    pw->previous_mouse_x, pw->previous_mouse_y);
371       }
372     else if (si->prefs.verbose_p)
373       fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
374                blurb(), pw->prompt_screen->number);
375   }
376
377   /* Figure out where on the desktop to place the window so that it will
378      actually be visible; this takes into account virtual viewports as
379      well as Xinerama. */
380   {
381     int x, y, w, h;
382     get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
383                          pw->previous_mouse_x, pw->previous_mouse_y,
384                          si->prefs.verbose_p);
385     if (si->prefs.debug_p) w /= 2;
386     pw->x = x + ((w + pw->width) / 2) - pw->width;
387     pw->y = y + ((h + pw->height) / 2) - pw->height;
388     if (pw->x < x) pw->x = x;
389     if (pw->y < y) pw->y = y;
390   }
391
392   pw->border_width = get_integer_resource ("passwd.borderWidth",
393                                            "Dialog.BorderWidth");
394
395   si->passwd_dialog =
396     XCreateWindow (si->dpy,
397                    RootWindowOfScreen(screen),
398                    pw->x, pw->y, pw->width, pw->height, pw->border_width,
399                    DefaultDepthOfScreen (screen), InputOutput,
400                    DefaultVisualOfScreen(screen),
401                    attrmask, &attrs);
402   XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
403
404   pw->logo_pixmap = xscreensaver_logo (si->dpy, si->passwd_dialog, cmap,
405                                        pw->background, 
406                                        &pw->logo_pixels, &pw->logo_npixels,
407                                        0, True);
408
409   /* Before mapping the window, save the bits that are underneath the
410      rectangle the window will occlude.  When we lower the window, we
411      restore these bits.  This works, because the running screenhack
412      has already been sent SIGSTOP, so we know nothing else is drawing
413      right now! */
414   {
415     XGCValues gcv;
416     GC gc;
417     pw->save_under = XCreatePixmap (si->dpy,
418                                     pw->prompt_screen->screensaver_window,
419                                     pw->width + (pw->border_width*2) + 1,
420                                     pw->height + (pw->border_width*2) + 1,
421                                     pw->prompt_screen->current_depth);
422     gcv.function = GXcopy;
423     gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
424     XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
425                pw->save_under, gc,
426                pw->x - pw->border_width, pw->y - pw->border_width,
427                pw->width + (pw->border_width*2) + 1,
428                pw->height + (pw->border_width*2) + 1,
429                0, 0);
430     XFreeGC (si->dpy, gc);
431   }
432
433   XMapRaised (si->dpy, si->passwd_dialog);
434   XSync (si->dpy, False);
435
436   move_mouse_grab (si, si->passwd_dialog,
437                    pw->prompt_screen->cursor,
438                    pw->prompt_screen->number);
439   undo_vp_motion (si);
440
441   si->pw_data = pw;
442
443   if (cmap)
444     XInstallColormap (si->dpy, cmap);
445   draw_passwd_window (si);
446   XSync (si->dpy, False);
447 }
448
449
450 static void
451 draw_passwd_window (saver_info *si)
452 {
453   passwd_dialog_data *pw = si->pw_data;
454   XGCValues gcv;
455   GC gc1, gc2;
456   int spacing, height;
457   int x1, x2, x3, y1, y2;
458   int sw;
459   int tb_height;
460
461   height = (pw->heading_font->ascent + pw->heading_font->descent +
462             pw->body_font->ascent + pw->body_font->descent +
463             (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
464                       (pw->passwd_font->ascent + pw->passwd_font->descent +
465                        (pw->shadow_width * 4)))) +
466             pw->date_font->ascent + pw->date_font->descent
467             );
468   spacing = ((pw->height - (2 * pw->shadow_width) -
469               pw->internal_border - height)) / 8;
470   if (spacing < 0) spacing = 0;
471
472   gcv.foreground = pw->foreground;
473   gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
474   gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
475   x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
476   x3 = pw->width - (pw->shadow_width * 2);
477   y1 = (pw->shadow_width * 2) + spacing + spacing;
478
479   /* top heading
480    */
481   XSetFont (si->dpy, gc1, pw->heading_font->fid);
482   sw = string_width (pw->heading_font, pw->heading_label);
483   x2 = (x1 + ((x3 - x1 - sw) / 2));
484   y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
485   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
486                pw->heading_label, strlen(pw->heading_label));
487
488   /* text below top heading
489    */
490   XSetFont (si->dpy, gc1, pw->body_font->fid);
491   y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
492   sw = string_width (pw->body_font, pw->body_label);
493   x2 = (x1 + ((x3 - x1 - sw) / 2));
494   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
495                pw->body_label, strlen(pw->body_label));
496
497
498   tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
499                (pw->shadow_width * 4));
500
501   /* the "User:" prompt
502    */
503   y1 += spacing;
504   y2 = y1;
505   XSetForeground (si->dpy, gc1, pw->foreground);
506   XSetFont (si->dpy, gc1, pw->label_font->fid);
507   y1 += (spacing + tb_height);
508   x2 = (x1 + pw->internal_border +
509         MAX(string_width (pw->label_font, pw->user_label),
510             string_width (pw->label_font, pw->passwd_label)));
511   XDrawString (si->dpy, si->passwd_dialog, gc1,
512                x2 - string_width (pw->label_font, pw->user_label),
513                y1,
514                pw->user_label, strlen(pw->user_label));
515
516   /* the "Password:" prompt
517    */
518   y1 += (spacing + tb_height);
519   XDrawString (si->dpy, si->passwd_dialog, gc1,
520                x2 - string_width (pw->label_font, pw->passwd_label),
521                y1,
522                pw->passwd_label, strlen(pw->passwd_label));
523
524
525   XSetForeground (si->dpy, gc2, pw->passwd_background);
526
527   /* the "user name" text field
528    */
529   y1 = y2;
530   XSetForeground (si->dpy, gc1, pw->passwd_foreground);
531   XSetFont (si->dpy, gc1, pw->passwd_font->fid);
532   y1 += (spacing + tb_height);
533   x2 += (pw->shadow_width * 4);
534
535   pw->passwd_field_width = x3 - x2 - pw->internal_border;
536   pw->passwd_field_height = (pw->passwd_font->ascent +
537                              pw->passwd_font->descent +
538                              pw->shadow_width);
539
540   XFillRectangle (si->dpy, si->passwd_dialog, gc2,
541                   x2 - pw->shadow_width,
542                   y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
543                   pw->passwd_field_width, pw->passwd_field_height);
544   XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
545                pw->user_string, strlen(pw->user_string));
546
547   /* the "password" text field
548    */
549   y1 += (spacing + tb_height);
550
551   pw->passwd_field_x = x2 - pw->shadow_width;
552   pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
553                              pw->passwd_font->descent);
554
555   /* The shadow around the text fields
556    */
557   y1 = y2;
558   y1 += (spacing + (pw->shadow_width * 3));
559   x1 = x2 - (pw->shadow_width * 2);
560   x2 = pw->passwd_field_width + (pw->shadow_width * 2);
561   y2 = pw->passwd_field_height + (pw->shadow_width * 2);
562
563   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
564                          x1, y1, x2, y2,
565                          pw->shadow_width,
566                          pw->shadow_bottom, pw->shadow_top);
567
568   y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
569          (pw->shadow_width * 4));
570   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
571                          x1, y1, x2, y2,
572                          pw->shadow_width,
573                          pw->shadow_bottom, pw->shadow_top);
574
575
576   /* The date, below the text fields
577    */
578   {
579     char buf[100];
580     time_t now = time ((time_t *) 0);
581     struct tm *tm = localtime (&now);
582     memset (buf, 0, sizeof(buf));
583     strftime (buf, sizeof(buf)-1, pw->date_label, tm);
584
585     XSetFont (si->dpy, gc1, pw->date_font->fid);
586     y1 += pw->shadow_width;
587     y1 += (spacing + tb_height);
588     y1 += spacing/2;
589     sw = string_width (pw->date_font, buf);
590     x2 = x1 + x2 - sw;
591     XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
592   }
593
594
595   /* The logo
596    */
597   x1 = pw->shadow_width * 6;
598   y1 = pw->shadow_width * 6;
599   x2 = pw->logo_width - (pw->shadow_width * 12);
600   y2 = pw->logo_height - (pw->shadow_width * 12);
601
602   if (pw->logo_pixmap)
603     {
604       Window root;
605       int x, y;
606       unsigned int w, h, bw, d;
607       XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
608       XSetForeground (si->dpy, gc1, pw->foreground);
609       XSetBackground (si->dpy, gc1, pw->background);
610       if (d == 1)
611         XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
612                     0, 0, w, h,
613                     x1 + ((x2 - (int)w) / 2),
614                     y1 + ((y2 - (int)h) / 2),
615                     1);
616       else
617         XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
618                    0, 0, w, h,
619                    x1 + ((x2 - (int)w) / 2),
620                    y1 + ((y2 - (int)h) / 2));
621     }
622
623   /* The thermometer
624    */
625   XSetForeground (si->dpy, gc1, pw->thermo_foreground);
626   XSetForeground (si->dpy, gc2, pw->thermo_background);
627
628   pw->thermo_field_x = pw->logo_width + pw->shadow_width;
629   pw->thermo_field_y = pw->shadow_width * 5;
630   pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
631
632 #if 0
633   /* Solid border inside the logo box. */
634   XSetForeground (si->dpy, gc1, pw->foreground);
635   XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
636 #endif
637
638   /* The shadow around the logo
639    */
640   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
641                          pw->shadow_width * 4,
642                          pw->shadow_width * 4,
643                          pw->logo_width - (pw->shadow_width * 8),
644                          pw->logo_height - (pw->shadow_width * 8),
645                          pw->shadow_width,
646                          pw->shadow_bottom, pw->shadow_top);
647
648   /* The shadow around the thermometer
649    */
650   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
651                          pw->logo_width,
652                          pw->shadow_width * 4,
653                          pw->thermo_width + (pw->shadow_width * 2),
654                          pw->height - (pw->shadow_width * 8),
655                          pw->shadow_width,
656                          pw->shadow_bottom, pw->shadow_top);
657
658 #if 1
659   /* Solid border inside the thermometer. */
660   XSetForeground (si->dpy, gc1, pw->foreground);
661   XDrawRectangle (si->dpy, si->passwd_dialog, gc1, 
662                   pw->thermo_field_x, pw->thermo_field_y,
663                   pw->thermo_width - 1, pw->thermo_field_height - 1);
664 #endif
665
666   /* The shadow around the whole window
667    */
668   draw_shaded_rectangle (si->dpy, si->passwd_dialog,
669                          0, 0, pw->width, pw->height, pw->shadow_width,
670                          pw->shadow_top, pw->shadow_bottom);
671
672   XFreeGC (si->dpy, gc1);
673   XFreeGC (si->dpy, gc2);
674
675   update_passwd_window (si, pw->passwd_string, pw->ratio);
676 }
677
678
679 static void
680 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
681 {
682   passwd_dialog_data *pw = si->pw_data;
683   XGCValues gcv;
684   GC gc1, gc2;
685   int x, y;
686   XRectangle rects[1];
687
688   pw->ratio = ratio;
689   gcv.foreground = pw->passwd_foreground;
690   gcv.font = pw->passwd_font->fid;
691   gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
692   gcv.foreground = pw->passwd_background;
693   gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
694
695   if (printed_passwd)
696     {
697       char *s = strdup (printed_passwd);
698       if (pw->passwd_string) free (pw->passwd_string);
699       pw->passwd_string = s;
700     }
701
702   /* the "password" text field
703    */
704   rects[0].x =  pw->passwd_field_x;
705   rects[0].y =  pw->passwd_field_y;
706   rects[0].width = pw->passwd_field_width;
707   rects[0].height = pw->passwd_field_height;
708
709   XFillRectangle (si->dpy, si->passwd_dialog, gc2,
710                   rects[0].x, rects[0].y, rects[0].width, rects[0].height);
711
712   XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
713
714   XDrawString (si->dpy, si->passwd_dialog, gc1,
715                rects[0].x + pw->shadow_width,
716                rects[0].y + (pw->passwd_font->ascent +
717                              pw->passwd_font->descent),
718                pw->passwd_string, strlen(pw->passwd_string));
719
720   XSetClipMask (si->dpy, gc1, None);
721
722   /* The I-beam
723    */
724   if (pw->i_beam != 0)
725     {
726       x = (rects[0].x + pw->shadow_width +
727            string_width (pw->passwd_font, pw->passwd_string));
728       y = rects[0].y + pw->shadow_width;
729
730       if (x > rects[0].x + rects[0].width - 1)
731         x = rects[0].x + rects[0].width - 1;
732       XDrawLine (si->dpy, si->passwd_dialog, gc1, 
733                  x, y, x, y + pw->passwd_font->ascent);
734     }
735
736   pw->i_beam = (pw->i_beam + 1) % 4;
737
738
739   /* the thermometer
740    */
741   y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
742   if (y > 0)
743     {
744       XFillRectangle (si->dpy, si->passwd_dialog, gc2,
745                       pw->thermo_field_x + 1,
746                       pw->thermo_field_y + 1,
747                       pw->thermo_width-2,
748                       y);
749       XSetForeground (si->dpy, gc1, pw->thermo_foreground);
750       XFillRectangle (si->dpy, si->passwd_dialog, gc1,
751                       pw->thermo_field_x + 1,
752                       pw->thermo_field_y + 1 + y,
753                       pw->thermo_width-2,
754                       MAX (0, pw->thermo_field_height - y - 2));
755     }
756
757   XFreeGC (si->dpy, gc1);
758   XFreeGC (si->dpy, gc2);
759   XSync (si->dpy, False);
760 }
761
762
763 static void
764 destroy_passwd_window (saver_info *si)
765 {
766   saver_preferences *p = &si->prefs;
767   passwd_dialog_data *pw = si->pw_data;
768   saver_screen_info *ssi = pw->prompt_screen;
769   Colormap cmap = DefaultColormapOfScreen (ssi->screen);
770   Pixel black = BlackPixelOfScreen (ssi->screen);
771   Pixel white = WhitePixelOfScreen (ssi->screen);
772   XEvent event;
773
774   if (pw->timer)
775     XtRemoveTimeOut (pw->timer);
776
777   move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
778                    ssi->cursor, ssi->number);
779
780   if (p->verbose_p)
781     fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
782              blurb(), ssi->number,
783              pw->previous_mouse_x, pw->previous_mouse_y);
784
785   XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
786                 0, 0, 0, 0,
787                 pw->previous_mouse_x, pw->previous_mouse_y);
788
789   XSync (si->dpy, False);
790   while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
791     if (p->verbose_p)
792       fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
793
794   if (si->passwd_dialog)
795     {
796       XDestroyWindow (si->dpy, si->passwd_dialog);
797       si->passwd_dialog = 0;
798     }
799   
800   if (pw->save_under)
801     {
802       XGCValues gcv;
803       GC gc;
804       gcv.function = GXcopy;
805       gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
806       XCopyArea (si->dpy, pw->save_under,
807                  ssi->screensaver_window, gc,
808                  0, 0,
809                  pw->width + (pw->border_width*2) + 1,
810                  pw->height + (pw->border_width*2) + 1,
811                  pw->x - pw->border_width, pw->y - pw->border_width);
812       XFreePixmap (si->dpy, pw->save_under);
813       pw->save_under = 0;
814       XFreeGC (si->dpy, gc);
815     }
816
817   if (pw->heading_label) free (pw->heading_label);
818   if (pw->body_label)    free (pw->body_label);
819   if (pw->user_label)    free (pw->user_label);
820   if (pw->passwd_label)  free (pw->passwd_label);
821
822   if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
823   if (pw->body_font)    XFreeFont (si->dpy, pw->body_font);
824   if (pw->label_font)   XFreeFont (si->dpy, pw->label_font);
825   if (pw->passwd_font)  XFreeFont (si->dpy, pw->passwd_font);
826
827   if (pw->foreground != black && pw->foreground != white)
828     XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
829   if (pw->background != black && pw->background != white)
830     XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
831   if (pw->passwd_foreground != black && pw->passwd_foreground != white)
832     XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
833   if (pw->passwd_background != black && pw->passwd_background != white)
834     XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
835   if (pw->thermo_foreground != black && pw->thermo_foreground != white)
836     XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
837   if (pw->thermo_background != black && pw->thermo_background != white)
838     XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
839   if (pw->shadow_top != black && pw->shadow_top != white)
840     XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
841   if (pw->shadow_bottom != black && pw->shadow_bottom != white)
842     XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
843
844   if (pw->logo_pixmap)
845     XFreePixmap (si->dpy, pw->logo_pixmap);
846   if (pw->logo_npixels && pw->logo_pixels)
847     XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
848   if (pw->logo_pixels)
849     free (pw->logo_pixels);
850
851   memset (pw, 0, sizeof(*pw));
852   free (pw);
853
854   if (cmap)
855     XInstallColormap (si->dpy, cmap);
856
857   si->pw_data = 0;
858 }
859
860
861 #ifdef HAVE_XHPDISABLERESET
862 /* This function enables and disables the C-Sh-Reset hot-key, which
863    normally resets the X server (logging out the logged-in user.)
864    We don't want random people to be able to do that while the
865    screen is locked.
866  */
867 static void
868 hp_lock_reset (saver_info *si, Bool lock_p)
869 {
870   static Bool hp_locked_p = False;
871
872   /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
873      or BadAccess errors occur.  (It's ok for this to be global,
874      since it affects the whole machine, not just the current screen.)
875   */
876   if (hp_locked_p == lock_p)
877     return;
878
879   if (lock_p)
880     XHPDisableReset (si->dpy);
881   else
882     XHPEnableReset (si->dpy);
883   hp_locked_p = lock_p;
884 }
885 #endif /* HAVE_XHPDISABLERESET */
886
887
888 \f
889 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
890    which, on Linux systems, switches to another virtual console.
891    We'd like the whole screen/keyboard to be locked, not just one
892    virtual console, so this function disables that while the X
893    screen is locked.
894
895    Unfortunately, this doesn't work -- this ioctl only works when
896    called by root, and we have disavowed our privileges long ago.
897  */
898 #ifdef HAVE_VT_LOCKSWITCH
899 static void
900 linux_lock_vt_switch (saver_info *si, Bool lock_p)
901 {
902   saver_preferences *p = &si->prefs;
903   static Bool vt_locked_p = False;
904   const char *dev_console = "/dev/console";
905   int fd;
906
907   if (lock_p == vt_locked_p)
908     return;
909
910   if (lock_p && !p->lock_vt_p)
911     return;
912
913   fd = open (dev_console, O_RDWR);
914   if (fd < 0)
915     {
916       char buf [255];
917       sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
918                (lock_p ? "lock" : "unlock"),
919                dev_console);
920 #if 1 /* #### doesn't work yet, so don't bother complaining */
921       perror (buf);
922 #endif
923       return;
924     }
925
926   if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
927     {
928       vt_locked_p = lock_p;
929
930       if (p->verbose_p)
931         fprintf (stderr, "%s: %s VTs\n", blurb(),
932                  (lock_p ? "locked" : "unlocked"));
933     }
934   else
935     {
936       char buf [255];
937       sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
938                (lock_p ? "lock" : "unlock"));
939 #if 0 /* #### doesn't work yet, so don't bother complaining */
940       perror (buf);
941 #endif
942     }
943
944   close (fd);
945 }
946 #endif /* HAVE_VT_LOCKSWITCH */
947
948 \f
949 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
950    hot-keys, which normally change the resolution of the X server.
951    We don't want people to be able to switch the server resolution
952    while the screen is locked, because if they switch to a higher
953    resolution, it could cause part of the underlying desktop to become
954    exposed.
955  */
956 #ifdef HAVE_XF86VMODE
957
958 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
959 static Bool vp_got_error = False;
960
961 static void
962 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
963 {
964   static Bool any_mode_locked_p = False;
965   saver_preferences *p = &si->prefs;
966   int screen;
967   int event, error;
968   Bool status;
969   XErrorHandler old_handler;
970
971   if (any_mode_locked_p == lock_p)
972     return;
973   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
974     return;
975
976   for (screen = 0; screen < si->nscreens; screen++)
977     {
978       XSync (si->dpy, False);
979       old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
980       status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
981       XSync (si->dpy, False);
982       XSetErrorHandler (old_handler);
983       if (vp_got_error) status = False;
984
985       if (status)
986         any_mode_locked_p = lock_p;
987
988       if (!status && (p->verbose_p || !lock_p))
989         /* Only print this when verbose, or when we locked but can't unlock.
990            I tried printing this message whenever it comes up, but
991            mode-locking always fails if DontZoom is set in XF86Config. */
992         fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
993                  blurb(), screen, (lock_p ? "lock" : "unlock"));
994       else if (p->verbose_p)
995         fprintf (stderr, "%s: %d: %s mode switching.\n",
996                  blurb(), screen, (lock_p ? "locked" : "unlocked"));
997     }
998 }
999
1000 static int
1001 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1002 {
1003   vp_got_error = True;
1004   return 0;
1005 }
1006
1007 #endif /* HAVE_XF86VMODE */
1008
1009 \f
1010 /* If the viewport has been scrolled since the screen was blanked,
1011    then scroll it back to where it belongs.  This function only exists
1012    to patch over a very brief race condition.
1013  */
1014 static void
1015 undo_vp_motion (saver_info *si)
1016 {
1017 #ifdef HAVE_XF86VMODE
1018   saver_preferences *p = &si->prefs;
1019   int screen;
1020   int event, error;
1021
1022   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1023     return;
1024
1025   for (screen = 0; screen < si->nscreens; screen++)
1026     {
1027       saver_screen_info *ssi = &si->screens[screen];
1028       int x, y;
1029       Bool status;
1030
1031       if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1032         break;
1033       if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1034         return;
1035       if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1036         return;
1037     
1038       /* We're going to move the viewport.  The mouse has just been grabbed on
1039          (and constrained to, thus warped to) the password window, so it is no
1040          longer near the edge of the screen.  However, wait a bit anyway, just
1041          to make sure the server drains its last motion event, so that the
1042          screen doesn't continue to scroll after we've reset the viewport.
1043        */
1044       XSync (si->dpy, False);
1045       usleep (250000);  /* 1/4 second */
1046       XSync (si->dpy, False);
1047
1048       status = XF86VidModeSetViewPort (si->dpy, screen,
1049                                        ssi->blank_vp_x, ssi->blank_vp_y);
1050
1051       if (!status)
1052         fprintf (stderr,
1053                  "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1054                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1055       else if (p->verbose_p)
1056         fprintf (stderr,
1057                  "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1058                  blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1059     }
1060 #endif /* HAVE_XF86VMODE */
1061 }
1062
1063
1064 \f
1065 /* Interactions
1066  */
1067
1068 static void
1069 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1070 {
1071   saver_info *si = (saver_info *) closure;
1072   int tick = 166;
1073   passwd_dialog_data *pw = si->pw_data;
1074
1075   if (!pw) return;
1076
1077   pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1078   if (pw->ratio < 0)
1079     {
1080       pw->ratio = 0;
1081       if (pw->state == pw_read)
1082         pw->state = pw_time;
1083     }
1084
1085   update_passwd_window (si, 0, pw->ratio);
1086
1087   if (pw->state == pw_read)
1088     pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1089                                  (XtPointer) si);
1090   else
1091     pw->timer = 0;
1092
1093   idle_timer ((XtPointer) si, id);
1094 }
1095
1096
1097 static XComposeStatus *compose_status;
1098
1099 static void
1100 handle_passwd_key (saver_info *si, XKeyEvent *event)
1101 {
1102   saver_preferences *p = &si->prefs;
1103   passwd_dialog_data *pw = si->pw_data;
1104   int pw_size = sizeof (pw->typed_passwd) - 1;
1105   char *typed_passwd = pw->typed_passwd;
1106   char s[2];
1107   char *stars = 0;
1108   int i;
1109   int size = XLookupString (event, s, 1, 0, compose_status);
1110
1111   if (size != 1) return;
1112
1113   s[1] = 0;
1114
1115   switch (*s)
1116     {
1117     case '\010': case '\177':                           /* Backspace */
1118       if (!*typed_passwd)
1119         XBell (si->dpy, 0);
1120       else
1121         typed_passwd [strlen(typed_passwd)-1] = 0;
1122       break;
1123
1124     case '\025': case '\030':                           /* Erase line */
1125       memset (typed_passwd, 0, pw_size);
1126       break;
1127
1128     case '\012': case '\015':                           /* Enter */
1129       if (pw->state != pw_read)
1130         ;  /* already done? */
1131       else if (typed_passwd[0] == 0)
1132         pw->state = pw_null;
1133       else
1134         {
1135           update_passwd_window (si, "Checking...", pw->ratio);
1136           XSync (si->dpy, False);
1137           if (passwd_valid_p (typed_passwd, p->verbose_p))
1138             pw->state = pw_ok;
1139           else
1140             pw->state = pw_fail;
1141           update_passwd_window (si, "", pw->ratio);
1142         }
1143       break;
1144
1145     default:
1146       i = strlen (typed_passwd);
1147       if (i >= pw_size-1)
1148         XBell (si->dpy, 0);
1149       else
1150         {
1151           typed_passwd [i] = *s;
1152           typed_passwd [i+1] = 0;
1153         }
1154       break;
1155     }
1156
1157   i = strlen(typed_passwd);
1158   stars = (char *) malloc(i+1);
1159   memset (stars, '*', i);
1160   stars[i] = 0;
1161   update_passwd_window (si, stars, pw->ratio);
1162   free (stars);
1163 }
1164
1165
1166 static void
1167 passwd_event_loop (saver_info *si)
1168 {
1169   saver_preferences *p = &si->prefs;
1170   char *msg = 0;
1171   XEvent event;
1172   passwd_animate_timer ((XtPointer) si, 0);
1173
1174   while (si->pw_data && si->pw_data->state == pw_read)
1175     {
1176       XtAppNextEvent (si->app, &event);
1177       if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1178         draw_passwd_window (si);
1179       else if (event.xany.type == KeyPress)
1180         handle_passwd_key (si, &event.xkey);
1181       else
1182         XtDispatchEvent (&event);
1183     }
1184
1185   switch (si->pw_data->state)
1186     {
1187     case pw_ok:   msg = 0; break;
1188     case pw_null: msg = ""; break;
1189     case pw_time: msg = "Timed out!"; break;
1190     default:      msg = "Sorry!"; break;
1191     }
1192
1193   if (si->pw_data->state == pw_fail)
1194     si->unlock_failures++;
1195
1196   if (p->verbose_p)
1197     switch (si->pw_data->state)
1198       {
1199       case pw_ok:
1200         fprintf (stderr, "%s: password correct.\n", blurb()); break;
1201       case pw_fail:
1202         fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1203       case pw_null:
1204       case pw_cancel:
1205         fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1206       case pw_time:
1207         fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1208       default: break;
1209       }
1210
1211 #ifdef HAVE_SYSLOG
1212   if (si->pw_data->state == pw_fail)
1213     {
1214       /* If they typed a password (as opposed to just hitting return) and
1215          the password was invalid, log it.
1216       */
1217       struct passwd *pw = getpwuid (getuid ());
1218       char *d = DisplayString (si->dpy);
1219       char *u = (pw->pw_name ? pw->pw_name : "???");
1220       int opt = 0;
1221       int fac = 0;
1222
1223 # ifdef LOG_PID
1224       opt = LOG_PID;
1225 # endif
1226
1227 # if defined(LOG_AUTHPRIV)
1228       fac = LOG_AUTHPRIV;
1229 # elif defined(LOG_AUTH)
1230       fac = LOG_AUTH;
1231 # else
1232       fac = LOG_DAEMON;
1233 # endif
1234
1235       if (!d) d = "";
1236       openlog (progname, opt, fac);
1237       syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1238               si->unlock_failures, d, u);
1239       closelog ();
1240     }
1241 #endif /* HAVE_SYSLOG */
1242
1243   if (si->pw_data->state == pw_fail)
1244     XBell (si->dpy, False);
1245
1246   if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1247     {
1248       if (si->unlock_failures == 1)
1249         fprintf (real_stderr,
1250                  "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1251                  blurb());
1252       else
1253         fprintf (real_stderr,
1254                  "%s: WARNING: %d failed attempts to unlock the screen.\n",
1255                  blurb(), si->unlock_failures);
1256       fflush (real_stderr);
1257
1258       si->unlock_failures = 0;
1259     }
1260
1261   if (msg)
1262     {
1263       si->pw_data->i_beam = 0;
1264       update_passwd_window (si, msg, 0.0);
1265       XSync (si->dpy, False);
1266       sleep (1);
1267
1268       /* Swallow all pending KeyPress/KeyRelease events. */
1269       {
1270         XEvent e;
1271         while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1272           ;
1273       }
1274     }
1275 }
1276
1277
1278 static void
1279 handle_typeahead (saver_info *si)
1280 {
1281   passwd_dialog_data *pw = si->pw_data;
1282   int i;
1283   if (!si->unlock_typeahead)
1284     return;
1285
1286   i = strlen (si->unlock_typeahead);
1287   if (i >= sizeof(pw->typed_passwd) - 1)
1288     i = sizeof(pw->typed_passwd) - 1;
1289
1290   memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1291   pw->typed_passwd [i] = 0;
1292
1293   memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1294   si->unlock_typeahead[i] = 0;
1295   update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1296
1297   free (si->unlock_typeahead);
1298   si->unlock_typeahead = 0;
1299 }
1300
1301
1302 Bool
1303 unlock_p (saver_info *si)
1304 {
1305   saver_preferences *p = &si->prefs;
1306   Bool status;
1307
1308   raise_window (si, True, True, True);
1309
1310   if (p->verbose_p)
1311     fprintf (stderr, "%s: prompting for password.\n", blurb());
1312
1313   if (si->pw_data || si->passwd_dialog)
1314     destroy_passwd_window (si);
1315
1316   make_passwd_window (si);
1317
1318   compose_status = calloc (1, sizeof (*compose_status));
1319
1320   handle_typeahead (si);
1321   passwd_event_loop (si);
1322
1323   status = (si->pw_data->state == pw_ok);
1324   destroy_passwd_window (si);
1325
1326   free (compose_status);
1327   compose_status = 0;
1328
1329   return status;
1330 }
1331
1332
1333 void
1334 set_locked_p (saver_info *si, Bool locked_p)
1335 {
1336   si->locked_p = locked_p;
1337
1338 #ifdef HAVE_XHPDISABLERESET
1339   hp_lock_reset (si, locked_p);                 /* turn off/on C-Sh-Reset */
1340 #endif
1341 #ifdef HAVE_VT_LOCKSWITCH
1342   linux_lock_vt_switch (si, locked_p);          /* turn off/on C-Alt-F1 */
1343 #endif
1344 #ifdef HAVE_XF86VMODE
1345   xfree_lock_mode_switch (si, locked_p);        /* turn off/on C-Alt-Plus */
1346 #endif
1347
1348   store_saver_status (si);                      /* store locked-p */
1349 }
1350
1351
1352 #else  /*  NO_LOCKING -- whole file */
1353
1354 void
1355 set_locked_p (saver_info *si, Bool locked_p)
1356 {
1357   if (locked_p) abort();
1358 }
1359
1360 #endif /* !NO_LOCKING */