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