Login.c revision c06e8ac6
1/*
2
3Copyright 1988, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28/*
29 * Copyright (c) 2006, Oracle and/or its affiliates.
30 *
31 * Permission is hereby granted, free of charge, to any person obtaining a
32 * copy of this software and associated documentation files (the "Software"),
33 * to deal in the Software without restriction, including without limitation
34 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35 * and/or sell copies of the Software, and to permit persons to whom the
36 * Software is furnished to do so, subject to the following conditions:
37 *
38 * The above copyright notice and this permission notice (including the next
39 * paragraph) shall be included in all copies or substantial portions of the
40 * Software.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
45 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48 * DEALINGS IN THE SOFTWARE.
49 */
50
51
52/*
53 * xdm - display manager daemon
54 * Author:  Keith Packard, MIT X Consortium
55 *
56 * Login.c
57 */
58
59#include <X11/IntrinsicP.h>
60#include <X11/StringDefs.h>
61#include <X11/keysym.h>
62#include <X11/DECkeysym.h>
63#include <X11/Xfuncs.h>
64
65#include <stdio.h>
66#include <ctype.h>
67#include <time.h>
68#include <string.h>
69
70#include "dm.h"
71#include "dm_error.h"
72#include "greet.h"
73#include "LoginP.h"
74
75#ifdef XPM
76# include <sys/stat.h>
77# include <unistd.h>
78# include <X11/Xlib.h>
79# include <X11/xpm.h>
80# include <X11/extensions/shape.h>
81#endif /* XPM */
82
83#include <X11/cursorfont.h>
84
85#ifdef USE_XINERAMA
86# include <X11/extensions/Xinerama.h>
87#endif
88
89#ifdef USE_XFT
90# include <X11/extensions/Xrender.h>
91#endif
92
93#ifndef DEBUG
94# define XDM_ASSERT(a)	/* do nothing */
95#else
96# if defined(__STDC__) && __STDC_VERSION__ - 0 >= 199901L
97#  define XDM_ASSERT(a)	if (!(a)) { \
98	Debug("Assertion failed in %s() at file %s line %d\n", \
99	      __func__, __FILE__, __LINE__); }
100# else
101#  define XDM_ASSERT(a)	if (!(a)) { \
102	Debug("Assertion failed at file %s line %d\n", __FILE__, __LINE__); }
103# endif
104#endif
105
106static void RedrawFail (LoginWidget w);
107static void ResetLogin (LoginWidget w);
108static void failTimeout (XtPointer client_data, XtIntervalId * id);
109static void EraseCursor (LoginWidget w);
110static void XorCursor (LoginWidget w);
111
112#define offset(field) XtOffsetOf(LoginRec, login.field)
113#define goffset(field) XtOffsetOf(WidgetRec, core.field)
114
115
116static XtResource resources[] = {
117    {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
118	goffset(width), XtRImmediate,	(XtPointer) 0},
119    {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
120	goffset(height), XtRImmediate,	(XtPointer) 0},
121    {XtNx, XtCX, XtRPosition, sizeof (Position),
122	goffset(x), XtRImmediate,	(XtPointer) -1},
123    {XtNy, XtCY, XtRPosition, sizeof (Position),
124	goffset(y), XtRImmediate,	(XtPointer) -1},
125#ifndef USE_XFT
126    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
127        offset(textpixel), XtRString,	XtDefaultForeground},
128    {XtNpromptColor, XtCForeground, XtRPixel, sizeof(Pixel),
129        offset(promptpixel), XtRString,	XtDefaultForeground},
130    {XtNgreetColor, XtCForeground, XtRPixel, sizeof(Pixel),
131        offset(greetpixel), XtRString,	XtDefaultForeground},
132    {XtNfailColor, XtCForeground, XtRPixel, sizeof (Pixel),
133	offset(failpixel), XtRString,	XtDefaultForeground},
134#endif
135
136#ifdef DANCING
137/* added by Caolan McNamara */
138	{XtNlastEventTime, XtCLastEventTime, XtRInt , sizeof (int),
139	offset(lastEventTime), XtRImmediate,	(XtPointer)0},
140/* end (caolan) */
141#endif /* DANCING */
142
143#ifdef XPM
144/* added by Ivan Griffin (ivan.griffin@ul.ie) */
145        {XtNlogoFileName, XtCLogoFileName, XtRString, sizeof(char*),
146        offset(logoFileName), XtRImmediate, (XtPointer)0},
147        {XtNuseShape, XtCUseShape, XtRBoolean, sizeof(Boolean),
148        offset(useShape), XtRImmediate, (XtPointer) True},
149        {XtNlogoPadding, XtCLogoPadding, XtRInt, sizeof(int),
150        offset(logoPadding), XtRImmediate, (XtPointer) 5},
151/* end (ivan) */
152#endif /* XPM */
153
154/* added by Amit Margalit */
155    {XtNhiColor, XtCForeground, XtRPixel, sizeof (Pixel),
156	offset(hipixel), XtRString,	XtDefaultForeground},
157    {XtNshdColor, XtCForeground, XtRPixel, sizeof (Pixel),
158	offset(shdpixel), XtRString,	XtDefaultForeground},
159    {XtNinpColor, XtCForeground, XtRPixel, sizeof (Pixel),
160	offset(inppixel), XtRString,	XtDefaultBackground},
161    {XtNframeWidth, XtCFrameWidth, XtRInt, sizeof(int),
162        offset(outframewidth), XtRImmediate, (XtPointer) 1},
163    {XtNinnerFramesWidth, XtCFrameWidth, XtRInt, sizeof(int),
164        offset(inframeswidth), XtRImmediate, (XtPointer) 1},
165    {XtNsepWidth, XtCFrameWidth, XtRInt, sizeof(int),
166        offset(sepwidth), XtRImmediate, (XtPointer) 1},
167/* end (amit) */
168
169#ifndef USE_XFT
170    {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
171	offset (textFont), XtRString,	"*-new century schoolbook-medium-r-normal-*-180-*"},
172    {XtNpromptFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
173	offset (promptFont), XtRString, "*-new century schoolbook-bold-r-normal-*-180-*"},
174    {XtNgreetFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
175	offset (greetFont), XtRString,	"*-new century schoolbook-bold-i-normal-*-240-*"},
176    {XtNfailFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
177	offset (failFont), XtRString,	"*-new century schoolbook-bold-r-normal-*-180-*"},
178#else /* USE_XFT */
179    {XtNface, XtCFace, XtRXftFont, sizeof (XftFont *),
180        offset (textFace), XtRString, "Serif-18"},
181    {XtNpromptFace, XtCFace, XtRXftFont, sizeof (XftFont *),
182        offset (promptFace), XtRString, "Serif-18:bold"},
183    {XtNgreetFace, XtCFace, XtRXftFont, sizeof (XftFont *),
184        offset (greetFace), XtRString, "Serif-24:italic"},
185    {XtNfailFace, XtCFace, XtRXftFont, sizeof (XftFont *),
186        offset (failFace), XtRString, "Serif-18:bold"},
187    {XtNforeground, XtCForeground, XtRXftColor, sizeof(XftColor),
188        offset(textcolor), XtRString,	XtDefaultForeground},
189    {XtNpromptColor, XtCForeground, XtRXftColor, sizeof(XftColor),
190        offset(promptcolor), XtRString,	XtDefaultForeground},
191    {XtNgreetColor, XtCForeground, XtRXftColor, sizeof(XftColor),
192        offset(greetcolor), XtRString,	XtDefaultForeground},
193    {XtNfailColor, XtCForeground, XtRXftColor, sizeof (XftColor),
194	offset(failcolor), XtRString,	XtDefaultForeground},
195#endif
196    {XtNgreeting, XtCGreeting, XtRString, sizeof (char *),
197	offset(greeting), XtRString, "X Window System"},
198    {XtNunsecureGreeting, XtCGreeting, XtRString, sizeof (char *),
199	offset(unsecure_greet), XtRString, "This is an unsecure session"},
200    {XtNnamePrompt, XtCNamePrompt, XtRString, sizeof (char *),
201	offset(namePrompt), XtRString, "Login:  "},
202    {XtNpasswdPrompt, XtCPasswdPrompt, XtRString, sizeof (char *),
203	offset(passwdPrompt), XtRString, "Password:  "},
204    {XtNfail, XtCFail, XtRString, sizeof (char *),
205	offset(failMsg), XtRString,
206	"Login incorrect or forbidden by policy"
207    },
208    {XtNchangePasswdMessage, XtCChangePasswdMessage, XtRString,
209	sizeof (char *), offset(passwdChangeMsg), XtRString,
210	(XtPointer) "Password Change Required" },
211    {XtNfailTimeout, XtCFailTimeout, XtRInt, sizeof (int),
212	offset(failTimeout), XtRImmediate, (XtPointer) 10},
213    {XtNnotifyDone, XtCCallback, XtRFunction, sizeof (XtPointer),
214	offset(notify_done), XtRFunction, (XtPointer) 0},
215    {XtNsessionArgument, XtCSessionArgument, XtRString,	sizeof (char *),
216	offset(sessionArg), XtRString, (XtPointer) 0 },
217    {XtNsecureSession, XtCSecureSession, XtRBoolean, sizeof (Boolean),
218	offset(secure_session), XtRImmediate, (XtPointer) False },
219    {XtNallowAccess, XtCAllowAccess, XtRBoolean, sizeof (Boolean),
220	offset(allow_access), XtRImmediate, (XtPointer) False },
221    {XtNallowNullPasswd, XtCAllowNullPasswd, XtRBoolean, sizeof (Boolean),
222	offset(allow_null_passwd), XtRImmediate, (XtPointer) False},
223    {XtNallowRootLogin, XtCAllowRootLogin, XtRBoolean, sizeof(Boolean),
224	offset(allow_root_login), XtRImmediate, (XtPointer) True},
225    {XtNechoPasswd, XtCEchoPasswd, XtRBoolean, sizeof(Boolean),
226	offset(echo_passwd), XtRImmediate, (XtPointer) False},
227    {XtNechoPasswdChar, XtCEchoPasswdChar, XtRString,	sizeof (char *),
228	offset(echo_passwd_char), XtRString, (XtPointer) "*" }
229};
230
231#undef offset
232#undef goffset
233
234#ifdef USE_XFT
235# define F_MAX_WIDTH(f)	((w)->login.f##Face->max_advance_width)
236# define F_ASCENT(f)	((w)->login.f##Face->ascent)
237# define F_DESCENT(f)	((w)->login.f##Face->descent)
238#else
239# define F_MAX_WIDTH(f)	((w)->login.f##Font->max_bounds.width)
240# define F_ASCENT(f)	((w)->login.f##Font->max_bounds.ascent)
241# define F_DESCENT(f)	((w)->login.f##Font->max_bounds.descent)
242#endif
243
244#define TEXT_X_INC(w)		F_MAX_WIDTH(text)
245#define TEXT_Y_INC(w)		(F_ASCENT(text) + F_DESCENT(text))
246
247#define PROMPT_X_INC(w)		F_MAX_WIDTH(prompt)
248#define PROMPT_Y_INC(w)		(F_ASCENT(prompt) + F_DESCENT(prompt))
249
250#define GREET_X_INC(w)		F_MAX_WIDTH(greet)
251#define GREET_Y_INC(w)		(F_ASCENT(greet) + F_DESCENT(greet))
252
253#define FAIL_X_INC(w)		F_MAX_WIDTH(fail)
254#define FAIL_Y_INC(w)		(F_ASCENT(fail) + F_DESCENT(fail))
255
256#define Y_ASCENT(w)	max (F_ASCENT(prompt), F_ASCENT(text))
257#define Y_DESCENT(w)	max (F_DESCENT(prompt), F_DESCENT(text))
258#define Y_INC(w)	(Y_ASCENT(w) + Y_DESCENT(w))
259
260#define CURSOR_W	5
261
262#define PROMPT_TEXT(w,n) 	((w)->login.prompts[n].promptText)
263#define DEF_PROMPT_TEXT(w,n) 	((w)->login.prompts[n].defaultPrompt)
264#define VALUE_TEXT(w,n) 	((w)->login.prompts[n].valueText)
265#define VALUE_TEXT_MAX(w,n)	((w)->login.prompts[n].valueTextMax)
266#define VALUE_SHOW_START(w,n)	((w)->login.prompts[n].valueShownStart)
267#define VALUE_SHOW_END(w,n)	((w)->login.prompts[n].valueShownEnd)
268#define PROMPT_STATE(w,n) 	((w)->login.prompts[n].state)
269#define PROMPT_CURSOR(w,n)	((w)->login.prompts[n].cursor)
270
271#define CUR_PROMPT_CURSOR(w)	PROMPT_CURSOR(w,w->login.activePrompt)
272
273#define CUR_PROMPT_TEXT(w, n)	(PROMPT_TEXT(w,n) != NULL ? \
274				 PROMPT_TEXT(w,n) : DEF_PROMPT_TEXT(w,n))
275
276#ifdef USE_XFT
277
278# define TEXT_COLOR(f)		(w->login.f##color.pixel)
279
280# define TEXT_WIDTH(f, m, l) 	XmuXftTextWidth(XtDisplay (w), \
281					w->login.f##Face, (FcChar8 *) (m), l)
282static int
283XmuXftTextWidth(Display *dpy, XftFont *font, FcChar8 *string, int len);
284
285# define DRAW_STRING(f, x, y, m, l) \
286	/* Debug("DRAW_STRING(%s, %d, %d, %s, %d)\n", #f, x, y, m, l); */ \
287	XftDrawString8 (w->login.draw, &w->login.f##color, w->login.f##Face, \
288			x, y, (FcChar8 *) (m), l)
289
290#else
291
292# define TEXT_COLOR(f)		(w->login.f##pixel)
293# define TEXT_WIDTH(f, m, l) 	(XTextWidth (w->login.f##Font, m, l))
294# define DRAW_STRING(f, x, y, m, l) \
295	XDrawString (XtDisplay (w), XtWindow (w), w->login.f##GC, x, y, m, l)
296
297#endif
298
299
300#define STRING_WIDTH(f, s) 	TEXT_WIDTH (f, s, strlen(s))
301
302/* Padded width of logo image, if compiled with XPM support */
303#ifdef XPM
304# define LOGO_PAD(w)   ((w)->login.logoPadding)
305# define LOGO_W(w)     ((w)->login.logoWidth + (LOGO_PAD(w) * 2))
306#else
307# define LOGO_PAD(w)   0
308# define LOGO_W(w)     0
309#endif
310
311#define TEXT_PROMPT_W(w, m) (STRING_WIDTH(prompt, m) + w->login.inframeswidth)
312
313#define DEF_PROMPT_W(w,n)	TEXT_PROMPT_W(w, w->login.prompts[n].defaultPrompt)
314#define MAX_DEF_PROMPT_W(w)	(max(DEF_PROMPT_W(w,0), DEF_PROMPT_W(w,1)))
315#define CUR_PROMPT_W(w,n)	(max(MAX_DEF_PROMPT_W(w), PROMPT_TEXT(w,n) ? \
316					TEXT_PROMPT_W(w, PROMPT_TEXT(w,n)) : 0))
317
318#define GREETING(w)	((w)->login.secure_session  && !(w)->login.allow_access ?\
319				(w)->login.greeting : (w)->login.unsecure_greet)
320#define GREET_X(w)	((int)((w->core.width - LOGO_W(w) + LOGO_PAD(w) - \
321			     	STRING_WIDTH (greet, GREETING(w))) / 2))
322#define GREET_Y(w)	(GREETING(w)[0] ? 2 * GREET_Y_INC (w) : 0)
323#define GREET_W(w)	(max (STRING_WIDTH (greet, w->login.greeting), \
324			      STRING_WIDTH (greet, w->login.unsecure_greet)))
325
326#define SEP_X(w)	((w)->login.outframewidth + LOGO_PAD(w))
327#define SEP_Y(w)	(GREET_Y(w) + GREET_Y_INC(w))
328#define SEP_W(w)	((w)->core.width - 2*(w->login.outframewidth) - LOGO_W(w) - LOGO_PAD(w))
329#define SEP_H(w)	((w)->login.inframeswidth * 2)
330
331#define PROMPT_X(w)	(2 * PROMPT_X_INC(w))
332#define PROMPT_Y(w,n) 	(SEP_Y(w) + GREET_Y_INC(w) + (n) * Y_INC(w) + (2*(n)+1) * ((w)->login.inframeswidth + VALUE_VPAD(w,n)))
333#define PROMPT_W(w)	(w->core.width - PROMPT_X(w) - 2 * TEXT_X_INC(w) - LOGO_W(w))
334#define PROMPT_H(w)	Y_INC(w)
335
336#define VALUE_HPAD(w,n)	(TEXT_X_INC(w)/8)
337#define VALUE_VPAD(w,n)	((Y_INC(w)+3)/4)
338#define VALUE_X(w,n)	(PROMPT_X(w) + CUR_PROMPT_W(w,n) + VALUE_HPAD(w,n))
339#define VALUE_Y(w,n)	(PROMPT_Y(w,n))
340#define VALUE_W(w,n)	(PROMPT_W(w) - VALUE_X(w,n) + PROMPT_X(w) - CURSOR_W)
341#define VALUE_H(w,n)	Y_INC(w)
342
343#define ERROR_X(w,m)	((int)(w->core.width - LOGO_W(w) - STRING_WIDTH (fail, m)) / 2)
344#define ERROR_W(w,m)	(STRING_WIDTH (fail, m) + LOGO_W(w))
345
346#define FAIL_X(w)	ERROR_X(w, w->login.fail)
347#define FAIL_Y(w)	(PROMPT_Y(w,1) + 2 * FAIL_Y_INC (w) + F_ASCENT(fail))
348#define FAIL_W(w)	max(ERROR_W(w, w->login.failMsg), \
349			    ERROR_W(w, w->login.passwdChangeMsg))
350
351#define PAD_X(w)	(2 * (PROMPT_X(w) + max (GREET_X_INC(w), FAIL_X_INC(w)) + 4*w->login.outframewidth))
352#define PAD_Y(w)	(max (max (Y_INC(w), GREET_Y_INC(w)),\
353			     FAIL_Y_INC(w)))
354
355#ifndef max
356static inline int max (int a, int b) { return a > b ? a : b; }
357#endif
358
359static void
360realizeValue (LoginWidget w, int cursor, int promptNum, GC gc)
361{
362    loginPromptState state = PROMPT_STATE(w, promptNum);
363    char *text = VALUE_TEXT(w, promptNum);
364    int	x, y, height, width, curoff, offset, textlen;
365
366    XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT);
367
368    /* replace all password characters with asterisks */
369    if ((state == LOGIN_PROMPT_ECHO_OFF) && (w->login.echo_passwd == True))
370    {
371	Cardinal length = strlen(text);
372	Cardinal i = 0;
373
374	text = XtMalloc(length + 1);
375
376	if (text == NULL)
377	{
378	    LogOutOfMem("realizeValue");
379	    return;
380	}
381
382	while (i < length)
383	{
384	    text[i++] = w->login.echo_passwd_char[0];
385	}
386
387	text[i] = 0;
388    }
389
390    x = VALUE_X (w,promptNum) + VALUE_HPAD(w,promptNum);
391    y = VALUE_Y (w,promptNum);
392
393    height = VALUE_H(w,promptNum);
394    width = VALUE_W(w,promptNum);
395
396    offset = VALUE_SHOW_START(w, promptNum);
397    if (cursor > offset)
398	curoff = TEXT_WIDTH (text, text + offset, cursor - offset);
399    else
400	curoff = 0;
401
402    if (gc == w->login.bgGC) {
403	if (curoff < width) {
404	    XFillRectangle (XtDisplay (w), XtWindow (w), gc,
405			    x + curoff, y - Y_ASCENT(w),
406			    width - curoff, height);
407	}
408    } else if ((state == LOGIN_PROMPT_ECHO_ON) || (state == LOGIN_TEXT_INFO) ||
409	       ((state == LOGIN_PROMPT_ECHO_OFF) && (w->login.echo_passwd == True)))
410    {
411	offset = max(cursor, VALUE_SHOW_START(w, promptNum));
412	textlen = strlen (text + offset);
413
414	if (TEXT_WIDTH (text, text + offset, textlen) > (width - curoff)) {
415	    /* Recalculate amount of text that can fit in field */
416	    offset = VALUE_SHOW_START(w, promptNum);
417	    textlen = strlen (text + offset);
418
419	    while ((textlen > 0) &&
420		   (TEXT_WIDTH (text, text + offset, textlen) > width))
421	    {
422		if (offset < PROMPT_CURSOR(w, promptNum)) {
423		    offset++;
424		}
425		textlen--;
426	    }
427
428	    VALUE_SHOW_START(w, promptNum) = offset;
429	    VALUE_SHOW_END(w, promptNum) = offset + textlen;
430
431	    /* Erase old string */
432	    XFillRectangle (XtDisplay (w), XtWindow (w), w->login.bgGC,
433			    x, y - Y_ASCENT(w), width, height);
434
435	    DRAW_STRING(text, x, y, text + offset, textlen);
436	} else {
437	    DRAW_STRING(text, x + curoff, y, text + offset, textlen);
438	}
439    }
440    /* free memory */
441    if ((state == LOGIN_PROMPT_ECHO_OFF) && (w->login.echo_passwd == True))
442    {
443	XtFree(text);
444    }
445}
446
447static void
448EraseValue (LoginWidget w, int cursor, int promptNum)
449{
450    realizeValue(w, cursor, promptNum, w->login.bgGC);
451}
452
453static void
454DrawValue (LoginWidget w, int cursor, int promptNum)
455{
456    realizeValue(w, cursor, promptNum, w->login.textGC);
457#ifdef DANCING
458    /*as good a place as any Caolan begin*/
459    w->login.lastEventTime = time(NULL);
460    /*as good a place as any Caolan end*/
461#endif /* DANCING */
462}
463
464static void
465realizeCursor (LoginWidget w, GC gc)
466{
467    int	x, y;
468    int ascent, descent;
469
470    if (w->login.state != PROMPTING) {
471	return;
472    }
473
474    x = VALUE_X (w, w->login.activePrompt)
475      + VALUE_HPAD(w, w->login.activePrompt);
476    y = VALUE_Y (w, w->login.activePrompt);
477    ascent = F_ASCENT(text);
478    descent = F_DESCENT(text);
479
480    switch (PROMPT_STATE(w, w->login.activePrompt)) {
481    case LOGIN_PROMPT_NOT_SHOWN:
482    case LOGIN_TEXT_INFO:
483	return;
484    case LOGIN_PROMPT_ECHO_ON:
485	if (CUR_PROMPT_CURSOR(w) > 0) {
486	    x += TEXT_WIDTH (text,
487			     VALUE_TEXT(w, w->login.activePrompt)
488			     + VALUE_SHOW_START(w, w->login.activePrompt),
489			     PROMPT_CURSOR(w, w->login.activePrompt)
490			     - VALUE_SHOW_START(w, w->login.activePrompt) );
491	}
492	break;
493    case LOGIN_PROMPT_ECHO_OFF:
494	if (w->login.echo_passwd == True) {
495	    if (w->login.echo_passwd_char[0] != 0) {
496		int len = PROMPT_CURSOR(w, w->login.activePrompt) -
497		    VALUE_SHOW_START(w, w->login.activePrompt);
498
499		x += len*TEXT_WIDTH(text, w->login.echo_passwd_char, 1);
500	    } else {
501		/* Move cursor one pixel per character to give some feedback
502		   without giving away the password length */
503		if (PROMPT_CURSOR(w, w->login.activePrompt) <
504		    VALUE_W(w, w->login.activePrompt))
505		    x += PROMPT_CURSOR(w, w->login.activePrompt);
506		else
507		    x += VALUE_W(w, w->login.activePrompt);
508	    }
509	}
510	break;
511    }
512
513    x += 2;
514
515    XFillRectangle (XtDisplay (w), XtWindow (w), gc,
516		    x, y - ascent + 1, 1, ascent + descent - 2);
517
518    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
519		    x-1 , y - ascent);
520    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
521		    x+1 , y - ascent);
522    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
523		    x-1 , y + descent - 1);
524    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
525		    x+1 , y - descent - 1);
526
527    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
528		    x-2 , y - ascent);
529    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
530		    x+2 , y - ascent);
531    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
532		    x-2 , y + descent - 1);
533    XDrawPoint     (XtDisplay (w), XtWindow (w), gc,
534		    x+2 , y + descent - 1);
535
536    XFlush (XtDisplay(w));
537}
538
539static void
540EraseFail (LoginWidget w)
541{
542#ifdef USE_XFT
543    w->login.failUp = 0;
544    RedrawFail(w);
545#else
546    XSetForeground (XtDisplay (w), w->login.failGC,
547			w->core.background_pixel);
548    RedrawFail(w);
549    w->login.failUp = 0;
550    XSetForeground (XtDisplay (w), w->login.failGC,
551			TEXT_COLOR(fail));
552#endif
553}
554
555static void
556XorCursor (LoginWidget w)
557{
558    realizeCursor (w, w->login.xorGC);
559}
560
561static void
562RemoveFail (LoginWidget w)
563{
564    if (w->login.failUp)
565	EraseFail (w);
566}
567
568static void
569EraseCursor (LoginWidget w)
570{
571    realizeCursor (w, w->login.bgGC);
572}
573
574/*ARGSUSED*/
575static void failTimeout (XtPointer client_data, XtIntervalId * id)
576{
577    LoginWidget	w = (LoginWidget)client_data;
578
579    Debug ("failTimeout\n");
580    w->login.interval_id = 0;
581    EraseFail (w);
582}
583
584_X_INTERNAL
585void
586DrawFail (Widget ctx)
587{
588    LoginWidget	w;
589
590    w = (LoginWidget) ctx;
591    XorCursor (w);
592    ResetLogin (w);
593    XorCursor (w);
594    ErrorMessage(ctx, w->login.failMsg, True);
595}
596
597static void
598RedrawFail (LoginWidget w)
599{
600    int x = FAIL_X(w);
601    int y = FAIL_Y(w);
602    int maxw = w->core.width - PAD_X(w);
603
604#ifndef USE_XFT
605    if (w->login.failUp)
606#endif
607    {
608	Debug("RedrawFail('%s', %d)\n", w->login.fail, w->login.failUp);
609	if (ERROR_W(w, w->login.fail) > maxw) {
610	    /* Too long to fit on one line, break into multiple lines */
611	    char *tempCopy = strdup(w->login.fail);
612	    if (tempCopy != NULL) {
613		char *start, *next;
614		char lastspace = ' ';
615
616		y = PROMPT_Y(w,LAST_PROMPT) + (2 * PROMPT_Y_INC(w));
617
618		for (start = next = tempCopy; start != NULL ; start = next) {
619		    /* search for longest string broken by whitespace that
620		       will fit on a single line */
621		    do {
622			if (next != start) {
623			    *next = lastspace;
624			}
625			for (next = next + 1;
626			     (*next != '\0') && !isspace(*next) ; next++)
627			{
628			    /* this loop intentionally left blank */
629			}
630			if (*next != '\0') {
631			    lastspace = *next;
632			    *next = '\0';
633			} else {
634			    next = NULL;
635			}
636		    } while ((next != NULL) && ERROR_W(w, start) < maxw);
637
638		    x = ERROR_X(w, start);
639#ifdef USE_XFT
640		    if (w->login.failUp == 0) {
641			XClearArea(XtDisplay(w), XtWindow(w), x, y - F_ASCENT(fail),
642				   ERROR_W(w, start), FAIL_Y_INC(w), False);
643		    } else
644#endif
645			DRAW_STRING (fail, x, y, start, strlen(start));
646
647		    if (next != NULL) {
648			next++;
649			y += FAIL_Y_INC(w);
650		    }
651		}
652		free(tempCopy);
653		return;
654	    }
655	    /* if strdup failed, fall through to draw all at once, even
656	       though we know it can't all fit */
657	    LogOutOfMem("RedrawFail");
658	}
659
660#ifdef USE_XFT
661	if (w->login.failUp == 0) {
662	    XClearArea(XtDisplay(w), XtWindow(w), x, y - F_ASCENT(fail),
663		       ERROR_W(w, w->login.fail), FAIL_Y_INC(w), False);
664	} else
665#endif
666	    DRAW_STRING (fail, x, y, w->login.fail, strlen (w->login.fail));
667    }
668}
669
670_X_INTERNAL
671void
672ErrorMessage(Widget ctx, const char *message, Bool timeout)
673{
674    LoginWidget	w = (LoginWidget) ctx;
675
676/*  Debug("ErrorMessage: %s\n", message);   */
677    if (w->login.interval_id != 0) {
678	XtRemoveTimeOut(w->login.interval_id);
679	w->login.interval_id = 0;
680    }
681    RemoveFail(w);
682    if (w->login.fail != w->login.failMsg)
683	free(w->login.fail);
684    w->login.fail = strdup(message);
685    if (w->login.fail == NULL)
686	w->login.fail = (char *) w->login.failMsg;
687    w->login.failUp = 1;
688    RedrawFail (w);
689    if (timeout && (w->login.failTimeout > 0)) {
690	Debug ("failTimeout: %d\n", w->login.failTimeout);
691	w->login.interval_id =
692	    XtAppAddTimeOut(XtWidgetToApplicationContext ((Widget)w),
693			    w->login.failTimeout * 1000,
694			    failTimeout, (XtPointer) w);
695    }
696}
697
698_X_INTERNAL
699void
700ShowChangePasswdMessage(Widget ctx)
701{
702    LoginWidget	w = (LoginWidget) ctx;
703
704    ErrorMessage(ctx, w->login.passwdChangeMsg, False);
705}
706
707static void
708draw_it (LoginWidget w)
709{
710    int p;
711    int i;
712    int gr_line_x, gr_line_y, gr_line_w;
713
714    EraseCursor (w);
715
716    /* draw window borders */
717    for(i=1;i<=(w->login.outframewidth);i++)
718    {
719      XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
720		i-1,i-1,w->core.width-i,i-1);
721      XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
722		i-1,i-1,i-1,w->core.height-i);
723      XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
724		w->core.width-i,i-1,w->core.width-i,w->core.height-i);
725      XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
726		i-1,w->core.height-i,w->core.width-i,w->core.height-i);
727    }
728
729    /* make separator line */
730    gr_line_x = SEP_X(w);
731    gr_line_y = SEP_Y(w);
732    gr_line_w = SEP_W(w);
733
734    for(i=1;i<=(w->login.sepwidth);i++)
735    {
736      XDrawLine(XtDisplay (w), XtWindow (w), w->login.shdGC,
737        gr_line_x,           gr_line_y + i-1,
738        gr_line_x+gr_line_w, gr_line_y + i-1);
739      XDrawLine(XtDisplay (w), XtWindow (w), w->login.hiGC,
740        gr_line_x,           gr_line_y + SEP_H(w) -i,
741        gr_line_x+gr_line_w, gr_line_y + SEP_H(w) -i);
742    }
743
744    for (p = 0; p < NUM_PROMPTS ; p++)
745    {
746	int in_frame_x = VALUE_X(w,p) - w->login.inframeswidth;
747	int in_frame_y = VALUE_Y(w,p) - Y_ASCENT(w) - w->login.inframeswidth
748		- VALUE_VPAD(w,p);
749
750	int in_width = VALUE_W(w,p) + CURSOR_W + 2 * w->login.inframeswidth
751		+ 2 * VALUE_HPAD(w,p);
752	int in_height = VALUE_H(w,p) + 2 * w->login.inframeswidth
753		+ 2 * VALUE_VPAD(w,p);
754
755	GC topLeftGC, botRightGC, inpGC;
756
757	if ((PROMPT_STATE(w, p) == LOGIN_PROMPT_ECHO_ON) ||
758	    (PROMPT_STATE(w, p) == LOGIN_PROMPT_ECHO_OFF)) {
759	    topLeftGC = w->login.shdGC;
760	    botRightGC = w->login.hiGC;
761	    inpGC = w->login.inpGC;
762	} else {
763	    topLeftGC = botRightGC = inpGC = w->login.bgGC;
764	}
765
766	/* draw borders of editboxes */
767	for (i=1; i<=(w->login.inframeswidth); i++)
768	{
769	    /* Make top/left sides */
770	    XDrawLine(XtDisplay (w), XtWindow (w), topLeftGC,
771		      in_frame_x + i-1,         in_frame_y + i-1,
772		      in_frame_x + in_width-i,  in_frame_y + i-1);
773
774	    XDrawLine(XtDisplay (w), XtWindow (w), topLeftGC,
775		      in_frame_x + i-1,         in_frame_y + i-1,
776		      in_frame_x + i-1,         in_frame_y + in_height-i);
777
778	    /* Make bottom/right sides */
779	    XDrawLine(XtDisplay (w), XtWindow (w), botRightGC,
780		      in_frame_x + in_width-i,  in_frame_y + i-1,
781		      in_frame_x + in_width-i,  in_frame_y + in_height-i);
782
783	    XDrawLine(XtDisplay (w), XtWindow (w), botRightGC,
784		      in_frame_x + i-1,         in_frame_y + in_height-i,
785		      in_frame_x + in_width-i,  in_frame_y + in_height-i);
786	}
787	XFillRectangle(XtDisplay (w), XtWindow (w), inpGC,
788	    in_frame_x + w->login.inframeswidth,
789	    in_frame_y + w->login.inframeswidth,
790	    in_width - 2*w->login.inframeswidth,
791	    in_height - 2*w->login.inframeswidth);
792    }
793
794    if (GREETING(w)[0]) {
795	DRAW_STRING (greet, GREET_X(w), GREET_Y(w),
796		     GREETING(w), strlen (GREETING(w)));
797    }
798    for (p = 0; p < NUM_PROMPTS ; p++) {
799	if (PROMPT_STATE(w, p) != LOGIN_PROMPT_NOT_SHOWN) {
800	    DRAW_STRING (prompt, PROMPT_X(w), PROMPT_Y(w,p),
801			 CUR_PROMPT_TEXT(w,p), strlen (CUR_PROMPT_TEXT(w,p)));
802	    DrawValue (w, 0, p);
803	}
804    }
805    RedrawFail (w);
806    XorCursor (w);
807    XSetInputFocus (XtDisplay (w), XtWindow (w),
808		    RevertToPointerRoot, CurrentTime);
809}
810
811/* Returns 0 on success, -1 on failure */
812_X_INTERNAL
813int
814SetPrompt (Widget ctx, int promptNum, const char *message,
815	   loginPromptState state, Boolean minimumTime)
816{
817    LoginWidget	w = (LoginWidget) ctx;
818    char *prompt;
819    int messageLen, e;
820    const char *stateNames[4] = {
821	"LOGIN_PROMPT_NOT_SHOWN", "LOGIN_PROMPT_ECHO_ON",
822	"LOGIN_PROMPT_ECHO_OFF", "LOGIN_TEXT_INFO" };
823    loginPromptState priorState;
824
825    Debug("SetPrompt(%d, %s, %s(%d))\n", promptNum,
826	  message ? message : "<NULL>", stateNames[state], state);
827
828    XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT);
829
830    if (PROMPT_TEXT(w, promptNum) != NULL) {
831	XtFree(PROMPT_TEXT(w, promptNum));
832	PROMPT_TEXT(w, promptNum) = NULL;
833    }
834
835    priorState = PROMPT_STATE(w, promptNum);
836    PROMPT_STATE(w, promptNum) = state;
837
838    if (state == LOGIN_PROMPT_NOT_SHOWN) {
839	return 0;
840    }
841
842    if (message == NULL) {
843	message = DEF_PROMPT_TEXT(w, promptNum);
844    }
845
846    messageLen = strlen(message);
847
848    prompt = XtMalloc(messageLen + 3);
849    if (prompt == NULL) {
850	LogOutOfMem ("SetPrompt");
851	return -1;
852    }
853
854    strncpy(prompt, message, messageLen);
855
856    /* Make sure text prompts have at least two spaces at end */
857    e = messageLen;
858
859    if (!isspace(message[messageLen - 2])) {
860	prompt[e] = ' ';
861	e++;
862    }
863    if (!isspace(message[messageLen - 1])) {
864	prompt[e] = ' ';
865	e++;
866    }
867    prompt[e] = '\0';
868
869    PROMPT_TEXT(w, promptNum) = prompt;
870
871    if (w->login.state == INITIALIZING) {
872	return 0;
873    }
874
875    if ((priorState == LOGIN_TEXT_INFO) && (w->login.msgTimeout != 0)) {
876	time_t now = time(NULL);
877	int timeleft = w->login.msgTimeout - now;
878
879	if (timeleft > 0) {
880	    sleep(timeleft);
881	}
882	w->login.msgTimeout = 0;
883    }
884
885    if (state == LOGIN_TEXT_INFO) {
886	if (minimumTime) {
887	    time_t now = time(NULL);
888	    w->login.msgTimeout = now + w->login.failTimeout;
889	}
890	w->login.state = SHOW_MESSAGE;
891    } else {
892	w->login.activePrompt = promptNum;
893	w->login.state = PROMPTING;
894    }
895
896    PROMPT_CURSOR(w, promptNum) = 0;
897    XClearArea (XtDisplay(w), XtWindow(w), 0, 0, 0, 0, FALSE);
898    draw_it(w);
899    return 0;
900}
901
902_X_INTERNAL
903const char *
904GetPrompt(Widget ctx, int promptNum)
905{
906    LoginWidget	w = (LoginWidget) ctx;
907
908    XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT);
909
910    return CUR_PROMPT_TEXT(w,promptNum);
911}
912
913_X_INTERNAL
914int
915SetValue(Widget ctx, int promptNum, const char *value)
916{
917    LoginWidget	w = (LoginWidget) ctx;
918
919    XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT);
920
921    if ((promptNum < 0) || (promptNum > LAST_PROMPT))
922	return -1;
923
924    XDM_ASSERT(VALUE_TEXT(w, promptNum) != NULL);
925
926    if (VALUE_TEXT(w, promptNum) == NULL)
927	return -1;
928
929    if (value == NULL) {
930	bzero(VALUE_TEXT(w, promptNum), VALUE_TEXT_MAX(w, promptNum));
931    } else {
932	strncpy(VALUE_TEXT(w, promptNum), value, VALUE_TEXT_MAX(w, promptNum));
933	VALUE_TEXT(w, promptNum)[VALUE_TEXT_MAX(w, promptNum)] = '\0';
934    }
935
936    VALUE_SHOW_START(w, promptNum) = 0;
937    VALUE_SHOW_END(w, promptNum) = 0;
938    PROMPT_CURSOR(w, promptNum) = 0;
939
940    return 0;
941}
942
943_X_INTERNAL
944const char *
945GetValue(Widget ctx, int promptNum)
946{
947    LoginWidget	w = (LoginWidget) ctx;
948
949    XDM_ASSERT(promptNum >= 0 && promptNum <= LAST_PROMPT);
950
951    if ((promptNum < 0) || (promptNum > LAST_PROMPT))
952	return NULL;
953
954    XDM_ASSERT(VALUE_TEXT(w, promptNum) != NULL);
955
956    return VALUE_TEXT(w, promptNum);
957}
958
959
960static void
961realizeDeleteChar (LoginWidget ctx)
962{
963    if (ctx->login.state == PROMPTING) {
964	int promptNum = ctx->login.activePrompt;
965	int redrawFrom = PROMPT_CURSOR(ctx, promptNum);
966
967	if (PROMPT_CURSOR(ctx,promptNum) <  (int)strlen(VALUE_TEXT(ctx,promptNum))) {
968	    if (redrawFrom <= VALUE_SHOW_START(ctx, ctx->login.activePrompt)) {
969		if (redrawFrom > 0)
970			redrawFrom--;
971		EraseValue (ctx, 0, promptNum);
972		VALUE_SHOW_START(ctx, ctx->login.activePrompt) = redrawFrom;
973	    } else {
974		EraseValue (ctx, redrawFrom, promptNum);
975	    }
976	    strcpy(VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum),
977		   VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum) + 1);
978	    DrawValue (ctx, redrawFrom, promptNum);
979	}
980    }
981}
982
983/*ARGSUSED*/
984static void
985DeleteBackwardChar (Widget ctxw, XEvent *event, String *params, Cardinal *num_params)
986{
987    LoginWidget ctx = (LoginWidget)ctxw;
988
989    RemoveFail (ctx);
990
991    if (ctx->login.state != PROMPTING) {
992	return;
993    }
994
995    XorCursor (ctx);
996    if (CUR_PROMPT_CURSOR(ctx) > 0) {
997	CUR_PROMPT_CURSOR(ctx) -= 1;
998	realizeDeleteChar(ctx);
999    }
1000    XorCursor (ctx);
1001}
1002
1003/*ARGSUSED*/
1004static void
1005DeleteForwardChar (Widget ctxw, XEvent *event, String *params, Cardinal *num_params)
1006{
1007    LoginWidget ctx = (LoginWidget)ctxw;
1008
1009    RemoveFail (ctx);
1010
1011    if (ctx->login.state != PROMPTING) {
1012	return;
1013    }
1014
1015    XorCursor (ctx);
1016    realizeDeleteChar(ctx);
1017    XorCursor (ctx);
1018}
1019
1020/*ARGSUSED*/
1021static void
1022MoveBackwardChar (
1023    Widget	ctxw,
1024    XEvent	*event,
1025    String	*params,
1026    Cardinal	*num_params)
1027{
1028    LoginWidget	ctx = (LoginWidget)ctxw;
1029
1030    RemoveFail (ctx);
1031
1032    if (ctx->login.state != PROMPTING) {
1033	return;
1034    }
1035
1036    XorCursor (ctx);
1037    if (CUR_PROMPT_CURSOR(ctx) > 0)
1038	CUR_PROMPT_CURSOR(ctx) -= 1;
1039    if (CUR_PROMPT_CURSOR(ctx) < VALUE_SHOW_START(ctx, ctx->login.activePrompt)) {
1040	EraseValue(ctx, 0, ctx->login.activePrompt);
1041	VALUE_SHOW_START(ctx, ctx->login.activePrompt)
1042	    = CUR_PROMPT_CURSOR(ctx);
1043	DrawValue(ctx, 0, ctx->login.activePrompt);
1044    }
1045    XorCursor (ctx);
1046}
1047
1048/*ARGSUSED*/
1049static void
1050MoveForwardChar (
1051    Widget	ctxw,
1052    XEvent	*event,
1053    String	*params,
1054    Cardinal	*num_params)
1055{
1056    LoginWidget ctx = (LoginWidget)ctxw;
1057
1058    RemoveFail (ctx);
1059
1060    if (ctx->login.state != PROMPTING) {
1061	return;
1062    }
1063
1064    XorCursor (ctx);
1065    if (CUR_PROMPT_CURSOR(ctx) <
1066	(int)strlen(VALUE_TEXT(ctx,ctx->login.activePrompt))) {
1067	CUR_PROMPT_CURSOR(ctx) += 1;
1068	if (VALUE_SHOW_END(ctx, ctx->login.activePrompt)
1069	    < CUR_PROMPT_CURSOR(ctx)) {
1070	    EraseValue(ctx, 0, ctx->login.activePrompt);
1071	    DrawValue(ctx, 0, ctx->login.activePrompt);
1072	}
1073    }
1074    XorCursor (ctx);
1075}
1076
1077/*ARGSUSED*/
1078static void
1079MoveToBegining (
1080    Widget	ctxw,
1081    XEvent	*event,
1082    String	*params,
1083    Cardinal	*num_params)
1084{
1085    LoginWidget ctx = (LoginWidget)ctxw;
1086
1087    RemoveFail (ctx);
1088
1089    if (ctx->login.state != PROMPTING) {
1090	return;
1091    }
1092
1093    XorCursor (ctx);
1094    CUR_PROMPT_CURSOR(ctx) = 0;
1095    if (VALUE_SHOW_START(ctx, ctx->login.activePrompt) > 0) {
1096	EraseValue(ctx, 0, ctx->login.activePrompt);
1097	VALUE_SHOW_START(ctx, ctx->login.activePrompt) = 0;
1098	DrawValue(ctx, 0, ctx->login.activePrompt);
1099    }
1100    XorCursor (ctx);
1101}
1102
1103/*ARGSUSED*/
1104static void
1105MoveToEnd (
1106    Widget	ctxw,
1107    XEvent	*event,
1108    String	*params,
1109    Cardinal	*num_params)
1110{
1111    LoginWidget ctx = (LoginWidget)ctxw;
1112
1113    RemoveFail (ctx);
1114
1115    if (ctx->login.state != PROMPTING) {
1116	return;
1117    }
1118
1119    XorCursor (ctx);
1120    CUR_PROMPT_CURSOR(ctx) = strlen (VALUE_TEXT(ctx, ctx->login.activePrompt));
1121    if (VALUE_SHOW_END(ctx, ctx->login.activePrompt) < CUR_PROMPT_CURSOR(ctx)) {
1122	EraseValue(ctx, 0, ctx->login.activePrompt);
1123	DrawValue(ctx, 0, ctx->login.activePrompt);
1124    }
1125    XorCursor (ctx);
1126}
1127
1128/*ARGSUSED*/
1129static void
1130EraseToEndOfLine (
1131    Widget	ctxw,
1132    XEvent	*event,
1133    String	*params,
1134    Cardinal	*num_params)
1135{
1136    LoginWidget ctx = (LoginWidget)ctxw;
1137
1138    RemoveFail (ctx);
1139
1140    if (ctx->login.state != PROMPTING) {
1141	return;
1142    }
1143
1144    XorCursor (ctx);
1145    EraseValue (ctx, CUR_PROMPT_CURSOR(ctx), ctx->login.activePrompt);
1146    bzero(VALUE_TEXT(ctx, ctx->login.activePrompt) +
1147	  CUR_PROMPT_CURSOR(ctx),
1148	  VALUE_TEXT_MAX(ctx, ctx->login.activePrompt) -
1149	  CUR_PROMPT_CURSOR(ctx));
1150    XorCursor (ctx);
1151}
1152
1153/*ARGSUSED*/
1154static void
1155EraseLine (
1156    Widget	ctxw,
1157    XEvent	*event,
1158    String	*params,
1159    Cardinal	*num_params)
1160{
1161    MoveToBegining (ctxw, event, params, num_params);
1162    EraseToEndOfLine (ctxw, event, params, num_params);
1163}
1164
1165/*ARGSUSED*/
1166static void
1167FinishField (
1168    Widget	ctxw,
1169    XEvent	*event,
1170    String	*params,
1171    Cardinal	*num_params)
1172{
1173    LoginWidget ctx = (LoginWidget)ctxw;
1174    int promptNum = ctx->login.activePrompt;
1175    int nextPrompt;
1176
1177    RemoveFail (ctx);
1178
1179    if (ctx->login.state != PROMPTING) {
1180	return;
1181    }
1182
1183    XorCursor (ctx);
1184
1185    for (nextPrompt = promptNum + 1; nextPrompt <= LAST_PROMPT; nextPrompt++) {
1186	if ((PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_ON) ||
1187	    (PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_OFF)) {
1188	    ctx->login.activePrompt = nextPrompt;
1189	    break;
1190	}
1191    }
1192    if (nextPrompt > LAST_PROMPT) {
1193	ctx->login.state = DONE;
1194	(*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_OK);
1195	Debug("FinishField #%d: now DONE\n", promptNum);
1196    } else {
1197	Debug("FinishField #%d: %d next\n", promptNum, nextPrompt);
1198    }
1199
1200    XorCursor (ctx);
1201}
1202
1203/*ARGSUSED*/
1204static void
1205TabField(Widget ctxw, XEvent *event, String *params, Cardinal *num_params)
1206{
1207    LoginWidget ctx = (LoginWidget)ctxw;
1208    int promptNum = ctx->login.activePrompt;
1209    int nextPrompt;
1210
1211    RemoveFail (ctx);
1212
1213    if (ctx->login.state != PROMPTING) {
1214	return;
1215    }
1216
1217    XorCursor (ctx);
1218
1219    for (nextPrompt = promptNum + 1; nextPrompt != promptNum; nextPrompt++) {
1220	if (nextPrompt > LAST_PROMPT) {
1221	    nextPrompt = 0;
1222	}
1223
1224	if ((PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_ON) ||
1225	    (PROMPT_STATE(ctx, nextPrompt) == LOGIN_PROMPT_ECHO_OFF)) {
1226	    ctx->login.activePrompt = nextPrompt;
1227	    break;
1228	}
1229    }
1230    XorCursor (ctx);
1231}
1232
1233/*ARGSUSED*/
1234static void
1235AllowAccess (
1236    Widget	ctxw,
1237    XEvent	*event,
1238    String	*params,
1239    Cardinal	*num_params)
1240{
1241    LoginWidget ctx = (LoginWidget)ctxw;
1242    Arg	arglist[1];
1243    Boolean allow;
1244
1245    RemoveFail (ctx);
1246    XtSetArg (arglist[0], XtNallowAccess, (char *) &allow);
1247    XtGetValues ((Widget) ctx, arglist, 1);
1248    XtSetArg (arglist[0], XtNallowAccess, !allow);
1249    XtSetValues ((Widget) ctx, arglist, 1);
1250}
1251
1252/*ARGSUSED*/
1253static void
1254SetSessionArgument (
1255    Widget	ctxw,
1256    XEvent	*event,
1257    String	*params,
1258    Cardinal	*num_params)
1259{
1260    LoginWidget ctx = (LoginWidget)ctxw;
1261
1262    RemoveFail (ctx);
1263    if (ctx->login.sessionArg)
1264	XtFree (ctx->login.sessionArg);
1265    ctx->login.sessionArg = NULL;
1266    if (*num_params > 0) {
1267	ctx->login.sessionArg = XtMalloc (strlen (params[0]) + 1);
1268	if (ctx->login.sessionArg)
1269	    strcpy (ctx->login.sessionArg, params[0]);
1270	else
1271	    LogOutOfMem ("set session argument");
1272    }
1273}
1274
1275/*ARGSUSED*/
1276static void
1277RestartSession (
1278    Widget	ctxw,
1279    XEvent	*event,
1280    String	*params,
1281    Cardinal	*num_params)
1282{
1283    LoginWidget ctx = (LoginWidget)ctxw;
1284
1285    XorCursor (ctx);
1286    RemoveFail (ctx);
1287    ctx->login.state = DONE;
1288    (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_RESTART);
1289    XorCursor (ctx);
1290}
1291
1292/*ARGSUSED*/
1293static void
1294AbortSession (
1295    Widget	ctxw,
1296    XEvent	*event,
1297    String	*params,
1298    Cardinal	*num_params)
1299{
1300    LoginWidget ctx = (LoginWidget)ctxw;
1301
1302    XorCursor (ctx);
1303    RemoveFail (ctx);
1304    ctx->login.state = DONE;
1305    (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT);
1306    XorCursor (ctx);
1307}
1308
1309/*ARGSUSED*/
1310static void
1311AbortDisplay (
1312    Widget	ctxw,
1313    XEvent	*event,
1314    String	*params,
1315    Cardinal	*num_params)
1316{
1317    LoginWidget ctx = (LoginWidget)ctxw;
1318
1319    XorCursor (ctx);
1320    RemoveFail (ctx);
1321    ctx->login.state = DONE;
1322    (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT_DISPLAY);
1323    XorCursor (ctx);
1324}
1325
1326static void
1327ResetLogin (LoginWidget w)
1328{
1329    int i;
1330
1331    for (i = 0; i < NUM_PROMPTS ; i++) {
1332	EraseValue(w, 0, i);
1333	bzero(VALUE_TEXT(w, i), VALUE_TEXT_MAX(w, i));
1334	VALUE_SHOW_START(w, i) = 0;
1335	PROMPT_CURSOR(w, i) = 0;
1336    }
1337    w->login.state = PROMPTING;
1338    w->login.activePrompt = 0;
1339}
1340
1341static void
1342InitI18N(Widget ctxw)
1343{
1344    LoginWidget ctx = (LoginWidget)ctxw;
1345    XIM         xim = (XIM) NULL;
1346    char *p;
1347
1348    ctx->login.xic = (XIC) NULL;
1349
1350    if ((p = XSetLocaleModifiers("@im=none")) != NULL && *p)
1351	xim = XOpenIM(XtDisplay(ctx), NULL, NULL, NULL);
1352
1353    if (!xim) {
1354	LogError("Failed to open input method\n");
1355	return;
1356    }
1357
1358    ctx->login.xic = XCreateIC(xim,
1359	XNInputStyle, (XIMPreeditNothing|XIMStatusNothing),
1360	XNClientWindow, ctx->core.window,
1361	XNFocusWindow,  ctx->core.window, NULL);
1362
1363    if (!ctx->login.xic) {
1364	LogError("Failed to create input context\n");
1365	XCloseIM(xim);
1366    }
1367    return;
1368}
1369
1370/* ARGSUSED */
1371static void
1372InsertChar (
1373    Widget	ctxw,
1374    XEvent	*event,
1375    String	*params,
1376    Cardinal	*num_params)
1377{
1378    LoginWidget ctx = (LoginWidget)ctxw;
1379
1380    char strbuf[128];
1381    int  len, promptNum = ctx->login.activePrompt;
1382    KeySym  keysym = 0;
1383
1384    if (ctx->login.xic) {
1385	static Status status;
1386	len = XmbLookupString(ctx->login.xic, &event->xkey, strbuf,
1387			      sizeof (strbuf), &keysym, &status);
1388    } else {
1389	static XComposeStatus compose_status = {NULL, 0};
1390	len = XLookupString (&event->xkey, strbuf, sizeof (strbuf),
1391			     &keysym, &compose_status);
1392    }
1393    strbuf[len] = '\0';
1394
1395    /*
1396     * Note: You can override this default key handling
1397     * by the settings in the translation table
1398     * loginActionsTable at the end of this file.
1399     */
1400    switch (keysym) {
1401    case XK_Return:
1402    case XK_KP_Enter:
1403    case XK_Linefeed:
1404    case XK_Execute:
1405	FinishField(ctxw, event, params, num_params);
1406	return;
1407    case XK_BackSpace:
1408	DeleteBackwardChar(ctxw, event, params, num_params);
1409	return;
1410    case XK_Delete:
1411    case XK_KP_Delete:
1412    case DXK_Remove:
1413	/* Sorry, it's not a telex machine, it's a terminal */
1414	DeleteForwardChar(ctxw, event, params, num_params);
1415	return;
1416    case XK_Left:
1417    case XK_KP_Left:
1418	MoveBackwardChar(ctxw, event, params, num_params);
1419	return;
1420    case XK_Right:
1421    case XK_KP_Right:
1422	MoveForwardChar(ctxw, event, params, num_params);
1423	return;
1424    case XK_End:
1425    case XK_KP_End:
1426	MoveToEnd(ctxw, event, params, num_params);
1427	return;
1428    case XK_Home:
1429    case XK_KP_Home:
1430	MoveToBegining(ctxw, event, params, num_params);
1431	return;
1432    default:
1433	if (len == 0) {
1434	    if (!IsModifierKey(keysym))  /* it's not a modifier */
1435		XBell(XtDisplay(ctxw), 60);
1436	    return;
1437	} else
1438	    break;
1439    }
1440
1441    if (ctx->login.state == PROMPTING) {
1442	if ((len + (int)strlen(VALUE_TEXT(ctx, promptNum)) >=
1443	     (VALUE_TEXT_MAX(ctx,promptNum) - 1))) {
1444	    len = VALUE_TEXT_MAX(ctx,promptNum) -
1445		strlen(VALUE_TEXT(ctx, promptNum)) - 2;
1446	}
1447    }
1448    EraseCursor (ctx);
1449    RemoveFail (ctx);
1450    if (len != 0)
1451    {
1452	if (ctx->login.state == PROMPTING) {
1453	    EraseValue (ctx, PROMPT_CURSOR(ctx, promptNum), promptNum);
1454	    memmove(VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum) + len,
1455		    VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum),
1456		    strlen (VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum))+1);
1457	    memmove(VALUE_TEXT(ctx, promptNum) + PROMPT_CURSOR(ctx, promptNum),
1458		     strbuf, len);
1459	    DrawValue (ctx, PROMPT_CURSOR(ctx, promptNum), promptNum);
1460	    PROMPT_CURSOR(ctx, promptNum) += len;
1461	}
1462    }
1463    XorCursor (ctx);
1464}
1465
1466
1467/**** Copied from xclock.c - original author: Keith Packard ****/
1468#ifdef USE_XFT
1469static XtConvertArgRec xftColorConvertArgs[] = {
1470    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
1471     sizeof(Screen *)},
1472    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
1473     sizeof(Colormap)}
1474};
1475
1476# define	donestr(type, value, tstr) \
1477	{							\
1478	    if (toVal->addr != NULL) {				\
1479		if (toVal->size < sizeof(type)) {		\
1480		    toVal->size = sizeof(type);			\
1481		    XtDisplayStringConversionWarning(dpy, 	\
1482			(char*) fromVal->addr, tstr);		\
1483		    return False;				\
1484		}						\
1485		*(type*)(toVal->addr) = (value);		\
1486	    }							\
1487	    else {						\
1488		static type static_val;				\
1489		static_val = (value);				\
1490		toVal->addr = (XPointer)&static_val;		\
1491	    }							\
1492	    toVal->size = sizeof(type);				\
1493	    return True;					\
1494	}
1495
1496static void
1497XmuFreeXftColor (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
1498		 XrmValuePtr args, Cardinal *num_args)
1499{
1500    Screen	*screen;
1501    Colormap	colormap;
1502    XftColor	*color;
1503
1504    if (*num_args != 2)
1505    {
1506	XtAppErrorMsg (app,
1507		       "freeXftColor", "wrongParameters",
1508		       "XtToolkitError",
1509		       "Freeing an XftColor requires screen and colormap arguments",
1510		       (String *) NULL, (Cardinal *)NULL);
1511	return;
1512    }
1513
1514    screen = *((Screen **) args[0].addr);
1515    colormap = *((Colormap *) args[1].addr);
1516    color = (XftColor *) toVal->addr;
1517    XftColorFree (DisplayOfScreen (screen),
1518		  DefaultVisual (DisplayOfScreen (screen),
1519				 XScreenNumberOfScreen (screen)),
1520		  colormap, color);
1521}
1522
1523static Boolean
1524XmuCvtStringToXftColor(Display *dpy,
1525		       XrmValue *args, Cardinal *num_args,
1526		       XrmValue *fromVal, XrmValue *toVal,
1527		       XtPointer *converter_data)
1528{
1529    char	    *spec;
1530    XRenderColor    renderColor;
1531    XftColor	    xftColor;
1532    Screen	    *screen;
1533    Colormap	    colormap;
1534
1535    if (*num_args != 2)
1536    {
1537	XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
1538		       "cvtStringToXftColor", "wrongParameters",
1539		       "XtToolkitError",
1540		       "String to render color conversion needs screen and colormap arguments",
1541		       (String *) NULL, (Cardinal *)NULL);
1542	return False;
1543    }
1544
1545    screen = *((Screen **) args[0].addr);
1546    colormap = *((Colormap *) args[1].addr);
1547
1548    spec = (char *) fromVal->addr;
1549    if (strcasecmp (spec, XtDefaultForeground) == 0)
1550    {
1551	renderColor.red = 0;
1552	renderColor.green = 0;
1553	renderColor.blue = 0;
1554	renderColor.alpha = 0xffff;
1555    }
1556    else if (strcasecmp (spec, XtDefaultBackground) == 0)
1557    {
1558	renderColor.red = 0xffff;
1559	renderColor.green = 0xffff;
1560	renderColor.blue = 0xffff;
1561	renderColor.alpha = 0xffff;
1562    }
1563    else if (!XRenderParseColor (dpy, spec, &renderColor))
1564	return False;
1565    if (!XftColorAllocValue (dpy,
1566			     DefaultVisual (dpy,
1567					    XScreenNumberOfScreen (screen)),
1568			     colormap,
1569			     &renderColor,
1570			     &xftColor))
1571	return False;
1572
1573    donestr (XftColor, xftColor, XtRXftColor);
1574}
1575
1576static void
1577XmuFreeXftFont (XtAppContext app, XrmValuePtr toVal, XtPointer closure,
1578		XrmValuePtr args, Cardinal *num_args)
1579{
1580    Screen  *screen;
1581    XftFont *font;
1582
1583    if (*num_args != 1)
1584    {
1585	XtAppErrorMsg (app,
1586		       "freeXftFont", "wrongParameters",
1587		       "XtToolkitError",
1588		       "Freeing an XftFont requires screen argument",
1589		       (String *) NULL, (Cardinal *)NULL);
1590	return;
1591    }
1592
1593    screen = *((Screen **) args[0].addr);
1594    font = *((XftFont **) toVal->addr);
1595    if (font)
1596	XftFontClose (DisplayOfScreen (screen), font);
1597}
1598
1599static Boolean
1600XmuCvtStringToXftFont(Display *dpy,
1601		      XrmValue *args, Cardinal *num_args,
1602		      XrmValue *fromVal, XrmValue *toVal,
1603		      XtPointer *converter_data)
1604{
1605    char    *name;
1606    XftFont *font;
1607    Screen  *screen;
1608
1609    if (*num_args != 1)
1610    {
1611	XtAppErrorMsg (XtDisplayToApplicationContext (dpy),
1612		       "cvtStringToXftFont", "wrongParameters",
1613		       "XtToolkitError",
1614		       "String to XftFont conversion needs screen argument",
1615		       (String *) NULL, (Cardinal *)NULL);
1616	return False;
1617    }
1618
1619    screen = *((Screen **) args[0].addr);
1620    name = (char *) fromVal->addr;
1621
1622    font = XftFontOpenName (dpy,
1623			    XScreenNumberOfScreen (screen),
1624			    name);
1625    if (font)
1626    {
1627	donestr (XftFont *, font, XtRXftFont);
1628    }
1629    XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRXftFont);
1630    return False;
1631}
1632
1633static XtConvertArgRec xftFontConvertArgs[] = {
1634    {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
1635     sizeof(Screen *)},
1636};
1637
1638
1639static int
1640XmuXftTextWidth(Display *dpy, XftFont *font, FcChar8 *string, int len)
1641{
1642    XGlyphInfo  extents;
1643
1644    XftTextExtents8 (dpy, font, string, len, &extents);
1645
1646    return extents.xOff;
1647}
1648
1649#endif /* USE_XFT */
1650
1651static void
1652ClassInitialize(void)
1653{
1654#ifdef USE_XFT
1655    XtSetTypeConverter (XtRString, XtRXftColor,
1656			XmuCvtStringToXftColor,
1657			xftColorConvertArgs, XtNumber(xftColorConvertArgs),
1658			XtCacheByDisplay, XmuFreeXftColor);
1659    XtSetTypeConverter (XtRString, XtRXftFont,
1660			XmuCvtStringToXftFont,
1661			xftFontConvertArgs, XtNumber(xftFontConvertArgs),
1662			XtCacheByDisplay, XmuFreeXftFont);
1663#endif /* USE_XFT */
1664}
1665/**** End of portion borrowed from xclock ****/
1666
1667/* ARGSUSED */
1668static void Initialize (
1669    Widget greq,
1670    Widget gnew,
1671    ArgList args,
1672    Cardinal *num_args)
1673{
1674    LoginWidget w = (LoginWidget)gnew;
1675    XtGCMask	valuemask, xvaluemask;
1676    XGCValues	myXGCV;
1677    Arg		position[2];
1678    Position	x, y;
1679#ifdef USE_XINERAMA
1680    XineramaScreenInfo *screens;
1681    int                 s_num;
1682#endif
1683    int 	rv = 0;
1684
1685    myXGCV.foreground = w->login.hipixel;
1686    myXGCV.background = w->core.background_pixel;
1687    valuemask = GCForeground | GCBackground;
1688    w->login.hiGC = XtGetGC(gnew, valuemask, &myXGCV);
1689
1690    myXGCV.foreground = w->login.shdpixel;
1691    myXGCV.background = w->core.background_pixel;
1692    valuemask = GCForeground | GCBackground;
1693    w->login.shdGC = XtGetGC(gnew, valuemask, &myXGCV);
1694
1695    myXGCV.foreground = w->login.inppixel;
1696    myXGCV.background = w->core.background_pixel;
1697    valuemask = GCForeground | GCBackground;
1698    w->login.inpGC = XtGetGC(gnew, valuemask, &myXGCV);
1699
1700    myXGCV.foreground = TEXT_COLOR(text);
1701    myXGCV.background = w->core.background_pixel;
1702    valuemask = GCForeground | GCBackground;
1703#ifndef USE_XFT
1704    if (w->login.textFont) {
1705	myXGCV.font = w->login.textFont->fid;
1706	valuemask |= GCFont;
1707    }
1708#endif
1709    w->login.textGC = XtGetGC(gnew, valuemask, &myXGCV);
1710    myXGCV.foreground = w->login.inppixel;
1711    w->login.bgGC = XtGetGC(gnew, valuemask, &myXGCV);
1712
1713    myXGCV.foreground = TEXT_COLOR(text) ^ w->login.inppixel;
1714    myXGCV.function = GXxor;
1715    xvaluemask = valuemask | GCFunction;
1716    w->login.xorGC = XtGetGC (gnew, xvaluemask, &myXGCV);
1717
1718#ifndef USE_XFT
1719    /*
1720     * Note that the second argument is a GCid -- QueryFont accepts a GCid and
1721     * returns the currently contained font.
1722     */
1723
1724    if (w->login.textFont == NULL)
1725	w->login.textFont = XQueryFont (XtDisplay (w),
1726		XGContextFromGC (XDefaultGCOfScreen (XtScreen (w))));
1727
1728    xvaluemask = valuemask;
1729    if (w->login.promptFont == NULL)
1730        w->login.promptFont = w->login.textFont;
1731    else
1732	xvaluemask |= GCFont;
1733
1734    myXGCV.foreground = TEXT_COLOR(prompt);
1735    myXGCV.font = w->login.promptFont->fid;
1736    w->login.promptGC = XtGetGC (gnew, xvaluemask, &myXGCV);
1737
1738    xvaluemask = valuemask;
1739    if (w->login.greetFont == NULL)
1740	w->login.greetFont = w->login.textFont;
1741    else
1742	xvaluemask |= GCFont;
1743
1744    myXGCV.foreground = TEXT_COLOR(greet);
1745    myXGCV.font = w->login.greetFont->fid;
1746    w->login.greetGC = XtGetGC (gnew, xvaluemask, &myXGCV);
1747
1748    xvaluemask = valuemask;
1749    if (w->login.failFont == NULL)
1750	w->login.failFont = w->login.textFont;
1751    else
1752	xvaluemask |= GCFont;
1753    myXGCV.foreground = TEXT_COLOR(fail);
1754    myXGCV.font = w->login.failFont->fid;
1755    w->login.failGC = XtGetGC (gnew, xvaluemask, &myXGCV);
1756#endif /* USE_XFT */
1757
1758#ifdef XPM
1759    w->login.logoValid = False;
1760
1761    if (NULL != w->login.logoFileName)
1762    {
1763        XpmAttributes myAttributes = { 0 };
1764        Window tmpWindow = { 0 };
1765        struct stat myBuffer = { 0 };
1766        unsigned int myPixmapDepth = 0;
1767
1768        if (0 != stat(w->login.logoFileName, &myBuffer))
1769        {
1770            LogError("Unable to stat() pixmap file %s\n",
1771                w->login.logoFileName);
1772            w->login.logoValid = False;
1773            goto SkipXpmLoad;
1774        }
1775
1776        myAttributes.valuemask |= XpmReturnPixels;
1777        myAttributes.valuemask |= XpmReturnExtensions;
1778
1779        rv = XpmReadFileToPixmap(XtDisplay(w),		/* display */
1780	     RootWindowOfScreen(XtScreen(w)),		/* window */
1781	     w->login.logoFileName,			/* XPM filename */
1782	     &(w->login.logoPixmap),			/* pixmap */
1783	     &(w->login.logoMask),			/* pixmap mask */
1784	     &myAttributes);				/* XPM attributes */
1785
1786	if ( rv < 0 )
1787	{
1788	    LogError("Cannot load xpm file %s: %s.\n", w->login.logoFileName,
1789		     XpmGetErrorString(rv));
1790	    goto SkipXpmLoad;
1791	}
1792
1793	w->login.logoValid = True;
1794
1795        XGetGeometry(XtDisplay(w), w->login.logoPixmap,
1796            &tmpWindow,
1797            &(w->login.logoX),
1798            &(w->login.logoY),
1799            &(w->login.logoWidth),
1800            &(w->login.logoHeight),
1801            &(w->login.logoBorderWidth),
1802            &myPixmapDepth);
1803    } else {
1804	w->login.logoX = 0;
1805	w->login.logoY = 0;
1806	w->login.logoWidth = 0;
1807	w->login.logoHeight = 0;
1808	w->login.logoBorderWidth = 0;
1809    }
1810
1811
1812SkipXpmLoad:
1813#endif /* XPM */
1814    w->login.data.name[0] = '\0';
1815    w->login.data.passwd[0] = '\0';
1816    w->login.state = INITIALIZING;
1817    w->login.activePrompt = LOGIN_PROMPT_USERNAME;
1818    w->login.failUp = 0;
1819    w->login.fail = (char *) w->login.failMsg;
1820
1821    /* Set prompt defaults */
1822    PROMPT_TEXT(w, LOGIN_PROMPT_USERNAME) 	= NULL;
1823    DEF_PROMPT_TEXT(w, LOGIN_PROMPT_USERNAME) 	= w->login.namePrompt;
1824    VALUE_TEXT(w, LOGIN_PROMPT_USERNAME) 	= w->login.data.name;
1825    VALUE_TEXT_MAX(w, LOGIN_PROMPT_USERNAME)	= sizeof(w->login.data.name);
1826    VALUE_SHOW_START(w, LOGIN_PROMPT_USERNAME)	= 0;
1827
1828    PROMPT_TEXT(w, LOGIN_PROMPT_PASSWORD) 	= NULL;
1829    DEF_PROMPT_TEXT(w, LOGIN_PROMPT_PASSWORD) 	= w->login.passwdPrompt;
1830    VALUE_TEXT(w, LOGIN_PROMPT_PASSWORD) 	= w->login.data.passwd;
1831    VALUE_TEXT_MAX(w, LOGIN_PROMPT_PASSWORD)	= sizeof(w->login.data.passwd);
1832    VALUE_SHOW_START(w, LOGIN_PROMPT_PASSWORD)	= 0;
1833
1834    SetPrompt(gnew, LOGIN_PROMPT_PASSWORD, NULL, LOGIN_PROMPT_ECHO_OFF, False);
1835    SetPrompt(gnew, LOGIN_PROMPT_USERNAME, NULL, LOGIN_PROMPT_ECHO_ON, False);
1836
1837    if (w->core.width == 0)
1838	w->core.width = max (GREET_W(w), FAIL_W(w)) + PAD_X(w);
1839    if (w->core.height == 0) {
1840	int fy = FAIL_Y(w);
1841	int pady = PAD_Y(w);
1842
1843#ifndef XPM
1844	w->core.height = fy + pady;	/* for stupid compilers */
1845#else
1846/*	w->core.height = fy + pady;	* for stupid compilers */
1847
1848        w->core.height = max(fy + pady,
1849            (w->login.logoHeight + (2*w->login.logoPadding)) + pady);
1850
1851#endif /* XPM */
1852    }
1853#ifdef USE_XINERAMA
1854    if (
1855	XineramaIsActive(XtDisplay(w)) &&
1856	(screens = XineramaQueryScreens(XtDisplay(w), &s_num)) != NULL
1857       )
1858    {
1859	if ((x = w->core.x) == -1)
1860	    x = screens[0].x_org + (int)(screens[0].width - w->core.width) / 2;
1861	if ((y = w->core.y) == -1)
1862	    y = screens[0].y_org + (int)(screens[0].height - w->core.height) / 3;
1863
1864	XFree(screens);
1865    }
1866    else
1867#endif
1868    {
1869	if ((x = w->core.x) == -1)
1870	    x = (int)(XWidthOfScreen (XtScreen (w)) - w->core.width) / 2;
1871	if ((y = w->core.y) == -1)
1872	    y = (int)(XHeightOfScreen (XtScreen (w)) - w->core.height) / 3;
1873    }
1874    XtSetArg (position[0], XtNx, x);
1875    XtSetArg (position[1], XtNy, y);
1876    XtSetValues (XtParent (w), position, (Cardinal) 2);
1877
1878    w->login.state = PROMPTING;
1879}
1880
1881
1882static void Realize (
1883     Widget gw,
1884     XtValueMask *valueMask,
1885     XSetWindowAttributes *attrs)
1886{
1887    LoginWidget	w = (LoginWidget) gw;
1888    Cursor cursor;
1889
1890    XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent,
1891		     *valueMask, attrs );
1892    InitI18N(gw);
1893
1894#ifdef USE_XFT
1895    w->login.draw = XftDrawCreate (XtDisplay (w), XtWindow(w),
1896	   DefaultVisual (XtDisplay (w), DefaultScreen(XtDisplay (w))),
1897				   w->core.colormap);
1898
1899#endif
1900
1901    cursor = XCreateFontCursor(XtDisplay(gw), XC_left_ptr);
1902    XDefineCursor(XtDisplay(gw), DefaultRootWindow(XtDisplay(gw)), cursor);
1903
1904#ifdef XPM
1905    /*
1906     * Check if Pixmap was valid
1907     */
1908    if (True == w->login.logoValid)
1909    {
1910        /*
1911         * Create pixmap window
1912         */
1913        {
1914            XSetWindowAttributes windowAttributes = {
1915                .background_pixel = w->core.background_pixel,
1916                .background_pixmap = None
1917            };
1918
1919            w->login.logoWindow = XCreateWindow(XtDisplay(w),
1920                XtWindow(w),
1921                w->core.width - w->login.outframewidth -
1922                    w->login.logoWidth - w->login.logoPadding,
1923                (w->core.height - w->login.logoHeight) /2,
1924                w->login.logoWidth, w->login.logoHeight, 0,
1925                CopyFromParent, InputOutput, CopyFromParent,
1926                CWBackPixel | CWBackPixmap, &windowAttributes);
1927        }
1928
1929        /*
1930         * check if we can use shape extension
1931         */
1932        if (True == w->login.useShape)
1933        {
1934            int foo, bar;
1935
1936            if (XShapeQueryExtension(XtDisplay(w), &foo, &bar) == TRUE)
1937            {
1938                XShapeCombineMask(XtDisplay(w), w->login.logoWindow,
1939                    ShapeBounding, w->login.logoX, w->login.logoY,
1940                    w->login.logoMask, ShapeSet);
1941            }
1942        }
1943
1944        XSetWindowBackgroundPixmap(XtDisplay(w), w->login.logoWindow,
1945            w->login.logoPixmap);
1946        XMapWindow(XtDisplay(w), w->login.logoWindow);
1947    }
1948#endif /* XPM */
1949}
1950
1951static void Destroy (Widget gw)
1952{
1953    LoginWidget w = (LoginWidget)gw;
1954    bzero (w->login.data.name, NAME_LEN);
1955    bzero (w->login.data.passwd, PASSWORD_LEN);
1956
1957    if (PROMPT_TEXT(w,0) != NULL)
1958	XtFree(PROMPT_TEXT(w,0));
1959    if (PROMPT_TEXT(w,1) != NULL)
1960	XtFree(PROMPT_TEXT(w,1));
1961
1962#ifdef USE_XFT
1963    if (w->login.draw) {
1964	XftDrawDestroy(w->login.draw);
1965	w->login.draw = NULL;
1966    }
1967#endif
1968
1969    XtReleaseGC(gw, w->login.textGC);
1970    XtReleaseGC(gw, w->login.bgGC);
1971    XtReleaseGC(gw, w->login.xorGC);
1972#ifndef USE_XFT
1973    XtReleaseGC(gw, w->login.promptGC);
1974    XtReleaseGC(gw, w->login.greetGC);
1975    XtReleaseGC(gw, w->login.failGC);
1976#endif
1977    XtReleaseGC(gw, w->login.hiGC);
1978    XtReleaseGC(gw, w->login.shdGC);
1979    XtReleaseGC(gw, w->login.inpGC);
1980
1981#ifdef XPM
1982    if (True == w->login.logoValid)
1983    {
1984        if (w->login.logoPixmap != 0)
1985            XFreePixmap(XtDisplay(w), w->login.logoPixmap);
1986
1987        if (w->login.logoMask != 0)
1988            XFreePixmap(XtDisplay(w), w->login.logoMask);
1989    }
1990#endif /* XPM */
1991}
1992
1993/* ARGSUSED */
1994static void Redisplay(
1995     Widget gw,
1996     XEvent *event,
1997     Region region)
1998{
1999    draw_it ((LoginWidget) gw);
2000}
2001
2002/*ARGSUSED*/
2003static Boolean SetValues (
2004    Widget  current,
2005    Widget  request,
2006    Widget  new,
2007    ArgList args,
2008    Cardinal *num_args)
2009{
2010    LoginWidget currentL, newL;
2011
2012    currentL = (LoginWidget) current;
2013    newL = (LoginWidget) new;
2014    if (GREETING (currentL) != GREETING (newL))
2015	return True;
2016    return False;
2017}
2018
2019static
2020char defaultLoginTranslations [] =
2021"Ctrl<Key>H:	delete-previous-character() \n"
2022"Ctrl<Key>D:	delete-character() \n"
2023"Ctrl<Key>B:	move-backward-character() \n"
2024"Ctrl<Key>F:	move-forward-character() \n"
2025"Ctrl<Key>A:	move-to-begining() \n"
2026"Ctrl<Key>E:	move-to-end() \n"
2027"Ctrl<Key>K:	erase-to-end-of-line() \n"
2028"Ctrl<Key>U:	erase-line() \n"
2029"Ctrl<Key>X:	erase-line() \n"
2030"Ctrl<Key>C:	restart-session() \n"
2031"Ctrl<Key>\\\\:	abort-session() \n"
2032":Ctrl<Key>plus:	allow-all-access() \n"
2033"<Key>BackSpace:	delete-previous-character() \n"
2034#ifdef linux
2035"<Key>Delete:	delete-character() \n"
2036#else
2037"<Key>Delete:	delete-previous-character() \n"
2038#endif
2039"<Key>Return:	finish-field() \n"
2040"<Key>Tab:	tab-field() \n"
2041"<KeyPress>:	insert-char()"
2042;
2043
2044static
2045XtActionsRec loginActionsTable [] = {
2046  {"delete-previous-character",	DeleteBackwardChar},
2047  {"delete-character",		DeleteForwardChar},
2048  {"move-backward-character",	MoveBackwardChar},
2049  {"move-forward-character",	MoveForwardChar},
2050  {"move-to-begining",		MoveToBegining},
2051  {"move-to-end",		MoveToEnd},
2052  {"erase-to-end-of-line",	EraseToEndOfLine},
2053  {"erase-line",		EraseLine},
2054  {"finish-field", 		FinishField},
2055  {"tab-field", 		TabField},
2056  {"abort-session",		AbortSession},
2057  {"abort-display",		AbortDisplay},
2058  {"restart-session",		RestartSession},
2059  {"insert-char", 		InsertChar},
2060  {"set-session-argument",	SetSessionArgument},
2061  {"allow-all-access",		AllowAccess},
2062};
2063
2064LoginClassRec loginClassRec = {
2065    { /* core fields */
2066    /* superclass		*/	&widgetClassRec,
2067    /* class_name		*/	"Login",
2068    /* size			*/	sizeof(LoginRec),
2069    /* class_initialize		*/	ClassInitialize,
2070    /* class_part_initialize	*/	NULL,
2071    /* class_inited		*/	FALSE,
2072    /* initialize		*/	Initialize,
2073    /* initialize_hook		*/	NULL,
2074    /* realize			*/	Realize,
2075    /* actions			*/	loginActionsTable,
2076    /* num_actions		*/	XtNumber (loginActionsTable),
2077    /* resources		*/	resources,
2078    /* num_resources		*/	XtNumber(resources),
2079    /* xrm_class		*/	NULLQUARK,
2080    /* compress_motion		*/	TRUE,
2081    /* compress_exposure	*/	TRUE,
2082    /* compress_enterleave	*/	TRUE,
2083    /* visible_interest		*/	FALSE,
2084    /* destroy			*/	Destroy,
2085    /* resize			*/	NULL,
2086    /* expose			*/	Redisplay,
2087    /* set_values		*/	SetValues,
2088    /* set_values_hook		*/	NULL,
2089    /* set_values_almost	*/	XtInheritSetValuesAlmost,
2090    /* get_values_hook		*/	NULL,
2091    /* accept_focus		*/	NULL,
2092    /* version			*/	XtVersion,
2093    /* callback_private		*/	NULL,
2094    /* tm_table			*/	defaultLoginTranslations,
2095    /* query_geometry		*/	XtInheritQueryGeometry,
2096    /* display_accelerator	*/	XtInheritDisplayAccelerator,
2097    /* extension		*/	NULL
2098    }
2099};
2100
2101WidgetClass loginWidgetClass = (WidgetClass) &loginClassRec;
2102