Home | History | Annotate | Line # | Download | only in greeter
      1 /*
      2 
      3 Copyright 1988, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from 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 
    106 static void RedrawFail (LoginWidget w);
    107 static void ResetLogin (LoginWidget w);
    108 static void failTimeout (XtPointer client_data, XtIntervalId * id);
    109 static void EraseCursor (LoginWidget w);
    110 static void XorCursor (LoginWidget w);
    111 
    112 #define offset(field) XtOffsetOf(LoginRec, login.field)
    113 #define goffset(field) XtOffsetOf(WidgetRec, core.field)
    114 
    115 
    116 static 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 (at) 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)
    282 static int
    283 XmuXftTextWidth(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
    356 static inline int max (int a, int b) { return a > b ? a : b; }
    357 #endif
    358 
    359 static void
    360 realizeValue (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 
    447 static void
    448 EraseValue (LoginWidget w, int cursor, int promptNum)
    449 {
    450     realizeValue(w, cursor, promptNum, w->login.bgGC);
    451 }
    452 
    453 static void
    454 DrawValue (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 
    464 static void
    465 realizeCursor (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 
    539 static void
    540 EraseFail (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 
    555 static void
    556 XorCursor (LoginWidget w)
    557 {
    558     realizeCursor (w, w->login.xorGC);
    559 }
    560 
    561 static void
    562 RemoveFail (LoginWidget w)
    563 {
    564     if (w->login.failUp)
    565 	EraseFail (w);
    566 }
    567 
    568 static void
    569 EraseCursor (LoginWidget w)
    570 {
    571     realizeCursor (w, w->login.bgGC);
    572 }
    573 
    574 /*ARGSUSED*/
    575 static 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
    585 void
    586 DrawFail (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 
    597 static void
    598 RedrawFail (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
    671 void
    672 ErrorMessage(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
    699 void
    700 ShowChangePasswdMessage(Widget ctx)
    701 {
    702     LoginWidget	w = (LoginWidget) ctx;
    703 
    704     ErrorMessage(ctx, w->login.passwdChangeMsg, False);
    705 }
    706 
    707 static void
    708 draw_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
    813 int
    814 SetPrompt (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
    903 const char *
    904 GetPrompt(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
    914 int
    915 SetValue(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
    944 const char *
    945 GetValue(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 
    960 static void
    961 realizeDeleteChar (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*/
    984 static void
    985 DeleteBackwardChar (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*/
   1004 static void
   1005 DeleteForwardChar (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*/
   1021 static void
   1022 MoveBackwardChar (
   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*/
   1049 static void
   1050 MoveForwardChar (
   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*/
   1078 static void
   1079 MoveToBegining (
   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*/
   1104 static void
   1105 MoveToEnd (
   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*/
   1129 static void
   1130 EraseToEndOfLine (
   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*/
   1154 static void
   1155 EraseLine (
   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*/
   1166 static void
   1167 FinishField (
   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*/
   1204 static void
   1205 TabField(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*/
   1234 static void
   1235 AllowAccess (
   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*/
   1253 static void
   1254 SetSessionArgument (
   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*/
   1276 static void
   1277 RestartSession (
   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*/
   1293 static void
   1294 AbortSession (
   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*/
   1310 static void
   1311 AbortDisplay (
   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 
   1326 static void
   1327 ResetLogin (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 
   1341 static void
   1342 InitI18N(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 */
   1371 static void
   1372 InsertChar (
   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
   1469 static 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 
   1496 static void
   1497 XmuFreeXftColor (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 
   1523 static Boolean
   1524 XmuCvtStringToXftColor(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 
   1576 static void
   1577 XmuFreeXftFont (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 
   1599 static Boolean
   1600 XmuCvtStringToXftFont(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 
   1633 static XtConvertArgRec xftFontConvertArgs[] = {
   1634     {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
   1635      sizeof(Screen *)},
   1636 };
   1637 
   1638 
   1639 static int
   1640 XmuXftTextWidth(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 
   1651 static void
   1652 ClassInitialize(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 */
   1668 static 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 
   1812 SkipXpmLoad:
   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 
   1882 static 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 
   1951 static 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 */
   1994 static void Redisplay(
   1995      Widget gw,
   1996      XEvent *event,
   1997      Region region)
   1998 {
   1999     draw_it ((LoginWidget) gw);
   2000 }
   2001 
   2002 /*ARGSUSED*/
   2003 static 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 
   2019 static
   2020 char 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 
   2044 static
   2045 XtActionsRec 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 
   2064 LoginClassRec 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 
   2101 WidgetClass loginWidgetClass = (WidgetClass) &loginClassRec;
   2102