From c19ab6060548347dda30026f8510ec4e4050d2db Mon Sep 17 00:00:00 2001 From: Unknown User d91-jda Date: Tue, 5 Mar 1996 16:57:47 +0000 Subject: [PATCH] x git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@284 ec53bebd-3082-4978-b11e-865c3cabbd6b --- appl/xnlock/xnlock.c | 987 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 987 insertions(+) diff --git a/appl/xnlock/xnlock.c b/appl/xnlock/xnlock.c index e69de29bb..f3e211774 100644 --- a/appl/xnlock/xnlock.c +++ b/appl/xnlock/xnlock.c @@ -0,0 +1,987 @@ +/* + * xnlock -- Dan Heller, 1990 + * "nlock" is a "new lockscreen" type program... something that prevents + * screen burnout by making most of it "black" while providing something + * of interest to be displayed in case anyone is watching. + * "xnlock" is the X11 version of the program. + * Original sunview version written by Dan Heller 1985 (not included here). + */ +#ifdef HAVE_CONFIG_H +#include +#include +#define KERBEROS +RCSID("$Id$"); +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS +#include +#include + +char inst[100]; +char name[100]; +char realm[REALM_SZ + 1]; +#endif + +char *SPACE_STRING = " "; +char STRING[] = "****************"; +#define MAX_PASSWD_LENGTH (sizeof(STRING)) + +/* The program should be something that outputs a small amount of text */ +#define DEFAULT_PROGRAM "fortune -s" +#define DEFAULT_TEXT "I'm out running around." +#define font_height(font) (font->ascent + font->descent) +#define FONT_NAME "-*-new century schoolbook-*-*-*-18-*" +#define when break;case +#define otherwise break;default + +#define PROMPT "Password: " +#define FAIL_MSG "Sorry, try again" +#define LEFT 001 +#define RIGHT 002 +#define DOWN 004 +#define UP 010 +#define FRONT 020 +#define X_INCR 3 +#define Y_INCR 2 +#define CTRL 1 +#define NOCTRL 0 + +XtAppContext app; +Display *dpy; +unsigned short Width, Height; +Widget widget; +GC gc; +XtIntervalId timeout_id; +char *ProgName, *words; +int x, y; +Pixel Black, White; +XFontStruct *font; +struct passwd *pw; +char root_pw[16]; +char *def_words = DEFAULT_TEXT; +int time_left, prompt_x, prompt_y, time_x, time_y; +unsigned long interval; +Pixmap left0, left1, right0, right1, left_front, + right_front, front, down; +int test; + +#define MAXLINES 40 + +#define FROM_ARGV 1 +#define FROM_PROGRAM 2 +#define FROM_FILE 3 +#define FROM_RESRC 4 +int getwordsfrom = FROM_RESRC; + +#define IS_MOVING 1 +#define GET_PASSWD 2 +int state; /* indicates states: walking or getting passwd */ + +int ALLOW_LOGOUT = (60*10); /* Allow logout after nn seconds */ +char LOGOUT_PASSWD[] = "LOGOUT"; /* when given password "xx" */ +time_t locked_at; + +struct _resrcs { + Pixel fg, bg; + XFontStruct *font; + Boolean ignore_passwd; + Boolean do_reverse; + Boolean accept_root; + char *text, *text_prog, *file; +} Resrcs; + +static XtResource resources[] = { + { XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), + XtOffsetOf(struct _resrcs,font), XtRImmediate, NULL }, + { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel), + /* note: the background is really the foreground color */ + XtOffsetOf(struct _resrcs,fg), XtRString, XtDefaultBackground }, + { XtNbackground, XtCBackground, XtRPixel, sizeof (Pixel), + /* note: the foreground is really the background color */ + XtOffsetOf(struct _resrcs,bg), XtRString, XtDefaultForeground }, + { XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof(Boolean), + XtOffsetOf(struct _resrcs,do_reverse), XtRImmediate, (char *)False }, + { "ignorePasswd", "IgnorePasswd", XtRBoolean, sizeof(Boolean), + XtOffsetOf(struct _resrcs,ignore_passwd), XtRImmediate, (char *)False }, + { "acceptRootPasswd", "AcceptRootPasswd", XtRBoolean, sizeof(Boolean), + XtOffsetOf(struct _resrcs,accept_root), XtRImmediate, (char *)True }, + { "text", "Text", XtRString, sizeof(char *), + XtOffsetOf(struct _resrcs,text), XtRImmediate, DEFAULT_TEXT }, + { "program", "Program", XtRString, sizeof(char *), + XtOffsetOf(struct _resrcs,text_prog), XtRImmediate, DEFAULT_PROGRAM }, + { "file", "File", XtRString, sizeof(char *), + XtOffsetOf(struct _resrcs,file), XtRImmediate, NULL }, +}; + +static XrmOptionDescRec options[] = { + { "-fn", "font", XrmoptionSepArg, NULL }, + { "-fg", "foreground", XrmoptionSepArg, NULL }, + { "-bg", "background", XrmoptionSepArg, NULL }, + { "-rv", "reverseVideo", XrmoptionNoArg, "True" }, + { "-norv", "reverseVideo", XrmoptionNoArg, "False" }, + { "-ip", "ignorePasswd", XrmoptionNoArg, "True" }, + { "-noip", "ignorePasswd", XrmoptionNoArg, "False" }, + { "-ar", "acceptRootPasswd", XrmoptionNoArg, "True" }, + { "-noar", "acceptRootPasswd", XrmoptionNoArg, "False" }, +}; + +static char * +get_words(char **argv) +{ + FILE *pp = 0; + static char buf[BUFSIZ]; + register char *p = buf; + + if (getwordsfrom == FROM_RESRC) + return Resrcs.text; + if (getwordsfrom == FROM_PROGRAM) { + if (!(pp = popen(Resrcs.text_prog, "r"))) { + perror(Resrcs.text_prog); + return def_words; + } + } else if (getwordsfrom == FROM_FILE) + if (!(pp = fopen(Resrcs.file, "r"))) { + perror(Resrcs.file); + return def_words; + } + else if (getwordsfrom != FROM_PROGRAM && getwordsfrom != FROM_FILE) + return def_words; + + buf[0] = 0; + if (getwordsfrom == FROM_ARGV) { + while (*argv) { + p += strlen(strcpy(p, *argv)); + if (*++argv) + strcpy(p++, " "); + } + return buf; + } + + /* BUG Alert: does not check for overflow */ + while (fgets(p, sizeof buf, pp)) + p += strlen(p); + if (getwordsfrom == FROM_PROGRAM) + (void) pclose(pp); + else + (void) fclose (pp); + if (!buf[0]) + return def_words; + return buf; +} + +static void +init_words (int argc, char **argv) +{ + char buf[BUFSIZ]; + + while (*argv && **argv == '-') { + switch(argv[0][1]) { + case 'p': + getwordsfrom = FROM_PROGRAM; + if (!*++argv) + puts("specify a program name to get text from!"), exit(1); + Resrcs.text_prog = *argv; + case 'f': + getwordsfrom = FROM_FILE; + if (argv[1]) + Resrcs.file = *++argv; + else { + sprintf(buf, "%s/.msgfile", pw->pw_dir); + Resrcs.file = strcpy(XtMalloc(strlen(buf)+1), buf); + } + default : + printf("usage: %s [options] [message]\n", ProgName); + puts("-fg color foreground color"); + puts("-bg color background color"); + puts("-rv reverse foreground/background colors"); + puts("-nrv no reverse video"); + puts("-ip ignore passwd"); + puts("-nip don't ignore passwd"); + puts("-ar accept root's passwd to unlock"); + puts("-nar don't accept root's passwd"); + puts("-f [file] message is read from file or ~/.msgfile"); + puts("-prog program text is gotten from executing `program'"); + exit(1); + } + argv++; + } + if (*argv) { + if (getwordsfrom != FROM_RESRC) + puts("I don't know what text you want displayed."); + getwordsfrom = FROM_ARGV; + } else if (!getwordsfrom) + if (Resrcs.text) + getwordsfrom = FROM_RESRC; + else if (Resrcs.file) + getwordsfrom = FROM_FILE; + else + getwordsfrom = FROM_PROGRAM; + words = get_words(argv); /* if getwordsfrom != FROM_ARGV, argv is a nop */ +} + +static void +ScreenSaver(int save) +{ + static int timeout, interval, prefer_blank, allow_exp; + if (save) { + XGetScreenSaver(dpy, &timeout, &interval, &prefer_blank, &allow_exp); + XSetScreenSaver(dpy, 0, interval, prefer_blank, allow_exp); + } else + /* restore state */ + XSetScreenSaver(dpy, timeout, interval, prefer_blank, allow_exp); +} + +/* Forward decls necessary */ +static void talk(int force_erase); +static unsigned long look(void); + +static int +zrefresh() +{ + switch (fork()) { + case -1: + fprintf(stderr, "Warning %s: Failed to fork zrefresh\n", ProgName); + return -1; + case 0: + /* Child */ + execlp("zrefresh", "zrefresh", 0); + execl("/usr/athena/bin/zrefresh", "zrefresh", 0); +#if 0 + fprintf(stderr, "Warning %s: Failed to exec zrefresh\n", ProgName); +#endif + return -1; + default: + /* Parent */ + break; + } + return 0; +} + +static void +leave(void) +{ +#if 0 + XUngrabServer(dpy); +#else + XUngrabPointer(dpy, CurrentTime); + XUngrabKeyboard(dpy, CurrentTime); +#endif + ScreenSaver(0); + zrefresh(); + exit(0); +} + +static void +walk(int dir) +{ + register int incr = 0; + static int lastdir; + static int up = 1; + static Pixmap frame; + + if (dir & (LEFT|RIGHT)) { /* left/right movement (mabye up/down too) */ + up = -up; /* bouncing effect (even if hit a wall) */ + if (dir & LEFT) { + incr = X_INCR; + frame = (up < 0) ? left0 : left1; + } else { + incr = -X_INCR; + frame = (up < 0) ? right0 : right1; + } + if ((lastdir == FRONT || lastdir == DOWN) && dir & UP) { + /* workaround silly bug that leaves screen dust when + * guy is facing forward or down and moves up-left/right. + */ + XCopyPlane(dpy, frame, XtWindow(widget), gc, 0, 0, 64,64, x, y, 1L); + XFlush(dpy); + } + /* note that maybe neither UP nor DOWN is set! */ + if (dir & UP && y > Y_INCR) + y -= Y_INCR; + else if (dir & DOWN && y < (int)Height - 64) + y += Y_INCR; + } + /* Explicit up/down movement only (no left/right) */ + else if (dir == UP) + XCopyPlane(dpy, front, XtWindow(widget), gc, + 0,0, 64,64, x, y -= Y_INCR, 1L); + else if (dir == DOWN) + XCopyPlane(dpy, down, XtWindow(widget), gc, + 0,0, 64,64, x, y += Y_INCR, 1L); + else if (dir == FRONT && frame != front) { + if (up > 0) + up = -up; + if (lastdir & LEFT) + frame = left_front; + else if (lastdir & RIGHT) + frame = right_front; + else + frame = front; + XCopyPlane(dpy, frame, XtWindow(widget), gc, 0, 0, 64,64, x, y, 1L); + } + if (dir & LEFT) + while(--incr >= 0) { + XCopyPlane(dpy, frame, XtWindow(widget), gc, + 0,0, 64,64, --x, y+up, 1L); + XFlush(dpy); + } + else if (dir & RIGHT) + while(++incr <= 0) { + XCopyPlane(dpy, frame, XtWindow(widget), gc, + 0,0, 64,64, ++x, y+up, 1L); + XFlush(dpy); + } + lastdir = dir; +} + +static int +think(void) +{ + if (rand() & 1) + walk(FRONT); + if (rand() & 1) { + if (getwordsfrom > 1) + words = get_words((char **)NULL); + return 1; + } + return 0; +} + +static void +move(XtPointer _p, XtIntervalId *_id) +{ + static int length, dir; + + if (!length) { + register int tries = 0; + dir = 0; + if ((rand() & 1) && think()) { + talk(0); /* sets timeout to itself */ + return; + } + if (!(rand() % 3) && (interval = look())) { + timeout_id = XtAppAddTimeOut(app, interval, move, NULL); + return; + } + interval = 20 + rand() % 100; + do { + if (!tries) + length = Width/100 + rand() % 90, tries = 8; + else + tries--; + switch (rand() % 8) { + case 0: + if (x - X_INCR*length >= 5) + dir = LEFT; + case 1: + if (x + X_INCR*length <= (int)Width - 70) + dir = RIGHT; + case 2: + if (y - (Y_INCR*length) >= 5) + dir = UP, interval = 40; + case 3: + if (y + Y_INCR*length <= (int)Height - 70) + dir = DOWN, interval = 20; + case 4: + if (x - X_INCR*length >= 5 && y - (Y_INCR*length) >= 5) + dir = (LEFT|UP); + case 5: + if (x + X_INCR * length <= (int)Width - 70 && + y-Y_INCR * length >= 5) + dir = (RIGHT|UP); + case 6: + if (x - X_INCR * length >= 5 && + y + Y_INCR * length <= (int)Height - 70) + dir = (LEFT|DOWN); + case 7: + if (x + X_INCR*length <= (int)Width - 70 && + y + Y_INCR*length <= (int)Height - 70) + dir = (RIGHT|DOWN); + } + } while (!dir); + } + walk(dir); + --length; + timeout_id = XtAppAddTimeOut(app, interval, move, NULL); +} + +static void +post_prompt_box(Window window) +{ + char s[64]; + int width = (Width / 3); + int height = font_height(font) * 6; + int box_x, box_y; + + /* make sure the entire nose icon fits in the box */ + if (height < 100) + height = 100; + + time_x = prompt_x = Width / 3; + time_y = prompt_y = Height / 2; + box_x = prompt_x - 105; + box_y = prompt_y - 3 * font_height(font); + +#ifdef KERBEROS + if (inst[0] == 0) + sprintf (s, "User: %s@%s", name, realm); + else + sprintf (s, "User: %s.%s@%s", name, inst, realm); +#else + sprintf (s, "User: %s", pw->pw_name); +#endif + /* erase current guy -- text message may still exist */ + XSetForeground(dpy, gc, Black); + XFillRectangle(dpy, window, gc, x, y, 64, 64); + talk(1); /* forcefully erase message if one is being displayed */ + /* Clear area in middle of screen for prompt box */ + XSetForeground(dpy, gc, White); + XFillRectangle(dpy, window, gc, box_x, box_y, width, height); + XSetForeground(dpy, gc, Black); + + /* make a box that's 5 pixels thick. Then add a thin box inside it */ + XSetLineAttributes(dpy, gc, 5, 0, 0, 0); + XDrawRectangle(dpy, window, gc, box_x+5, box_y+5, width-10, height-10); + XSetLineAttributes(dpy, gc, 0, 0, 0, 0); + XDrawRectangle(dpy, window, gc, box_x+12, box_y+12, width-23, height-23); + + XDrawString(dpy, window, gc, + prompt_x, prompt_y-font_height(font), s, strlen(s)); + XDrawString(dpy, window, gc, prompt_x, prompt_y, PROMPT, strlen(PROMPT)); + /* set background for copyplane and DrawImageString; need reverse video */ + XSetBackground(dpy, gc, White); + XCopyPlane(dpy, right0, window, gc, 0,0, 64,64, + box_x + 20, box_y + (height - 64)/2, 1L); + prompt_x += XTextWidth(font, PROMPT, strlen(PROMPT)); + time_y += 2*font_height(font); +} + +static void +RaiseWindow(Widget w, XEvent *ev, String *s, Cardinal *n) +{ + Widget x; + if(!XtIsRealized(w)) + return; + x = XtParent(w); + fprintf(stderr, "%s\n", XtName(x)); + XRaiseWindow(dpy, XtWindow(x)); +} + + +static void +ClearWindow(Widget w, XEvent *_event, String *_s, Cardinal *_n) +{ + XExposeEvent *event = (XExposeEvent *)_event; + if (!XtIsRealized(w)) + return; + XSetForeground(dpy, gc, Black); + XFillRectangle(dpy, XtWindow(w), gc, + event->x, event->y, event->width, event->height); + XSetForeground(dpy, gc, White); + XSetBackground(dpy, gc, Black); + if (state == GET_PASSWD) + post_prompt_box(XtWindow(w)); + if (timeout_id == 0 && event->count == 0) { + timeout_id = XtAppAddTimeOut(app, 1000L, move, NULL); + /* first grab the input focus */ + XSetInputFocus(dpy, XtWindow(w), RevertToPointerRoot, CurrentTime); + /* now grab the pointer and keyboard and contrain to this window */ + XGrabPointer(dpy, XtWindow(w), TRUE, 0, GrabModeAsync, + GrabModeAsync, XtWindow(w), None, CurrentTime); + } +} + +static void +countdown(XtPointer _t, XtIntervalId *_d) +{ + int *timeout = (int *)_t; + char buf[16]; + time_t seconds; + + if (--(*timeout) < 0) { + XExposeEvent event; + XtRemoveTimeOut(timeout_id); + state = IS_MOVING; + event.x = event.y = 0; + event.width = Width, event.height = Height; + ClearWindow(widget, (XEvent *)&event, 0, 0); + timeout_id = XtAppAddTimeOut(app, 200L, move, NULL); + return; + } + seconds = time(0) - locked_at; + if (seconds >= 3600) + (void) sprintf(buf, "Locked for %d:%02d:%02d ", + (int)seconds/3600, (int)seconds/60%60, (int)seconds%60); + else + (void) sprintf(buf, "Locked for %2d:%02d ", + (int)seconds/60, (int)seconds%60); + + XDrawImageString(dpy, XtWindow(widget), gc, + time_x, time_y, buf, strlen(buf)); + XtAppAddTimeOut(app, 1000L, countdown, timeout); + return; +} + +static void +GetPasswd(Widget w, XEvent *_event, String *_s, Cardinal *_n) +{ + XKeyEvent *event = (XKeyEvent *)_event; + static char passwd[MAX_PASSWD_LENGTH]; + static int cnt; + static int is_ctrl = NOCTRL; + char c; + KeySym keysym; + + if (event->type == ButtonPress) { + x = event->x, y = event->y, test = 2; + return; + } + if (state == IS_MOVING) { + /* guy is running around--change to post prompt box. */ + XtRemoveTimeOut(timeout_id); + state = GET_PASSWD; + if (Resrcs.ignore_passwd || !strlen(pw->pw_passwd)) + leave(); + post_prompt_box(XtWindow(w)); + cnt = 0; + time_left = 30; + countdown((XtPointer)&time_left, 0); + return; + } + if (event->type == KeyRelease) { + keysym = XLookupKeysym(event, 0); + if (keysym == XK_Control_L || keysym == XK_Control_R) { + is_ctrl = NOCTRL; + } + } + if (event->type != KeyPress) + return; + keysym = XLookupKeysym(event, 0); + if (keysym == XK_Control_L || keysym == XK_Control_R) { + is_ctrl = CTRL; + return; + } + if (!XLookupString(event, &c, 1, &keysym, 0)) + return; + if (keysym == XK_Return || keysym == XK_Linefeed) { + passwd[cnt] = 0; + XtRemoveTimeOut(timeout_id); + /* + * First try with root password, if allowed. + */ + if (Resrcs.accept_root && + (root_pw[0] == 0 && cnt == 0 || + cnt && root_pw[0] && !strcmp(crypt(passwd, root_pw), root_pw))) + leave(); + /* + * Password that log out user + */ + if ( getuid() != 0 + && geteuid() != 0 + && (time(0) - locked_at) > ALLOW_LOGOUT + && strncmp(passwd, LOGOUT_PASSWD, sizeof(LOGOUT_PASSWD)) == 0) + { + signal(SIGHUP, SIG_IGN); + kill(-1, SIGHUP); + sleep(5); + /* If the X-server shut down then so will we, else + * continue */ + signal(SIGHUP, SIG_DFL); + } +#ifdef KERBEROS + /* + * Try to verify as user with kerberos. + */ + if (realm[0] != 0) + { + if (KSUCCESS == krb_get_pw_in_tkt(name, + inst, + realm, + "krbtgt", + realm, + DEFAULT_TKT_LIFE, + passwd)) + { + int code; + if (k_hasafs()) + { + if ((code = k_afsklog(NULL, realm)) != KSUCCESS + && code != KDC_PR_UNKNOWN) + fprintf(stderr, + "%s: Warning %s\n", + ProgName, + krb_err_msg(code)); + } + leave(); + } + } +#endif /* KERBEROS */ + /* + * Try to verify as user. + */ + if (!strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) + leave(); + + XDrawImageString(dpy, XtWindow(widget), gc, + time_x, time_y, FAIL_MSG, strlen(FAIL_MSG)); + time_left = 0; + state = IS_MOVING; + timeout_id = XtAppAddTimeOut(app, 2000L, countdown, &time_left); + return; + } + if (keysym == XK_BackSpace || keysym == XK_Delete || keysym == XK_Left) { + if (cnt) + passwd[cnt--] = ' '; + } else if (keysym == XK_u && is_ctrl == CTRL) { + while (cnt) { + passwd[cnt--] = ' '; + XDrawImageString(dpy, XtWindow(w), gc, + prompt_x, prompt_y, STRING, cnt); + XDrawImageString(dpy, XtWindow(w), gc, + prompt_x + XTextWidth(font, STRING, cnt), + prompt_y, SPACE_STRING, MAX_PASSWD_LENGTH - cnt + 1); + } + } else if (isprint(c)) + if ((cnt + 1) >= MAX_PASSWD_LENGTH) + XBell(dpy, 50); + else + passwd[cnt++] = c; + else + return; + XDrawImageString(dpy, XtWindow(w), gc, + prompt_x, prompt_y, STRING, cnt); + XDrawImageString(dpy, XtWindow(w), gc, + prompt_x + XTextWidth(font, STRING, cnt), + prompt_y, SPACE_STRING, MAX_PASSWD_LENGTH - cnt + 1); +} + +#include "nose.0.left" +#include "nose.1.left" +#include "nose.0.right" +#include "nose.1.right" +#include "nose.left.front" +#include "nose.right.front" +#include "nose.front" +#include "nose.down" + +static void +init_images(void) +{ + static Pixmap *images[] = { + &left0, &left1, &right0, &right1, + &left_front, &right_front, &front, &down + }; + static unsigned char *bits[] = { + nose_0_left_bits, nose_1_left_bits, nose_0_right_bits, + nose_1_right_bits, nose_left_front_bits, nose_right_front_bits, + nose_front_bits, nose_down_bits + }; + int i; + + for (i = 0; i < XtNumber(images); i++) + if (!(*images[i] = + XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), + bits[i], 64, 64, 1, 0, 1))) + XtError("Can't load nose images"); +} + +static void +talk(int force_erase) +{ + int width = 0, height, Z, total = 0; + static int X, Y, talking; + static struct { int x, y, width, height; } s_rect; + register char *p, *p2; + char buf[BUFSIZ], args[MAXLINES][256]; + + /* clear what we've written */ + if (talking || force_erase) { + if (!talking) + return; + if (talking == 2) { + XSetForeground(dpy, gc, Black); + XDrawString(dpy, XtWindow(widget), gc, X, Y, words, strlen(words)); + XSetForeground(dpy, gc, White); + } else if (talking == 1) { + XSetForeground(dpy, gc, Black); + XFillRectangle(dpy, XtWindow(widget), gc, s_rect.x-5, s_rect.y-5, + s_rect.width+10, s_rect.height+10); + XSetForeground(dpy, gc, White); + } + talking = 0; + if (!force_erase) + timeout_id = XtAppAddTimeOut(app, 40L, + (XtTimerCallbackProc)move, + NULL); + return; + } + talking = 1; + walk(FRONT); + p = strcpy(buf, words); + + /* possibly avoid a lot of work here + * if no CR or only one, then just print the line + */ + if (!(p2 = index(p, '\n')) || !p2[1]) { + register int w; + + if (p2) + *p2 = 0; + w = XTextWidth(font, words, strlen(words)); + X = x + 32 - w/2; + Y = y - 5 - font_height(font); + /* give us a nice 5 pixel margin */ + if (X < 5) + X = 5; + else if (X + w + 15 > (int)Width + 5) + X = Width - w - 5; + if (Y < 5) + Y = y + 64 + 5 + font_height(font); + XDrawString(dpy, XtWindow(widget), gc, X, Y, words, strlen(words)); + timeout_id = XtAppAddTimeOut(app, 5000L, (XtTimerCallbackProc)talk, + NULL); + talking++; + return; + } + + /* p2 now points to the first '\n' */ + for (height = 0; p; height++) { + int w; + *p2 = 0; + if ((w = XTextWidth(font, p, p2 - p)) > width) + width = w; + total += p2 - p; /* total chars; count to determine reading time */ + strcpy(args[height], p); + if (height == MAXLINES - 1) { + puts("Message too long!"); + break; + } + p = p2+1; + if (!(p2 = index(p, '\n'))) + break; + } + height++; + + /* Figure out the height and width in pixels (height, width) extend + * the new box by 15 pixels on the sides (30 total) top and bottom. + */ + s_rect.width = width + 30; + s_rect.height = height * font_height(font) + 30; + if (x - s_rect.width - 10 < 5) + s_rect.x = 5; + else + if ((s_rect.x = x+32-(s_rect.width+15)/2) + + s_rect.width+15 > (int)Width-5) + s_rect.x = Width - 15 - s_rect.width; + if (y - s_rect.height - 10 < 5) + s_rect.y = y + 64 + 5; + else + s_rect.y = y - 5 - s_rect.height; + + XSetForeground(dpy, gc, White); + XFillRectangle(dpy, XtWindow(widget), gc, + s_rect.x-5, s_rect.y-5, s_rect.width+10, s_rect.height+10); + XSetForeground(dpy, gc, Black); + + /* make a box that's 5 pixels thick. Then add a thin box inside it */ + XSetLineAttributes(dpy, gc, 5, 0, 0, 0); + XDrawRectangle(dpy, XtWindow(widget), gc, + s_rect.x, s_rect.y, s_rect.width-1, s_rect.height-1); + XSetLineAttributes(dpy, gc, 0, 0, 0, 0); + XDrawRectangle(dpy, XtWindow(widget), gc, + s_rect.x + 7, s_rect.y + 7, s_rect.width - 15, s_rect.height - 15); + + X = 15; + Y = 15 + font_height(font); + + /* now print each string in reverse order (start at bottom of box) */ + for (Z = 0; Z < height; Z++) { + XDrawString(dpy, XtWindow(widget), gc, s_rect.x+X, s_rect.y+Y, + args[Z], strlen(args[Z])); + Y += font_height(font); + } + timeout_id = XtAppAddTimeOut(app, (total/15) * 1000, + (XtTimerCallbackProc)talk, NULL); +} + +static unsigned long +look(void) +{ + if (rand() % 3) { + XCopyPlane(dpy, (rand() & 1)? down : front, XtWindow(widget), gc, + 0, 0, 64,64, x, y, 1L); + return 1000L; + } + if (!(rand() % 5)) + return 0; + if (rand() % 3) { + XCopyPlane(dpy, (rand() & 1)? left_front : right_front, + XtWindow(widget), gc, 0, 0, 64,64, x, y, 1L); + return 1000L; + } + if (!(rand() % 5)) + return 0; + XCopyPlane(dpy, (rand() & 1)? left0 : right0, XtWindow(widget), gc, + 0, 0, 64,64, x, y, 1L); + return 1000L; +} + +int +main (int argc, char **argv) +{ + register int i; + int foo; + Widget override; + XGCValues gcvalues; + char **list; + + srand(getpid()); + for (i = 0; i < (sizeof(STRING)-2); i++) + STRING[i] = ((unsigned long)rand() % ('~' - ' ')) + ' '; + + locked_at = time(0); + + if ((ProgName = rindex(*argv, '/')) != 0) + ProgName++; + else + ProgName = *argv; + + /* getpwuid() returns static pointer, so get root's passwd first */ + if (!(pw = getpwuid(0))) + printf("%s: can't get root's passwd!\n", ProgName), exit(1); + strcpy(root_pw, pw->pw_passwd); + if (!(pw = getpwuid(getuid()))) + printf("%s: Intruder alert!\n", ProgName), exit(1); + +#ifdef KERBEROS + { + int code = KSUCCESS; + char *file; + strcpy(name, pw->pw_name); /* Unix name is default name */ + if ((file = getenv("KRBTKFILE")) == 0) + file = TKT_FILE; + code = tf_init(file, R_TKT_FIL); + if (code == KSUCCESS) + { + (void) tf_close(); + if ((code = krb_get_tf_realm(file, realm)) == KSUCCESS && + (code = tf_init(file, R_TKT_FIL)) == KSUCCESS && + (code = tf_get_pname(name)) == KSUCCESS && + (code = tf_get_pinst(inst)) == KSUCCESS) + { + (void) tf_close(); /* Alles gut */ + dest_tkt(); /* Nuke old ticket file */ + creat(file, 0600); /* but keep a place holder */ + } + } + if (code != KSUCCESS) + { + code = krb_get_lrealm(realm, 1); + if (code != KSUCCESS) + realm[0] = 0; /* No kerberos today */ + } + } +#endif /* KERBEROS */ + + XtToolkitInitialize(); + app = XtCreateApplicationContext(); + dpy = XtOpenDisplay(app, NULL, + "xnlock", "XNlock", options, XtNumber(options), &argc, argv); + + if (dpy == 0) + { + fprintf(stderr, "Error: Can't open display:\n"); + exit(1); + } + + Width = DisplayWidth(dpy, DefaultScreen(dpy)) + 2; + Height = DisplayHeight(dpy, DefaultScreen(dpy)) + 2; + override = XtVaAppCreateShell("xnlock", "XNlock", + overrideShellWidgetClass, dpy, + XtNx, -1, + XtNy, -1, + NULL); + + XtGetApplicationResources(override, &Resrcs, + resources, XtNumber(resources), NULL, 0); + + widget = XtVaCreateManagedWidget("_foo", widgetClass, override, + XtNwidth, Width, + XtNheight, Height, + NULL); + + init_words(--argc, ++argv); + init_images(); + + /* the background is black and the little guy is white */ + Black = Resrcs.do_reverse? Resrcs.fg : Resrcs.bg; + White = Resrcs.do_reverse? Resrcs.bg : Resrcs.fg; + gcvalues.foreground = Black; + gcvalues.background = White; + + if (!(font = Resrcs.font)) { + list = XListFonts(dpy, FONT_NAME, 32767, &foo); + for (i = 0; i < foo; i++) + if ((font = XLoadQueryFont(dpy, list[i])) != 0) + break; + if (!font) + { + list = XListFonts(dpy, "fixed", 1, &foo); + font = XLoadQueryFont(dpy, list[0]); + } + if (!font) + XtError("Can't find a font (so call me stupid)."); + XFreeFontNames(list); + } + gcvalues.font = font->fid; + gcvalues.graphics_exposures = False; + gc = XCreateGC(dpy, DefaultRootWindow(dpy), + GCForeground | GCBackground | GCGraphicsExposures | GCFont, + &gcvalues); + + x = Width / 2; + y = Height / 2; + srand (time(0)); + state = IS_MOVING; + + { + static XtActionsRec actions[] = { + { "ClearWindow", ClearWindow }, + { "GetPasswd", GetPasswd }, + { "RaiseWindow", RaiseWindow }, + }; + XtAppAddActions(app, actions, XtNumber(actions)); + XtOverrideTranslations(widget, + XtParseTranslationTable( + ": ClearWindow() \n" + ": GetPasswd() \n" + ": RaiseWindow() \n" + ": GetPasswd() \n" + ": GetPasswd()")); + } + + XtRealizeWidget(override); +#if 0 + XGrabServer(dpy); +#else + XGrabPointer(dpy, XtWindow(widget), TRUE, 0, GrabModeAsync, + GrabModeAsync, XtWindow(widget), None, CurrentTime); + XGrabKeyboard(dpy, XtWindow(widget), TRUE, GrabModeAsync, + GrabModeAsync, CurrentTime); +#endif + ScreenSaver(1); + XtAppMainLoop(app); + exit(0); +}