1 #if 0
2 static const char sccsid[] = "@(#)xlock.c	5.34 2011/05/23 xlockmore";
3 
4 #endif
5 
6 /*-
7  * xlock.c - X11 client to lock a display and show a screen saver.
8  *
9  * Copyright (c) 1988-1991 by Patrick J. Naughton
10  * Copyright (c) 1993-2011 by David A. Bagley
11  *
12  * xscreensaver code, Copyright (c) 1997 Jamie Zawinski <jwz AT jwz.org>
13  *
14  * Permission to use, copy, modify, and distribute this software and its
15  * documentation for any purpose and without fee is hereby granted,
16  * provided that the above copyright notice appear in all copies and that
17  * both that copyright notice and this permission notice appear in
18  * supporting documentation.
19  *
20  * This file is provided AS IS with no warranties of any kind.  The author
21  * shall have no liability with respect to the infringement of copyrights,
22  * trade secrets or any patents by this file or any part thereof.  In no
23  * event will the author be liable for any lost revenue or profits or
24  * other special, indirect and consequential damages.
25  *
26  * Revision History:
27  *
28  * Changes maintained by David Bagley <bagleyd AT verizon.net>
29  * 23-Feb-03: Timothy Reed <treed1@twcny.rr.com>
30  *            Added PAM_putText to converse with passwd.c PAM_conv function
31  *            to converse with any PAM.
32  * 09-Mar-01: showfps stuff corrected
33  * 01-Nov-00: Allocation checks
34  * 08-Apr-98: A way for users to unlock each others display.  Kind of defeats
35  *            the lock but the unlocked user is mailed and and entry is
36  *            written to syslogd.  Thanks to Mark Kirk <mkirk@pdi.com> for
37  *            his vizlock-1.0 patch.  Compile-time switch for this is
38  *            GLOBAL_UNLOCK.  This is probably full of security holes when
39  *            enabled... :)
40  * 01-Jul-98: Eric Lassauge <lassauge AT users.sourceforge.net> &
41  *              Remi Cohen-Scali <remi.cohenscali@pobox.com>
42  *            Added support for locking VT switching (-/+vtlock)
43  *            Added code is enclosed in USE_VTLOCK
44  * 01-May-97: Matthew Rench <mdrench@mtu.edu>
45  *            Added DPMS options.
46  * 02-Dec-97: Strong user authentication, utilizing the SafeWord API.
47  *            Author unknown.
48  * 01-May-97: Scott Carter <scarter@sdsc.edu>
49  *            Added code to stat .xlocktext, .plan, and .signature files
50  *            before reading the message;  only regular files are read (no
51  *            pipes or special files).
52  *            Added code to replace tabs with 8 spaces in the plantext buffer.
53  * 01-Sep-96: Ron Hitchens <ron AT idiom.com>
54  *            Updated xlock so it would refresh more reliably and
55  *            handle window resizing.
56  * 18-Mar-96: Ron Hitchens <ron AT idiom.com>
57  *            Implemented new ModeInfo hook calling scheme.
58  *            Created mode_info() to gather and pass info to hooks.
59  *            Watch for and use MI_PAUSE value if mode hook sets it.
60  *            Catch SIGSEGV, SIGBUS and SIGFPE signals.  Other should
61  *            be caught.  Eliminate some globals.
62  * 23-Dec-95: Ron Hitchens <ron AT idiom.com>
63  *            Rewrote event loop so as not to use signals.
64  * 01-Sep-95: initPasswd function, more stuff removed to passwd.c
65  * 24-Jun-95: Cut out passwd stuff to passwd.c-> getPasswd & checkPasswd
66  * 17-Jun-95: Added xlockrc password compile time option.
67  * 12-May-95: Added defines for SunOS's Adjunct password file from
68  *            Dale A. Harris <rodmur@ecst.csuchico.edu>
69  * 21-Feb-95: MANY patches from Heath A. Kehoe <hakehoe@icaen.uiowa.edu>.
70  * 24-Jan-95: time_displayed fixed from Chris Ross <cross@va.pubnix.com>.
71  * 18-Jan-95: Ultrix systems (at least DECstations) running enhanced
72  *            security from Chris Fuhrman <cfuhrman@vt.edu> and friend.
73  * 26-Oct-94: In order to use extra-long passwords with the Linux changed
74  *            PASSLENGTH to 64 <slouken@virtbrew.water.ca.gov>
75  * 11-Jul-94: added -inwindow option from Greg Bowering
76  *            <greg@cs.adelaide.edu.au>
77  * 22-Jun-94: Modified for VMS
78  *            <Anthony.D.Clarke@Support.Hatfield.Raytheon.bae.eurokom.ie>
79  * 10-Jun-94: patch for BSD from Victor Langeveld <vic@mbfys.kun.nl>
80  * 02-May-94: patched to work on Linux from Darren Senn's
81  *            <sinster@scintilla.capitola.ca.us> xlock for Linux.
82  *            Took out "bounce" since it was too buggy (maybe I will put
83  *            it back later).
84  * 21-Mar-94: patch to to trap Shift-Ctrl-Reset courtesy of Jamie Zawinski
85  *            <jwz AT jwz.org>, patched the patch (my mistake) for AIXV3
86  *            and HP from <R.K.Lloyd@csc.liv.ac.uk>.
87  * 01-Dec-93: added patch for AIXV3 from Tom McConnell
88  *            <tmcconne@sedona.intel.com> also added a patch for HP-UX 8.0.
89  * 29-Jul-93: "hyper", "helix", "rock", and "blot" (also tips on "maze") I
90  *            got courtesy of Jamie Zawinski <jwz AT jwz.org>;
91  *            at the time I could not get his stuff to work for the hpux 8.0,
92  *            so I scrapped it but threw his stuff in xlock.
93  *            "maze" and "sphere" I got courtesy of Sun Microsystems.
94  *            "spline" I got courtesy of Jef Poskanzer <jef@netcom.com or
95  *            jef@well.sf.ca.us>.
96  *
97  * Changes of Patrick J. Naughton
98  * 24-Jun-91: make foreground and background color get used on mono.
99  * 24-May-91: added -usefirst.
100  * 16-May-91: added pyro and random modes.
101  *	      ripped big comment block out of all other files.
102  * 08-Jan-91: fix some problems with password entry.
103  *	      removed renicing code.
104  * 29-Oct-90: added cast to XFree() arg.
105  *	      added volume arg to call to XBell().
106  * 28-Oct-90: center prompt screen.
107  *	      make sure Xlib input buffer does not use up all of swap.
108  *	      make displayed text come from resource file for better I18N.
109  *	      add backward compatible signal handlers for pre 4.1 machines.
110  * 31-Aug-90: added blank mode.
111  *	      added swarm mode.
112  *	      moved usleep() and seconds() out to usleep.c.
113  *	      added SVR4 defines to xlock.h
114  * 29-Jul-90: added support for multiple screens to be locked by one xlock.
115  *	      moved global defines to xlock.h
116  *	      removed use of allowsig().
117  * 07-Jul-90: reworked commandline args and resources to use Xrm.
118  *	      moved resource processing out to resource.c
119  * 02-Jul-90: reworked colors to not use dynamic colormap.
120  * 23-May-90: added autoraise when obscured.
121  * 15-Apr-90: added hostent alias searching for host authentication.
122  * 18-Feb-90: added SunOS3.5 fix.
123  *	      changed -mono -> -color, and -saver -> -lock.
124  *	      allow non-locking screensavers to display on remote machine.
125  *	      added -echokeys to disable echoing of '?'s on input.
126  *	      cleaned up all of the parameters and defaults.
127  * 20-Dec-89: added -xhost to allow access control list to be left alone.
128  *	      added -screensaver (do not disable screen saver) for the paranoid.
129  *	      Moved seconds() here from all of the display mode source files.
130  *	      Fixed bug with calling XUngrabHosts() in finish().
131  * 19-Dec-89: Fixed bug in GrabPointer.
132  *	      Changed fontname to XLFD style.
133  * 23-Sep-89: Added fix to allow local hostname:0 as a display.
134  *	      Put empty case for Enter/Leave events.
135  *	      Moved colormap installation later in startup.
136  * 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
137  *	      Replaced SunView code for life mode with Jim Graham's version,
138  *		so I could contrib it without legal problems.
139  *	      Sent to expo for X11R4 contrib.
140  * 19-Sep-89: Added '?'s on input.
141  * 27-Mar-89: Added -qix mode.
142  *	      Fixed GContext->GC.
143  * 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
144  *	      Changed default font to lucida-sans-24.
145  * 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
146  * 24-Feb-89: Replaced hopalong display with life display from SunView1.
147  * 22-Feb-89: Added fix for color servers with n < 8 planes.
148  * 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
149  *	      Added -count for number of iterations per color.
150  *	      Fixed defaulting mechanism.
151  *	      Ripped out VMS hacks.
152  *	      Sent to expo for X11R3 contrib.
153  * 15-Feb-89: Changed default font to pellucida-sans-18.
154  * 20-Jan-89: Added -verbose and fixed usage message.
155  * 19-Jan-89: Fixed monochrome gc bug.
156  * 16-Dec-88: Added SunView style password prompting.
157  * 19-Sep-88: Changed -color to -mono. (default is color on color displays).
158  *	      Added -saver option. (just do display... do not lock.)
159  * 31-Aug-88: Added -time option.
160  *	      Removed code for fractals to separate file for modularity.
161  *	      Added signal handler to restore host access.
162  *	      Installs dynamic colormap with a Hue Ramp.
163  *	      If grabs fail then exit.
164  *	      Added VMS Hacks. (password 'iwiwuu').
165  *	      Sent to expo for X11R2 contrib.
166  * 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
167  * 20-May-88: Added -root to allow root to unlock.
168  * 12-Apr-88: Added root password override.
169  *	      Added screen saver override.
170  *	      Removed XGrabServer/XUngrabServer.
171  *	      Added access control handling instead.
172  * 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
173  * 30-Mar-88: Removed startup password requirement.
174  *	      Removed cursor to avoid phosphor burn.
175  * 27-Mar-88: Rotate fractal by 45 degrees clockwise.
176  * 24-Mar-88: Added color support. [-color]
177  *	      wrote the man page.
178  * 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
179  *	      added password requirement for invocation
180  *	      removed option for command line password
181  *	      added requirement for display to be "unix:0".
182  * 22-Mar-88: Received Walter Milliken's comp.windows.x posting.
183  *
184  */
185 
186 #ifdef STANDALONE
187 
188 /*-
189  * xscreensaver compatibility layer for xlockmore modules.
190  * xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz AT jwz.org>
191  *
192  * Permission to use, copy, modify, distribute, and sell this software and its
193  * documentation for any purpose is hereby granted without fee, provided that
194  * the above copyright notice appear in all copies and that both that
195  * copyright notice and this permission notice appear in supporting
196  * documentation.  No representations are made about the suitability of this
197  * software for any purpose.  It is provided "as is" without express or
198  * implied warranty.
199  *
200  * This file, along with xlockmore.h, make it possible to compile an xlockmore
201  * module into a standalone program, and thus use it with xscreensaver.
202  * By Jamie Zawinski <jwz AT jwz.org> on 10-May-97; based on the ideas
203  * in the older xlock.h by Charles Hannum <mycroft@ai.mit.edu>.  (I had
204  * to redo it, since xlockmore has diverged so far from xlock...)
205  */
206 
207 #include <stdio.h>
208 #include <math.h>
209 #include <string.h>
210 #include "screenhack.h"
211 #include "mode.h"
212 #include "vis.h"
213 
214 #define countof(x) (sizeof((x))/sizeof(*(x)))
215 
216 extern ModeSpecOpt xlockmore_opts[];
217 extern const char *app_defaults;
218 char       *message, *messagefile, *messagesfile, *program;
219 char       *messagefontname;
220 
221 void
pre_merge_options(void)222 pre_merge_options(void)
223 {
224 	int         i, j;
225 	char       *s;
226 
227 	/* Translate the xlockmore `opts[]' argument to a form that
228 	   screenhack.c expects.
229 	 */
230 	for (i = 0; i < xlockmore_opts->numopts; i++) {
231 		XrmOptionDescRec *old = &xlockmore_opts->opts[i];
232 		XrmOptionDescRec *new = &options[i];
233 
234 		if (old->option[0] == '-')
235 			new->option = old->option;
236 		else {
237 			/* Convert "+foo" to "-no-foo". */
238 			if ((new->option = (char *) malloc(strlen(old->option) +
239 					5)) != NULL) {
240 				(void) strcpy(new->option, "-no-");
241 				(void) strcat(new->option, old->option + 1);
242 			}
243 		}
244 
245 		new->specifier = strrchr(old->specifier, '.');
246 		if (!new->specifier)
247 			abort();
248 
249 		new->argKind = old->argKind;
250 		new->value = old->value;
251 	}
252 
253 	/* Add extra args, if they're mentioned in the defaults... */
254 	{
255 		char       *args[] =
256 		{"-delay", "-count", "-cycles", "-size", "-ncolors", "-bitmap",
257 		 "-text", "-filename", "-program",
258 		 "-wireframe", "-use3d", "-verbose"};
259 
260 		for (j = 0; j < countof(args); j++)
261 			if (strstr(app_defaults, args[j] + 1)) {
262 				XrmOptionDescRec *new = &options[i++];
263 
264 				new->option = args[j];
265 				new->specifier = strdup(args[j]);
266 				new->specifier[0] = '.';
267 				if (!strcmp(new->option, "-wireframe")) {
268 					new->argKind = XrmoptionNoArg;
269 					new->value = "True";
270 					new = &options[i++];
271 					new->option = "-no-wireframe";
272 					new->specifier = options[i - 2].specifier;
273 					new->argKind = XrmoptionNoArg;
274 					new->value = "False";
275 				} else if (!strcmp(new->option, "-use3d")) {
276 					new->option = "-3d";
277 					new->argKind = XrmoptionNoArg;
278 					new->value = "True";
279 					new = &options[i++];
280 					new->option = "-no-3d";
281 					new->specifier = options[i - 2].specifier;
282 					new->argKind = XrmoptionNoArg;
283 					new->value = "False";
284 				} else if (!strcmp(new->option, "-verbose")) {
285 					new->option = "-verbose";
286 					new->argKind = XrmoptionNoArg;
287 					new->value = "True";
288 					new = &options[i++];
289 					new->option = "-no-verbose";
290 					new->specifier = options[i - 2].specifier;
291 					new->argKind = XrmoptionNoArg;
292 					new->value = "False";
293 				} else {
294 					new->argKind = XrmoptionSepArg;
295 					new->value = 0;
296 				}
297 			}
298 	}
299 
300 
301 	/* Construct the kind of `defaults' that screenhack.c expects from
302 	   the xlockmore `vars[]' argument.
303 	 */
304 	i = 0;
305 
306 	/* Put on the PROGCLASS.background/foreground resources. */
307 	if ((s = (char *) malloc(50)) != NULL) {
308 		(void) strcpy(s, progclass);
309 		(void) strcat(s, ".background: black");
310 		defaults[i++] = s;
311 	}
312 
313 	if ((s = (char *) malloc(50)) != NULL) {
314 		(void) strcpy(s, progclass);
315 		(void) strcat(s, ".foreground: white");
316 		defaults[i++] = s;
317 	}
318 
319 	/* Copy the lines out of the `app_defaults' var and into this array. */
320 	s = strdup(app_defaults);
321 	while (s && *s) {
322 		defaults[i++] = s;
323 		s = strchr(s, '\n');
324 		if (s)
325 			*s++ = 0;
326 	}
327 
328 	/* Copy the defaults out of the `xlockmore_opts->' variable. */
329 	for (j = 0; j < xlockmore_opts->numvarsdesc; j++) {
330 		const char *def = xlockmore_opts->vars[j].def;
331 
332 		if (!def)
333 			def = "False";
334 		if (def == ((char *) 1))
335 			def = "True";
336 		if ((s = (char *) malloc(strlen(xlockmore_opts->vars[j].name) +
337 				strlen(def) + 10)) != NULL) {
338 			(void) strcpy(s, "*");
339 			(void) strcat(s, xlockmore_opts->vars[j].name);
340 			(void) strcat(s, ": ");
341 			(void) strcat(s, def);
342 			defaults[i++] = s;
343 		}
344 	}
345 
346 	defaults[i] = 0;
347 }
348 
349 
350 static void
xlockmore_read_resources(void)351 xlockmore_read_resources(void)
352 {
353 	int         i;
354 
355 	for (i = 0; i < xlockmore_opts->numvarsdesc; i++) {
356 		void       *var = xlockmore_opts->vars[i].var;
357 		Bool       *var_b = (Bool *) var;
358 		char      **var_c = (char **) var;
359 		int        *var_i = (int *) var;
360 		float      *var_f = (float *) var;
361 
362 		switch (xlockmore_opts->vars[i].type) {
363 			case t_String:
364 				*var_c = get_string_resource(xlockmore_opts->vars[i].name,
365 					xlockmore_opts->vars[i].classname);
366 				break;
367 			case t_Float:
368 				*var_f = get_float_resource(xlockmore_opts->vars[i].name,
369 					xlockmore_opts->vars[i].classname);
370 				break;
371 			case t_Int:
372 				*var_i = get_integer_resource(xlockmore_opts->vars[i].name,
373 					xlockmore_opts->vars[i].classname);
374 				break;
375 			case t_Bool:
376 				*var_b = get_boolean_resource(xlockmore_opts->vars[i].name,
377 					xlockmore_opts->vars[i].classname);
378 				break;
379 			default:
380 				abort();
381 		}
382 	}
383 }
384 
385 void
xlockmore_screenhack(Display * dpy,Window window,Bool want_writable_colors,Bool want_uniform_colors,Bool want_smooth_colors,Bool want_bright_colors,void (* hack_init)(ModeInfo *),void (* hack_draw)(ModeInfo *),void (* hack_free)(ModeInfo *))386 xlockmore_screenhack(Display * dpy, Window window,
387 	Bool want_writable_colors,
388 	Bool want_uniform_colors,
389 	Bool want_smooth_colors,
390 	Bool want_bright_colors,
391 	void        (*hack_init) (ModeInfo *),
392 	void        (*hack_draw) (ModeInfo *),
393 	void        (*hack_free) (ModeInfo *))
394 {
395 	ModeInfo    mi;
396 	XGCValues   gcv;
397 	XColor      color;
398 	int         i;
399 	time_t      start, now;
400 	struct timeval drawstart, drawstop;
401 	unsigned long drawelapsed;
402 	int         orig_pause;
403 
404 	(void) memset((char *) &mi, 0, sizeof (mi));
405 	mi.dpy = dpy;
406 	mi.window = window;
407 	(void) XGetWindowAttributes(dpy, window, &mi.xgwa);
408 
409 	color.flags = DoRed | DoGreen | DoBlue;
410 	color.red = color.green = color.blue = 0;
411 	if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
412 		abort();
413 	mi.black = color.pixel;
414 	color.red = color.green = color.blue = 0xFFFF;
415 	if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
416 		abort();
417 	mi.white = color.pixel;
418 
419 	if (mono_p) {
420 		static unsigned long pixels[2];
421 		static XColor colors[2];
422 
423 	MONO:
424 		mi.npixels = 2;
425 		mi.pixels = pixels;
426 		mi.colors = colors;
427 		pixels[0] = mi.black;
428 		pixels[1] = mi.white;
429 		colors[0].flags = DoRed | DoGreen | DoBlue;
430 		colors[1].flags = DoRed | DoGreen | DoBlue;
431 		colors[0].red = colors[0].green = colors[0].blue = 0;
432 		colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
433 		mi.writable_p = False;
434 	} else {
435 		mi.npixels = get_integer_resource("ncolors", "Integer");
436 		if (mi.npixels <= 0)
437 			mi.npixels = 64;
438 		else if (mi.npixels > 256)
439 			mi.npixels = 256;
440 
441 		mi.writable_p = want_writable_colors;
442 		if ((mi.colors = (XColor *) calloc(mi.npixels,
443 			sizeof (*mi.colors))) != NULL) {
444 
445 			if (want_uniform_colors)
446 				make_uniform_colormap(dpy, mi.xgwa.visual, mi.xgwa.colormap,
447 					mi.colors, &mi.npixels,
448 					True, &mi.writable_p, True);
449 			else if (want_smooth_colors)
450 				make_smooth_colormap(dpy, mi.xgwa.visual, mi.xgwa.colormap,
451 					mi.colors, &mi.npixels,
452 					True, &mi.writable_p, True);
453 			else
454 				make_random_colormap(dpy, mi.xgwa.visual, mi.xgwa.colormap,
455 					mi.colors, &mi.npixels,
456 					want_bright_colors,
457 					True, &mi.writable_p, True);
458 		}
459 
460 		if (mi.npixels <= 2)
461 			goto MONO;
462 		else {
463 			if ((mi.pixels = (unsigned long *)
464 				calloc(mi.npixels, sizeof (*mi.pixels))) != NULL) {
465 				int         i;
466 
467 				for (i = 0; i < mi.npixels; i++)
468 					mi.pixels[i] = mi.colors[i].pixel;
469 			}
470 		}
471 	}
472 
473 	gcv.foreground = mi.white;
474 	gcv.background = mi.black;
475 	mi.gc = XCreateGC(dpy, window, GCForeground | GCBackground, &gcv);
476 
477 	mi.pause = get_integer_resource("delay", "Usecs");
478 
479 	mi.count = get_integer_resource("count", "Int");
480 	mi.cycles = get_integer_resource("cycles", "Int");
481 	mi.size = get_integer_resource("size", "Int");
482 	mi.ncolors = get_integer_resource("ncolors", "Int");
483 	mi.bitmap = get_string_resource("bitmap", "String");
484 	messagefontname = get_string_resource("font", "String");
485 	message = get_string_resource("text", "String");
486 	messagefile = get_string_resource("filename", "String");
487 	messagesfile = get_string_resource("fortunefile", "String");
488 	program = get_string_resource("program", "String");
489 
490 
491 #if 0
492 	decay = get_boolean_resource("decay", "Boolean");
493 	if (decay)
494 		mi.fullrandom = False;
495 
496 	trail = get_boolean_resource("trail", "Boolean");
497 	if (trail)
498 		mi.fullrandom = False;
499 
500 	grow = get_boolean_resource("grow", "Boolean");
501 	if (grow)
502 		mi.fullrandom = False;
503 
504 	liss = get_boolean_resource("liss", "Boolean");
505 	if (liss)
506 		mi.fullrandom = False;
507 
508 	ammann = get_boolean_resource("ammann", "Boolean");
509 	if (ammann)
510 		mi.fullrandom = False;
511 
512 	jong = get_boolean_resource("jong", "Boolean");
513 	if (jong)
514 		mi.fullrandom = False;
515 
516 	sine = get_boolean_resource("sine", "Boolean");
517 	if (sine)
518 		mi.fullrandom = False;
519 #endif
520 
521 	mi.threed = get_boolean_resource("use3d", "Boolean");
522 	mi.threed_delta = get_float_resource("delta3d", "Boolean");
523 	mi.threed_right_color = get_pixel_resource("right3d", "Color", dpy,
524 		mi.xgwa.colormap);
525 	mi.threed_left_color = get_pixel_resource("left3d", "Color", dpy,
526 		mi.xgwa.colormap);
527 	mi.threed_both_color = get_pixel_resource("both3d", "Color", dpy,
528 		mi.xgwa.colormap);
529 	mi.threed_none_color = get_pixel_resource("none3d", "Color", dpy,
530 		mi.xgwa.colormap);
531 
532 	mi.wireframe_p = get_boolean_resource("wireframe", "Boolean");
533         mi.fps_p = get_boolean_resource("showfps", "Boolean");
534 	mi.verbose = get_boolean_resource("verbose", "Boolean");
535 
536 	mi.root_p = (window == RootWindowOfScreen(mi.xgwa.screen));
537 	mi.is_drawn = False;
538 
539 
540 	if (mi.pause < 0)
541 		mi.pause = 0;
542 	else if (mi.pause > 100000000)
543 		mi.pause = 100000000;
544 	orig_pause = mi.pause;
545 
546 	xlockmore_read_resources();
547 
548 	XClearWindow(dpy, window);
549 
550 	i = 0;
551 	start = time((time_t) 0);
552 
553 	hack_init(&mi);
554 	do {
555 		(void) gettimeofday(&drawstart, NULL);
556 		hack_draw(&mi);
557 		XSync(dpy, False);
558 		(void) gettimeofday(&drawstop, NULL);
559 		drawelapsed = (drawstop.tv_sec - drawstart.tv_sec)*1000000 +
560 			(drawstop.tv_usec - drawstart.tv_usec);
561 		if (mi.pause > drawelapsed)
562 			(void) usleep(mi.pause - drawelapsed);
563 		mi.pause = orig_pause;
564 
565 		if (hack_free) {
566 			if (i++ > (mi.count / 4) &&
567 					(start + 5) < (now = time((time_t) 0))) {
568 				i = 0;
569 				start = now;
570 				hack_free(&mi);
571 				hack_init(&mi);
572 				XSync(dpy, False);
573 			}
574 		}
575 	} while (1);
576 }
577 
578 #else /* STANDALONE */
579 #include "xlock.h"
580 #include "color.h"
581 #include "util.h"
582 #include "iostuff.h"
583 #include "passwd.h"
584 #include <sys/stat.h>
585 #include <signal.h>
586 #include <errno.h>
587 #if HAVE_SYS_RESOURCE_H
588 #include <sys/resource.h>
589 #endif
590 #if HAVE_SYS_TIME_H
591 #include <sys/time.h>
592 #endif
593 #if HAVE_SYS_SELECT_H && defined(AIXV3)
594 #include <sys/select.h>
595 #endif
596 
597 #ifndef WIN32
598 #include <X11/cursorfont.h>
599 #include <X11/Xatom.h>
600 #include <X11/keysym.h>
601 #else
602 #include "Xapi.h"
603 int GCCreate(void);
604 #endif /* WIN32 */
605 
606 #if USE_XVMSUTILS
607 #if 0
608 #include "../xvmsutils/unix_types.h"
609 #include "../xvmsutils/unix_time.h"
610 #else
611 #include <X11/unix_types.h>
612 #include <X11/unix_time.h>
613 #endif
614 #endif /* USE_XVMSUTILS */
615 #ifdef USE_DTSAVER
616 #include <X11/Intrinsic.h>
617 #include <Dt/Saver.h>
618 #endif
619 #if defined( __hpux ) || defined( __apollo )
620 #include <X11/XHPlib.h>
621 extern int  XHPEnableReset(Display * dsp);
622 
623 #endif
624 #ifdef USE_DPMS
625 #ifndef MIN_DPMS
626 #define MIN_DPMS 5		/* 5 second minimum */
627 #endif
628 #if 1
629 #include <X11/Xmd.h>
630 #include <X11/Xdmcp.h>
631 #include <X11/extensions/dpms.h>
632 #ifdef SunCplusplus
633 extern Bool DPMSQueryExtension(Display *, int *, int *);
634 extern Bool  DPMSGetTimeouts(Display *, unsigned short *, unsigned short *, unsigned short *);
635 extern Status  DPMSSetTimeouts(Display *, unsigned short, unsigned short, unsigned short);
636 extern int  DPMSCapable(Display *);
637 extern int  DPMSInfo(Display *, CARD16 *, BOOL *);
638 #endif
639 #else /* XFree86 < 4.x */
640 #include <X11/extensions/dpms.h>
641 #ifndef __NetBSD
642 extern unsigned char DPMSQueryExtension(Display *, int *, int *);
643 #endif
644 extern int  DPMSGetTimeouts(Display *, unsigned short *, unsigned short *, unsigned short *);
645 extern int  DPMSSetTimeouts(Display *, unsigned short, unsigned short, unsigned short);
646 #endif
647 extern int  dpmsstandby;
648 extern int  dpmssuspend;
649 extern int  dpmsoff;
650 
651 #endif
652 
653 #ifdef USE_XINERAMA
654 #include <X11/extensions/Xinerama.h>
655 #endif
656 
657 #ifdef HAVE_KRB5
658 #include <krb5.h>
659 #endif /* HAVE_KRB5 */
660 
661 #if ( HAVE_SYSLOG_H && (defined( USE_SYSLOG ) || defined( GLOBAL_UNLOCK )))
662 #include <pwd.h>
663 #include <grp.h>
664 #include <syslog.h>
665 #ifndef SYSLOG_FACILITY
666 #define SYSLOG_FACILITY LOG_AUTH
667 #endif
668 #endif
669 
670 #if ( __VMS_VER >= 70000000 )
671 #include <lib$routines.h>
672 #include <mail$routines.h>
673 #include <maildef.h>
674 struct itmlst_3 {
675 	unsigned short int buflen;
676 	unsigned short int itmcode;
677 	void       *bufadr;
678 	unsigned short int *retlen;
679 };
680 
681 #endif
682 
683 #ifdef __FreeBSD__
684 #include <floatingpoint.h>
685 #endif
686 
687 extern void checkResources(void);
688 extern void defaultVisualInfo(Display * display, int screen);
689 
690 #ifdef USE_OLD_EVENT_LOOP
691 extern int  usleep(unsigned int);
692 
693 #endif
694 
695 #if defined( USE_AUTO_LOGOUT ) || defined( USE_BUTTON_LOGOUT )
696 extern void logoutUser(Display * display
697 #ifdef CLOSEDOWN_LOGOUT
698  , int screens
699 #endif
700 );
701 
702 #endif
703 
704 #if 0
705 	/* #if !defined( AIXV3 ) && !defined( __hpux ) && !defined( __bsdi__ ) */
706 extern int  select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
707 
708 #if !defined( __hpux ) && !defined( apollo )
709 extern int  select(size_t, int *, int *, int *, const struct timeval *);
710 
711 #endif
712 
713 #endif
714 
715 char       *ProgramName;	/* argv[0] */
716 
717 #ifdef DEBUG
718 pid_t       ProgramPID;		/* for memcheck.c */
719 
720 #endif
721 ScreenInfo *Scr = (ScreenInfo *) NULL;
722 
723 /* This is a private data structure, don't touch */
724 static ModeInfo *modeinfo = (ModeInfo *) NULL;
725 
726 Window      parent;
727 Bool        parentSet = False;
728 Display    *dsp = (Display *) NULL;	/* server display connection */
729 
730 extern char user[PASSLENGTH];
731 extern char hostname[MAXHOSTNAMELEN];
732 extern char *displayname;
733 extern char *bitmap;
734 extern int  delay;
735 extern int  count;
736 extern int  cycles;
737 extern int  size;
738 extern int  ncolors;
739 extern float saturation;
740 extern float delta3d;
741 extern Bool nolock;
742 extern Bool resetsaver;
743 extern Bool inwindow;
744 extern Bool inroot;
745 extern Bool mono;
746 extern Bool allowaccess;
747 extern Bool allowroot;
748 extern Bool debug;
749 extern Bool description;
750 extern Bool echokeys;
751 extern char* echokey;
752 extern Bool enablesaver;
753 extern Bool fullrandom;
754 extern Bool grabmouse;
755 extern Bool grabserver;
756 extern Bool install;
757 extern Bool mousemotion;
758 extern int  unlockdelay;
759 extern Bool showdate;
760 extern Bool timeelapsed;
761 extern Bool usefirst;
762 extern Bool verbose;
763 extern Bool remote;
764 extern int  nicelevel;
765 extern int  lockdelay;
766 extern int  timeout;
767 extern Bool wireframe;
768 #ifdef USE_GL
769 extern Bool showfps;
770 extern Bool fpsTop;
771 #endif
772 extern Bool use3d;
773 #ifdef HAVE_KRB5
774 extern int krb5_valid;
775 #endif
776 
777 extern char *fontname;
778 extern char *planfontname;
779 
780 #ifdef USE_MB
781 XFontSet    fontset = NULL;
782 extern char *fontsetname;
783 XFontSet    planfontset = NULL;
784 extern char *planfontsetname;
785 
786 XRectangle  mbRect;
787 XRectangle  planmbRect;
788 
789 #define fontHeight (mbRect.height)
790 #define fontDescent (mbRect.height / 5)
791 #define fontAscent (mbRect.height - fontDescent)
792 #define planFontHeight (planmbRect.height)
793 #define planFontDescent (planmbRect.height / 5)
794 #define planFontAscent (planmbRect.height - planFontDescent)
795 
796 #else
797 
798 #define fontHeight (font->ascent + font->descent)
799 #define fontAscent (font->ascent)
800 #define fontDescent (font->descent)
801 #define planFontHeight (planfont->ascent + planfont->descent)
802 #define planFontAscent (planfont->ascent)
803 #define planFontDescent (planfont->descent)
804 
805 #endif
806 extern char *background;
807 extern char *foreground;
808 extern char *text_user;
809 extern char *text_pass;
810 extern char *text_info;
811 #ifdef HAVE_KRB5
812 extern char *text_krbinfo;
813 #endif
814 extern char *text_valid;
815 extern char *text_invalid;
816 extern char *text_invalidCapsLock;
817 extern char *failed_attempt;
818 extern char *failed_attempts;
819 
820 extern char *geometry;
821 extern char *icongeometry;
822 
823 #ifdef FX
824 extern char *glgeometry;
825 
826 #endif
827 extern char *none3d;
828 extern char *right3d;
829 extern char *left3d;
830 extern char *both3d;
831 
832 #ifdef USE_SOUND
833 extern char *locksound;
834 extern char *infosound;
835 extern char *validsound;
836 extern char *invalidsound;
837 #if 0
838 extern char *welcomesound;
839 extern char *shutdownsound;
840 #endif
841 extern void playSound(char *string, Bool verbose);
842 #ifdef USE_ESOUND
843 extern int init_sound(void);
844 extern void shutdown_sound(void);
845 #endif
846 extern Bool sound;
847 
848 #endif
849 
850 extern char *startCmd;
851 extern char *endCmd;
852 #ifndef VMS
853 extern char *pipepassCmd;
854 #endif
855 extern char *logoutCmd;
856 
857 extern char *mailCmd;
858 extern char *mailIcon;
859 extern char *nomailIcon;
860 
861 #ifdef USE_AUTO_LOGOUT
862 extern int  logoutAuto;
863 
864 #endif
865 
866 #ifdef USE_BUTTON_LOGOUT
867 extern int  logoutButton;
868 extern int  enable_button;
869 extern char *logoutButtonLabel;
870 extern char *logoutButtonHelp;
871 extern char *logoutFailedString;
872 
873 #endif
874 
875 #ifdef USE_DTSAVER
876 extern Bool dtsaver;
877 
878 #endif
879 
880 static int  screen = 0;		/* current screen */
881 int         startscreen = 0;
882 static int  screens;		/* number of screens */
883 
884 #ifdef FX
885 static int  glwidth, glheight;
886 
887 #endif
888 static XFontStruct *font;
889 #ifndef WIN32
890 static Cursor mycursor;		/* blank cursor */
891 static int  passx, passy;	/* position of the ?'s */
892 static XFontStruct *planfont;
893 static Pixmap lockc;
894 static Pixmap lockm;		/* pixmaps for cursor and mask */
895 static char no_bits[] =
896 {0};				/* dummy array for the blank cursor */
897 static int  iconwidth, iconheight;
898 static int  lock_delay;
899 static int  count_failed;
900 /* GEOMETRY STUFF */
901 static int  sizeconfiguremask;
902 static XWindowChanges minisizeconfigure;
903 static int  signalUSR1 = 0;
904 static int  signalUSR2 = 0;
905 static int  timex, timey;	/* position for the times */
906 static unsigned long start_time;
907 static Bool fullscreen = False;
908 static char *plantext[TEXTLINES + 2];	/* Message is stored here */
909 #endif
910 
911 static int  sstimeout;		/* screen saver parameters */
912 static int  ssinterval;
913 static int  ssblanking;
914 static int  ssexposures;
915 
916 #if defined( USE_AUTO_LOGOUT ) || defined( USE_BUTTON_LOGOUT )
917 static int  tried_logout = 0;
918 
919 #endif
920 
921 #ifdef USE_SOUND
922 static int  got_invalid = 0;
923 
924 #endif
925 
926 /* This still might not be right for Solaris, change the "1"->"0" if error */
927 #if 1
928 #if (defined( SYSV ) || defined( SVR4 )) && defined( SOLARIS2 ) && !defined( HAVE_STRUCT_SIGSET_T )
929 #if !defined( __cplusplus ) && !defined( c_plusplus ) && !defined ( _SIGSET_T )
930 
931 #define _SIGSET_T
932 typedef struct {		/* signal set type */
933 	unsigned long __sigbits[4];
934 } sigset_t;
935 
936  /* This is good for gcc compiled on Solaris-2.5 but used on Solaris-2.6 */
937 
938 #endif
939 #endif
940 #endif
941 #if !defined( SYSV ) && !defined( SVR4 ) && !defined( VMS ) && !defined(__cplusplus) && !defined(c_plusplus)
942 extern int  sigblock(int);
943 extern int  sigsetmask(int);
944 #endif
945 
946 #ifdef ORIGINAL_XPM_PATCH
947 #ifdef HAVE_XPM
948 #include <X11/xpm.h>
949 #endif
950 
951 static XpmImage *mail_xpmimg = NULL;
952 static XpmImage *nomail_xpmimg = NULL;
953 
954 #else
955 #ifndef WIN32
956 #include <bitmaps/mailempty.xbm>
957 #include <bitmaps/mailfull.xbm>
958 
959 #define NOMAIL_WIDTH   mailempty_width
960 #define NOMAIL_HEIGHT  mailempty_height
961 #define NOMAIL_BITS    mailempty_bits
962 #define MAIL_WIDTH   mailfull_width
963 #define MAIL_HEIGHT  mailfull_height
964 #define MAIL_BITS    mailfull_bits
965 #endif /* !WIN32 */
966 #endif
967 
968 #ifdef USE_VTLOCK
969 	/* EL - RCS : for VT switching locking */
970 extern int  vtlock;		/* Have to lock VT switching */
971 extern int  vtlocked;		/* VT switching is locked */
972 
973 extern void dovtlock(void);	/* Actual do it */
974 extern void dovtunlock(void);	/* & undo it functions */
975 
976 #endif
977 
978 #if defined( USE_MB ) && defined( __VMS )
979 int screenOffset = 4;
980 #else
981 int screenOffset = 0;
982 #endif
983 
984 char * old_default_mode = (char *) NULL;
985 
986 #define AllPointerEventMask \
987 	(ButtonPressMask | ButtonReleaseMask | \
988 	EnterWindowMask | LeaveWindowMask | \
989 	PointerMotionMask | PointerMotionHintMask | \
990 	Button1MotionMask | Button2MotionMask | \
991 	Button3MotionMask | Button4MotionMask | \
992 	Button5MotionMask | ButtonMotionMask | \
993 	KeymapStateMask)
994 
995 #ifdef USE_VROOT
996 #include "vroot.h"
997 #endif
998 
999 #ifdef SAFEWORD
1000 #include "custpb.h"
1001 #include "custf.h"
1002 
1003 extern char *text_dpass;
1004 extern char *text_fpass;
1005 extern char *text_chall;
1006 static int  challx, chally;
1007 
1008 extern      pbmain();
1009 
1010 struct pblk pblock;		/* our instance of the pblk */
1011 struct pblk *pb;		/* global pointer to the pblk */
1012 
1013 extern int  checkDynamic();
1014 
1015 #endif
1016 
1017 #if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
1018 static void
syslogStart(void)1019 syslogStart(void)
1020 {
1021 	struct passwd *pw = NULL;
1022 	struct group *gr = NULL;
1023 	char uid[16];
1024 	char gid[16];
1025 
1026 	pw = getpwuid(getuid());
1027 	gr = getgrgid(getgid());
1028 	if (pw == NULL)
1029 		sprintf(uid, "%ld", (long) getuid());
1030 	if (gr == NULL)
1031 		sprintf(gid, "%ld", (long) getgid());
1032 	(void) openlog(ProgramName, LOG_PID, SYSLOG_FACILITY);
1033 	syslog(SYSLOG_INFO, "Start: %s, %s, %s",
1034 		(pw == NULL) ? uid : pw->pw_name,
1035 		(gr == NULL) ? gid : gr->gr_name,
1036 		XDisplayString(dsp));
1037 }
1038 
1039 void
syslogStop(char * displayName)1040 syslogStop(char *displayName)
1041 {
1042 	int         secs, mins;
1043 	struct passwd *pw = NULL;
1044 	struct group *gr = NULL;
1045 	char uid[16];
1046 	char gid[16];
1047 
1048 	pw = getpwuid(getuid());
1049 	gr = getgrgid(getgid());
1050 	if (pw == NULL)
1051 		sprintf(uid, "%ld", (long) getuid());
1052 	if (gr == NULL)
1053 		sprintf(gid, "%ld", (long) getgid());
1054 	secs = (int) (seconds() - start_time);
1055 	mins = secs / 60;
1056 	secs %= 60;
1057 	syslog(SYSLOG_INFO, "Stop: %s, %s, %s, %dm %ds",
1058 		(pw == NULL) ? uid : pw->pw_name,
1059 		(gr == NULL) ? gid : gr->gr_name,
1060 		displayName, mins, secs);
1061 }
1062 
1063 #endif
1064 
1065 char error_buf[ERROR_BUF];
1066 static int error_exitcode = 1;
1067 
1068 void
error(const char * buf)1069 error(const char *buf)
1070 {
1071 #if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
1072 	syslog(SYSLOG_WARNING, "%s", buf);
1073 	if (!nolock) {
1074 		if (strstr(buf, "unable to open display") == NULL)
1075 			syslogStop(XDisplayString(dsp));
1076 		else
1077 			syslogStop("unknown display");
1078 		closelog();
1079 	}
1080 #else
1081 	(void) fprintf(stderr, "%s", buf);
1082 #endif
1083 	if (error_exitcode < 0) {
1084 		int sig = -error_exitcode;
1085 		signal(sig, SIG_DFL);
1086 		raise(sig);
1087 		/* We are still alive?? */
1088 		error_exitcode = sig + 128;
1089 	}
1090 	exit(error_exitcode);
1091 }
1092 
1093 /* Server access control support. */
1094 
1095 static XHostAddress *XHosts;	/* the list of "friendly" client machines */
1096 static int  HostAccessCount;	/* the number of machines in XHosts */
1097 static Bool HostAccessState;	/* whether or not we even look at the list */
1098 
1099 /* define window class (used by WindowMaker attributes configuration) */
1100 XClassHint xclasshint={(char *) DEFAULT_NAME, (char *) DEFAULT_NAME};
1101 
1102 #ifndef WIN32
1103 static void
XGrabHosts(Display * display)1104 XGrabHosts(Display * display)
1105 {
1106 	XHosts = XListHosts(display, &HostAccessCount, &HostAccessState);
1107 	if (XHosts)
1108 		XRemoveHosts(display, XHosts, HostAccessCount);
1109 	XEnableAccessControl(display);
1110 }
1111 #endif
1112 
1113 static void
XUngrabHosts(Display * display)1114 XUngrabHosts(Display * display)
1115 {
1116 	if (XHosts) {
1117 		XAddHosts(display, XHosts, HostAccessCount);
1118 		XFree((caddr_t) XHosts);
1119 	}
1120 	if (HostAccessState == False)
1121 		XDisableAccessControl(display);
1122 }
1123 
1124 /* Provides support for the DPMS options. */
1125 #ifdef USE_DPMS
1126 static void
SetDPMS(Display * display,int nstandby,int nsuspend,int noff)1127 SetDPMS(Display * display, int nstandby, int nsuspend, int noff)
1128 {
1129 	static unsigned short standby = 0, suspend = 0, off = 0, flag = 0;
1130 	int         dummy;
1131 
1132 	if (DPMSQueryExtension(display, &dummy, &dummy)) {
1133 		if (!flag) {
1134 			DPMSGetTimeouts(display, &standby, &suspend, &off);
1135 			flag++;
1136 		}
1137 		if ((nstandby < 0) && (nsuspend < 0) && (noff < 0))
1138 			DPMSSetTimeouts(display, standby, suspend, off);
1139 		else
1140 			DPMSSetTimeouts(display,
1141 					(nstandby <= 0 ? 0 : (nstandby > MIN_DPMS ? nstandby : MIN_DPMS)),
1142 					(nsuspend <= 0 ? 0 : (nsuspend > MIN_DPMS ? nsuspend : MIN_DPMS)),
1143 					(noff <= 0 ? 0 : (noff > MIN_DPMS ? noff : MIN_DPMS)));
1144 	}
1145 }
1146 
1147 static int
monitor_powered_on_p(Display * dpy)1148 monitor_powered_on_p(Display *dpy)
1149 {
1150   int result;
1151   int event_number, error_number;
1152   BOOL onoff = False;
1153   CARD16 state;
1154 
1155   if (!DPMSQueryExtension(dpy, &event_number, &error_number))
1156     /* DPMS extension is not supported */
1157     result = True;
1158 
1159   else if (!DPMSCapable(dpy))
1160     /* Monitor is incapable of DPMS */
1161     result = True;
1162 
1163   else
1164     {
1165       DPMSInfo(dpy, &state, &onoff);
1166       if (!onoff)
1167 	/*  DPMS is disabled */
1168 	result = True;
1169       else {
1170 	switch (state) {
1171 	case DPMSModeOn:	result = True;  break;
1172 	case DPMSModeStandby:	result = False; break;
1173 	case DPMSModeSuspend:	result = False; break;
1174 	case DPMSModeOff:	result = False; break;
1175 	default:		result = True;  break;
1176 	}
1177       }
1178     }
1179   return result;
1180 }
1181 #else
1182 #ifndef WIN32
1183 static int
monitor_powered_on_p(Display * dpy)1184 monitor_powered_on_p(Display *dpy)
1185 {
1186   return 1;
1187 }
1188 #endif
1189 #endif
1190 
1191 
1192 #ifndef WIN32
1193 /*-
1194  * Simple wrapper to get an asynchronous grab on the keyboard and mouse. If
1195  * either grab fails, we sleep for one second and try again since some window
1196  * manager might have had the mouse grabbed to drive the menu choice that
1197  * picked "Lock Screen..".  If either one fails the second time we print an
1198  * error message and exit.
1199  */
1200 static void
GrabKeyboardAndMouse(Display * display,Window window)1201 GrabKeyboardAndMouse(Display * display, Window window)
1202 {
1203 	Status      status;
1204 
1205 	status = XGrabKeyboard(display, window, True,
1206 		GrabModeAsync, GrabModeAsync, CurrentTime);
1207 	if (status != GrabSuccess) {
1208 		(void) sleep(1);
1209 		status = XGrabKeyboard(display, window, True,
1210 			GrabModeAsync, GrabModeAsync, CurrentTime);
1211 
1212 		if (status != GrabSuccess) {
1213 			(void) sprintf(error_buf,
1214 				"%s, could not grab keyboard! (%d)\n",
1215 				(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
1216 				ProgramName : DEFAULT_NAME, status);
1217 			error(error_buf);
1218 		}
1219 	}
1220 	status = XGrabPointer(display, window, True,
1221 		(unsigned int) AllPointerEventMask, GrabModeAsync,
1222 		GrabModeAsync, None, mycursor, CurrentTime);
1223 	if (status != GrabSuccess) {
1224 		(void) sleep(1);
1225 		status = XGrabPointer(display, window, True,
1226 			(unsigned int) AllPointerEventMask, GrabModeAsync,
1227 			GrabModeAsync, None, mycursor, CurrentTime);
1228 
1229 		if (status != GrabSuccess) {
1230 			(void) sprintf(error_buf,
1231 				"%s, could not grab pointer! (%d)\n",
1232 				(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
1233 				ProgramName : DEFAULT_NAME, status);
1234 			error(error_buf);
1235 		}
1236 	}
1237 }
1238 
1239 /* Assuming that we already have an asynch grab on the pointer, just grab it
1240    again with a new cursor shape and ignore the return code. */
1241 static void
ChangeGrabbedCursor(Display * display,Window window,Cursor cursor)1242 ChangeGrabbedCursor(Display * display, Window window, Cursor cursor)
1243 {
1244 	if (!debug && grabmouse && !inwindow && !inroot)
1245 		(void) XGrabPointer(display, window, True,
1246 			(unsigned int) AllPointerEventMask, GrabModeAsync,
1247 			GrabModeAsync, None, cursor, CurrentTime);
1248 }
1249 
1250 /*-
1251  *    Return True or False indicating if the given window has changed
1252  *    size relative to the window geometry cached in the mode_info
1253  *    struct.  If the window handle given does not match the one in
1254  *    the cache, or if the width/height are not the same, then True
1255  *    is returned and the window handle in the cache is cleared.
1256  *    This causes mode_info() to reload the window info next time
1257  *    it is called.
1258  *    This function has non-obvious side-effects.  I feel so dirty.  Rh
1259  */
1260 
1261 static int
window_size_changed(int scrn,Window window)1262 window_size_changed(int scrn, Window window)
1263 {
1264 	XWindowAttributes xgwa;
1265 	ModeInfo   *mi = &modeinfo[scrn];
1266 
1267 	if (MI_WINDOW(mi) != window) {
1268 		MI_WINDOW(mi) = None;	/* forces reload on next mode_info() */
1269 		return (True);
1270 	} else {
1271 		(void) XGetWindowAttributes(dsp, window, &xgwa);
1272 		if ((MI_WIDTH(mi) != xgwa.width) ||
1273 				(MI_HEIGHT(mi) != xgwa.height)) {
1274 			MI_WINDOW(mi) = None;
1275 			return (True);
1276 		}
1277 	}
1278 
1279 	return (False);
1280 }
1281 #endif /* WIN32 */
1282 
1283 #ifdef FX
1284 void
resetSize(ModeInfo * mi,Bool setGL)1285 resetSize(ModeInfo * mi, Bool setGL)
1286 {
1287 	char       *mesa_3Dfx_env;
1288 	static int  width = 0, height = 0;
1289 
1290 	mesa_3Dfx_env = getenv("MESA_GLX_FX");
1291 	if (!mesa_3Dfx_env)
1292 		return;
1293 	if (tolower(mesa_3Dfx_env[0]) != 'f')
1294 		return;
1295 
1296 	/*
1297 	 * This is not correct for multiscreens, but there are other problems
1298 	 * here for multiscreens as well so I am not going bother
1299 	 */
1300 	if (!width)
1301 		width = MI_WIDTH(mi);
1302 	if (!height)
1303 		height = MI_HEIGHT(mi);
1304 
1305 	if (setGL) {
1306 		MI_WIDTH(mi) = glwidth;
1307 		MI_HEIGHT(mi) = glheight;
1308 	} else {
1309 		MI_WIDTH(mi) = width;
1310 		MI_HEIGHT(mi) = height;
1311 	}
1312 	XResizeWindow(MI_DISPLAY(mi), MI_WINDOW(mi),
1313 		      MI_WIDTH(mi), MI_HEIGHT(mi));
1314 }
1315 #endif
1316 
1317 /*-
1318  *    Return a pointer to an up-to-date ModeInfo struct for the given
1319  *      screen, window and iconic mode.  Because the number of screens
1320  *      is limited, and much of the information is screen-specific, this
1321  *      function keeps static copies of ModeInfo structs are kept for
1322  *      each screen.  This also eliminates redundant calls to the X server
1323  *      to acquire info that does change.
1324  */
1325 
1326 static ModeInfo *
mode_info(Display * display,int scrn,Window window,int iconic)1327 mode_info(Display * display, int scrn, Window window, int iconic)
1328 {
1329 	XWindowAttributes xgwa;
1330 	ModeInfo   *mi;
1331 
1332 	mi = &modeinfo[scrn];
1333 
1334 	if (MI_FLAG_NOT_SET(mi, WI_FLAG_INFO_INITTED)) {
1335 		/* This stuff only needs to be set once per screen */
1336 
1337 		(void) memset((char *) mi, 0, sizeof (ModeInfo));
1338 
1339 		MI_DISPLAY(mi) = display;
1340 		MI_SCREEN(mi) = scrn;
1341 		MI_REAL_SCREEN(mi) = scrn;	/* TODO, for multiscreen debugging */
1342 		MI_SCREENPTR(mi) = ScreenOfDisplay(display, scrn);
1343 		MI_NUM_SCREENS(mi) = screens;
1344 		MI_MAX_SCREENS(mi) = screens;	/* TODO, for multiscreen debugging */
1345 
1346 		MI_SCREENINFO(mi) = &Scr[scrn];
1347 
1348 		/* accessing globals here */
1349 		MI_SET_FLAG_STATE(mi, WI_FLAG_MONO,
1350 			(mono || CellsOfScreen(MI_SCREENPTR(mi)) <= 2));
1351 		MI_SET_FLAG_STATE(mi, WI_FLAG_INWINDOW, inwindow);
1352 		MI_SET_FLAG_STATE(mi, WI_FLAG_INROOT, inroot);
1353 		MI_SET_FLAG_STATE(mi, WI_FLAG_NOLOCK, nolock);
1354 #ifdef USE_DTSAVER
1355 		MI_SET_FLAG_STATE(mi, WI_FLAG_INSTALL, install && !inroot && !dtsaver);
1356 #else
1357 		MI_SET_FLAG_STATE(mi, WI_FLAG_INSTALL, install && !inroot);
1358 #endif
1359 		MI_SET_FLAG_STATE(mi, WI_FLAG_DEBUG, debug);
1360 		MI_SET_FLAG_STATE(mi, WI_FLAG_USE3D, use3d &&
1361 			!(mono || CellsOfScreen(MI_SCREENPTR(mi)) <= 2));
1362 		MI_SET_FLAG_STATE(mi, WI_FLAG_VERBOSE, verbose);
1363 #ifdef WIN32
1364 		MI_SET_FLAG_STATE(mi, WI_FLAG_FULLRANDOM, True);
1365 #else
1366 		MI_SET_FLAG_STATE(mi, WI_FLAG_FULLRANDOM, False);
1367 #endif
1368 		MI_SET_FLAG_STATE(mi, WI_FLAG_WIREFRAME, wireframe);
1369 #ifdef USE_GL
1370 		MI_SET_FLAG_STATE(mi, WI_FLAG_FPS, showfps);
1371 #endif
1372 		MI_SET_FLAG_STATE(mi, WI_FLAG_INFO_INITTED, True);
1373 		MI_IS_DRAWN(mi) = False;
1374 	}
1375 	if (MI_WINDOW(mi) != window) {
1376 		MI_WINDOW(mi) = window;
1377 
1378 		(void) XGetWindowAttributes(display, window, &xgwa);
1379 
1380 		MI_WIDTH(mi) = xgwa.width;
1381 		MI_HEIGHT(mi) = xgwa.height;
1382 	}
1383 	MI_SET_FLAG_STATE(mi, WI_FLAG_ICONIC, iconic);
1384 
1385 	MI_DELTA3D(mi) = delta3d;
1386 
1387 	MI_DELAY(mi) = delay;	/* globals */
1388 	MI_COUNT(mi) = count;
1389 	MI_CYCLES(mi) = cycles;
1390 	MI_SIZE(mi) = size;
1391 	MI_NCOLORS(mi) = ncolors;
1392 	MI_SATURATION(mi) = saturation;
1393 	MI_BITMAP(mi) = bitmap;
1394 	return (mi);
1395 }
1396 
1397 
1398 #if defined( GLOBAL_UNLOCK ) || defined( USE_PAM )
1399 static int unamex = 0, unamey = 0;
1400 #endif
1401 #ifdef GLOBAL_UNLOCK
1402 
1403 extern char *text_guser;
1404 extern char global_user[PASSLENGTH];
1405 extern void checkUser(char *buffer);
1406 #define LOG_FACILITY    LOG_LOCAL2
1407 #define LOG_LEVEL       LOG_INFO
1408 
1409 static int
inform()1410 inform()
1411 {
1412 	/*
1413 	- the time, in date(1) style, is generated with a combination of the
1414 	  time(2) and ctime(3C) system calls.
1415 	- the owner of the xlock process is learned with getlogin(3C).
1416 	- global_user is a global character array  that holds the username
1417 	  of the person wishing to unlock the display.
1418 	- the hostname is learned with gethostname(2).
1419 	- the syslog(3B) call uses the syslog facility to log
1420 	  happenings at LOG_LEVEL to LOG_FACILITY
1421 	- yes, a system(3S) call is used...
1422 	- I never said it was pretty.
1423 
1424 	*/
1425 
1426 	char Mail[256];
1427 	time_t unlock_time;
1428 
1429 	/* learn what time it is and what host we are on */
1430 	time(&unlock_time);
1431 
1432 #if defined( HAVE_SYSLOG_H ) /* && defined( USE_SYSLOG ) */
1433 	/* log this event to syslogd as defined */
1434 	syslog(LOG_FACILITY | LOG_LEVEL, "%s: %s unlocked %s's display",
1435 	  ProgramName, global_user, getlogin());
1436 #endif
1437 	/* if (mailCmd && mailCmd[0]) { */
1438 		/* build a string suitable for use in system(3S) */
1439 		(void) sprintf(Mail, "%s -s \"%s:\" %s << EOF\n %s unlocked "
1440 			"%s's display on %s\n EOF",
1441 			/* Want the mail with the subject line control */
1442 #if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 )
1443 			"/usr/ucb/mail" ,
1444 #else
1445 			"/usr/bin/mail" ,
1446 #endif
1447 			ProgramName, getlogin(),
1448 			global_user, hostname, ctime(&unlock_time));
1449 
1450 		if (debug)
1451 			(void) printf("%s\n", Mail);
1452 		(void) system(Mail);
1453 	/* } */
1454 }
1455 #endif
1456 
1457 /* Restore all grabs, reset screensaver, restore colormap, close connection. */
1458 void
finish(Display * display,Bool closeDisplay)1459 finish(Display * display, Bool closeDisplay)
1460 {
1461 	int         scrn;
1462 
1463 	for (scrn = startscreen; scrn < screens; scrn++) {
1464 		if (Scr[scrn].window != None) {
1465 			release_last_mode(mode_info(display, scrn, Scr[scrn].window, False));
1466 		}
1467 		if (Scr[scrn].icon != None) {
1468 			release_last_mode(mode_info(display, scrn, Scr[scrn].icon, True));
1469 		}
1470 	}
1471 #ifdef ORIGINAL_XPM_PATCH
1472 	if (mail_xpmimg)
1473 		free(mail_xpmimg);
1474 	if (nomail_xpmimg)
1475 		free(nomail_xpmimg);
1476 #endif
1477 
1478 	XSync(display, False);
1479 #ifdef USE_VROOT
1480 	if (inroot)
1481 		XClearWindow(display, Scr[startscreen].window);
1482 #endif
1483 
1484 #ifdef GLOBAL_UNLOCK
1485 	/* Check to see if the owner is doing the unlocking themselves,
1486 	and if not then inform the display owner of who is unlocking */
1487 
1488 	if (strcmp(global_user, getlogin()) != 0)
1489 		inform();
1490 #endif
1491 
1492 	if (!nolock && !allowaccess) {
1493 		if (grabserver)
1494 			XUngrabServer(display);
1495 		XUngrabHosts(display);
1496 	}
1497 	XUngrabPointer(display, CurrentTime);
1498 	XUngrabKeyboard(display, CurrentTime);
1499 	if (!enablesaver && !nolock) {
1500 		XSetScreenSaver(display, sstimeout, ssinterval, ssblanking, ssexposures);
1501 	}
1502 	XFlush(display);
1503 #if 0
1504 /* Report that this gives "bad file descriptor" on XFree86 4.x */
1505 #ifndef __sgi
1506   /*-
1507    * The following line seems to cause a core dump on the SGI.
1508    * More work is needed on the cleanup code.
1509    */
1510 	if (closeDisplay)
1511 		(void) XCloseDisplay(display);
1512 #endif
1513 #endif
1514 #ifdef HAVE_SETPRIORITY
1515 	(void) setpriority(0, 0, 0);
1516 #else /* !HAVE_SETPRIORITY */
1517 	(void) nice(0);
1518 #endif /* HAVE_SETPRIORITY */
1519 #ifdef USE_VTLOCK
1520 	/* EL - RCS : Unlock VT switching */
1521 	if (vtlock && vtlocked)
1522 		dovtunlock();
1523 #endif
1524 }
1525 
1526 #ifndef WIN32
1527 #ifdef __cplusplus
1528 extern "C" {
1529 #endif
1530 
1531 static int
xio_error(Display * d)1532 xio_error(Display * d)
1533 {
1534 #ifdef USE_DTSAVER
1535 	if (dtsaver) {		/* this is normal when run as -dtsaver */
1536 		/* X connection to :0.0 broken (explicit kill or server shutdown). */
1537 		exit(0);
1538 	}
1539 #endif
1540 	(void) sprintf(error_buf,
1541 		"%s: xio_error\n",
1542 		(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
1543 		ProgramName : DEFAULT_NAME);
1544 	error(error_buf);
1545 	return ((debug) ? 0 : 1);	/* suppress message unless debugging */
1546 }
1547 
1548 #ifdef __cplusplus
1549 }
1550 #endif
1551 #endif /* WIN32 */
1552 
1553 /* Convenience function for drawing text */
1554 static void
putText(Display * display,Window window,GC gc,const char * string,int bold,int left,int * px,int * py)1555 putText(Display * display, Window window, GC gc,
1556 	const char *string, int bold, int left, int *px, int *py)
1557 				/* which window */
1558 				/* gc */
1559 				/* text to write */
1560 				/* 1 = make it bold */
1561 				/* left edge of text */
1562 				/* current x and y, input & return */
1563 {
1564 #define PT_BUFSZ 2048
1565 	char        buf[PT_BUFSZ], *p, *s;
1566 	int         x = *px, y = *py, last, len;
1567 
1568 	(void) strncpy(buf, string, PT_BUFSZ);
1569 	buf[PT_BUFSZ - 1] = 0;
1570 
1571 	p = buf;
1572 	last = 0;
1573 	for (;;) {
1574 		s = p;
1575 		for (; *p; ++p)
1576 			if (*p == '\n')
1577 				break;
1578 		if (!*p)
1579 			last = 1;
1580 		*p = 0;
1581 
1582 		if ((len = strlen(s))) {	/* yes, "=", not "==" */
1583 			(void) XDrawImageString(display, window, gc, x, y, s, len);
1584 			if (bold)
1585 				(void) XDrawString(display, window, gc, x + 1, y, s, len);
1586 		}
1587 		if (!last) {
1588 			y += fontHeight + 6;
1589 			x = left;
1590 		} else {
1591 			if (len)
1592 				x += XTextWidth(font, s, len);
1593 			break;
1594 		}
1595 		p++;
1596 	}
1597 	*px = x;
1598 	*py = y;
1599 }
1600 
1601 /* language dependent strings */
1602 #if defined DE
1603 #include "xlock-msg-de.h"
1604 #elif defined FR
1605 #include "xlock-msg-fr.h"
1606 #elif defined NL
1607 #include "xlock-msg-nl.h"
1608 #elif defined JA
1609 #include "xlock-msg-ja.h"
1610 #elif defined ZH
1611 #include "xlock-msg-zh_TW.h"
1612 #else
1613 #include "xlock-msg-en.h"
1614 #endif
1615 
1616 #ifndef WIN32
1617 static void
statusUpdate(int isnew,int scr)1618 statusUpdate(int isnew, int scr)
1619 {
1620 	int         left, x, y, len;
1621 	char        buf[1024];
1622 	XWindowAttributes xgwa;
1623 	static int  last_time;
1624 
1625 #ifdef USE_BUTTON_LOGOUT
1626 	int         ysave;
1627 	static int  made_button, last_tried_lo = 0;
1628 
1629 #endif /* USE_BUTTON_LOGOUT */
1630 
1631 	len = (int) (seconds() - start_time) / 60;
1632 
1633 #ifdef USE_BUTTON_LOGOUT
1634 	if (tried_logout && !last_tried_lo) {
1635 		last_tried_lo = 1;
1636 		isnew = 1;
1637 #ifdef USE_AUTO_LOGOUT
1638 		logoutAuto = 0;
1639 #endif
1640 	}
1641 	if (isnew)
1642 		made_button = 0;
1643 #endif /* USE_BUTTON_LOGOUT */
1644 
1645 	if (isnew || last_time != len)
1646 		last_time = len;
1647 	else
1648 		return;
1649 
1650 	(void) XGetWindowAttributes(dsp, Scr[scr].window, &xgwa);
1651 	x = left = timex;
1652 	y = timey;
1653 
1654 	if (timeelapsed) {
1655 		if (len < 60) {
1656 			if (len == 1)
1657 				(void) sprintf(buf, TIME_ELAPSED_MINUTE, len);
1658 			else
1659 				(void) sprintf(buf, TIME_ELAPSED_MINUTES, len);
1660 		} else {
1661 			(void) sprintf(buf, TIME_ELAPSED_HOURS, len / 60, len % 60);
1662 		}
1663 		putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y);
1664 	}
1665 #ifdef USE_BUTTON_LOGOUT
1666 	if (enable_button) {
1667 		if (logoutButton > len) {
1668 			int         tmp = logoutButton - len;
1669 
1670 			if (tmp < 60) {
1671 				if (tmp == 1)
1672 					(void) sprintf(buf, BUTTON_MINUTE, tmp);
1673 				else
1674 					(void) sprintf(buf, BUTTON_MINUTES, tmp);
1675 			} else {
1676 					(void) sprintf(buf, BUTTON_HOURS, tmp / 60, tmp % 60);
1677 			}
1678 			putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y);
1679 		} else {
1680 			/* Erase previous logout button message */
1681 			putText(dsp, Scr[scr].window, Scr[scr].textgc,
1682 				"                                                                                      \n",
1683 				False, left, &x, &y);
1684 			if (!made_button || (isnew && tried_logout)) {
1685 				made_button = 1;
1686 				ysave = y;
1687 
1688 				y += fontHeight + 8;	/* Leave a gap for validating */
1689 				XUnmapWindow(dsp, Scr[scr].button);
1690 				XSetForeground(dsp, Scr[scr].gc, Scr[scr].bg_pixel);
1691 				XFillRectangle(dsp, Scr[scr].window, Scr[scr].gc, left, y,
1692 					xgwa.width - left,
1693 					5 + 2 * (fontHeight));
1694 				XSetForeground(dsp, Scr[scr].gc, Scr[scr].fg_pixel);
1695 
1696 				if (tried_logout) {
1697 					putText(dsp, Scr[scr].window, Scr[scr].textgc, logoutFailedString,
1698 						True, left, &x, &y);
1699 				} else {
1700 					XMoveWindow(dsp, Scr[scr].button, left, y);
1701 					XMapWindow(dsp, Scr[scr].button);
1702 					XRaiseWindow(dsp, Scr[scr].button);
1703 					(void) sprintf(buf, " %s ", logoutButtonLabel);
1704 					XSetForeground(dsp, Scr[scr].gc, Scr[scr].white_pixel);
1705 					(void) XDrawString(dsp, Scr[scr].button, Scr[scr].gc,
1706 						0, fontAscent + 1, buf, strlen(buf));
1707 					XSetForeground(dsp, Scr[scr].gc, Scr[scr].fg_pixel);
1708 					y += 5 + 2 * fontHeight;
1709 					putText(dsp, Scr[scr].window, Scr[scr].textgc, logoutButtonHelp,
1710 						False, left, &x, &y);
1711 				}
1712 				y = ysave;
1713 				x = left;
1714 			}
1715 		}
1716 	}
1717 #endif /* USE_BUTTON_LOGOUT */
1718 #ifdef USE_AUTO_LOGOUT
1719 	if (logoutAuto) {
1720 		int         tmp = logoutAuto - len;
1721 
1722 		if (tmp < 60) {
1723 			if (tmp == 1)
1724 				(void) sprintf(buf, AUTOLOGOUT_MINUTE, tmp);
1725 			else
1726 				(void) sprintf(buf, AUTOLOGOUT_MINUTES, tmp);
1727 		} else {
1728 				(void) sprintf(buf, AUTOLOGOUT_HOURS, tmp / 60, tmp % 60);
1729 		}
1730 		putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y);
1731 	}
1732 #endif /* USE_AUTO_LOGOUT */
1733 }
1734 #endif /* WIN32 */
1735 
1736 #ifdef USE_AUTO_LOGOUT
1737 static void
checkLogout(Display * display)1738 checkLogout(Display * display)
1739 {
1740 	if (nolock || tried_logout || !logoutAuto)
1741 		return;
1742 	if (logoutAuto * 60 < (int) (seconds() - start_time)) {
1743 		tried_logout = 1;
1744 		logoutAuto = 0;
1745 		logoutUser(display
1746 #ifdef CLOSEDOWN_LOGOUT
1747  , screens
1748 #endif
1749 		);
1750 	}
1751 }
1752 
1753 #endif /* USE_AUTO_LOGOUT */
1754 
1755 #ifndef WIN32
1756 #ifndef USE_OLD_EVENT_LOOP
1757 
1758 /* subtract timer t2 from t1, return result in t3.  Result is not allowed to
1759    go negative, set to zero if result underflows */
1760 
1761 static
1762 void
sub_timers(struct timeval * t1,struct timeval * t2,struct timeval * t3)1763 sub_timers(struct timeval *t1, struct timeval *t2, struct timeval *t3)
1764 {
1765 	struct timeval tmp;
1766 	int         borrow = 0;
1767 
1768 	if (t1->tv_usec < t2->tv_usec) {
1769 		borrow++;
1770 		tmp.tv_usec = (1000000 + t1->tv_usec) - t2->tv_usec;
1771 	} else {
1772 		tmp.tv_usec = t1->tv_usec - t2->tv_usec;
1773 	}
1774 
1775 	/* Be careful here, timeval fields may be unsigned.  To avoid
1776 	   underflow in an unsigned int, add the borrow value to the
1777 	   subtrahend for the relational test.  Same effect, but avoids the
1778 	   possibility of a negative intermediate value. */
1779 	if (t1->tv_sec < (t2->tv_sec + borrow)) {
1780 		tmp.tv_usec = tmp.tv_sec = 0;
1781 	} else {
1782 		tmp.tv_sec = t1->tv_sec - t2->tv_sec - borrow;
1783 	}
1784 
1785 	*t3 = tmp;
1786 }
1787 
1788 /* return 0 on event received, -1 on timeout */
1789 static int
runMainLoop(int maxtime,int iconscreen)1790 runMainLoop(int maxtime, int iconscreen)
1791 {
1792 	static int  lastdelay = -1, lastmaxtime = -1;
1793 	int         fd = ConnectionNumber(dsp), r;
1794         int         poweron=True;
1795 	struct timeval sleep_time, first, repeat, elapsed, tmp;
1796 	fd_set      reads;
1797 	unsigned long started;
1798 
1799 #ifdef USE_NEW_EVENT_LOOP
1800 	struct timeval loopStart, timeSinceLoop;
1801 	unsigned long lastIter = 0, desiredIter = 0;
1802 
1803 	GETTIMEOFDAY(&loopStart);
1804 #endif
1805 
1806 	first.tv_sec = 0;
1807 	first.tv_usec = 0;
1808 	elapsed.tv_sec = 0;
1809 	elapsed.tv_usec = 0;
1810 	repeat.tv_sec = delay / 1000000;
1811 	repeat.tv_usec = delay % 1000000;
1812 
1813 	started = seconds();
1814 
1815 	for (;;) {
1816 		poweron= monitor_powered_on_p(dsp);
1817                 if(!poweron) (void) usleep(100000);
1818 
1819 		if (signalUSR1 || signalUSR2) {
1820 			int         i;
1821 
1822 			if (signalUSR1) {
1823 #ifdef DEBUG
1824 				(void) printf("switch to mode %s\n", "blank");
1825 #endif
1826 				for (i = 0; i < numprocs; i++) {
1827 					if (!strcmp(LockProcs[i].cmdline_arg, "blank")) {
1828 						set_default_mode(&LockProcs[i]);
1829 						break;
1830 					}
1831 				}
1832 			} else {
1833 #ifdef DEBUG
1834 				(void) printf("switch to mode %s\n", old_default_mode);
1835 #endif
1836 				for (i = 0; i < numprocs; i++) {
1837 					if (!strcmp(LockProcs[i].cmdline_arg, old_default_mode)) {
1838 						set_default_mode(&LockProcs[i]);
1839 						break;
1840 					}
1841 				}
1842 			}
1843 
1844 			for (screen = startscreen; screen < screens; screen++) {
1845 				call_change_hook((LockStruct *) NULL,
1846 					mode_info(dsp, screen, Scr[screen].window, False));
1847 			}
1848 
1849 			signalUSR1 = signalUSR2 = 0;
1850 		}
1851 		if (delay != lastdelay || maxtime != lastmaxtime) {
1852 			if (!delay || (maxtime && delay / 1000000 > maxtime)) {
1853 				repeat.tv_sec = maxtime;
1854 				repeat.tv_usec = 0;
1855 			} else {
1856 				repeat.tv_sec = delay / 1000000;
1857 				repeat.tv_usec = delay % 1000000;
1858 			}
1859 			first = repeat;
1860 			lastdelay = delay;
1861 			lastmaxtime = maxtime;
1862 			sleep_time = first;
1863 		} else {
1864 			sleep_time = repeat;
1865 		}
1866 
1867 		/* subtract time spent doing last loop iteration */
1868 		sub_timers(&sleep_time, &elapsed, &sleep_time);
1869 
1870 		/* (void) */ FD_ZERO(&reads);
1871 		FD_SET(fd, &reads);
1872 #ifdef VMS
1873 		FD_SET(fd + 1, &reads);
1874 #endif
1875 #if DCE_PASSWD
1876 		r = _select_sys(fd + 1,
1877 			(fd_set *) & reads, (fd_set *) NULL, (fd_set *) NULL,
1878 				(struct timeval *) &sleep_time);
1879 #else
1880 #if defined( __cplusplus ) || defined( c_plusplus )
1881 		r = select(fd + 1,
1882 			(fd_set *) & reads, (fd_set *) NULL, (fd_set *) NULL,
1883 			(struct timeval *) &sleep_time);
1884 #else
1885 		r = select(fd + 1,
1886 			(void *) &reads, (void *) NULL, (void *) NULL,
1887 			(struct timeval *) &sleep_time);
1888 #endif
1889 #endif
1890 
1891 		if (r == 1)
1892 			return 0;
1893 		if (r > 0 || (r == -1 && errno != EINTR))
1894 			(void) fprintf(stderr,
1895 				"Unexpected select() return value: %d (errno=%d)\n", r, errno);
1896 
1897 		GETTIMEOFDAY(&tmp);	/* get time before calling mode proc */
1898 
1899 #ifdef USE_NEW_EVENT_LOOP
1900 		if (delay == 0) {
1901 			desiredIter = lastIter + 1;
1902 		} else {
1903 			sub_timers(&tmp, &loopStart, &timeSinceLoop);
1904 			desiredIter =
1905 				(timeSinceLoop.tv_usec / delay) +
1906 				(((timeSinceLoop.tv_sec % delay) * 1000000) / delay) +
1907 				(timeSinceLoop.tv_sec / delay) * 1000000;
1908 		}
1909 		while (lastIter != desiredIter) {
1910 			++lastIter;
1911 #endif
1912 
1913 			for (screen = startscreen; screen < screens; screen++) {
1914 				Window      cbwin;
1915 				Bool        iconic;
1916 				ModeInfo   *mi;
1917 
1918 				if (screen == iconscreen) {
1919 					cbwin = Scr[screen].icon;
1920 					iconic = True;
1921 				} else {
1922 					cbwin = Scr[screen].window;
1923 					iconic = False;
1924 				}
1925 				if (cbwin != None && poweron) {
1926 					mi = mode_info(dsp, screen, cbwin, iconic);
1927 					call_callback_hook((LockStruct *) NULL, mi);
1928 				}
1929 			}
1930 
1931 			if (poweron)
1932 				XSync(dsp, False);
1933 			else
1934 				(void) usleep(100000);
1935 
1936 			/* check for events received during the XSync() */
1937 			if (QLength(dsp)) {
1938 				return 0;
1939 			}
1940 			if (maxtime && ((int) (seconds() - started) > maxtime)) {
1941 				return -1;
1942 			}
1943 #ifdef USE_NEW_EVENT_LOOP
1944 		}
1945 #endif
1946 		/* if (mindelay) (void) usleep(mindelay); */
1947 
1948 		/* get the time now, figure how long it took */
1949 		GETTIMEOFDAY(&elapsed);
1950 		sub_timers(&elapsed, &tmp, &elapsed);
1951 	}
1952 }
1953 #endif /* !USE_OLD_EVENT_LOOP */
1954 
1955 static int
ReadXString(char * s,int slen,Bool * capsLock,Bool pass)1956 ReadXString(char *s, int slen, Bool *capsLock
1957 #ifdef GLOBAL_UNLOCK
1958   , Bool pass
1959 #elif defined( USE_PAM )
1960   , Bool PAM_echokeys
1961 #endif
1962 
1963 )
1964 {
1965 	XEvent      event;
1966 	char        keystr[20];
1967 	char        c;
1968 	int         i;
1969 	int         bp;
1970 	int         len;
1971 	int         thisscreen = screen;
1972 	char        pwbuf[PASSLENGTH];
1973 	int         first_key = 1;
1974 
1975 	if (capsLock != NULL)
1976 		*capsLock = False;
1977 	for (screen = startscreen; screen < screens; screen++)
1978 		if (thisscreen == screen) {
1979 			call_init_hook((LockStruct *) NULL,
1980 				mode_info(dsp, screen, Scr[screen].icon, True));
1981 		} else {
1982 			call_init_hook((LockStruct *) NULL,
1983 				mode_info(dsp, screen, Scr[screen].window, False));
1984 		}
1985 	statusUpdate(True, thisscreen);
1986 	bp = 0;
1987 	*s = 0;
1988 
1989 	for (;;) {
1990 		unsigned long lasteventtime = seconds();
1991 		KeySym keysym;
1992 
1993 		while (!XPending(dsp)) {
1994 #ifdef USE_OLD_EVENT_LOOP
1995 			for (screen = startscreen; screen < screens; screen++)
1996 				if (thisscreen == screen)
1997 					call_callback_hook(NULL, mode_info(dsp, screen,
1998 						Scr[screen].icon, True));
1999 				else
2000 					call_callback_hook(NULL, mode_info(dsp, screen,
2001 						Scr[screen].window, False));
2002 			statusUpdate(False, thisscreen);
2003 			XSync(dsp, False);
2004 			(void) usleep(delay);
2005 #else
2006 			statusUpdate(False, thisscreen);
2007 			if (runMainLoop(MIN(timeout, 5), thisscreen) == 0)
2008 				break;
2009 #endif
2010 
2011 			if ((timeout < (int) (seconds() - lasteventtime))) {
2012 				screen = thisscreen;
2013 				return 1;
2014 			}
2015 		}
2016 
2017 		screen = thisscreen;
2018 		(void) XNextEvent(dsp, &event);
2019 
2020 		/*
2021 		 * This event handling code should be unified with the
2022 		 * similar code in justDisplay().
2023 		 */
2024 		switch (event.type) {
2025 			case KeyPress:
2026 				len = XLookupString((XKeyEvent *) & event,
2027 					keystr, 20, /*(KeySym *) NULL,*/
2028 					&keysym,
2029 					(XComposeStatus *) NULL);
2030 				if (capsLock != NULL)
2031 					*capsLock = ((event.xkey.state & LockMask) != 0);
2032 
2033 				for (i = 0; i < len; i++) {
2034 					c = keystr[i];
2035 					switch (c) {
2036 						case 8:	/* ^H */
2037 						case 127:	/* DEL */
2038 							if (bp > 0)
2039 								bp--;
2040 							break;
2041 						case 10:	/* ^J */
2042 						case 13:	/* ^M */
2043 							if (first_key && usefirst)
2044 								break;
2045 							s[bp] = '\0';
2046 							return 0;
2047 						case 21:	/* ^U */
2048 						case 27:	/* ESC */
2049 							bp = 0;
2050 							break;
2051 						default:
2052 							s[bp] = c;
2053 							if (bp < slen - 1)
2054 								bp++;
2055 							else
2056 								XSync(dsp, True);	/* flush input buffer */
2057 					}
2058 				}
2059 				XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
2060 #ifdef GLOBAL_UNLOCK
2061 				if (!pass) {
2062 					XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2063 						unamex, unamey - fontAscent,
2064 						XTextWidth(font, s, slen),
2065 						fontHeight  + 3);
2066 					(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
2067 						unamex, unamey, s, bp);
2068 				} else
2069 #elif defined( USE_PAM )
2070 				if (PAM_echokeys) {
2071 
2072 					XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2073 						unamex, unamey - fontAscent,
2074 						XTextWidth(font, s, slen),
2075 						fontHeight  + 3);
2076 
2077 					(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
2078 						unamex, unamey, s, bp);
2079 				} else
2080 #endif
2081 				if (echokeys) {
2082 					if (bp > 0 && strcmp("swear", echokey) == 0) {
2083 						char swearkeys[] = "@^!$%?#*";
2084 
2085 						pwbuf[bp - 1] =
2086 							swearkeys[NRAND(strlen(swearkeys))];
2087 						pwbuf[bp] = '\0';
2088 					} else
2089 						(void) memset((char *) pwbuf,
2090 							echokey[0], slen);
2091 					XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2092 						passx, passy - fontAscent,
2093 						XTextWidth(font, pwbuf, slen),
2094 						fontHeight  + 3);
2095 					(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
2096 						passx, passy, pwbuf, bp);
2097 				}
2098 				/* eat all events if there are more than
2099 				   enough pending... this keeps the Xlib event
2100 				   buffer from growing larger than all
2101 				   available memory and crashing xlock. */
2102 				if (XPending(dsp) > 100) {	/* 100 is arbitrarily
2103 								   big enough */
2104 					register Status status;
2105 
2106 					do {
2107 						status = XCheckMaskEvent(dsp,
2108 							KeyPressMask | KeyReleaseMask, &event);
2109 					} while (status);
2110 					XBell(dsp, 100);
2111 				}
2112 				break;
2113 
2114 			case MotionNotify:
2115 				if (!mousemotion)
2116 					break;
2117 				/* fall through on last mouse event */
2118 			case ButtonPress:
2119 				if (((XButtonEvent *) & event)->window == Scr[screen].icon) {
2120 					return 1;
2121 				}
2122 #ifdef USE_BUTTON_LOGOUT
2123 				if (((XButtonEvent *) & event)->window == Scr[screen].button) {
2124 					XSetFunction(dsp, Scr[screen].gc, GXxor);
2125 					XSetForeground(dsp, Scr[screen].gc, Scr[screen].fg_pixel);
2126 					XFillRectangle(dsp, Scr[screen].button, Scr[screen].gc,
2127 						0, 0, 500, 100);
2128 					XSync(dsp, False);
2129 					tried_logout = 1;
2130 					logoutUser(dsp
2131 #ifdef CLOSEDOWN_LOGOUT
2132  , screens
2133 #endif
2134 					);
2135 					XSetFunction(dsp, Scr[screen].gc, GXcopy);
2136 				}
2137 #endif
2138 				break;
2139 
2140 			case Expose:
2141 				if (event.xexpose.count != 0)
2142 					break;
2143 				/* fall through on last expose event */
2144 			case VisibilityNotify:
2145 				/* next line for -geometry */
2146 				if (event.xvisibility.state != VisibilityUnobscured) {
2147 					/* window was restacked or exposed */
2148 #ifndef __CYGWIN__
2149 					if (!debug && !inwindow)
2150 						XRaiseWindow(dsp, event.xvisibility.window);
2151 #endif
2152 					call_refresh_hook((LockStruct *) NULL,
2153 						mode_info(dsp, screen, Scr[screen].window, False));
2154 #ifndef USE_WINDOW_VISIBILITY
2155 					s[0] = '\0';
2156 					return 1;
2157 #endif
2158 				}
2159 				break;
2160 			case ConfigureNotify:
2161 				/* next line for -geometry */
2162 				if (!fullscreen)
2163 					break;
2164 				/* window config changed */
2165 #ifndef __CYGWIN__
2166 				if (!debug && !inwindow) {
2167 					XRaiseWindow(dsp, event.xconfigure.window);
2168 					fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors,
2169 						saturation, mono, install, inroot, inwindow, verbose);
2170 				}
2171 #endif
2172 				if (window_size_changed(screen, Scr[screen].window)) {
2173 					call_init_hook((LockStruct *) NULL,
2174 						mode_info(dsp, screen, Scr[screen].window, False));
2175 				} else if (install)
2176 					/* next line : refresh would be logical. But some modes
2177  					 * look weird when continuing from an erased screen */
2178 					call_refresh_hook((LockStruct *) NULL,
2179 						mode_info(dsp, screen, Scr[screen].window, False));
2180 
2181 				s[0] = '\0';
2182 				return 1;
2183 			case KeymapNotify:
2184 			case KeyRelease:
2185 			case ButtonRelease:
2186 			case LeaveNotify:
2187 			case EnterNotify:
2188 			case NoExpose:
2189 			case CirculateNotify:
2190 			case DestroyNotify:
2191 			case GravityNotify:
2192 			case MapNotify:
2193 			case ReparentNotify:
2194 			case UnmapNotify:
2195 				break;
2196 
2197 			default:
2198 				(void) fprintf(stderr, "%s: unexpected event: %d\n",
2199 					ProgramName, event.type);
2200 				break;
2201 		}
2202 		first_key = 0;
2203 	}
2204 }
2205 #endif
2206 
2207 void
modeDescription(ModeInfo * mi)2208 modeDescription(ModeInfo * mi)
2209 {
2210 	int         left, x, y;
2211 	int         scrn = MI_SCREEN(mi);
2212 	XWindowAttributes xgwa;
2213 
2214 	(void) XGetWindowAttributes(dsp, Scr[scrn].window, &xgwa);
2215 
2216 	x = left = Scr[scrn].iconpos.x;
2217 	y = Scr[scrn].iconpos.y - fontHeight + 8;
2218 
2219 	XSetForeground(dsp, Scr[scrn].gc, Scr[scrn].bg_pixel);
2220 	XFillRectangle(dsp, Scr[scrn].window, Scr[scrn].gc,
2221 		x, y - fontAscent - 4 + screenOffset ,
2222 		xgwa.width - x, fontHeight + 6 + screenOffset);
2223 
2224 	putText(dsp, Scr[scrn].window, Scr[scrn].textgc, MI_NAME(mi),
2225 		True, left, &x, &y);
2226 	putText(dsp, Scr[scrn].window, Scr[scrn].textgc, ": ", True, left, &x, &y);
2227 	putText(dsp, Scr[scrn].window, Scr[scrn].textgc, MI_DESC(mi),
2228 		False, left, &x, &y);
2229 	putText(dsp, Scr[scrn].window, Scr[scrn].textgc, "\n", False, left, &x, &y);
2230 }
2231 
2232 /* WIN32 machines handle reading passwords automatically */
2233 #ifndef WIN32
2234 
2235 static void
update_plan(void)2236 update_plan(void) /* updates current time in plantext */
2237 {
2238 	if (showdate) {
2239 		time_t t;
2240 
2241 		t = time(NULL);
2242 		if (plantext[0] != NULL) {
2243 			(void) strcpy(plantext[0], (char *) ctime(&t));
2244 			plantext[0][strlen(plantext[0]) - 1] = '\0';
2245 		}
2246 	}
2247 }
2248 
2249 static int
getPassword(void)2250 getPassword(void)
2251 {
2252 	XWindowAttributes xgwa;
2253 	int         x, y, left, done, remy;
2254 	char        buffer[PASSLENGTH];
2255 	char      **planp;
2256 	char       *hostbuf = (char *) NULL;
2257 	ModeInfo   *mi = &modeinfo[screen];
2258 	Bool        capsLock = False;
2259 #ifdef USE_MB
2260 	XFontSet    backfontset;
2261 #endif
2262 
2263 #ifdef FX
2264 	Bool        mesa_3Dfx_fullscreen;
2265 	char       *mesa_3Dfx_env;
2266 
2267 	mesa_3Dfx_env = getenv("MESA_GLX_FX");
2268 	if (mesa_3Dfx_env)
2269 		if (tolower(mesa_3Dfx_env[0] == 'f')) {
2270 			/* disabling fullscreen HW 3dfx rendering to
2271 			   allow iconic mode window. */
2272 			mesa_3Dfx_fullscreen = True;
2273 			unsetenv("MESA_GLX_FX");
2274 		}
2275 #endif
2276 #ifdef HAVE_SETPRIORITY
2277 	(void) setpriority(0, 0, 0);
2278 #else /* !HAVE_SETPRIORITY */
2279 	(void) nice(0);
2280 #endif /* HAVE_SETPRIORITY */
2281 	if (!fullscreen)
2282 		XConfigureWindow(dsp, Scr[screen].window, sizeconfiguremask,
2283 			&(Scr[screen].fullsizeconfigure));
2284 
2285 
2286 	(void) XGetWindowAttributes(dsp, Scr[screen].window, &xgwa);
2287 
2288 	ChangeGrabbedCursor(dsp, Scr[screen].window,
2289 			XCreateFontCursor(dsp, XC_left_ptr));
2290 
2291 #ifdef DIRECTCOLOR_FIX
2292 	MI_CLEARWINDOWCOLOR(mi, MI_BLACK_PIXEL(mi));
2293 #else
2294 	MI_CLEARWINDOWCOLOR(mi, Scr[screen].bg_pixel);
2295 #endif
2296 	XMapWindow(dsp, Scr[screen].icon);
2297 	XRaiseWindow(dsp, Scr[screen].icon);
2298 #ifdef DIRECTCOLOR_FIX
2299 	XSetForeground(dsp, Scr[screen].textgc, MI_WHITE_PIXEL(mi));
2300 	XSetForeground(dsp, Scr[screen].plantextgc, MI_WHITE_PIXEL(mi));
2301 #endif
2302 	if (description)
2303 		modeDescription(mi);
2304 
2305 	/* redraw rectangle around icon */
2306 	XDrawRectangle(dsp, Scr[screen].window, Scr[screen].textgc,
2307 		Scr[screen].iconpos.x - 1, Scr[screen].iconpos.y - 1,
2308 		iconwidth + 3, iconheight + 3);
2309 	x = left = Scr[screen].iconpos.x + iconwidth + font->max_bounds.width + 4;
2310 	y = Scr[screen].iconpos.y + fontAscent;
2311 
2312 	if ((hostbuf = (char *) malloc(strlen(user) + strlen(hostname) +
2313 			2)) != NULL) {
2314 #ifdef HAVE_KRB5
2315 		if (krb5_valid) {
2316 			strcpy(hostbuf, user);
2317 		} else
2318 #endif /* HAVE_KRB5 */
2319 		(void) sprintf(hostbuf, "%s@%s", user, hostname);
2320 
2321 		putText(dsp, Scr[screen].window, Scr[screen].textgc, text_user, True, left, &x, &y);
2322 		putText(dsp, Scr[screen].window, Scr[screen].textgc, hostbuf, False, left, &x, &y);
2323 		free(hostbuf);
2324 	}
2325 	if (displayname && displayname[0] != ':') {
2326 		char  *displaybuf = (char *) NULL;
2327 		char  *colon = (char *) strchr(displayname, ':');
2328 		int   n = colon - displayname;
2329 
2330 		if ((displaybuf = (char *) malloc(n + 1)) != NULL) {
2331 			(void) strncpy(displaybuf, displayname, n);
2332 			displaybuf[n] = '\0';
2333 			if (remote && n
2334 					&& strcmp(displaybuf, "unix") != 0
2335 					&& strcmp(displaybuf, "localhost") != 0
2336 					&& strcmp(displaybuf, hostname) != 0) {
2337 				putText(dsp, Scr[screen].window, Scr[screen].textgc, "  Display: ", True, left, &x, &y);
2338 				putText(dsp, Scr[screen].window, Scr[screen].textgc, displaybuf, False, left, &x, &y);
2339 			}
2340 			free(displaybuf);
2341 		}
2342 	}
2343 	putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
2344 
2345 #ifdef GLOBAL_UNLOCK
2346 	putText(dsp, Scr[screen].window, Scr[screen].textgc, text_guser,
2347 		True, left, &x, &y);
2348 	putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
2349 		False, left, &x, &y);
2350 		unamex = x;
2351                 unamey = y;
2352 	putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
2353 #endif
2354 
2355 #ifdef SAFEWORD
2356 	if (checkDynamic()) {
2357 		pb = &pblock;
2358 		(void) memset((char *) &pblock, 0, sizeof (pblock));
2359 #if 0
2360 		(void) strcpy(pblock.uport, "custpb");
2361 		pblock.status = NO_STATUS;
2362 #endif
2363 		challx = x;
2364 		chally = y;
2365 		putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n\n",
2366 			False, left, &x, &y);
2367 		pb->mode = CHALLENGE;
2368 		(void) strcpy(pb->id, user);
2369 		pbmain(pb);
2370 		if (pb->status != GOOD_USER) {
2371 			chall[0] = 0;
2372 			return 1;
2373 		}
2374 		if (pb->dynpwdf) {
2375 			/* We do not really care if they also got a fixed password... */
2376 			putText(dsp, Scr[screen].window, Scr[screen].textgc, text_dpass,
2377 				True, left, &x, &y);
2378 			putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
2379 				False, left, &x, &y);
2380 			passx = x;
2381 			passy = y;
2382 		} else if (pb->fixpwdf) {
2383 			/* In the unlikely event they only got a fixed password... */
2384 			putText(dsp, Scr[screen].window, Scr[screen].textgc, text_fpass,
2385 				True, left, &x, &y);
2386 			putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
2387 				False, left, &x, &y);
2388 			passx = x;
2389 			passy = y;
2390 		}
2391 	} else
2392 #endif
2393 	{
2394 		putText(dsp, Scr[screen].window, Scr[screen].textgc, text_pass, True, left, &x, &y);
2395 		putText(dsp, Scr[screen].window, Scr[screen].textgc, " ", False, left, &x, &y);
2396 
2397 		passx = x;
2398 		passy = y;
2399 	}
2400 
2401 	y += fontHeight + 6;
2402 	if (y < Scr[screen].iconpos.y + iconheight + fontAscent + 14)
2403 		y = Scr[screen].iconpos.y + iconheight + fontAscent + 14;
2404 	x = left = Scr[screen].iconpos.x;
2405 #ifdef HAVE_KRB5
2406 	if (krb5_valid)
2407 		putText(dsp, Scr[screen].window, Scr[screen].textgc, text_krbinfo, False, left, &x, &y);
2408 	else
2409 #endif /* HAVE_KRB5 */
2410 	putText(dsp, Scr[screen].window, Scr[screen].textgc, text_info, False, left, &x, &y);
2411 	putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
2412 	if (count_failed > 0) {
2413 		char * cnt = NULL;
2414 		y += fontHeight + 6;
2415 		if (y < Scr[screen].iconpos.y + iconheight + fontAscent + 14)
2416 			y = Scr[screen].iconpos.y + iconheight + fontAscent + 14;
2417 		x = left = Scr[screen].iconpos.x;
2418 		if ((cnt = (char *) malloc(strlen((count_failed == 1) ? failed_attempt : failed_attempts) + 16)) != NULL) {
2419 			(void) sprintf(cnt, "%d%s", count_failed,
2420 				(count_failed == 1) ? failed_attempt : failed_attempts);
2421 			putText(dsp, Scr[screen].window, Scr[screen].textgc,
2422 				cnt, False, left, &x, &y);
2423 			putText(dsp, Scr[screen].window, Scr[screen].textgc,
2424 				"\n", False, left, &x, &y);
2425 			free(cnt);
2426 			y -= 2 * (fontHeight + 6); /* go up */
2427 		}
2428 	}
2429 	timex = x;
2430 	timey = y;
2431 
2432 #ifdef USE_AUTO_LOGOUT
2433 	if (logoutAuto) {
2434 		y += fontHeight + 2;
2435 	}
2436 #endif
2437 #ifdef USE_BUTTON_LOGOUT
2438 	if (enable_button) {
2439 		y += fontHeight + 2;
2440 	}
2441 #endif
2442 	if (timeelapsed) {
2443 		y += fontHeight + 2;
2444 	}
2445 	remy = y;
2446 
2447 	putText(dsp, Scr[screen].window, Scr[screen].textgc,
2448 		"\n", False, left, &x, &y);
2449 
2450 	update_plan();
2451 #ifdef USE_MB
2452 	backfontset = fontset;
2453 	if (planfontset != NULL)
2454 		fontset = planfontset;
2455 #endif
2456 	if (*plantext) {
2457 		y = Scr[screen].planpos.y;
2458 		for (planp = plantext; *planp; ++planp) {
2459 			int size = strlen(*planp);
2460 
2461 			y += planFontHeight + 2;
2462 			/*printf("%s:%d\n", *planp, strlen(*planp));*/
2463 			(void) XDrawString
2464 				(dsp, Scr[screen].window,
2465 				Scr[screen].plantextgc,
2466 				Scr[screen].planpos.x, y,
2467 				*planp, size);
2468 		}
2469 	}
2470 #ifdef USE_MB
2471 	fontset = backfontset;
2472 #endif
2473 	XFlush(dsp);
2474 
2475 	if (mailCmd && mailCmd[0]) {
2476 #ifdef ORIGINAL_XPM_PATCH
2477 		XpmImage   *mbxpm;
2478 		mailboxInfo *mbi;
2479 		int         x, y;
2480 
2481 		if (system(mailCmd)) {
2482 			mbxpm = nomail_xpmimg;
2483 			mbi = &Scr[screen].mb.nomail;
2484 		} else {
2485 			mbxpm = mail_xpmimg;
2486 			mbi = &Scr[screen].mb.mail;
2487 		}
2488 
2489 		if (mbxpm) {
2490 			x = (DisplayWidth(dsp, screen) - mbxpm->width) / 2;
2491 			y = (Scr[screen].planpos.y - 5) - mbxpm->height;
2492 			XCopyArea(dsp, mbi->pixmap,
2493 				Scr[screen].window, Scr[screen].mb.mbgc,
2494 				0, 0,
2495 				mbxpm->width, mbxpm->height, x, y);
2496 		}
2497 #else
2498 		mailboxInfo *mbi;
2499 		int         mbx, mby;
2500 
2501 		if (system(mailCmd)) {
2502 			mbi = &Scr[screen].mb.nomail;
2503 		} else {
2504 			mbi = &Scr[screen].mb.mail;
2505 		}
2506 		if (mbi) {
2507 			mbx = (DisplayWidth(dsp, screen) - mbi->width) / 2;
2508 			mby = (Scr[screen].planpos.y - 5) - mbi->height;
2509 			XSetTSOrigin(dsp, Scr[screen].mb.mbgc, mbx, mby);
2510 			XSetStipple(dsp, Scr[screen].mb.mbgc, mbi->pixmap);
2511 			XSetFillStyle(dsp, Scr[screen].mb.mbgc, FillOpaqueStippled);
2512 			XFillRectangle(dsp, Scr[screen].window, Scr[screen].mb.mbgc,
2513 				mbx, mby, mbi->width, mbi->height);
2514 		}
2515 #endif
2516 	}
2517 	done = False;
2518 	while (!done) {
2519 #ifdef USE_SOUND
2520 		if (sound && !got_invalid) {
2521 			playSound(infosound, verbose);
2522 		}
2523 		got_invalid = 0;
2524 #endif
2525 
2526 #ifdef SAFEWORD
2527 		pb->mode = CHALLENGE;
2528 		(void) strcpy(pb->id, user);
2529 		pbmain(pb);
2530 		if (pb->status != GOOD_USER) {
2531 			chall[0] = 0;
2532 			return 1;
2533 		}
2534 		left = x = challx;
2535 		y = chally;
2536 		if (strlen(pb->chal) > 0) {
2537 			(void) strcpy(chall, pb->chal);
2538 			putText(dsp, Scr[screen].window, Scr[screen].textgc, text_chall,
2539 				True, left, &x, &y);
2540 			putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
2541 				False, left, &x, &y);
2542 			XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2543 				left + XTextWidth(font, text_chall, strlen(text_chall)),
2544 				y - fontAscent, XTextWidth(font, chall, strlen(chall)),
2545 				fontHeight +  5);
2546 
2547 			putText(dsp, Scr[screen].window, Scr[screen].textgc, chall,
2548 				False, left, &x, &y);
2549 		}
2550 		putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n",
2551 			False, left, &x, &y);
2552 		if (pb->dynpwdf || pb->fixpwdf) {
2553 			/* If they have a dynamic passwd we do not really care about
2554 			   the fixed password... */
2555 			putText(dsp, Scr[screen].window, Scr[screen].textgc,
2556 				(pb->dynpwdf) ? text_dpass : text_fpass,
2557 				True, left, &x, &y);
2558 			putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
2559 				False, left, &x, &y);
2560 			passx = x;
2561 			passy = y;
2562 		}
2563 #endif
2564 
2565 #ifdef GLOBAL_UNLOCK
2566 		if (ReadXString(global_user, PASSLENGTH, (Bool *) NULL, False))
2567 			break;
2568 		(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
2569 			unamex, unamey,
2570 			global_user, strlen(global_user));
2571 		checkUser(global_user);
2572 #endif
2573 		if (ReadXString(buffer, PASSLENGTH, &capsLock
2574 #ifdef GLOBAL_UNLOCK
2575 			, True
2576 #elif defined( USE_PAM )
2577 			, False
2578 #endif
2579 			))
2580 			break;
2581 		y = remy + 6;
2582 #ifdef DIRECTCOLOR_FIX
2583 		XSetForeground(dsp, Scr[screen].gc, MI_BLACK_PIXEL(mi));
2584 #else
2585 		XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
2586 #endif
2587 #ifdef SAFEWORD
2588 		(void) strcpy(pb->dynpwd, buffer);
2589 		pb->mode = EVALUATE_ALL;
2590 		pbmain(pb);
2591 
2592 		done = (pb->status == PASS || pb->status == PASS_MASTER);
2593 		pb->mode = UPDATE_LOGS;
2594 		pbmain(pb);
2595 #else
2596 		{
2597 			XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2598 				Scr[screen].iconpos.x, y - fontAscent + screenOffset,
2599 				2 * XTextWidth(font, text_invalidCapsLock, strlen(text_invalidCapsLock)),
2600 				fontHeight +  5 + screenOffset);
2601 		}
2602 
2603 		(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
2604 			Scr[screen].iconpos.x, y, text_valid, strlen(text_valid));
2605 		XFlush(dsp);
2606 
2607 		done = checkPasswd(buffer);
2608 
2609 		if (!done && !*buffer) {
2610 			/* just hit return, and it was not his password */
2611 			/* count_failed++; */  /* not really an attempt, is it? */
2612 			break;
2613 		} else if (!done) {
2614 			/* bad password... log it... */
2615 			count_failed++;
2616 #if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
2617 			(void) printf("failed unlock attempt on user %s\n", user);
2618 			syslog(SYSLOG_NOTICE, "%s: failed unlock attempt on user %s\n",
2619 				ProgramName, user);
2620 #endif
2621 		}
2622 #endif
2623 
2624 #ifndef VMS
2625                 if (done && pipepassCmd && pipepassCmd[0]) {
2626                         FILE *f;
2627                         if ((f = (FILE *) popen(pipepassCmd, "w"))) {
2628                                 /* avoid stdio for this since we don't want to leave
2629                                    the plaintext password in memory */
2630                                 char *p = buffer;
2631                                 int len = strlen(buffer);
2632 
2633                                 while (len > 0) {
2634                                         int wrote = write(fileno(f), p, len);
2635                                         if (wrote <= 0) break;
2636                                         len -= wrote;
2637                                         p   += wrote;
2638                                 }
2639                                 (void) pclose(f);
2640                         }
2641                 }
2642 #endif
2643 		/* clear plaintext password so you can not grunge around
2644 		   /dev/kmem */
2645 		(void) memset((char *) buffer, 0, sizeof (buffer));
2646 
2647 		if (done) {
2648 #ifdef USE_SOUND
2649 			if (sound)
2650 				playSound(validsound, verbose);
2651 #endif
2652 			XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2653 				Scr[screen].iconpos.x, y - fontAscent + screenOffset,
2654 				2 * XTextWidth(font, text_invalidCapsLock, strlen(text_invalidCapsLock)),
2655 				fontHeight +  5 + screenOffset);
2656 
2657 			(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
2658 				Scr[screen].iconpos.x, y, text_valid, strlen(text_valid));
2659 			XFlush(dsp);
2660 
2661 			if (!fullscreen)
2662 				XConfigureWindow(dsp, Scr[screen].window, sizeconfiguremask,
2663 					&minisizeconfigure);
2664 			return 0;
2665 		} else {
2666 			char *textInvalid = (capsLock) ? text_invalidCapsLock :
2667 				text_invalid;
2668 
2669 			XSync(dsp, True);	/* flush input buffer */
2670 			(void) sleep(1);
2671 			XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2672 				Scr[screen].iconpos.x, y - fontAscent + screenOffset,
2673 				XTextWidth(font, text_valid, strlen(text_valid)),
2674 				fontHeight +  8 + screenOffset);
2675 			(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
2676 				Scr[screen].iconpos.x, y, textInvalid, strlen(textInvalid));
2677 			if (echokeys)	/* erase old echo */
2678 				XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2679 					passx, passy - fontAscent,
2680 					xgwa.width - passx,
2681 					fontHeight +  3);
2682 			XSync(dsp, True);	/* flush input buffer */
2683 			(void) sleep(1);
2684 			XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
2685 				Scr[screen].iconpos.x, y - fontAscent + screenOffset,
2686 				XTextWidth(font, textInvalid, strlen(textInvalid)),
2687 				fontHeight +  5 + screenOffset);
2688 	if (count_failed > 0) {
2689 		char * cnt = NULL;
2690 		y += fontHeight + 6;
2691 		if (y < Scr[screen].iconpos.y + iconheight + fontAscent + 14)
2692 			y = Scr[screen].iconpos.y + iconheight + fontAscent + 14;
2693 		x = left = Scr[screen].iconpos.x;
2694 		if ((cnt = (char *) malloc(strlen((count_failed == 1) ? failed_attempt : failed_attempts) + 16)) != NULL) {
2695 			(void) sprintf(cnt, "%d%s", count_failed,
2696 				(count_failed == 1) ? failed_attempt : failed_attempts);
2697 				putText(dsp, Scr[screen].window, Scr[screen].textgc,
2698 					cnt, False, left, &x, &y);
2699 				putText(dsp, Scr[screen].window, Scr[screen].textgc,
2700 					"\n", False, left, &x, &y);
2701 				free(cnt);
2702 		}
2703 	}
2704 
2705 #ifdef USE_SOUND
2706 			if (sound)
2707 				playSound(invalidsound, verbose);
2708 			got_invalid = 1;
2709 #endif
2710 		}
2711 	}
2712 
2713 	ChangeGrabbedCursor(dsp, Scr[screen].window, mycursor);
2714 	XUnmapWindow(dsp, Scr[screen].icon);
2715 #ifdef USE_BUTTON_LOGOUT
2716 	XUnmapWindow(dsp, Scr[screen].button);
2717 #endif
2718 	if (!fullscreen)
2719 		XConfigureWindow(dsp, Scr[screen].window, sizeconfiguremask,
2720 				&minisizeconfigure);
2721 #ifdef HAVE_SETPRIORITY
2722 	(void) setpriority(0, 0, nicelevel);
2723 #else /* !HAVE_SETPRIORITY */
2724 	(void) nice(nicelevel);
2725 #endif /* HAVE_SETPRIORITY */
2726 #ifdef FX
2727 	if (mesa_3Dfx_fullscreen)
2728 		setenv("MESA_GLX_FX", "fullscreen", 0);
2729 #endif
2730 	return 1;
2731 }
2732 
2733 static int
event_screen(Display * display,Window event_win)2734 event_screen(Display * display, Window event_win)
2735 {
2736 	int         i;
2737 
2738 	for (i = startscreen; i < screens; i++) {
2739 		if (event_win == RootWindow(display, i)) {
2740 			return (i);
2741 		}
2742 	}
2743 	return (0);
2744 }
2745 
2746 static int
justDisplay(Display * display)2747 justDisplay(Display * display)
2748 {
2749 	int         timetodie = False;
2750 	int         not_done = True;
2751 	XEvent      event;
2752 
2753 #ifdef USE_VTLOCK
2754         /* EL - RCS : lock VT switching */
2755 	/*
2756 	 * I think it has to be done here or 'switch/restore' modes won't
2757          * ever be useful!
2758 	 */
2759         if (!nolock && vtlock && !vtlocked)
2760                 dovtlock();
2761 #endif
2762 
2763 	for (screen = startscreen; screen < screens; screen++) {
2764 		call_init_hook((LockStruct *) NULL,
2765 			mode_info(display, screen, Scr[screen].window, False));
2766 	}
2767 
2768 	while (not_done) {
2769 		while (!XPending(display)) {
2770 #ifdef USE_OLD_EVENT_LOOP
2771 			(void) usleep(delay);
2772 			for (screen = startscreen; screen < screens; screen++)
2773 				call_callback_hook((LockStruct *) NULL,
2774 					mode_info(display, screen, Scr[screen].window, False));
2775 #ifdef USE_AUTO_LOGOUT
2776 			checkLogout(display);
2777 #endif
2778 			XSync(display, False);
2779 #else /* !USE_OLD_EVENT_LOOP */
2780 #ifdef USE_AUTO_LOGOUT
2781 			if (runMainLoop(30, -1) == 0)
2782 				break;
2783 			checkLogout(display);
2784 #else
2785 			(void) runMainLoop(0, -1);
2786 #endif
2787 #endif /* !USE_OLD_EVENT_LOOP */
2788 		}
2789 		(void) XNextEvent(display, &event);
2790 		/*
2791 		 * This event handling code should be unified with the
2792 		 * similar code in ReadXString().
2793 		 */
2794 		switch (event.type) {
2795 			case Expose:
2796 				if (event.xexpose.count != 0) {
2797 					break;
2798 				}
2799 				/* fall through on last expose event of the series */
2800 
2801 			case VisibilityNotify:
2802 #ifndef __CYGWIN__
2803 				if (!debug && !inwindow) {
2804 					XRaiseWindow(display, event.xany.window);
2805 				}
2806 #endif
2807 				for (screen = startscreen; screen < screens; screen++) {
2808 					call_refresh_hook((LockStruct *) NULL,
2809 						mode_info(display, screen, Scr[screen].window, False));
2810 				}
2811 				break;
2812 
2813 			case ConfigureNotify:
2814 #ifndef __CYGWIN__
2815 				if (!debug && !inwindow) {
2816 					XRaiseWindow(display, event.xconfigure.window);
2817 				}
2818 #endif
2819 				for (screen = startscreen; screen < screens; screen++) {
2820 					if (install)
2821 						fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors, saturation,
2822 							mono, install, inroot, inwindow, verbose);
2823 					if (window_size_changed(screen, Scr[screen].window)) {
2824 						call_init_hook((LockStruct *) NULL,
2825 							mode_info(display, screen, Scr[screen].window, False));
2826 					} else if (install)
2827 						/* next line : refresh would be logical. But some modes
2828 						 * look weird when continuing from an erased screen */
2829 						call_refresh_hook((LockStruct *) NULL,
2830 							mode_info(display, screen, Scr[screen].window, False));
2831 				}
2832 				break;
2833 
2834 			case ButtonPress:
2835 				if (event.xbutton.button == Button2) {
2836 					/* call change hook only for clicked window? */
2837 					for (screen = startscreen; screen < screens; screen++) {
2838 						call_change_hook((LockStruct *) NULL,
2839 							mode_info(display, screen, Scr[screen].window,
2840 							False));
2841 					}
2842 				} else {
2843 					screen = event_screen(display, event.xbutton.root);
2844 					not_done = False;
2845 				}
2846 				break;
2847 
2848 			case MotionNotify:
2849 				if (mousemotion) {
2850 					screen = event_screen(display, event.xmotion.root);
2851 					not_done = False;
2852 				}
2853 				break;
2854 
2855 			case KeyPress:
2856 				screen = event_screen(display, event.xkey.root);
2857 				not_done = False;
2858 				break;
2859 		}
2860 
2861 		if (!nolock)
2862 		{
2863 		    if (lock_delay && (lock_delay <= (int) (seconds() - start_time))) {
2864 				timetodie = True;
2865 				/* not_done = False; */
2866 		    }
2867 		    else if (unlockdelay && (unlockdelay > (int) (seconds() - start_time)))
2868 		    {
2869 				not_done = True;
2870 		    }
2871 		}
2872 	}
2873 
2874 	/* KLUDGE SO TVTWM AND VROOT WILL NOT MAKE XLOCK DIE */
2875 	if (screen >= screens)
2876 		screen = startscreen;
2877 
2878 	lock_delay = False;
2879 	if (usefirst)
2880 		(void) XPutBackEvent(display, &event);
2881 	return timetodie;
2882 }
2883 
2884 #ifdef __cplusplus
2885 extern "C" {
2886 #endif
2887 
2888 static void
sigcatch(int signum)2889 sigcatch(int signum)
2890 {
2891 #ifndef WIN32
2892 	ModeInfo   *mi = mode_info(dsp, startscreen, Scr[startscreen].window, False);
2893 	const char *name = (mi == NULL) ? "unknown" : MI_NAME(mi);
2894 
2895 	finish(dsp, True);
2896 	(void) sprintf(error_buf,
2897 		"Access control list restored.\n%s: caught signal %d while running %s mode (uid %ld).\n",
2898 		(strlen(ProgramName) < ERROR_BUF - 2 * ERROR_LINE) ?
2899 		ProgramName: DEFAULT_NAME, signum,
2900 		(strlen(ProgramName) + strlen(name) <
2901 		ERROR_BUF - 2 * ERROR_LINE) ?  name: "?", (long) getuid());
2902 	error_exitcode = -signum;
2903 	error(error_buf);
2904 #endif /* !WIN32 */
2905 }
2906 
2907 #ifdef __cplusplus
2908 }
2909 #endif
2910 
2911 static void
lockDisplay(Display * display,Bool do_display)2912 lockDisplay(Display * display, Bool do_display)
2913 {
2914 #ifdef USE_VTLOCK
2915 	/* EL - RCS : lock VT switching */
2916 	if (!nolock && vtlock && !vtlocked)
2917 		dovtlock();
2918 #endif
2919 #if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
2920 	syslogStart();
2921 #endif
2922 #ifdef USE_SOUND
2923 	if (sound && !inwindow && !inroot && !lockdelay)
2924 		playSound(locksound, verbose);
2925 #endif
2926 	if (!allowaccess) {
2927 #if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 ) || defined( __CYGWIN__ ) || defined( __linux__ )
2928 		sigset_t    oldsigmask;
2929 		sigset_t    newsigmask;
2930 
2931 		(void) sigemptyset(&newsigmask);
2932 #ifndef DEBUG
2933 		(void) sigaddset(&newsigmask, SIGHUP);
2934 #endif
2935 		(void) sigaddset(&newsigmask, SIGINT);
2936 		(void) sigaddset(&newsigmask, SIGQUIT);
2937 		(void) sigaddset(&newsigmask, SIGTERM);
2938 		(void) sigprocmask(SIG_BLOCK, (sigset_t *)&newsigmask, (sigset_t *)&oldsigmask);
2939 #else
2940 		int         oldsigmask;
2941 
2942 #ifndef VMS
2943 		oldsigmask = sigblock(
2944 #ifndef DEBUG
2945 					sigmask(SIGHUP) |
2946 #endif
2947 					sigmask(SIGINT) |
2948 					sigmask(SIGQUIT) |
2949 					sigmask(SIGTERM));
2950 #endif
2951 #endif
2952 
2953 		/* (void (*)(int)) sigcatch */
2954 #ifndef DEBUG
2955 		(void) signal(SIGHUP, sigcatch);
2956 #endif
2957 		(void) signal(SIGINT, sigcatch);
2958 		(void) signal(SIGQUIT, sigcatch);
2959 		(void) signal(SIGTERM, sigcatch);
2960 		/* we should trap ALL signals, especially the deadly ones */
2961 		(void) signal(SIGSEGV, sigcatch);
2962 		(void) signal(SIGBUS, sigcatch);
2963 		(void) signal(SIGFPE, sigcatch);
2964 
2965 		if (grabserver)
2966 			XGrabServer(display);
2967 		XGrabHosts(display);
2968 
2969 #if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 ) || defined( __CYGWIN__ ) || defined( __linux__ )
2970 		(void) sigprocmask(SIG_SETMASK, &oldsigmask, &oldsigmask);
2971 #else
2972 		(void) sigsetmask(oldsigmask);
2973 #endif
2974 	}
2975 #if defined( __hpux ) || defined( __apollo )
2976 	XHPDisableReset(display);
2977 #endif
2978 	do {
2979 		if (do_display)
2980 			(void) justDisplay(display);
2981 		else
2982 			do_display = True;
2983 	} while (getPassword());
2984 #if defined( __hpux ) || defined( __apollo )
2985 	XHPEnableReset(display);
2986 #endif
2987 }
2988 
2989 static void
read_plan(void)2990 read_plan(void)
2991 {
2992 	FILE       *planf = (FILE *) NULL;
2993 	char        buf[121];
2994 	const char *home = getenv("HOME");
2995 	char       *buffer;
2996 	int         i, j, len = 0;
2997 
2998 	if (!home)
2999 		home = "";
3000 
3001 	if ((buffer = (char *) malloc(
3002 #if ( __VMS_VER >= 70000000 )
3003 	255
3004 
3005 #else
3006 	strlen(home) + 32
3007 
3008 #endif
3009 	)) == NULL) {
3010 		error("low memory for plan");
3011 	}
3012 
3013 #ifdef VMS
3014 	(void) sprintf(buffer, "%s%s", home, ".xlocktext");
3015 #else
3016 	(void) sprintf(buffer, "%s/%s", home, ".xlocktext");
3017 #endif
3018 	planf = my_fopen(buffer, "r");
3019 	if (planf == NULL) {
3020 #ifdef VMS
3021 		(void) sprintf(buffer, "%s%s", home, ".plan");
3022 #else
3023 		(void) sprintf(buffer, "%s/%s", home, ".plan");
3024 #endif
3025 		planf = my_fopen(buffer, "r");
3026 	}
3027 	if (planf == NULL) {
3028 #ifndef VMS
3029 		(void) sprintf(buffer, "%s/%s", home, ".signature");
3030 #else
3031 #if ( __VMS_VER >= 70000000 )
3032 /* Get signature file for VMS 7.0 and higher */
3033 		char       *buffer1;
3034 		unsigned int ival;
3035 		unsigned long int mail_context = 0;
3036 		unsigned short int buflen, buflen1;
3037 		struct itmlst_3 item[2], itm_d[1];
3038 
3039 		if ((buffer1 = (char *) malloc(256)) == NULL) {
3040 			error("low memory for signature");
3041 		}
3042 		itm_d[0].buflen = 0;
3043 		itm_d[0].itmcode = 0;
3044 		item[0].buflen = 255;
3045 		item[0].itmcode = MAIL$_USER_SIGFILE;
3046 		item[0].bufadr = buffer1;
3047 		item[0].retlen = &buflen1;
3048 		item[1].buflen = 255;
3049 		item[1].itmcode = MAIL$_USER_FULL_DIRECTORY;
3050 		item[1].bufadr = buffer;
3051 		item[1].retlen = &buflen;
3052 		item[2].buflen = 0;
3053 		item[2].itmcode = 0;
3054 		ival = mail$user_begin(&mail_context, itm_d, item);
3055 		(void) mail$user_end(&mail_context, itm_d, itm_d);
3056 		(void) strncat(buffer, buffer1, buflen1);
3057 		free(buffer1);
3058 #else
3059 		(void) sprintf(buffer, "%s%s", home, ".signature");
3060 #endif
3061 #endif
3062 		planf = my_fopen(buffer, "r");
3063 	}
3064 	if ((plantext[0] = (char *) malloc(30)) == NULL) {
3065 		/* this is for the current time */
3066 		error("low memory for plan");
3067 	} else {
3068 		plantext[0][0] = '\0';
3069 	}
3070 	if (planf != NULL) {
3071 		for (i = 0; i < TEXTLINES; i++) {
3072 			if (fgets(buf, 120, planf) && (len = strlen(buf)) > 0) {
3073 				if (buf[len - 1] == '\n') {
3074 					buf[--len] = '\0';
3075 				}
3076 				/* this expands tabs to 8 spaces */
3077 				for (j = 0; j < len; j++) {
3078 					if (buf[j] == '\t') {
3079 						int         k, tab = 8 - (j % 8);
3080 
3081 						for (k = 120 - tab; k > j; k--) {
3082 							buf[k + tab - 1] = buf[k];
3083 						}
3084 						for (k = j; k < j + tab; k++) {
3085 							buf[k] = ' ';
3086 						}
3087 						len += tab;
3088 						if (len > 120)
3089 							len = 120;
3090 					}
3091 				}
3092 
3093 				if ((plantext[i + 1] = (char *) malloc(strlen(buf) + 1)) == NULL) {
3094 					error("low memory for plan");
3095 				}
3096 				(void) strcpy(plantext[i + 1], buf);
3097 			}
3098 		}
3099 		plantext[i + 1] = (char *) NULL;
3100 		(void) fclose(planf);
3101 	} else {
3102 		plantext[1] = (char *) NULL;
3103 	}
3104 	free(buffer);
3105 	buffer = (char *) NULL;
3106 }
3107 #endif /* !WIN32 */
3108 
3109 #ifdef USE_MB
3110 static      XFontSet
createFontSet(Display * display,char * name)3111 createFontSet(Display * display, char *name)
3112 {
3113 	XFontSet    xfs;
3114 	char       **miss, *def;
3115 	int         miss_count;
3116 
3117 #define DEF_FONTSET2 "fixed,-*-14-*"
3118 
3119 	if ((xfs = XCreateFontSet(display, name, &miss, &miss_count, &def)) == NULL) {
3120 		(void) fprintf(stderr, "Could not create FontSet %s\n", name);
3121 		if ((xfs = XCreateFontSet(display, DEF_FONTSET2, &miss, &miss_count, &def)) == NULL)
3122 			(void) fprintf(stderr, "Could not create FontSet %s\n", DEF_FONTSET2);
3123 	}
3124 #if 0
3125 /* This needs to be freed but this way is invalid */
3126 	if (miss != NULL) {
3127 		int i;
3128 		for (i = 0; i < sizeof(miss); i++)
3129 			free(miss[i]);
3130 		free(miss);
3131 	}
3132 #endif
3133 	return xfs;
3134 }
3135 #endif
3136 
3137 #ifndef WIN32
3138 
3139 #ifdef __cplusplus
3140 extern "C" {
3141 #endif
3142 
3143 static void SigUsr2(int sig);
3144 
3145 static void
SigUsr1(int sig)3146 SigUsr1(int sig)
3147 {
3148 #ifdef DEBUG
3149 	(void) printf("Signal %d received\n", sig);
3150 #endif
3151 	signalUSR1 = 1;
3152 	signalUSR2 = 0;
3153 
3154 	(void) signal(SIGUSR1, SigUsr1);
3155 	(void) signal(SIGUSR2, SigUsr2);
3156 }
3157 
3158 static void
SigUsr2(int sig)3159 SigUsr2(int sig)
3160 {
3161 #ifdef DEBUG
3162 	(void) printf("Signal %d received\n", sig);
3163 #endif
3164 	signalUSR1 = 0;
3165 	signalUSR2 = 1;
3166 
3167 	(void) signal(SIGUSR1, SigUsr1);
3168 	(void) signal(SIGUSR2, SigUsr2);
3169 }
3170 
3171 #ifdef __cplusplus
3172 }
3173 #endif
3174 
3175 int
main(int argc,char ** argv)3176 main(int argc, char **argv)
3177 {
3178 	XSetWindowAttributes xswa;
3179 	XGCValues   xgcv;
3180 	XColor      nullcolor;
3181 	uid_t       ruid;
3182 	pid_t       cmd_pid = 0;
3183 #ifdef USE_XINERAMA
3184 	int         xinerama_evtbase;
3185 	int         xinerama_errbase;
3186 	int         xinerama_nscreens;
3187 	XineramaScreenInfo *xinerama_info = NULL;
3188 #endif
3189 
3190 #if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 )
3191 	static sigset_t old_sigmask;
3192 
3193 #else
3194 	static int  old_sigmask;
3195 
3196 #endif
3197 
3198 #if ultrix
3199 	extern gid_t rgid;
3200 
3201 #else
3202 	gid_t       rgid;
3203 
3204 #endif
3205 #if defined( HAVE_SETEUID ) || defined( HAVE_SETREUID )
3206 	uid_t       euid;
3207 
3208 #if ultrix
3209 	extern gid_t egid;
3210 
3211 #else
3212 	gid_t       egid;
3213 
3214 #endif
3215 #endif
3216 
3217 #ifdef USE_MB
3218 	setlocale(LC_ALL, "");
3219 #endif
3220 
3221 	(void) signal(SIGUSR1, SigUsr1);
3222 	(void) signal(SIGUSR2, SigUsr2);
3223 
3224 #if defined( __FreeBSD__ ) && !defined( DEBUG )
3225 	/* do not exit on FPE */
3226 	fpsetmask(0);
3227 #endif
3228 
3229 #ifdef OSF1_ENH_SEC
3230 	set_auth_parameters(argc, argv);
3231 #endif
3232 
3233 	ruid = getuid();
3234 	rgid = getgid();
3235 #ifdef HAVE_SETEUID
3236 	/* save effective uid and gid for later */
3237 	euid = geteuid();
3238 	egid = getegid();
3239 
3240 	/* revoke root privs temporarily, to get the correct .Xauthority */
3241 	(void) setegid(rgid);
3242 	(void) seteuid(ruid);
3243 #else
3244 #ifdef HAVE_SETREUID
3245 	/* save effective uid and gid for later */
3246 	euid = geteuid();
3247 	egid = getegid();
3248 
3249 	/* revoke root privs temporarily, to get the correct .Xauthority */
3250 	(void) setregid(egid, rgid);
3251 	(void) setreuid(euid, ruid);
3252 
3253 #endif
3254 #endif
3255 
3256 	ProgramName = strrchr(argv[0], '/');
3257 	if (ProgramName)
3258 		ProgramName++;
3259 	else
3260 		ProgramName = argv[0];
3261 
3262 	start_time = seconds();
3263 #ifdef DEBUG
3264 	ProgramPID = getpid();	/* for memcheck.c */
3265 #endif
3266 #if 1
3267 	SRAND((long) start_time);	/* random mode needs the seed set. */
3268 #else
3269 	SRAND((long) ProgramPID);
3270 #endif
3271 
3272 	getResources(&dsp, argc, argv);
3273 
3274 #ifdef HAVE_SETEUID
3275 	/* become root to get the password */
3276 	(void) setegid(egid);
3277 	(void) seteuid(euid);
3278 #else
3279 #ifdef HAVE_SETREUID
3280 	/* become root to get the password */
3281 	(void) setregid(rgid, egid);
3282 	(void) setreuid(ruid, euid);
3283 
3284 #endif
3285 #endif
3286 
3287 	initPasswd();
3288 
3289 /* revoke root privs, if there were any */
3290 #ifdef ultrix
3291 /*-
3292  * Potential security problem on ultrix
3293  * Here's the problem.  Later on you need setgid to a root group to
3294  * use the crypt program.  I do not want to keep the password in memory.
3295  * That means other parts will be running setgid as well.
3296  */
3297 
3298 #if 1
3299 	/* Change 1 to 0 */
3300 #error	UNTESTED CODE, COMMENT OUT AND SEE IF IT WORKS, PLEASE GET BACK TO ME
3301 #endif
3302 
3303 #ifdef HAVE_SETEUID
3304 	/* Lets try to dampen it a bit */
3305 	(void) setegid(rgid);
3306 
3307 #else
3308 #ifdef HAVE_SETREUID
3309 	(void) setregid(egid, rgid);
3310 
3311 #else
3312 	(void) setgid(rgid);	/* Forget it */
3313 
3314 #endif
3315 #endif
3316 #else
3317 #ifdef BAD_PAM
3318 /* BAD_PAM must have root access to authenticate against shadow passwords */
3319       (void) seteuid(ruid);
3320 /* for BAD_PAM to use shadow passwords, must call seteuid() later */
3321 /* this prevent xlock from dropping privileges when using PAM modules, */
3322 /* that needs root rights (pam_unix e.g.) */
3323 #else
3324 
3325 #ifdef USE_VTLOCK
3326 	/* In order to lock VT switch we must issue an ioctl on console */
3327 	/* (VT_LOCKSWITCH). This ioctl MUST be issued by root. */
3328 	/* We need later to be able to do another seteuid(0), so let's */
3329 	/* disable the overwrite of saved uid/gid */
3330 
3331 	if (!vtlock)
3332 #endif
3333 	{
3334 		(void) setgid(rgid);
3335 		(void) setuid(ruid);
3336 	}
3337 #endif
3338 #endif
3339 
3340 #ifdef SYNCHRONIZE
3341 	/* synchronize -- so I am aware of errors immediately */
3342 	/* Too slow only for debugging */
3343 	(void) printf("DEBUGGING: XSynchronize version\n");
3344 	XSynchronize(dsp, True);
3345 #endif
3346 
3347 #ifdef USE_MB
3348 	fontset = createFontSet(dsp, fontsetname);
3349 	if (fontset == NULL) {
3350 		(void) sprintf(error_buf,
3351 			"%s: can not create fonset %s!!!\n",
3352 			(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
3353 			ProgramName : DEFAULT_NAME,
3354 			(strlen(ProgramName) + strlen(fontsetname) < ERROR_BUF - ERROR_LINE) ?
3355 			fontsetname: "a font");
3356 		error(error_buf);
3357 	}
3358 	XmbTextExtents(fontset, "Aj", 1, NULL, &mbRect);
3359 	planfontset = createFontSet(dsp, planfontsetname);
3360 	XmbTextExtents(planfontset, "Aj", 1, NULL, &planmbRect);
3361 #endif
3362 	checkResources();
3363 
3364 	font = XLoadQueryFont(dsp, fontname);
3365 	if (font == NULL) {
3366 		(void) fprintf(stderr, "%s: can not find font: %s, using %s...\n",
3367 			ProgramName, fontname, FALLBACK_FONTNAME);
3368 		font = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
3369 		if (font == NULL) {
3370 			(void) sprintf(error_buf,
3371 				"%s: can not even find %s!!!\n",
3372 				(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
3373 				ProgramName : DEFAULT_NAME,
3374 				(strlen(ProgramName) + strlen(FALLBACK_FONTNAME) < ERROR_BUF - ERROR_LINE) ?
3375 				FALLBACK_FONTNAME: "a font");
3376 			error(error_buf);
3377 		}
3378 	} {
3379 		int         flags, x, y;
3380 		unsigned int w, h;
3381 
3382 #ifdef FX
3383 		if (!glgeometry || !*glgeometry) {
3384 			glwidth = DEF_GLW;
3385 			glheight = DEF_GLH;
3386 		} else {
3387 			flags = XParseGeometry(glgeometry, &x, &y, &w, &h);
3388 			glwidth = flags & WidthValue ? w : DEF_GLW;
3389 			glheight = flags & HeightValue ? h : DEF_GLH;
3390 			if (glwidth < MINICONW)
3391 				glwidth = MINICONW;
3392 			if (glheight < MINICONH)
3393 				glheight = MINICONH;
3394 		}
3395 #endif
3396 		if (!icongeometry || !*icongeometry) {
3397 			iconwidth = DEF_ICONW;
3398 			iconheight = DEF_ICONH;
3399 		} else {
3400 			flags = XParseGeometry(icongeometry, &x, &y, &w, &h);
3401 			iconwidth = flags & WidthValue ? w : DEF_ICONW;
3402 			iconheight = flags & HeightValue ? h : DEF_ICONH;
3403 			if (iconwidth < MINICONW)
3404 				iconwidth = MINICONW;
3405 			else if (iconwidth > MAXICONW)
3406 				iconwidth = MAXICONW;
3407 			if (iconheight < MINICONH)
3408 				iconheight = MINICONH;
3409 			else if (iconheight > MAXICONH)
3410 				iconheight = MAXICONH;
3411 		}
3412 		if (!geometry || !*geometry) {
3413 			fullscreen = True;
3414 		} else {
3415 			flags = XParseGeometry(geometry, &x, &y, &w, &h);
3416 			if (w < MINICONW)
3417 				w = MINICONW;
3418 			if (h < MINICONH)
3419 				h = MINICONH;
3420 			minisizeconfigure.x = flags & XValue ? x : 0;
3421 			minisizeconfigure.y = flags & YValue ? y : 0;
3422 			minisizeconfigure.width = flags & WidthValue ? w : iconwidth;
3423 			minisizeconfigure.height = flags & HeightValue ? h : iconheight;
3424 		}
3425 	}
3426 
3427 	planfont = XLoadQueryFont(dsp, planfontname);
3428 	if (planfont == NULL) {
3429 		(void) fprintf(stderr, "%s: can't find font: %s, using %s...\n",
3430 			ProgramName, planfontname, FALLBACK_FONTNAME);
3431 		planfont = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
3432 		if (planfont == NULL) {
3433 			(void) sprintf(error_buf,
3434 				"%s: can not even find %s!!!\n",
3435 				(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
3436 				ProgramName : DEFAULT_NAME,
3437 				(strlen(ProgramName) + strlen(FALLBACK_FONTNAME) < ERROR_BUF - ERROR_LINE) ?
3438 				FALLBACK_FONTNAME: "a font");
3439 			error(error_buf);
3440 		}
3441 	}
3442 	read_plan();
3443 	update_plan();
3444 
3445 	screens = ScreenCount(dsp);
3446 	if (((modeinfo = (ModeInfo *) calloc(screens,
3447 			sizeof (ModeInfo))) == NULL) ||
3448 		((Scr = (ScreenInfo *) calloc(screens,
3449 			sizeof (ScreenInfo))) == NULL)) {
3450 		error("low memory for info");
3451 	}
3452 
3453 #ifdef FORCESINGLE
3454 	/* Safer to keep this after the calloc in case ScreenCount is used */
3455 	startscreen = DefaultScreen(dsp);
3456 	screens = startscreen + 1;
3457 #endif
3458 
3459 #if defined( USE_ESOUND )
3460         sound = (sound && (init_sound() != -1));
3461 #endif
3462 
3463 #ifdef USE_XINERAMA
3464 	if (XineramaQueryExtension(dsp, &xinerama_evtbase, &xinerama_errbase))
3465 		xinerama_info = XineramaQueryScreens(dsp, &xinerama_nscreens);
3466 #endif
3467 
3468 #ifdef USE_DTSAVER
3469 	/* The CDE Session Manager provides the windows for the screen saver
3470 	   to draw into. */
3471 	if (dtsaver) {
3472 		Window     *saver_wins;
3473 		int         num_wins;
3474 		int         this_win;
3475 		int         this_screen;
3476 		XWindowAttributes xgwa;
3477 
3478 
3479 		/* Get the list of requested windows */
3480 		if (!DtSaverGetWindows(dsp, &saver_wins, &num_wins)) {
3481 			(void) sprintf(error_buf,
3482 				"%s: Unable to get screen saver info.\n",
3483 				(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
3484 				ProgramName : DEFAULT_NAME);
3485 			error(error_buf);
3486 		}
3487 		for (this_win = 0; this_win < num_wins; this_win++) {
3488 			(void) XGetWindowAttributes(dsp, saver_wins[this_win], &xgwa);
3489 			this_screen = XScreenNumberOfScreen(xgwa.screen);
3490 			if (Scr[this_screen].window != None) {
3491 				(void) sprintf(error_buf,
3492 					"%s: Two windows on screen %d\n",
3493 					(strlen(ProgramName) < ERROR_BUF - ERROR_LINE) ?
3494 					ProgramName : DEFAULT_NAME, this_screen);
3495 				error(error_buf);
3496 			}
3497 			Scr[this_screen].window = saver_wins[this_win];
3498 		}
3499 		/* Reduce to the screens that have windows.  Avoid problems and */
3500 		/* assume that if one fails there is only one good window. */
3501 		for (this_screen = startscreen; this_screen < screens; this_screen++) {
3502 			if (Scr[this_screen].window == None) {
3503 				startscreen = DefaultScreen(dsp);
3504 				screens = startscreen + 1;
3505 				break;
3506 			}
3507 		}
3508 	} else
3509 #endif
3510 
3511 	if (inwindow) {
3512 		/* Reduce to the last screen requested */
3513 		startscreen = DefaultScreen(dsp);
3514 		screens = startscreen + 1;
3515 	}
3516 	for (screen = startscreen; screen < screens; screen++) {
3517 		Screen     *scr = ScreenOfDisplay(dsp, screen);
3518 		Colormap    cmap = (Colormap) NULL;
3519 
3520 /* Start of MI_ROOT_PIXMAP hack */
3521 		Window 			temp_rw;
3522 		XGCValues		temp_gcv;
3523 		GC			temp_gc;
3524 		XWindowAttributes	temp_xgwa;
3525 
3526 		temp_rw = (parentSet) ? parent : RootWindowOfScreen(scr);
3527 		(void) XGetWindowAttributes(dsp, temp_rw, &temp_xgwa);
3528 		temp_gcv.function = GXcopy;
3529 		temp_gcv.subwindow_mode = IncludeInferiors;
3530 		temp_gc = XCreateGC(dsp, temp_rw, GCFunction|GCSubwindowMode,
3531 			&temp_gcv);
3532 		Scr[screen].root_pixmap = XCreatePixmap(dsp, temp_rw,
3533 			temp_xgwa.width,
3534 			temp_xgwa.height,
3535 			temp_xgwa.depth);
3536 		XCopyArea(dsp, temp_rw, Scr[screen].root_pixmap,
3537 			temp_gc, 0, 0, temp_xgwa.width, temp_xgwa.height,
3538 			0, 0);
3539 		XFreeGC(dsp, temp_gc);
3540 
3541 /* End of MI_ROOT_PIXMAP hack */
3542 
3543 		if (*plantext) {
3544 			char **planp;
3545 			int tmp;
3546 
3547 			Scr[screen].planpos.x = Scr[screen].planpos.y = 0;
3548 			for (planp = plantext; *planp; ++planp) {
3549 				tmp = XTextWidth(planfont, *planp, strlen(*planp));
3550 				if (tmp > Scr[screen].planpos.x)
3551 					Scr[screen].planpos.x = tmp;
3552 				++Scr[screen].planpos.y;
3553 			}
3554 			if (debug) {
3555 				Scr[screen].planpos.x = (DisplayWidth(dsp, screen) -
3556 					100 - Scr[screen].planpos.x) / 2;
3557 				Scr[screen].planpos.y = DisplayHeight(dsp, screen) -
3558 					100 - (Scr[screen].planpos.y + 4) * (planFontHeight + 2);
3559 #ifdef USE_XINERAMA
3560 			} else if (xinerama_info) {
3561 				Scr[screen].planpos.x = (xinerama_info[0].width -
3562 					Scr[screen].planpos.x) / 2 + xinerama_info[0].x_org;
3563 				Scr[screen].planpos.y = xinerama_info[0].y_org + xinerama_info[0].height -
3564 					(Scr[screen].planpos.y + 4) * (planFontHeight + 2);
3565 #endif
3566 			} else {
3567 				Scr[screen].planpos.x = (DisplayWidth(dsp, screen) -
3568 					Scr[screen].planpos.x) / 2;
3569 				Scr[screen].planpos.y = DisplayHeight(dsp, screen) -
3570 					(Scr[screen].planpos.y + 4) * (planFontHeight + 2);
3571 			}
3572 		}
3573 #ifdef ORIGINAL_XPM_PATCH
3574 		if (mailIcon && mailIcon[0]) {
3575 			if ((mail_xpmimg = (XpmImage *) malloc(sizeof (XpmImage))))
3576 				if (XpmReadFileToXpmImage(mailIcon, mail_xpmimg,
3577 						(XpmInfo *) NULL) != XpmSuccess) {
3578 					free(mail_xpmimg);
3579 					mail_xpmimg = NULL;
3580 				}
3581 		}
3582 		if (nomailIcon && nomailIcon[0]) {
3583 			if ((nomail_xpmimg = (XpmImage *) malloc(sizeof (XpmImage))))
3584 				if (XpmReadFileToXpmImage(nomailIcon, nomail_xpmimg,
3585 						(XpmInfo *) NULL) != XpmSuccess) {
3586 					free(nomail_xpmimg);
3587 					nomail_xpmimg = NULL;
3588 				}
3589 		}
3590 #endif
3591 
3592 		Scr[screen].root = (parentSet) ? parent : RootWindowOfScreen(scr);
3593 		defaultVisualInfo(dsp, screen);
3594 
3595 /*-
3596  * Some window managers like fvwm and tvtwm do not like it when an application
3597  * thinks it can install a full screen colormap (i.e xlock).  It promptly
3598  * deinstalls the colormap and this might lead to white backgrounds if
3599  * CopyFromParent is not used.
3600  * But if CopyFromParent is used one can not change the visual
3601  * and one may get White = Black on PseudoColor (see bug mode).
3602  * There is another spot in xlock.c like this one...
3603  * As far as I can tell, this problem exists only if your using MesaGL.
3604  */
3605 #if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
3606 		Scr[screen].colormap = cmap = xswa.colormap =
3607 			XCreateColormap(dsp, Scr[screen].root, Scr[screen].visual, AllocNone);
3608 #else
3609 		cmap = DefaultColormapOfScreen(scr);
3610 		Scr[screen].colormap = None;
3611 #endif
3612 
3613 		xswa.override_redirect = True;
3614 		xswa.background_pixel = Scr[screen].black_pixel;
3615 		xswa.border_pixel = Scr[screen].white_pixel;
3616 		xswa.event_mask = KeyPressMask | ButtonPressMask |
3617 			VisibilityChangeMask | ExposureMask | StructureNotifyMask;
3618 		if (mousemotion)
3619 			xswa.event_mask |= MotionNotify;
3620 
3621 #ifdef USE_VROOT
3622 		if (inroot) {
3623 			Scr[screen].window = Scr[screen].root;
3624 			XChangeWindowAttributes(dsp, Scr[screen].window, CWBackPixel, &xswa);
3625 			/* this gives us these events from the root window */
3626 			XSelectInput(dsp, Scr[screen].window,
3627 				VisibilityChangeMask | ExposureMask);
3628 		} else
3629 #endif
3630 #ifdef USE_DTSAVER
3631 		if (!dtsaver)
3632 #endif
3633 		{
3634 #define WIDTH (inwindow? WidthOfScreen(scr)/2 : (debug? WidthOfScreen(scr) - 100 : WidthOfScreen(scr)))
3635 #define HEIGHT (inwindow? HeightOfScreen(scr)/2 : (debug? HeightOfScreen(scr) - 100 : HeightOfScreen(scr)))
3636 #if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
3637 #define CWMASK (((debug||inwindow||inroot)? 0 : CWOverrideRedirect) | CWBackPixel | CWBorderPixel | CWEventMask | CWColormap)
3638 #else
3639 #define CWMASK (((debug||inwindow||inroot)? 0 : CWOverrideRedirect) | CWBackPixel | CWBorderPixel | CWEventMask)
3640 #endif
3641 
3642 #if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
3643 #define XLOCKWIN_DEPTH (Scr[screen].depth)
3644 #define XLOCKWIN_VISUAL (Scr[screen].visual)
3645 #else
3646 #define XLOCKWIN_DEPTH CopyFromParent
3647 #define XLOCKWIN_VISUAL CopyFromParent
3648 #endif
3649 
3650 			if (fullscreen) {
3651 				Scr[screen].window = XCreateWindow(dsp, Scr[screen].root, 0, 0,
3652 					(unsigned int) WIDTH, (unsigned int) HEIGHT, 0,
3653 				XLOCKWIN_DEPTH, InputOutput, XLOCKWIN_VISUAL,
3654 					CWMASK, &xswa);
3655 			} else {
3656 				sizeconfiguremask = CWX | CWY | CWWidth | CWHeight;
3657 				Scr[screen].fullsizeconfigure.x = 0;
3658 				Scr[screen].fullsizeconfigure.y = 0;
3659 				Scr[screen].fullsizeconfigure.width = WIDTH;
3660 				Scr[screen].fullsizeconfigure.height = HEIGHT;
3661 				Scr[screen].window = XCreateWindow(dsp, Scr[screen].root,
3662 					(int) minisizeconfigure.x,
3663 					(int) minisizeconfigure.y,
3664 					(unsigned int) minisizeconfigure.width,
3665 					(unsigned int) minisizeconfigure.height,
3666 					0, XLOCKWIN_DEPTH, InputOutput, XLOCKWIN_VISUAL,
3667 					CWMASK, &xswa);
3668 			}
3669 #ifdef USE_MB
3670 			XmbSetWMProperties(dsp, Scr[screen].window,
3671 				DEFAULT_NAME, DEFAULT_NAME, NULL, 0, NULL, NULL,
3672 				&xclasshint);
3673 #endif
3674 		}
3675 		if (use3d) {
3676 			XColor      C;
3677 
3678 #ifdef CALCULATE_BOTH
3679 			XColor      C2;
3680 
3681 #endif
3682 			unsigned long planemasks[10];
3683 			unsigned long pixels[10];
3684 
3685 			if (!install || !XAllocColorCells(dsp, cmap, False, planemasks, 2, pixels,
3686 					1)) {
3687 				/* did not get the needed colours.  Use normal 3d view without */
3688 				/* color overlapping */
3689 				Scr[screen].none_pixel = allocPixel(dsp, cmap,
3690 none3d, (char *)DEF_NONE3D);
3691 				Scr[screen].right_pixel = allocPixel(dsp, cmap,
3692 right3d, (char *)DEF_RIGHT3D);
3693 				Scr[screen].left_pixel = allocPixel(dsp, cmap,
3694 left3d, (char *)DEF_LEFT3D);
3695 				Scr[screen].both_pixel = allocPixel(dsp, cmap,
3696 both3d, (char *)DEF_BOTH3D);
3697 
3698 			} else {
3699 				/*
3700 				   * attention: the mixture of colours will only be guaranteed, if
3701 				   * the right black is used.  The problems with BlackPixel would
3702 				   * be that BlackPixel | left_pixel need not be equal to left_pixel.
3703 				   * The same holds for rightcol (of course). That is why the right
3704 				   * black (black3dcol) must be used when GXor is used as put
3705 				   * function.  I have allocated four colors above:
3706 				   * pixels[0],                                - 3d black
3707 				   * pixels[0] | planemasks[0],                - 3d right eye color
3708 				   * pixels[0] | planemasks[1],                - 3d left eye color
3709 				   * pixels[0] | planemasks[0] | planemasks[1] - 3d white
3710 				 */
3711 
3712 				if (!XParseColor(dsp, cmap, none3d, &C))
3713 					(void) XParseColor(dsp, cmap, DEF_NONE3D, &C);
3714 				Scr[screen].none_pixel = C.pixel = pixels[0];
3715 				XStoreColor(dsp, cmap, &C);
3716 
3717 				if (!XParseColor(dsp, cmap, right3d, &C))
3718 					(void) XParseColor(dsp, cmap, DEF_RIGHT3D, &C);
3719 				Scr[screen].right_pixel = C.pixel = pixels[0] | planemasks[0];
3720 				XStoreColor(dsp, cmap, &C);
3721 
3722 #ifdef CALCULATE_BOTH
3723 				C2.red = C.red;
3724 				C2.green = C.green;
3725 				C2.blue = C.blue;
3726 #else
3727 				if (!XParseColor(dsp, cmap, left3d, &C))
3728 					(void) XParseColor(dsp, cmap, DEF_LEFT3D, &C);
3729 #endif
3730 				Scr[screen].left_pixel = C.pixel = pixels[0] | planemasks[1];
3731 				XStoreColor(dsp, cmap, &C);
3732 
3733 #ifdef CALCULATE_BOTH
3734 				C.red |= C2.red;	/* or them together... */
3735 				C.green |= C2.green;
3736 				C.blue |= C2.blue;
3737 #else
3738 				if (!XParseColor(dsp, cmap, both3d, &C))
3739 					(void) XParseColor(dsp, cmap, DEF_BOTH3D, &C);
3740 #endif
3741 				Scr[screen].both_pixel = C.pixel =
3742 					pixels[0] | planemasks[0] | planemasks[1];
3743 				XStoreColor(dsp, cmap, &C);
3744 			}
3745 
3746 		}
3747 		fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors, saturation,
3748 			mono, install, inroot, inwindow, verbose);
3749 		if (debug || inwindow) {
3750 			XWMHints    xwmh;
3751 
3752 			xwmh.flags = InputHint;
3753 			xwmh.input = True;
3754 			XSetWMHints(dsp, Scr[screen].window, &xwmh);
3755 		}
3756 		if (debug) {
3757 			Scr[screen].iconpos.x = (DisplayWidth(dsp, screen) - 100 -
3758 #ifdef HAVE_KRB5
3759 				MAX(512, MAX(XTextWidth(font, text_info, strlen(text_info)), XTextWidth(font, text_krbinfo, strlen(text_krbinfo))))
3760 #else /* HAVE_KRB5 */
3761 				MAX(512, XTextWidth(font, text_info, strlen(text_info)))
3762 #endif /* HAVE_KRB5 */
3763 				) / 2;
3764 			Scr[screen].iconpos.y = (DisplayHeight(dsp, screen) - 100) / 6;
3765 #ifdef USE_XINERAMA
3766 		} else if (xinerama_info) {
3767 			Scr[screen].iconpos.x = (xinerama_info[0].width -
3768 #ifdef HAVE_KRB5
3769 					MAX(512, MAX(XTextWidth(font, text_info, strlen(text_info)), XTextWidth(font, text_krbinfo, strlen(text_krbinfo))))
3770 #else /* HAVE_KRB5 */
3771 					MAX(512, XTextWidth(font, text_info, strlen(text_info)))
3772 #endif /* HAVE_KRB5 */
3773 				) / 2 + xinerama_info[0].x_org;
3774 			Scr[screen].iconpos.y = xinerama_info[0].y_org + xinerama_info[0].height / 6;
3775 #endif
3776 		} else {
3777 			Scr[screen].iconpos.x = (DisplayWidth(dsp, screen) -
3778 #ifdef HAVE_KRB5
3779 					MAX(512, MAX(XTextWidth(font, text_info, strlen(text_info)), XTextWidth(font, text_krbinfo, strlen(text_krbinfo))))
3780 #else /* HAVE_KRB5 */
3781 					MAX(512, XTextWidth(font, text_info, strlen(text_info)))
3782 #endif /* HAVE_KRB5 */
3783 				) / 2;
3784 			Scr[screen].iconpos.y = DisplayHeight(dsp, screen) / 6;
3785 		}
3786 
3787 		xswa.border_pixel = Scr[screen].white_pixel;
3788 		xswa.background_pixel = Scr[screen].black_pixel;
3789 		xswa.event_mask = ButtonPressMask;
3790 #if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
3791 #define CIMASK CWBorderPixel | CWBackPixel | CWEventMask | CWColormap
3792 #else
3793 #define CIMASK CWBorderPixel | CWBackPixel | CWEventMask
3794 #endif
3795 		if (nolock)
3796 			Scr[screen].icon = None;
3797 		else {
3798 			Scr[screen].icon = XCreateWindow(dsp, Scr[screen].window,
3799 				Scr[screen].iconpos.x, Scr[screen].iconpos.y,
3800 				iconwidth, iconheight, 1, (int) CopyFromParent,
3801 				InputOutput, CopyFromParent,
3802 				CIMASK, &xswa);
3803 #ifdef USE_BUTTON_LOGOUT
3804 			{
3805 				char       *buf;
3806 				int         w, h;
3807 
3808 				if ((buf = (char *) malloc(strlen(logoutButtonLabel) +
3809 						3)) == NULL) {
3810 					w = (strlen(logoutButtonLabel) + 5) * 8;
3811 				} else {
3812 					(void) sprintf(buf, " %s ", logoutButtonLabel);
3813 					w = XTextWidth(font, buf, strlen(buf));
3814 					free(buf);
3815 				}
3816 				h = fontHeight + 2;
3817 				Scr[screen].button = XCreateWindow(dsp, Scr[screen].window,
3818 					0, 0, w, h, 1, (int) CopyFromParent,
3819 					InputOutput, CopyFromParent,
3820 					CIMASK, &xswa);
3821 			}
3822 #endif
3823 		}
3824 		XMapWindow(dsp, Scr[screen].window);
3825 		XRaiseWindow(dsp, Scr[screen].window);
3826 
3827 #if 0
3828 		if (install && cmap != DefaultColormapOfScreen(scr))
3829 			setColormap(dsp, Scr[screen].window, cmap, inwindow);
3830 #endif
3831 
3832 		xgcv.font = font->fid;
3833 		xgcv.foreground = Scr[screen].white_pixel;
3834 		xgcv.background = Scr[screen].black_pixel;
3835 		Scr[screen].gc = XCreateGC(dsp, Scr[screen].window,
3836 				GCFont | GCForeground | GCBackground, &xgcv);
3837 
3838 		xgcv.foreground = Scr[screen].fg_pixel;
3839 		xgcv.background = Scr[screen].bg_pixel;
3840 		Scr[screen].textgc = XCreateGC(dsp, Scr[screen].window,
3841 				GCFont | GCForeground | GCBackground, &xgcv);
3842 		xgcv.font = planfont->fid;
3843 		Scr[screen].plantextgc = XCreateGC(dsp, Scr[screen].window,
3844 				GCFont | GCForeground | GCBackground, &xgcv);
3845 
3846 #ifdef ORIGINAL_XPM_PATCH
3847 		if (mail_xpmimg) {
3848 			XpmAttributes xpm_attr;
3849 
3850 			xpm_attr.valuemask = 0;
3851 			XpmCreatePixmapFromXpmImage(dsp, Scr[screen].window,
3852 				mail_xpmimg, &Scr[screen].mb.mail.pixmap,
3853 				&Scr[screen].mb.mail.bitmap, &xpm_attr);
3854 		}
3855 		if (nomail_xpmimg) {
3856 			XpmAttributes xpm_attr;
3857 
3858 			xpm_attr.valuemask = 0;
3859 			XpmCreatePixmapFromXpmImage(dsp, Scr[screen].window, nomail_xpmimg,
3860 				&Scr[screen].mb.nomail.pixmap,
3861 				&Scr[screen].mb.nomail.bitmap, &xpm_attr);
3862 		}
3863 		if (mail_xpmimg || nomail_xpmimg) {
3864 			Scr[screen].mb.mbgc = XCreateGC(dsp, Scr[screen].window,
3865 				GCFont | GCForeground | GCBackground,
3866 				&xgcv);
3867 		}
3868 #else
3869 		if (mailCmd && mailCmd[0]) {
3870 			pickPixmap(dsp, Scr[screen].window, nomailIcon,
3871 				NOMAIL_WIDTH, NOMAIL_HEIGHT, NOMAIL_BITS,
3872 				&(Scr[screen].mb.nomail.width),
3873 				&(Scr[screen].mb.nomail.height),
3874 				&(Scr[screen].mb.nomail.pixmap),
3875 				&(Scr[screen].mb.nomail.graphics_format));
3876 				pickPixmap(dsp, Scr[screen].window, mailIcon,
3877 				MAIL_WIDTH, MAIL_HEIGHT, MAIL_BITS,
3878 				&(Scr[screen].mb.mail.width),
3879 				&(Scr[screen].mb.mail.height),
3880 				&(Scr[screen].mb.mail.pixmap),
3881 				&(Scr[screen].mb.mail.graphics_format));
3882 			Scr[screen].mb.mbgc = XCreateGC(dsp, Scr[screen].window,
3883 				GCFont | GCForeground | GCBackground,
3884 				&xgcv);
3885 		}
3886 #endif
3887 	}
3888 	lockc = XCreateBitmapFromData(dsp, Scr[startscreen].root, no_bits, 1, 1);
3889 	lockm = XCreateBitmapFromData(dsp, Scr[startscreen].root, no_bits, 1, 1);
3890 	mycursor = XCreatePixmapCursor(dsp, lockc, lockm,
3891 		&nullcolor, &nullcolor, 0, 0);
3892 	XFreePixmap(dsp, lockc);
3893 	XFreePixmap(dsp, lockm);
3894 
3895 	if (!grabmouse || inwindow || inroot) {
3896 		nolock = 1;
3897 		enablesaver = 1;
3898 	} else if (!debug) {
3899 		GrabKeyboardAndMouse(dsp, Scr[startscreen].window);
3900 	}
3901 	if (!nolock) {
3902 		XGetScreenSaver(dsp, &sstimeout, &ssinterval,
3903 				&ssblanking, &ssexposures);
3904 		if (resetsaver)
3905 			XResetScreenSaver(dsp);		/* make sure not blank now */
3906 		if (!enablesaver)
3907 			XSetScreenSaver(dsp, 0, 0, 0, 0);	/* disable screen saver */
3908 	}
3909 #ifdef USE_DPMS
3910 	if ((dpmsstandby >= 0) || (dpmssuspend >= 0) || (dpmsoff >= 0))
3911 		SetDPMS(dsp, dpmsstandby, dpmssuspend, dpmsoff);
3912 #endif
3913 #ifdef HAVE_SETPRIORITY
3914 	(void) setpriority(0, 0, nicelevel);
3915 #else /* !HAVE_SETPRIORITY */
3916 	(void) nice(nicelevel);
3917 #endif /* HAVE_SETPRIORITY */
3918 
3919 	(void) XSetIOErrorHandler(xio_error);
3920 
3921 	/* start the command startcmd */
3922 	if (startCmd && *startCmd) {
3923 
3924 		if ((cmd_pid = FORK()) == -1) {
3925 			(void) fprintf(stderr, "Failed to launch \"%s\"\n", startCmd);
3926 			perror(ProgramName);
3927 			cmd_pid = 0;
3928 		} else if (!cmd_pid) {
3929 #ifndef VMS
3930 			(void) setpgid(0, 0);
3931 #endif
3932 #if 0
3933 #if (defined(sun) && defined(__svr4__)) || defined(sgi) || defined(__hpux) || defined(linux)
3934 			setsid();
3935 #else
3936 			setpgrp(getpid(), getpid());
3937 #endif
3938 #endif
3939 #if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 ) || defined( __CYGWIN__ ) || defined( __linux__ )
3940 			(void) sigprocmask(SIG_SETMASK, (sigset_t *)&old_sigmask, (sigset_t *)&old_sigmask);
3941 #else
3942 			(void) sigsetmask(old_sigmask);
3943 #endif
3944 			(void) system(startCmd);
3945 			_exit(0);
3946 		}
3947 	}
3948 	lock_delay = lockdelay;
3949 	if (nolock) {
3950 		(void) justDisplay(dsp);
3951 	} else if (lock_delay) {
3952 		if (justDisplay(dsp)) {
3953 			lockDisplay(dsp, False);
3954 		} else
3955 			nolock = 1;
3956 	} else {
3957 		lockDisplay(dsp, True);
3958 	}
3959 #if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
3960 	if (!nolock) {
3961 		syslogStop(XDisplayString(dsp));
3962 		closelog();
3963 	}
3964 #endif
3965 #ifdef USE_DPMS
3966 	SetDPMS(dsp, -1, -1, -1);
3967 #endif
3968 	finish(dsp, True);
3969 
3970 	if (cmd_pid) {
3971 #if defined(NO_KILLPG) || defined(__svr4__) || defined(sgi) || defined(__hpux) || defined(VMS)
3972 		kill(-cmd_pid, SIGTERM);
3973 #else
3974 		(void) killpg(cmd_pid, SIGTERM);
3975 #endif
3976 	}
3977 	if (endCmd && *endCmd) {
3978 		if ((cmd_pid = FORK()) == -1) {
3979 			(void) fprintf(stderr, "Failed to launch \"%s\"\n", endCmd);
3980 			perror(ProgramName);
3981 			cmd_pid = 0;
3982 		} else if (!cmd_pid) {
3983 			(void) system(endCmd);
3984 			_exit(0);
3985 		}
3986 	}
3987 
3988 #if defined( USE_ESOUND )
3989         shutdown_sound();
3990         sound = 0;
3991 #endif
3992 
3993 #ifdef VMS
3994 	return 1;
3995 #else
3996 	return 0;
3997 #endif
3998 }
3999 #endif
4000 
4001 
4002 #ifdef USE_PAM
4003 /* PAM_putText - method to have pam_converse functionality with in XLOCK */
PAM_putText(const struct pam_message * msg,struct pam_response * resp,Bool PAM_echokeys)4004 void PAM_putText( const struct pam_message *msg, struct pam_response *resp, Bool PAM_echokeys )
4005 {
4006   int x = 50, y = 50;
4007   int oldX, oldY;
4008   int left;
4009   char buffer[PASSLENGTH];
4010 
4011   x = left = Scr[screen].iconpos.x;
4012   y = Scr[screen].iconpos.y + fontAscent + 200;
4013 
4014 #ifdef DEBUG
4015     (void) printf( "PAM_putText: message of style %d received: (%s)\n", msg->msg_style, msg->msg );
4016 #endif
4017   if( ( msg->msg_style == PAM_PROMPT_ECHO_ON ) ||
4018       ( msg->msg_style == PAM_PROMPT_ECHO_OFF ) )
4019   {
4020     XFlush(dsp);
4021     XSync( dsp, True );  /* Flush Input Buffer */
4022 
4023     putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, msg->msg, True, left, &x, &y);
4024     putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, " ", True, left, &x, &y);
4025 
4026     unamex = x;
4027     unamey = y;
4028 
4029     (void) ReadXString(buffer, PASSLENGTH, (Bool *) NULL
4030 #ifdef GLOBAL_UNLOCK
4031 		, True
4032 #elif defined( USE_PAM )
4033 		, PAM_echokeys
4034 #endif
4035 		);
4036 
4037     XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
4038     resp->resp = strdup(buffer);
4039     resp->resp_retcode = PAM_SUCCESS;
4040 
4041 #ifdef DEBUG
4042     (void) printf( "Received Username: (%s)\n", resp->resp );
4043 #endif
4044   }
4045   else
4046   {
4047     XFlush( dsp );
4048     /* Clears three lines of text before displaying the next message */
4049     oldX = x;
4050     oldY = y;
4051     XFillRectangle(dsp, Scr[startscreen].window, Scr[startscreen].gc,
4052 		Scr[screen].iconpos.x, y - fontAscent,
4053 		XTextWidth(font, msg->msg, strlen(msg->msg)),
4054 		(fontHeight + 2) * 3);
4055     XSync( dsp, True );
4056     (void) sleep(1);
4057     /* display the message */
4058     putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, msg->msg, True, left, &x, &y);
4059     putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, " ", True, left, &x, &y);
4060 
4061     x = oldX;
4062     y = oldY;
4063 
4064     XSync( dsp, True );
4065     (void) sleep(3);
4066 
4067     XFlush( dsp );
4068     /* Clears three lines of text before displaying the next message */
4069     XFillRectangle(dsp, Scr[startscreen].window, Scr[startscreen].gc,
4070 		Scr[screen].iconpos.x, y - fontAscent,
4071 		XTextWidth(font, msg->msg, strlen(msg->msg)),
4072 		(fontHeight + 2) * 3);
4073     XSync( dsp, True );
4074   }
4075 }
4076 #endif
4077 
4078 #if defined( __hpux ) || defined( __apollo )
4079 int
_main(int argc,char ** argv)4080 _main(int argc, char **argv)
4081 {
4082   main(argc, argv);
4083 }
4084 #endif
4085 
4086 #ifdef HAVE_KRB5
4087 /* like putText, but takes a font argument */
4088 static void
putTextFont(Display * display,Window window,XFontStruct * pfont,GC gc,const char * string,int bold,int left,int * px,int * py)4089 putTextFont(Display * display, Window window, XFontStruct *pfont, GC gc,
4090 	const char *string, int bold, int left, int *px, int *py)
4091 				/* which window */
4092 				/* font */
4093 				/* gc */
4094 				/* text to write */
4095 				/* 1 = make it bold */
4096 				/* left edge of text */
4097 				/* current x and y, input & return */
4098 {
4099 #define PT_BUFSZ 2048
4100 	char        buf[PT_BUFSZ], *p, *s;
4101 	int         x = *px, y = *py, last, len;
4102 
4103 	(void) strncpy(buf, string, PT_BUFSZ);
4104 	buf[PT_BUFSZ - 1] = 0;
4105 
4106 	p = buf;
4107 	last = 0;
4108 	for (;;) {
4109 		s = p;
4110 		for (; *p; ++p)
4111 			if (*p == '\n')
4112 				break;
4113 		if (!*p)
4114 			last = 1;
4115 		*p = 0;
4116 
4117 		if ((len = strlen(s))) {	/* yes, "=", not "==" */
4118 			(void) XDrawImageString(display, window, gc, x, y, s, len);
4119 			if (bold)
4120 				(void) XDrawString(display, window, gc, x + 1, y, s, len);
4121 		}
4122 		if (!last) {
4123 			y += pfont->ascent + pfont->descent + 2;
4124 			x = left;
4125 		} else {
4126 			if (len)
4127 				x += XTextWidth(pfont, s, len);
4128 			break;
4129 		}
4130 		p++;
4131 	}
4132 	*px = x;
4133 	*py = y;
4134 }
4135 
4136 /*
4137  * Our Kerberos callback prompter.  Note that the widgets aren't exactly
4138  * pretty ... but see if I care.  We're assuming there won't be any embedded
4139  * newlines in the prompt strings (but we handle embedded newlines in
4140  * the banner string).
4141  */
4142 
4143 krb5_error_code
xlock_prompter(krb5_context context,void * data,const char * name,const char * banner,int numprompts,krb5_prompt prompts[])4144 xlock_prompter(krb5_context context, void *data, const char *name,
4145 	const char *banner, int numprompts, krb5_prompt prompts[])
4146 {
4147 	Window parent = Scr[screen].window;
4148 	Window win, button;
4149 	GC gc;
4150 	XGCValues xgcv;
4151 	int lines = 0, max = 0, width, i, height, bwidth, bheight, x, y;
4152 	int leave = 0, cp = 0, count;
4153 	XWindowAttributes xgwa;
4154 	XSetWindowAttributes xswa;
4155 	XEvent event;
4156 	KeySym keysym;
4157 	char buffer[20];
4158 	char *ok = "OK", *c;
4159 	const char *b;
4160 
4161 	struct _promptinfo {
4162 		int x;
4163 		int y;
4164 		int curx;
4165 		int rp;
4166 	} *pi = NULL;
4167 
4168 	if (numprompts > 0)
4169 		if (!(pi = malloc(sizeof(*pi) * numprompts)))
4170 			return ENOMEM;
4171 
4172 	/*
4173 	 * Let's see what our longest line is (handle embedded newlines,
4174 	 * but only in the banner)
4175 	 */
4176 
4177 	if (banner && banner[0] != NULL) {
4178 		for (b = banner, c = index(banner, '\n'); c != NULL;
4179 				b = c, c = index(c + 1, '\n')) {
4180 			width = XTextWidth(planfont, b, c - b);
4181 			if (width > max)
4182 				max = width;
4183 			lines++;
4184 		}
4185 		width = XTextWidth(planfont, b, strlen(b));
4186 		if (width > max)
4187 			max = width;
4188 		lines++;
4189 	}
4190 
4191 	for (i = 0; i < numprompts; i++) {
4192 		/* 32 asterisks for entry should be enough */
4193 		width = XTextWidth(planfont, prompts[i].prompt,
4194 				strlen(prompts[i].prompt)) +
4195 			XTextWidth(planfont,
4196 				": ********************************", 34);
4197 		if (width > max)
4198 			max = width;
4199 		lines++;
4200 	}
4201 
4202 	/*
4203 	 * we're saying a 10 pixel border around the text.  We add in
4204 	 * 40 to the height because of the OK button
4205 	 */
4206 
4207 	height = (lines + 1) * (planFontHeight + 2) + 40;
4208 	width = max + 20;
4209 
4210 	(void) XGetWindowAttributes(dsp, Scr[screen].window, &xgwa);
4211 
4212 	if (width > xgwa.width) {
4213 		x = 0;
4214 		width = xgwa.width;
4215 	} else
4216 		x = (xgwa.width - width) / 2;
4217 
4218 	if (height > xgwa.height) {
4219 		y = 0;
4220 		height = xgwa.height;
4221 	} else
4222 		y = (xgwa.height - height) / 2;
4223 
4224 	xswa.override_redirect = True;
4225 	xswa.border_pixel = Scr[screen].white_pixel;
4226 	xswa.background_pixel = Scr[screen].white_pixel;
4227 	xswa.event_mask = KeyPressMask;
4228 
4229 	/*
4230 	 * Create the main dialog window
4231 	 */
4232 
4233 	win = XCreateWindow(dsp, parent, x, y, width, height, 2,
4234 			CopyFromParent, CopyFromParent, Scr[screen].visual,
4235 			CWOverrideRedirect | CWBackPixel | CWBorderPixel |
4236 			CWEventMask, &xswa);
4237 
4238 	XMapWindow(dsp, win);
4239 	XRaiseWindow(dsp, win);
4240 
4241 	/*
4242 	 * Create the OK button window
4243 	 */
4244 
4245 	bheight = planFontHeight + 10;
4246 	bwidth = XTextWidth(planfont, ok, strlen(ok)) + 10;
4247 
4248 	xswa.border_pixel = Scr[screen].black_pixel;
4249 	xswa.event_mask = ButtonPressMask;
4250 
4251 	button = XCreateWindow(dsp, win, (width - bwidth) / 2,
4252 		height - bheight - 5, bwidth, bheight, 2,
4253 		CopyFromParent, CopyFromParent,
4254 		Scr[screen].visual, CWOverrideRedirect |
4255 		CWBackPixel | CWBorderPixel | CWEventMask,
4256 		&xswa);
4257 
4258 	XMapWindow(dsp, button);
4259 	XRaiseWindow(dsp, button);
4260 
4261 	x = 10;
4262 	y = 10 + planfont->ascent;
4263 
4264 	xgcv.font = planfont->fid;
4265 	xgcv.foreground = Scr[screen].black_pixel;
4266 	xgcv.background = Scr[screen].white_pixel;
4267 	gc = XCreateGC(dsp, Scr[screen].window,
4268 		GCFont | GCForeground | GCBackground, &xgcv);
4269 
4270 	if (banner && banner[0] != NULL)
4271 		putTextFont(dsp, win, planfont, gc, banner, 1, x, &x, &y);
4272 
4273 	for (i = 0; i < numprompts; i++) {
4274 		x = 10;
4275 		y += planFontHeight + 2;
4276 		putTextFont(dsp, win, planfont, gc, prompts[i].prompt, 1,
4277 			x, &x, &y);
4278 		putTextFont(dsp, win, planfont, gc, ": ", 1, x, &x, &y);
4279 		pi[i].x = pi[i].curx = x;
4280 		pi[i].y = y;
4281 		pi[i].rp = 0;
4282 		memset(prompts[i].reply->data, 0, prompts[i].reply->length);
4283 	}
4284 
4285 	x = 5;
4286 	y = 5 + planfont->ascent;
4287 
4288 	putTextFont(dsp, button, planfont, gc, ok, 1, x, &x, &y);
4289 
4290 	while (leave == 0) {
4291 		XNextEvent(dsp, &event);
4292 
4293 		switch (event.type) {
4294 
4295 		case ButtonPress:
4296 			if (event.xbutton.window == button)
4297 				leave = 1;
4298 			break;
4299 
4300 		case KeyPress:
4301 			count = XLookupString((XKeyEvent *) &event, buffer,
4302 				sizeof(buffer), &keysym, NULL);
4303 
4304 			/*
4305 			 * Try to handle specific keysyms
4306 			 */
4307 
4308 			if (keysym == XK_Return || keysym == XK_KP_Enter ||
4309 					keysym == XK_Linefeed) {
4310 				if (++cp >= numprompts)
4311 					leave = 1;
4312 				break;
4313 			}
4314 
4315 			/*
4316 			 * Ignore modifier keys
4317 			 */
4318 
4319 			if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
4320 				break;
4321 
4322 			/*
4323 			 * If we don't do any prompts, then we only accept
4324 			 * Return/Enter/Linefeed
4325 			 */
4326 
4327 			if (numprompts == 0) {
4328 				XBell(dsp, 100);
4329 				break;
4330 			}
4331 
4332 			/*
4333 			 * Handle Tab/Shift-Tab
4334 			 */
4335 
4336 			if (keysym == XK_Tab) {
4337 				if (!(event.xkey.state & ShiftMask)) {
4338 					if (++cp >= numprompts)
4339 						cp = 0;
4340 				} else {
4341 					if (--cp < 0)
4342 						cp = numprompts - 1;
4343 				}
4344 				break;
4345 			}
4346 
4347 			/*
4348 			 * Handle BS/Delete
4349 			 */
4350 
4351 			if (keysym == XK_BackSpace || keysym == XK_Delete) {
4352 				if (pi[cp].rp == 0) {
4353 					XBell(dsp, 100);
4354 					break;
4355 				}
4356 				prompts[cp].reply->data[--pi[cp].rp] = '\0';
4357 				if (pi[cp].rp < 32) {
4358 					pi[cp].curx -= XTextWidth(planfont,
4359 						"*", 1);
4360 					XClearArea(dsp, win, pi[cp].curx,
4361 						pi[cp].y - planfont->ascent,
4362 						0, planfont->ascent +
4363 						planfont->descent, False);
4364 				}
4365 				break;
4366 			}
4367 
4368 			/*
4369 			 * Handle keypresses
4370 			 */
4371 
4372 			for (i = 0; i < count; i++) {
4373 				switch (buffer[i]) {
4374 				case '\003':
4375 				case '\025':
4376 					XClearArea(dsp, win, pi[cp].x,
4377 						pi[cp].y - planfont->ascent,
4378 						0, planfont->ascent +
4379 						planfont->descent, False);
4380 					memset(prompts[cp].reply->data, 0,
4381 						prompts[cp].reply->length);
4382 					pi[cp].curx = pi[cp].x;
4383 					pi[cp].rp = 0;
4384 					break;
4385 				default:
4386 					if (pi[cp].rp + 1 >=
4387 							prompts[cp].reply->length) {
4388 						XBell(dsp, 100);
4389 						break;
4390 					}
4391 					prompts[cp].reply->data[pi[cp].rp++] =
4392 								buffer[i];
4393 					if (pi[cp].rp <= 32) {
4394 						putTextFont(dsp, win, planfont,
4395 							gc, "*", 1,
4396 							pi[cp].curx,
4397 							&pi[cp].curx,
4398 							&pi[cp].y);
4399 					}
4400 					break;
4401 				}
4402 			}
4403 
4404 			break;
4405 
4406 		default:
4407 			/* Nothing */
4408 			break;
4409 
4410 		}
4411 
4412 	}
4413 
4414 	if (pi)
4415 		free(pi);
4416 	XDestroyWindow(dsp, win);
4417 	XFreeGC(dsp, gc);
4418 
4419 	for (i = 0; i < numprompts; i++)
4420 		prompts[i].reply->length = strlen(prompts[i].reply->data);
4421 
4422 	return 0;
4423 }
4424 #endif /* HAVE_KRB5 */
4425 
4426 #ifdef WIN32
4427 #define MAX_TIMES 10
4428 int showtext = 0;
4429 
4430 void
4431 hsbramp(double h1, double s1, double b1, double h2, double s2, double b2,
4432     int count, unsigned char *red, unsigned char *green, unsigned char *blue);
4433 
CalculateColors(int noofcolors,double saturation)4434 static void CalculateColors(int noofcolors, double saturation)
4435 {
4436 
4437 	/* free any previously allocated colormap */
4438 	if (red != NULL)
4439 		free(red);
4440 	if (green != NULL)
4441 		free(green);
4442 	if (blue != NULL)
4443 		free(blue);
4444 
4445 	/* create a new colormap */
4446 	if ((red = calloc(noofcolors+2, sizeof(unsigned char))) == NULL)
4447 		return;
4448 	if ((green = calloc(noofcolors+2, sizeof(unsigned char))) == NULL)
4449 		return;
4450 	if ((blue = calloc(noofcolors+2, sizeof(unsigned char))) == NULL)
4451 		return;
4452 
4453 	/* set the number of colors in the colormap */
4454 	colorcount = noofcolors;
4455 
4456 	/* populate the colormap */
4457 	hsbramp(0.0, saturation, 1.0, 1.0, saturation, 1.0, noofcolors,
4458 		red, green, blue);
4459 
4460 	/* store white and black colormap entries */
4461 	red[noofcolors] = green[noofcolors] = blue[noofcolors] = 255;
4462 	red[noofcolors+1] = green[noofcolors+1] = blue[noofcolors+1] = 0;
4463 }
4464 
get_random_mode(void)4465 static int get_random_mode(void)
4466 {
4467 	extern char* xlock95_get_modelist(void);   /* from xlock95.c */
4468 	char *modelist, *p, *modestart;
4469 	int nmodes, randommode, curmode, i;
4470 
4471 	/* Get a list of the selected modes */
4472 	modelist = xlock95_get_modelist();
4473 
4474 	/* Determine how many modes are selected */
4475 	nmodes = 0;
4476 	p = modelist;
4477 	while (*p) {
4478 		if (*p == ',')
4479 			nmodes++;
4480 		p++;
4481 	}
4482 
4483 	/* When the user deselected them all, ignore it */
4484 	if (nmodes == 0)
4485 		return NRAND(numprocs);
4486 
4487 	/* Get the random mode */
4488 	randommode = NRAND(nmodes);
4489 
4490 	/* Get the name of this random mode */
4491 	p = modelist;
4492 	modestart = p;
4493 	curmode = 0;
4494 
4495 	while (*p) {
4496 		if (*p == ',') {
4497 			if (randommode == curmode)
4498 				break;
4499 
4500 			modestart = p + 1;
4501 			curmode++;
4502 		}
4503 		p++;
4504 	}
4505 
4506 	/* Get the mode number based upon the name */
4507 	for (i = 0; i < numprocs; i++)
4508 		if (strncmp(LockProcs[i].cmdline_arg,
4509 				modestart, p - modestart) == 0)
4510 			return(i);
4511 
4512 	/* Should never come here, just to prevent compile error */
4513 	return NRAND(numprocs);
4514 }
4515 
4516 void xlockmore_set_mode_options(ModeSpecOpt *ms);
4517 
4518 /*-
4519  *  xlockmore_create
4520  *    called when WIN32 event handling issues a create window
4521  */
xlockmore_create(void)4522 unsigned int xlockmore_create(void)
4523 {
4524 	int i;
4525 	ModeInfo *mi; /* get mode info */
4526 	ModeSpecOpt *ms;
4527 	extern TCHAR szSaverName[_MAX_PATH];
4528 
4529     /* seeds random number generation */
4530 	SRAND((unsigned)time(NULL));
4531 /*#define _DEBUG*/
4532 
4533 	if (strlen(szSaverName) > 0) {
4534 		randommode = NRAND(numprocs);		/* Start with a random number */
4535 		for (i = 0; i < numprocs; i++) {
4536 			/* did the name on the command line match a savers name? */
4537 			if (stricmp(LockProcs[i].cmdline_arg, szSaverName) == 0)
4538 			{
4539 				randommode = i;
4540 				break;
4541 			}
4542 		}
4543 	} else {
4544 
4545 #ifdef RANDOMMODE
4546 		randommode = numprocs - 1; /* random */
4547 #else
4548 		randommode = get_random_mode();
4549 #endif
4550 	}
4551 
4552 	/* set variables */
4553 	delay = LockProcs[randommode].def_delay;
4554 	count = LockProcs[randommode].def_count;
4555 	cycles = LockProcs[randommode].def_cycles;
4556 	size = LockProcs[randommode].def_size;
4557 	saturation = LockProcs[randommode].def_saturation;
4558 	bitmap = LockProcs[randommode].def_bitmap;
4559 
4560 	/* calculate new color map */
4561 	CalculateColors(NUMCOLORS, saturation);
4562 
4563     /* allocate mem to the ModeInfo & ScreenInfo structures */
4564 	screens = ScreenCount(dsp);
4565 	if (((modeinfo = (ModeInfo *) calloc(screens,
4566 			sizeof (ModeInfo))) == NULL) ||
4567 		((Scr = (ScreenInfo *) calloc(screens,
4568 			sizeof (ScreenInfo))) == NULL)) {
4569 		error("low memory for info");
4570 	}
4571 
4572 	/* set some WIN32 specific stuff */
4573 	mi = mode_info(dsp, 0, (int)hwnd, 0);
4574 	MI_COLORMAP_SIZE(mi) = ncolors = mi->screeninfo->npixels = colorcount;
4575 	MI_GC(mi) = GCCreate();
4576 	MI_NUM_SCREENS(mi) = screens;
4577 
4578 	for (screen = startscreen; screen < screens; screen++) {
4579 		fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors, saturation,
4580 				mono, install, inroot, inwindow, verbose);
4581 	}
4582 
4583 	for (i=0; i<NUMCOLORS; i++)
4584 		mi->screeninfo->pixels[i] = i;
4585 
4586 	/* set default options for mode */
4587 	ms = LockProcs[randommode].msopt;
4588 	xlockmore_set_mode_options(ms);
4589 
4590 	showtext = 0;
4591 	return delay;
4592 }
4593 
4594 /*-
4595  *  xlockmore_init
4596  *    called to initialise a mode
4597  */
xlockmore_init(void)4598 void xlockmore_init(void)
4599 {
4600 	call_init_hook(&LockProcs[randommode], mode_info(dsp, 0, (int)hwnd, 0));
4601 }
4602 
4603 /*-
4604  *  xlockmore_destroy
4605  *    called when WIN32 event handling issues a destroy window
4606  */
xlockmore_destroy(void)4607 void xlockmore_destroy(void)
4608 {
4609 	call_release_hook(&LockProcs[randommode], mode_info(dsp, 0, (int)hwnd, 0));
4610 }
4611 
4612 #ifdef _DEBUG
4613 static char debug_text[255] = { 0 };
4614 #endif
4615 
4616 /*-
4617  *  xlockmore_timer
4618  *    called when WIN32 event handling issues a timer request
4619  */
xlockmore_timer(void)4620 unsigned int xlockmore_timer(void)
4621 {
4622 	call_callback_hook(&LockProcs[randommode], mode_info(dsp, 0, (int)hwnd, 0));
4623 
4624 /* This may cause more problems than worth. */
4625 #if 0
4626 #ifndef RANDOMMODE
4627   if (showtext < MAX_TIMES)
4628   {
4629     xlockmore_win32_text(10, 10, LockProcs[randommode].cmdline_arg);
4630     xlockmore_win32_text(10, 30, LockProcs[randommode].desc);
4631     showtext++;
4632   }
4633 #endif
4634 #endif
4635 #ifdef _DEBUG
4636   xlockmore_win32_text(10, 60, debug_text, 0);
4637 #endif
4638 
4639 	return (LockProcs[randommode].def_delay / 1000);
4640 }
4641 
4642 /*-
4643  *  xlockmore_set_mode_options
4644  *    called from create. Sets any default options
4645  */
xlockmore_set_mode_options(ModeSpecOpt * ms)4646 void xlockmore_set_mode_options(ModeSpecOpt *ms)
4647 {
4648 	int i;
4649 	char **varChar;
4650 	float *varFloat;
4651 	int *varInt;
4652 
4653 	for (i=0; i < ms->numvarsdesc; i++)
4654 	{
4655 		switch (ms->vars[i].type)
4656 		{
4657 		case t_Bool:
4658 			varInt = (int *)ms->vars[i].var;
4659 			if (strcmp(ms->vars[i].def, "True") == 0)
4660 				*varInt = TRUE;
4661 			else
4662 				*varInt = FALSE;
4663 			break;
4664 		case t_Float:
4665 			varFloat = (float *)ms->vars[i].var;
4666 			*varFloat = atof(ms->vars[i].def);
4667 			break;
4668 		case t_Int:
4669 			varInt = (int *)ms->vars[i].var;
4670 			*varInt = atoi(ms->vars[i].def);
4671 			break;
4672 		case t_String:
4673 			varChar = (char **)ms->vars[i].var;
4674 			*varChar = ms->vars[i].def;
4675 			break;
4676 		}
4677 	}
4678 }
4679 
xlockmore_win32_text(int xloc,int yloc,char * text)4680 void xlockmore_win32_text(int xloc, int yloc, char *text)
4681 {
4682 	RECT rect;
4683 	UINT nFlags = SetTextAlign(hdc, TA_RIGHT);
4684 
4685 	(void) GetClientRect(hwnd, &rect);
4686 	TextOut(hdc, rect.right - xloc, yloc, text, strlen(text));
4687 	SetTextAlign(hdc, nFlags);
4688 }
4689 
4690 //	FILE *fp = NULL;
xlockmore_set_debug(char * text)4691 void xlockmore_set_debug(char *text)
4692 {
4693 #ifdef _DEBUG
4694 	static FILE *fp = NULL;
4695 
4696 	strcpy(debug_text, text);
4697 
4698 #if 1
4699 	if (fp == NULL)
4700 	{
4701 		fp = fopen("xlock_debug.log", "a");
4702 		fprintf(fp, "\n");
4703 	}
4704 
4705 	fprintf(fp, "%s\n", text);
4706 #endif
4707 #endif
4708 }
4709 
4710 #endif /* WIN32 */
4711 
4712 #endif /* STANDALONE */
4713