xenocara/app/xlockmore/xlock/xlock.c
matthieu a972c460fa OpenBSD customizations/adaptations:
- icons
- blank mode by default
- BSD auth
2006-11-26 17:13:23 +00:00

4588 lines
123 KiB
C
Raw Blame History

#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)xlock.c 5.15 2005/01/22 xlockmore";
#endif
/*-
* xlock.c - X11 client to lock a display and show a screen saver.
*
* Copyright (c) 1988-91 by Patrick J. Naughton.
* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* Revision History:
*
* Changes maintained by David Bagley <bagleyd@tux.org>
* 23-Feb-03: Timothy Reed <treed1@twcny.rr.com>
* Added PAM_putText to converse with passwd.c PAM_conv function
* to converse with any PAM.
* 09-Mar-01: showfps stuff corrected
* 01-Nov-00: Allocation checks
* 08-Apr-98: A way for users to unlock each others display. Kind of defeats
* the lock but the unlocked user is mailed and and entry is
* written to syslogd. Thanks to Mark Kirk <mkirk@pdi.com> for
* his vizlock-1.0 patch. Compile-time switch for this is
* GLOBAL_UNLOCK. This is probably full of security holes when
* enabled... :)
* 01-Jul-98: Eric Lassauge <lassauge AT users.sourceforge.net> &
* Remi Cohen-Scali <remi.cohenscali@pobox.com>
* Added support for locking VT switching (-/+vtlock)
* Added code is enclosed in USE_VTLOCK
* 01-May-97: Matthew Rench <mdrench@mtu.edu>
* Added DPMS options.
* 02-Dec-97: Strong user authentication, utilizing the SafeWord API.
* Author unknown.
* 01-May-97: Scott Carter <scarter@sdsc.edu>
* Added code to stat .xlocktext, .plan, and .signature files
* before reading the message; only regular files are read (no
* pipes or special files).
* Added code to replace tabs with 8 spaces in the plantext buffer.
* 01-Sep-96: Ron Hitchens <ron@idiom.com>
* Updated xlock so it would refresh more reliably and
* handle window resizing.
* 18-Mar-96: Ron Hitchens <ron@idiom.com>
* Implemented new ModeInfo hook calling scheme.
* Created mode_info() to gather and pass info to hooks.
* Watch for and use MI_PAUSE value if mode hook sets it.
* Catch SIGSEGV, SIGBUS and SIGFPE signals. Other should
* be caught. Eliminate some globals.
* 23-Dec-95: Ron Hitchens <ron@idiom.com>
* Rewrote event loop so as not to use signals.
* 01-Sep-95: initPasswd function, more stuff removed to passwd.c
* 24-Jun-95: Cut out passwd stuff to passwd.c-> getPasswd & checkPasswd
* 17-Jun-95: Added xlockrc password compile time option.
* 12-May-95: Added defines for SunOS's Adjunct password file from
* Dale A. Harris <rodmur@ecst.csuchico.edu>
* 21-Feb-95: MANY patches from Heath A. Kehoe <hakehoe@icaen.uiowa.edu>.
* 24-Jan-95: time_displayed fixed from Chris Ross <cross@va.pubnix.com>.
* 18-Jan-95: Ultrix systems (at least DECstations) running enhanced
* security from Chris Fuhrman <cfuhrman@vt.edu> and friend.
* 26-Oct-94: In order to use extra-long passwords with the Linux changed
* PASSLENGTH to 64 <slouken@virtbrew.water.ca.gov>
* 11-Jul-94: added -inwindow option from Greg Bowering
* <greg@cs.adelaide.edu.au>
* 22-Jun-94: Modified for VMS
* <Anthony.D.Clarke@Support.Hatfield.Raytheon.bae.eurokom.ie>
* 10-Jun-94: patch for BSD from Victor Langeveld <vic@mbfys.kun.nl>
* 02-May-94: patched to work on Linux from Darren Senn's
* <sinster@scintilla.capitola.ca.us> xlock for Linux.
* Took out "bounce" since it was too buggy (maybe I will put
* it back later).
* 21-Mar-94: patch to to trap Shift-Ctrl-Reset courtesy of Jamie Zawinski
* <jwz@jwz.org>, patched the patch (my mistake) for AIXV3
* and HP from <R.K.Lloyd@csc.liv.ac.uk>.
* 01-Dec-93: added patch for AIXV3 from Tom McConnell
* <tmcconne@sedona.intel.com> also added a patch for HP-UX 8.0.
* 29-Jul-93: "hyper", "helix", "rock", and "blot" (also tips on "maze") I
* got courtesy of Jamie Zawinski <jwz@jwz.org>;
* at the time I could not get his stuff to work for the hpux 8.0,
* so I scrapped it but threw his stuff in xlock.
* "maze" and "sphere" I got courtesy of Sun Microsystems.
* "spline" I got courtesy of Jef Poskanzer <jef@netcom.com or
* jef@well.sf.ca.us>.
*
* Changes of Patrick J. Naughton
* 24-Jun-91: make foreground and background color get used on mono.
* 24-May-91: added -usefirst.
* 16-May-91: added pyro and random modes.
* ripped big comment block out of all other files.
* 08-Jan-91: fix some problems with password entry.
* removed renicing code.
* 29-Oct-90: added cast to XFree() arg.
* added volume arg to call to XBell().
* 28-Oct-90: center prompt screen.
* make sure Xlib input buffer does not use up all of swap.
* make displayed text come from resource file for better I18N.
* add backward compatible signal handlers for pre 4.1 machines.
* 31-Aug-90: added blank mode.
* added swarm mode.
* moved usleep() and seconds() out to usleep.c.
* added SVR4 defines to xlock.h
* 29-Jul-90: added support for multiple screens to be locked by one xlock.
* moved global defines to xlock.h
* removed use of allowsig().
* 07-Jul-90: reworked commandline args and resources to use Xrm.
* moved resource processing out to resource.c
* 02-Jul-90: reworked colors to not use dynamic colormap.
* 23-May-90: added autoraise when obscured.
* 15-Apr-90: added hostent alias searching for host authentication.
* 18-Feb-90: added SunOS3.5 fix.
* changed -mono -> -color, and -saver -> -lock.
* allow non-locking screensavers to display on remote machine.
* added -echokeys to disable echoing of '?'s on input.
* cleaned up all of the parameters and defaults.
* 20-Dec-89: added -xhost to allow access control list to be left alone.
* added -screensaver (do not disable screen saver) for the paranoid.
* Moved seconds() here from all of the display mode source files.
* Fixed bug with calling XUngrabHosts() in finish().
* 19-Dec-89: Fixed bug in GrabPointer.
* Changed fontname to XLFD style.
* 23-Sep-89: Added fix to allow local hostname:0 as a display.
* Put empty case for Enter/Leave events.
* Moved colormap installation later in startup.
* 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
* Replaced SunView code for life mode with Jim Graham's version,
* so I could contrib it without legal problems.
* Sent to expo for X11R4 contrib.
* 19-Sep-89: Added '?'s on input.
* 27-Mar-89: Added -qix mode.
* Fixed GContext->GC.
* 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
* Changed default font to lucida-sans-24.
* 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
* 24-Feb-89: Replaced hopalong display with life display from SunView1.
* 22-Feb-89: Added fix for color servers with n < 8 planes.
* 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
* Added -count for number of iterations per color.
* Fixed defaulting mechanism.
* Ripped out VMS hacks.
* Sent to expo for X11R3 contrib.
* 15-Feb-89: Changed default font to pellucida-sans-18.
* 20-Jan-89: Added -verbose and fixed usage message.
* 19-Jan-89: Fixed monochrome gc bug.
* 16-Dec-88: Added SunView style password prompting.
* 19-Sep-88: Changed -color to -mono. (default is color on color displays).
* Added -saver option. (just do display... do not lock.)
* 31-Aug-88: Added -time option.
* Removed code for fractals to separate file for modularity.
* Added signal handler to restore host access.
* Installs dynamic colormap with a Hue Ramp.
* If grabs fail then exit.
* Added VMS Hacks. (password 'iwiwuu').
* Sent to expo for X11R2 contrib.
* 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
* 20-May-88: Added -root to allow root to unlock.
* 12-Apr-88: Added root password override.
* Added screen saver override.
* Removed XGrabServer/XUngrabServer.
* Added access control handling instead.
* 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
* 30-Mar-88: Removed startup password requirement.
* Removed cursor to avoid phosphor burn.
* 27-Mar-88: Rotate fractal by 45 degrees clockwise.
* 24-Mar-88: Added color support. [-color]
* wrote the man page.
* 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
* added password requirement for invokation
* removed option for command line password
* added requirement for display to be "unix:0".
* 22-Mar-88: Recieved Walter Milliken's comp.windows.x posting.
*
*/
#ifdef HAVE_SETPRIORITY
/* Problems using nice with setuid */
#include <sys/time.h>
#include <sys/resource.h>
#else /* !HAVE_SETPRIORITY */
/* extern int nice(int); */
#endif /* HAVE_SETPRIORITY */
#ifdef STANDALONE
/*-
* xscreensaver compatibility layer for xlockmore modules.
* xscreensaver, Copyright (c) 1997, 1998 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* This file, along with xlockmore.h, make it possible to compile an xlockmore
* module into a standalone program, and thus use it with xscreensaver.
* By Jamie Zawinski <jwz@jwz.org> on 10-May-97; based on the ideas
* in the older xlock.h by Charles Hannum <mycroft@ai.mit.edu>. (I had
* to redo it, since xlockmore has diverged so far from xlock...)
*/
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "screenhack.h"
#include "mode.h"
#include "vis.h"
#define countof(x) (sizeof((x))/sizeof(*(x)))
extern ModeSpecOpt xlockmore_opts[];
extern const char *app_defaults;
char *message, *messagefile, *messagesfile, *program;
char *messagefontname;
void
pre_merge_options(void)
{
int i, j;
char *s;
/* Translate the xlockmore `opts[]' argument to a form that
screenhack.c expects.
*/
for (i = 0; i < xlockmore_opts->numopts; i++) {
XrmOptionDescRec *old = &xlockmore_opts->opts[i];
XrmOptionDescRec *new = &options[i];
if (old->option[0] == '-')
new->option = old->option;
else {
/* Convert "+foo" to "-no-foo". */
if ((new->option = (char *) malloc(strlen(old->option) +
5)) != NULL) {
(void) strcpy(new->option, "-no-");
(void) strcat(new->option, old->option + 1);
}
}
new->specifier = strrchr(old->specifier, '.');
if (!new->specifier)
abort();
new->argKind = old->argKind;
new->value = old->value;
}
/* Add extra args, if they're mentioned in the defaults... */
{
char *args[] =
{"-delay", "-count", "-cycles", "-size", "-ncolors", "-bitmap",
"-text", "-filename", "-program",
"-wireframe", "-use3d", "-verbose"};
for (j = 0; j < countof(args); j++)
if (strstr(app_defaults, args[j] + 1)) {
XrmOptionDescRec *new = &options[i++];
new->option = args[j];
new->specifier = strdup(args[j]);
new->specifier[0] = '.';
if (!strcmp(new->option, "-wireframe")) {
new->argKind = XrmoptionNoArg;
new->value = "True";
new = &options[i++];
new->option = "-no-wireframe";
new->specifier = options[i - 2].specifier;
new->argKind = XrmoptionNoArg;
new->value = "False";
} else if (!strcmp(new->option, "-use3d")) {
new->option = "-3d";
new->argKind = XrmoptionNoArg;
new->value = "True";
new = &options[i++];
new->option = "-no-3d";
new->specifier = options[i - 2].specifier;
new->argKind = XrmoptionNoArg;
new->value = "False";
} else if (!strcmp(new->option, "-verbose")) {
new->option = "-verbose";
new->argKind = XrmoptionNoArg;
new->value = "True";
new = &options[i++];
new->option = "-no-verbose";
new->specifier = options[i - 2].specifier;
new->argKind = XrmoptionNoArg;
new->value = "False";
} else {
new->argKind = XrmoptionSepArg;
new->value = 0;
}
}
}
/* Construct the kind of `defaults' that screenhack.c expects from
the xlockmore `vars[]' argument.
*/
i = 0;
/* Put on the PROGCLASS.background/foreground resources. */
if ((s = (char *) malloc(50)) != NULL) {
(void) strlcpy(s, progclass, 50);
(void) strlcat(s, ".background: black", 50);
defaults[i++] = s;
}
if ((s = (char *) malloc(50)) != NULL) {
(void) strcpy(s, progclass);
(void) strcat(s, ".foreground: white");
defaults[i++] = s;
}
/* Copy the lines out of the `app_defaults' var and into this array. */
s = strdup(app_defaults);
while (s && *s) {
defaults[i++] = s;
s = strchr(s, '\n');
if (s)
*s++ = 0;
}
/* Copy the defaults out of the `xlockmore_opts->' variable. */
for (j = 0; j < xlockmore_opts->numvarsdesc; j++) {
const char *def = xlockmore_opts->vars[j].def;
if (!def)
def = "False";
if (def == ((char *) 1))
def = "True";
if ((s = (char *) malloc(strlen(xlockmore_opts->vars[j].name) +
strlen(def) + 10)) != NULL) {
(void) strcpy(s, "*");
(void) strcat(s, xlockmore_opts->vars[j].name);
(void) strcat(s, ": ");
(void) strcat(s, def);
defaults[i++] = s;
}
}
defaults[i] = 0;
}
static void
xlockmore_read_resources(void)
{
int i;
for (i = 0; i < xlockmore_opts->numvarsdesc; i++) {
void *var = xlockmore_opts->vars[i].var;
Bool *var_b = (Bool *) var;
char **var_c = (char **) var;
int *var_i = (int *) var;
float *var_f = (float *) var;
switch (xlockmore_opts->vars[i].type) {
case t_String:
*var_c = get_string_resource(xlockmore_opts->vars[i].name,
xlockmore_opts->vars[i].classname);
break;
case t_Float:
*var_f = get_float_resource(xlockmore_opts->vars[i].name,
xlockmore_opts->vars[i].classname);
break;
case t_Int:
*var_i = get_integer_resource(xlockmore_opts->vars[i].name,
xlockmore_opts->vars[i].classname);
break;
case t_Bool:
*var_b = get_boolean_resource(xlockmore_opts->vars[i].name,
xlockmore_opts->vars[i].classname);
break;
default:
abort();
}
}
}
void
xlockmore_screenhack(Display * dpy, Window window,
Bool want_writable_colors,
Bool want_uniform_colors,
Bool want_smooth_colors,
Bool want_bright_colors,
void (*hack_init) (ModeInfo *),
void (*hack_draw) (ModeInfo *),
void (*hack_free) (ModeInfo *))
{
ModeInfo mi;
XGCValues gcv;
XColor color;
int i;
time_t start, now;
struct timeval drawstart, drawstop;
unsigned long drawelapsed;
int orig_pause;
(void) memset((char *) &mi, 0, sizeof (mi));
mi.dpy = dpy;
mi.window = window;
(void) XGetWindowAttributes(dpy, window, &mi.xgwa);
color.flags = DoRed | DoGreen | DoBlue;
color.red = color.green = color.blue = 0;
if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
abort();
mi.black = color.pixel;
color.red = color.green = color.blue = 0xFFFF;
if (!XAllocColor(dpy, mi.xgwa.colormap, &color))
abort();
mi.white = color.pixel;
if (mono_p) {
static unsigned long pixels[2];
static XColor colors[2];
MONO:
mi.npixels = 2;
mi.pixels = pixels;
mi.colors = colors;
pixels[0] = mi.black;
pixels[1] = mi.white;
colors[0].flags = DoRed | DoGreen | DoBlue;
colors[1].flags = DoRed | DoGreen | DoBlue;
colors[0].red = colors[0].green = colors[0].blue = 0;
colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
mi.writable_p = False;
} else {
mi.npixels = get_integer_resource("ncolors", "Integer");
if (mi.npixels <= 0)
mi.npixels = 64;
else if (mi.npixels > 256)
mi.npixels = 256;
mi.writable_p = want_writable_colors;
if ((mi.colors = (XColor *) calloc(mi.npixels,
sizeof (*mi.colors))) != NULL) {
if (want_uniform_colors)
make_uniform_colormap(dpy, mi.xgwa.visual, mi.xgwa.colormap,
mi.colors, &mi.npixels,
True, &mi.writable_p, True);
else if (want_smooth_colors)
make_smooth_colormap(dpy, mi.xgwa.visual, mi.xgwa.colormap,
mi.colors, &mi.npixels,
True, &mi.writable_p, True);
else
make_random_colormap(dpy, mi.xgwa.visual, mi.xgwa.colormap,
mi.colors, &mi.npixels,
want_bright_colors,
True, &mi.writable_p, True);
}
if (mi.npixels <= 2)
goto MONO;
else {
if ((mi.pixels = (unsigned long *)
calloc(mi.npixels, sizeof (*mi.pixels))) != NULL) {
int i;
for (i = 0; i < mi.npixels; i++)
mi.pixels[i] = mi.colors[i].pixel;
}
}
}
gcv.foreground = mi.white;
gcv.background = mi.black;
mi.gc = XCreateGC(dpy, window, GCForeground | GCBackground, &gcv);
mi.pause = get_integer_resource("delay", "Usecs");
mi.count = get_integer_resource("count", "Int");
mi.cycles = get_integer_resource("cycles", "Int");
mi.size = get_integer_resource("size", "Int");
mi.ncolors = get_integer_resource("ncolors", "Int");
mi.bitmap = get_string_resource("bitmap", "String");
messagefontname = get_string_resource("font", "String");
message = get_string_resource("text", "String");
messagefile = get_string_resource("filename", "String");
messagesfile = get_string_resource("fortunefile", "String");
program = get_string_resource("program", "String");
#if 0
decay = get_boolean_resource("decay", "Boolean");
if (decay)
mi.fullrandom = False;
trail = get_boolean_resource("trail", "Boolean");
if (trail)
mi.fullrandom = False;
grow = get_boolean_resource("grow", "Boolean");
if (grow)
mi.fullrandom = False;
liss = get_boolean_resource("liss", "Boolean");
if (liss)
mi.fullrandom = False;
ammann = get_boolean_resource("ammann", "Boolean");
if (ammann)
mi.fullrandom = False;
jong = get_boolean_resource("jong", "Boolean");
if (jong)
mi.fullrandom = False;
sine = get_boolean_resource("sine", "Boolean");
if (sine)
mi.fullrandom = False;
#endif
mi.threed = get_boolean_resource("use3d", "Boolean");
mi.threed_delta = get_float_resource("delta3d", "Boolean");
mi.threed_right_color = get_pixel_resource("right3d", "Color", dpy,
mi.xgwa.colormap);
mi.threed_left_color = get_pixel_resource("left3d", "Color", dpy,
mi.xgwa.colormap);
mi.threed_both_color = get_pixel_resource("both3d", "Color", dpy,
mi.xgwa.colormap);
mi.threed_none_color = get_pixel_resource("none3d", "Color", dpy,
mi.xgwa.colormap);
mi.wireframe_p = get_boolean_resource("wireframe", "Boolean");
mi.fps_p = get_boolean_resource("showfps", "Boolean");
mi.verbose = get_boolean_resource("verbose", "Boolean");
mi.root_p = (window == RootWindowOfScreen(mi.xgwa.screen));
mi.is_drawn = False;
if (mi.pause < 0)
mi.pause = 0;
else if (mi.pause > 100000000)
mi.pause = 100000000;
orig_pause = mi.pause;
xlockmore_read_resources();
XClearWindow(dpy, window);
i = 0;
start = time((time_t) 0);
hack_init(&mi);
do {
(void) gettimeofday(&drawstart, NULL);
hack_draw(&mi);
XSync(dpy, False);
(void) gettimeofday(&drawstop, NULL);
drawelapsed = (drawstop.tv_sec - drawstart.tv_sec)*1000000 +
(drawstop.tv_usec - drawstart.tv_usec);
if (mi.pause > drawelapsed)
(void) usleep(mi.pause - drawelapsed);
mi.pause = orig_pause;
if (hack_free) {
if (i++ > (mi.count / 4) &&
(start + 5) < (now = time((time_t) 0))) {
i = 0;
start = now;
hack_free(&mi);
hack_init(&mi);
XSync(dpy, False);
}
}
} while (1);
}
#else /* STANDALONE */
#include "xlock.h"
#include "color.h"
#include "util.h"
#include "iostuff.h"
#include "passwd.h"
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_SELECT_H && defined(AIXV3)
#include <sys/select.h>
#endif
#ifndef WIN32
#include <X11/cursorfont.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#else
#include "Xapi.h"
#endif /* WIN32 */
#if USE_XVMSUTILS
#if 0
#include "../xvmsutils/unix_types.h"
#include "../xvmsutils/unix_time.h"
#else
#include <X11/unix_types.h>
#include <X11/unix_time.h>
#endif
#endif /* USE_XVMSUTILS */
#ifdef USE_DTSAVER
#include <X11/Intrinsic.h>
#include <Dt/Saver.h>
#endif
#if defined( __hpux ) || defined( __apollo )
#include <X11/XHPlib.h>
extern int XHPEnableReset(Display * dsp);
#endif
#ifdef USE_DPMS
#define MIN_DPMS 30 /* 30 second minimum */
#if 1
#include <X11/Xmd.h>
#include <X11/Xdmcp.h>
#include <X11/extensions/dpms.h>
#ifdef SunCplusplus
extern Bool DPMSQueryExtension(Display *, int *, int *);
extern Bool DPMSGetTimeouts(Display *, unsigned short *, unsigned short *, unsigned short *);
extern Status DPMSSetTimeouts(Display *, unsigned short, unsigned short, unsigned short);
extern int DPMSCapable(Display *);
extern int DPMSInfo(Display *, CARD16 *, BOOL *);
#endif
#else /* XFree86 < 4.x */
#include <X11/extensions/dpms.h>
#ifndef __NetBSD
extern unsigned char DPMSQueryExtension(Display *, int *, int *);
#endif
extern int DPMSGetTimeouts(Display *, unsigned short *, unsigned short *, unsigned short *);
extern int DPMSSetTimeouts(Display *, unsigned short, unsigned short, unsigned short);
#endif
extern int dpmsstandby;
extern int dpmssuspend;
extern int dpmsoff;
#endif
#ifdef HAVE_KRB5
#include <krb5.h>
#endif /* HAVE_KRB5 */
#if ( HAVE_SYSLOG_H && (defined( USE_SYSLOG ) || defined( GLOBAL_UNLOCK )))
#include <pwd.h>
#include <grp.h>
#include <syslog.h>
#ifndef SYSLOG_FACILITY
#define SYSLOG_FACILITY LOG_AUTH
#endif
#endif
#if ( __VMS_VER >= 70000000 )
#include <lib$routines.h>
#include <mail$routines.h>
#include <maildef.h>
struct itmlst_3 {
unsigned short int buflen;
unsigned short int itmcode;
void *bufadr;
unsigned short int *retlen;
};
#endif
#ifdef __FreeBSD__
#include <floatingpoint.h>
#endif
extern void checkResources(void);
extern void defaultVisualInfo(Display * display, int screen);
#ifdef USE_OLD_EVENT_LOOP
extern int usleep(unsigned int);
#endif
#if defined( USE_AUTO_LOGOUT ) || defined( USE_BUTTON_LOGOUT )
extern void logoutUser(Display * display
#ifdef CLOSEDOWN_LOGOUT
, int screens
#endif
);
#endif
#if 0
/* #if !defined( AIXV3 ) && !defined( __hpux ) && !defined( __bsdi__ ) */
extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
#if !defined( __hpux ) && !defined( apollo )
extern int select(size_t, int *, int *, int *, const struct timeval *);
#endif
#endif
char *ProgramName; /* argv[0] */
#ifdef DEBUG
pid_t ProgramPID; /* for memcheck.c */
#endif
ScreenInfo *Scr = (ScreenInfo *) NULL;
/* This is a private data structure, don't touch */
static ModeInfo *modeinfo = (ModeInfo *) NULL;
Window parent;
Bool parentSet = False;
Display *dsp = (Display *) NULL; /* server display connection */
gid_t rgid;
#if defined( HAVE_SETEUID ) || defined( HAVE_SETREUID )
uid_t euid;
gid_t egid;
#endif
extern char user[PASSLENGTH];
extern char hostname[MAXHOSTNAMELEN];
extern char *displayname;
extern char *bitmap;
extern int delay;
extern int count;
extern int cycles;
extern int size;
extern int ncolors;
extern float saturation;
extern float delta3d;
extern Bool nolock;
extern Bool resetsaver;
extern Bool inwindow;
extern Bool inroot;
extern Bool mono;
extern Bool allowaccess;
extern Bool allowroot;
extern Bool debug;
extern Bool description;
extern Bool echokeys;
extern char* echokey;
extern Bool enablesaver;
extern Bool fullrandom;
extern Bool grabmouse;
extern Bool grabserver;
extern Bool install;
extern Bool mousemotion;
extern int unlockdelay;
extern Bool timeelapsed;
extern Bool usefirst;
extern Bool verbose;
extern Bool remote;
extern int nicelevel;
extern int lockdelay;
extern int timeout;
extern Bool wireframe;
#ifdef USE_GL
extern Bool showfps;
extern Bool fpsTop;
#endif
extern Bool use3d;
#ifdef HAVE_KRB5
extern int krb5_valid;
#endif
extern char *fontname;
extern char *planfontname;
#ifdef USE_MB
XFontSet fontset;
extern char *fontsetname;
XFontSet planfontset;
extern char *planfontsetname;
XRectangle mbRect;
XRectangle planmbRect;
#define fontheight (mbRect.height)
#define planfontheight (planmbRect.height)
#else
#define fontheight (font->ascent + font->descent)
#define planfontheight (planfont->ascent + planfont->descent)
#endif
extern char *background;
extern char *foreground;
extern char *text_user;
extern char *text_pass;
extern char *text_info;
#ifdef HAVE_KRB5
extern char *text_krbinfo;
#endif
extern char *text_valid;
extern char *text_invalid;
extern char *text_invalidCapsLock;
extern char *failed_attempt;
extern char *failed_attempts;
extern char *geometry;
extern char *icongeometry;
#ifdef FX
extern char *glgeometry;
#endif
extern char *none3d;
extern char *right3d;
extern char *left3d;
extern char *both3d;
#ifdef USE_SOUND
extern char *locksound;
extern char *infosound;
extern char *validsound;
extern char *invalidsound;
#ifdef USE_ESOUND
extern char *welcomesound;
extern char *shutdownsound;
#endif
extern void playSound(char *string, Bool verbose);
#ifdef USE_ESOUND
extern int init_sound(void);
extern void shutdown_sound(void);
#endif
extern Bool sound;
#endif
extern char *startCmd;
extern char *endCmd;
#ifndef VMS
extern char *pipepassCmd;
#endif
extern char *logoutCmd;
extern char *mailCmd;
extern char *mailIcon;
extern char *nomailIcon;
#ifdef USE_AUTO_LOGOUT
extern int logoutAuto;
#endif
#ifdef USE_BUTTON_LOGOUT
extern int logoutButton;
extern int enable_button;
extern char *logoutButtonLabel;
extern char *logoutButtonHelp;
extern char *logoutFailedString;
#endif
#ifdef USE_DTSAVER
extern Bool dtsaver;
#endif
static int screen = 0; /* current screen */
int startscreen = 0;
static int screens; /* number of screens */
static Cursor mycursor; /* blank cursor */
static Pixmap lockc;
static Pixmap lockm; /* pixmaps for cursor and mask */
static char no_bits[] =
{0}; /* dummy array for the blank cursor */
static int passx, passy; /* position of the ?'s */
static int iconwidth, iconheight;
static int lock_delay;
static int count_failed;
#ifdef FX
static int glwidth, glheight;
#endif
static int timex, timey; /* position for the times */
static XFontStruct *font;
static XFontStruct *planfont;
static int sstimeout; /* screen saver parameters */
static int ssinterval;
static int ssblanking;
static int ssexposures;
static unsigned long start_time;
static char *plantext[TEXTLINES + 2]; /* Message is stored here */
/* GEOMETRY STUFF */
static int sizeconfiguremask;
static XWindowChanges minisizeconfigure;
static Bool fullscreen = False;
#if defined( USE_AUTO_LOGOUT ) || defined( USE_BUTTON_LOGOUT )
static int tried_logout = 0;
#endif
#ifdef USE_SOUND
static int got_invalid = 0;
#endif
/* This still might not be right for Solaris, change the "1"->"0" if error */
#if 1
#if (defined( SYSV ) || defined( SVR4 )) && defined( SOLARIS2 ) && !defined( HAVE_STRUCT_SIGSET_T )
#if !defined( __cplusplus ) && !defined( c_plusplus ) && !defined ( _SIGSET_T )
#define _SIGSET_T
typedef struct { /* signal set type */
unsigned long __sigbits[4];
} sigset_t;
/* This is good for gcc compiled on Solaris-2.5 but used on Solaris-2.6 */
#endif
#endif
#endif
#if !defined( SYSV ) && !defined( SVR4 ) && !defined( VMS ) && !defined(__cplusplus) && !defined(c_plusplus)
extern int sigblock(int);
extern int sigsetmask(int);
#endif
#ifdef ORIGINAL_XPM_PATCH
#ifdef HAVE_XPM
#include <X11/xpm.h>
#endif
static XpmImage *mail_xpmimg = NULL;
static XpmImage *nomail_xpmimg = NULL;
#else
#ifndef WIN32
#include <bitmaps/mailempty.xbm>
#include <bitmaps/mailfull.xbm>
#define NOMAIL_WIDTH mailempty_width
#define NOMAIL_HEIGHT mailempty_height
#define NOMAIL_BITS mailempty_bits
#define MAIL_WIDTH mailfull_width
#define MAIL_HEIGHT mailfull_height
#define MAIL_BITS mailfull_bits
#endif /* !WIN32 */
#endif
#ifdef USE_VTLOCK
/* EL - RCS : for VT switching locking */
extern int vtlock; /* Have to lock VT switching */
extern int vtlocked; /* VT switching is locked */
extern void dovtlock(void); /* Actual do it */
extern void dovtunlock(void); /* & undo it functions */
#endif
static int signalUSR1 = 0;
static int signalUSR2 = 0;
char * old_default_mode = (char *) NULL;
#define AllPointerEventMask \
(ButtonPressMask | ButtonReleaseMask | \
EnterWindowMask | LeaveWindowMask | \
PointerMotionMask | PointerMotionHintMask | \
Button1MotionMask | Button2MotionMask | \
Button3MotionMask | Button4MotionMask | \
Button5MotionMask | ButtonMotionMask | \
KeymapStateMask)
#ifdef USE_VROOT
#include "vroot.h"
#endif
#ifdef SAFEWORD
#include "custpb.h"
#include "custf.h"
extern char *text_dpass;
extern char *text_fpass;
extern char *text_chall;
static int challx, chally;
extern pbmain();
struct pblk pblock; /* our instance of the pblk */
struct pblk *pb; /* global pointer to the pblk */
extern int checkDynamic();
#endif
#if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
static void
syslogStart(void)
{
struct passwd *pw = NULL;
struct group *gr = NULL;
char uid[16];
char gid[16];
pw = getpwuid(getuid());
gr = getgrgid(getgid());
if (pw == NULL)
sprintf(uid, "%ld", (long) getuid());
if (gr == NULL)
sprintf(gid, "%ld", (long) getgid());
(void) openlog(ProgramName, LOG_PID, SYSLOG_FACILITY);
syslog(SYSLOG_INFO, "Start: %s, %s, %s",
(pw == NULL) ? uid : pw->pw_name,
(gr == NULL) ? gid : gr->gr_name,
XDisplayString(dsp));
}
void
syslogStop(char *displayName)
{
int secs, mins;
struct passwd *pw = NULL;
struct group *gr = NULL;
char uid[16];
char gid[16];
pw = getpwuid(getuid());
gr = getgrgid(getgid());
if (pw == NULL)
sprintf(uid, "%ld", (long) getuid());
if (gr == NULL)
sprintf(gid, "%ld", (long) getgid());
secs = (int) (seconds() - start_time);
mins = secs / 60;
secs %= 60;
syslog(SYSLOG_INFO, "Stop: %s, %s, %s, %dm %ds",
(pw == NULL) ? uid : pw->pw_name,
(gr == NULL) ? gid : gr->gr_name,
displayName, mins, secs);
}
#endif
#define ERROR_BUF 2048
char error_buf[ERROR_BUF];
void
error(const char *buf)
{
#if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
syslog(SYSLOG_WARNING, "%s", buf);
if (!nolock) {
if (strstr(buf, "unable to open display") == NULL)
syslogStop(XDisplayString(dsp));
else
syslogStop("unknown display");
closelog();
}
#else
(void) fprintf(stderr, "%s", buf);
#endif
exit(1);
}
/* Server access control support. */
static XHostAddress *XHosts; /* the list of "friendly" client machines */
static int HostAccessCount; /* the number of machines in XHosts */
static Bool HostAccessState; /* whether or not we even look at the list */
/* define window class (used by WindowMaker attributes configuration) */
XClassHint xclasshint={(char *) "xlock", (char *) "xlock"};
static void
XGrabHosts(Display * display)
{
XHosts = XListHosts(display, &HostAccessCount, &HostAccessState);
if (XHosts)
XRemoveHosts(display, XHosts, HostAccessCount);
XEnableAccessControl(display);
}
static void
XUngrabHosts(Display * display)
{
if (XHosts) {
XAddHosts(display, XHosts, HostAccessCount);
XFree((caddr_t) XHosts);
}
if (HostAccessState == False)
XDisableAccessControl(display);
}
/* Provides support for the DPMS options. */
#ifdef USE_DPMS
static void
SetDPMS(Display * display, int nstandby, int nsuspend, int noff)
{
static unsigned short standby = 0, suspend = 0, off = 0, flag = 0;
int dummy;
if (DPMSQueryExtension(display, &dummy, &dummy)) {
if (!flag) {
DPMSGetTimeouts(display, &standby, &suspend, &off);
flag++;
}
if ((nstandby < 0) && (nsuspend < 0) && (noff < 0))
DPMSSetTimeouts(display, standby, suspend, off);
else
DPMSSetTimeouts(display,
(nstandby <= 0 ? 0 : (nstandby > MIN_DPMS ? nstandby : MIN_DPMS)),
(nsuspend <= 0 ? 0 : (nsuspend > MIN_DPMS ? nsuspend : MIN_DPMS)),
(noff <= 0 ? 0 : (noff > MIN_DPMS ? noff : MIN_DPMS)));
}
}
static int
monitor_powered_on_p(Display *dpy)
{
int result;
int event_number, error_number;
BOOL onoff = False;
CARD16 state;
if (!DPMSQueryExtension(dpy, &event_number, &error_number))
/* DPMS extention is not supported */
result = True;
else if (!DPMSCapable(dpy))
/* Monitor is incapable of DPMS */
result = True;
else
{
DPMSInfo(dpy, &state, &onoff);
if (!onoff)
/* DPMS is disabled */
result = True;
else {
switch (state) {
case DPMSModeOn: result = True; break;
case DPMSModeStandby: result = False; break;
case DPMSModeSuspend: result = False; break;
case DPMSModeOff: result = False; break;
default: result = True; break;
}
}
}
return result;
}
#else
static int
monitor_powered_on_p(Display *dpy)
{
return 1;
}
#endif
/*-
* Simple wrapper to get an asynchronous grab on the keyboard and mouse. If
* either grab fails, we sleep for one second and try again since some window
* manager might have had the mouse grabbed to drive the menu choice that
* picked "Lock Screen..". If either one fails the second time we print an
* error message and exit.
*/
static void
GrabKeyboardAndMouse(Display * display, Window window)
{
Status status;
status = XGrabKeyboard(display, window, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
if (status != GrabSuccess) {
(void) sleep(1);
status = XGrabKeyboard(display, window, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
if (status != GrabSuccess) {
(void) sprintf(error_buf,
"%s, could not grab keyboard! (%d)\n",
(strlen(ProgramName) < ERROR_BUF - 80) ?
ProgramName : "xlock", status);
error(error_buf);
}
}
status = XGrabPointer(display, window, True,
(unsigned int) AllPointerEventMask, GrabModeAsync,
GrabModeAsync, None, mycursor, CurrentTime);
if (status != GrabSuccess) {
(void) sleep(1);
status = XGrabPointer(display, window, True,
(unsigned int) AllPointerEventMask, GrabModeAsync,
GrabModeAsync, None, mycursor, CurrentTime);
if (status != GrabSuccess) {
(void) sprintf(error_buf,
"%s, could not grab pointer! (%d)\n",
(strlen(ProgramName) < ERROR_BUF - 80) ?
ProgramName : "xlock", status);
error(error_buf);
}
}
}
/* Assuming that we already have an asynch grab on the pointer, just grab it
again with a new cursor shape and ignore the return code. */
static void
ChangeGrabbedCursor(Display * display, Window window, Cursor cursor)
{
if (!debug && grabmouse && !inwindow && !inroot)
(void) XGrabPointer(display, window, True,
(unsigned int) AllPointerEventMask, GrabModeAsync,
GrabModeAsync, None, cursor, CurrentTime);
}
/*-
* Return True of False indicating if the given window has changed
* size relative to the window geometry cached in the mode_info
* struct. If the window handle given does not match the one in
* the cache, or if the width/height are not the same, then True
* is returned and the window handle in the cache is cleared.
* This causes mode_info() to reload the window info next time
* it is called.
* This function has non-obvious side-effects. I feel so dirty. Rh
*/
static int
window_size_changed(int scrn, Window window)
{
XWindowAttributes xgwa;
ModeInfo *mi = &modeinfo[scrn];
if (MI_WINDOW(mi) != window) {
MI_WINDOW(mi) = None; /* forces reload on next mode_info() */
return (True);
} else {
(void) XGetWindowAttributes(dsp, window, &xgwa);
if ((MI_WIDTH(mi) != xgwa.width) ||
(MI_HEIGHT(mi) != xgwa.height)) {
MI_WINDOW(mi) = None;
return (True);
}
}
return (False);
}
#ifdef FX
void
resetSize(ModeInfo * mi, Bool setGL)
{
char *mesa_3Dfx_env;
static int width = 0, height = 0;
mesa_3Dfx_env = getenv("MESA_GLX_FX");
if (!mesa_3Dfx_env)
return;
if (tolower(mesa_3Dfx_env[0]) != 'f')
return;
/*
* This is not correct for multiscreens, but there are other problems
* here for multiscreens as well so I am not going bother
*/
if (!width)
width = MI_WIDTH(mi);
if (!height)
height = MI_HEIGHT(mi);
if (setGL) {
MI_WIDTH(mi) = glwidth;
MI_HEIGHT(mi) = glheight;
} else {
MI_WIDTH(mi) = width;
MI_HEIGHT(mi) = height;
}
XResizeWindow(MI_DISPLAY(mi), MI_WINDOW(mi),
MI_WIDTH(mi), MI_HEIGHT(mi));
}
#endif
/*-
* Return a pointer to an up-to-date ModeInfo struct for the given
* screen, window and iconic mode. Because the number of screens
* is limited, and much of the information is screen-specific, this
* function keeps static copies of ModeInfo structs are kept for
* each screen. This also eliminates redundant calls to the X server
* to acquire info that does change.
*/
static ModeInfo *
mode_info(Display * display, int scrn, Window window, int iconic)
{
XWindowAttributes xgwa;
ModeInfo *mi;
mi = &modeinfo[scrn];
if (MI_FLAG_NOT_SET(mi, WI_FLAG_INFO_INITTED)) {
/* This stuff only needs to be set once per screen */
(void) memset((char *) mi, 0, sizeof (ModeInfo));
MI_DISPLAY(mi) = display;
MI_SCREEN(mi) = scrn;
MI_REAL_SCREEN(mi) = scrn; /* TODO, for multiscreen debugging */
MI_SCREENPTR(mi) = ScreenOfDisplay(display, scrn);
MI_NUM_SCREENS(mi) = screens;
MI_MAX_SCREENS(mi) = screens; /* TODO, for multiscreen debugging */
MI_SCREENINFO(mi) = &Scr[scrn];
/* accessing globals here */
MI_SET_FLAG_STATE(mi, WI_FLAG_MONO,
(mono || CellsOfScreen(MI_SCREENPTR(mi)) <= 2));
MI_SET_FLAG_STATE(mi, WI_FLAG_INWINDOW, inwindow);
MI_SET_FLAG_STATE(mi, WI_FLAG_INROOT, inroot);
MI_SET_FLAG_STATE(mi, WI_FLAG_NOLOCK, nolock);
#ifdef USE_DTSAVER
MI_SET_FLAG_STATE(mi, WI_FLAG_INSTALL, install && !inroot && !dtsaver);
#else
MI_SET_FLAG_STATE(mi, WI_FLAG_INSTALL, install && !inroot);
#endif
MI_SET_FLAG_STATE(mi, WI_FLAG_DEBUG, debug);
MI_SET_FLAG_STATE(mi, WI_FLAG_USE3D, use3d &&
!(mono || CellsOfScreen(MI_SCREENPTR(mi)) <= 2));
MI_SET_FLAG_STATE(mi, WI_FLAG_VERBOSE, verbose);
#ifdef WIN32
MI_SET_FLAG_STATE(mi, WI_FLAG_FULLRANDOM, True);
#else
MI_SET_FLAG_STATE(mi, WI_FLAG_FULLRANDOM, False);
#endif
MI_SET_FLAG_STATE(mi, WI_FLAG_WIREFRAME, wireframe);
#ifdef USE_GL
MI_SET_FLAG_STATE(mi, WI_FLAG_FPS, showfps);
#endif
MI_SET_FLAG_STATE(mi, WI_FLAG_INFO_INITTED, True);
MI_IS_DRAWN(mi) = False;
}
if (MI_WINDOW(mi) != window) {
MI_WINDOW(mi) = window;
(void) XGetWindowAttributes(display, window, &xgwa);
MI_WIDTH(mi) = xgwa.width;
MI_HEIGHT(mi) = xgwa.height;
}
MI_SET_FLAG_STATE(mi, WI_FLAG_ICONIC, iconic);
MI_DELTA3D(mi) = delta3d;
MI_DELAY(mi) = delay; /* globals */
MI_COUNT(mi) = count;
MI_CYCLES(mi) = cycles;
MI_SIZE(mi) = size;
MI_NCOLORS(mi) = ncolors;
MI_SATURATION(mi) = saturation;
MI_BITMAP(mi) = bitmap;
return (mi);
}
#if defined( GLOBAL_UNLOCK ) || defined( USE_PAM )
static int unamex = 0, unamey = 0;
#endif
#ifdef GLOBAL_UNLOCK
extern char *text_guser;
extern char global_user[PASSLENGTH];
extern void checkUser(char *buffer);
#define LOG_FACILITY LOG_LOCAL2
#define LOG_LEVEL LOG_INFO
static int
inform()
{
/*
- the time, in date(1) style, is generated with a combination of the
time(2) and ctime(3C) system calls.
- the owner of the xlock process is learned with getlogin(3C).
- global_user is a global character array that holds the username
of the person wishing to unlock the display.
- the hostname is learned with gethostname(2).
- the syslog(3B) call uses the syslog facility to log
happenings at LOG_LEVEL to LOG_FACILITY
- yes, a system(3S) call is used...
- I never said it was pretty.
*/
char Mail[256];
time_t unlock_time;
/* learn what time it is and what host we are on */
time(&unlock_time);
#if defined( HAVE_SYSLOG_H ) /* && defined( USE_SYSLOG ) */
/* log this event to syslogd as defined */
syslog(LOG_FACILITY | LOG_LEVEL, "%s: %s unlocked %s's display",
ProgramName, global_user, getlogin());
#endif
/* if (mailCmd && mailCmd[0]) { */
/* build a string suitable for use in system(3S) */
(void) sprintf(Mail, "%s -s \"%s:\" %s << EOF\n %s unlocked "
"%s's display on %s\n EOF",
/* Want the mail with the subject line control */
#if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 )
"/usr/ucb/mail" ,
#else
"/usr/bin/mail" ,
#endif
ProgramName, getlogin(),
global_user, hostname, ctime(&unlock_time));
if (debug)
(void) printf("%s\n", Mail);
(void) system(Mail);
/* } */
}
#endif
/* Restore all grabs, reset screensaver, restore colormap, close connection. */
void
finish(Display * display, Bool closeDisplay)
{
int scrn;
for (scrn = startscreen; scrn < screens; scrn++) {
if (Scr[scrn].window != None) {
release_last_mode(mode_info(display, scrn, Scr[scrn].window, False));
}
if (Scr[scrn].icon != None) {
release_last_mode(mode_info(display, scrn, Scr[scrn].icon, True));
}
}
#ifdef ORIGINAL_XPM_PATCH
if (mail_xpmimg)
free(mail_xpmimg);
if (nomail_xpmimg)
free(nomail_xpmimg);
#endif
XSync(display, False);
#ifdef USE_VROOT
if (inroot)
XClearWindow(display, Scr[startscreen].window);
#endif
#ifdef GLOBAL_UNLOCK
/* Check to see if the owner is doing the unlocking themselves,
and if not then inform the display owner of who is unlocking */
if (strcmp(global_user, getlogin()) != 0)
inform();
#endif
if (!nolock && !allowaccess) {
if (grabserver)
XUngrabServer(display);
XUngrabHosts(display);
}
XUngrabPointer(display, CurrentTime);
XUngrabKeyboard(display, CurrentTime);
if (!enablesaver && !nolock) {
XSetScreenSaver(display, sstimeout, ssinterval, ssblanking, ssexposures);
}
XFlush(display);
#if 0
/* Report that this gives "bad file descriptor" on XFree86 4.x */
#ifndef __sgi
/*-
* The following line seems to cause a core dump on the SGI.
* More work is needed on the cleanup code.
*/
if (closeDisplay)
(void) XCloseDisplay(display);
#endif
#endif
#ifdef HAVE_SETPRIORITY
(void) setpriority(0, 0, 0);
#else /* !HAVE_SETPRIORITY */
(void) nice(0);
#endif /* HAVE_SETPRIORITY */
#ifdef USE_VTLOCK
/* EL - RCS : Unlock VT switching */
if (vtlock && vtlocked)
dovtunlock();
#endif
}
#ifdef __cplusplus
extern "C" {
#endif
static int
xio_error(Display * d)
{
#ifdef USE_DTSAVER
if (dtsaver) { /* this is normal when run as -dtsaver */
/* X connection to :0.0 broken (explicit kill or server shutdown). */
exit(0);
}
#endif
(void) sprintf(error_buf,
"%s: xio_error\n",
(strlen(ProgramName) < ERROR_BUF - 80) ?
ProgramName : "xlock");
error(error_buf);
return ((debug) ? 0 : 1); /* suppress message unless debugging */
}
#ifdef __cplusplus
}
#endif
/* Convenience function for drawing text */
static void
putText(Display * display, Window window, GC gc,
const char *string, int bold, int left, int *px, int *py)
/* which window */
/* gc */
/* text to write */
/* 1 = make it bold */
/* left edge of text */
/* current x and y, input & return */
{
#define PT_BUFSZ 2048
char buf[PT_BUFSZ], *p, *s;
int x = *px, y = *py, last, len;
(void) strncpy(buf, string, PT_BUFSZ);
buf[PT_BUFSZ - 1] = 0;
p = buf;
last = 0;
for (;;) {
s = p;
for (; *p; ++p)
if (*p == '\n')
break;
if (!*p)
last = 1;
*p = 0;
if ((len = strlen(s))) { /* yes, "=", not "==" */
(void) XDrawImageString(display, window, gc, x, y, s, len);
if (bold)
(void) XDrawString(display, window, gc, x + 1, y, s, len);
}
if (!last) {
y += fontheight + 2;
x = left;
} else {
if (len)
x += XTextWidth(font, s, len);
break;
}
p++;
}
*px = x;
*py = y;
}
#ifdef JA
#include "xlock-msg-ja.h"
#endif
static void
statusUpdate(int isnew, int scr)
{
int left, x, y, len;
char buf[1024];
XWindowAttributes xgwa;
static int last_time;
#ifdef USE_BUTTON_LOGOUT
int ysave;
static int made_button, last_tried_lo = 0;
#endif /* USE_BUTTON_LOGOUT */
len = (int) (seconds() - start_time) / 60;
#ifdef USE_BUTTON_LOGOUT
if (tried_logout && !last_tried_lo) {
last_tried_lo = 1;
isnew = 1;
#ifdef USE_AUTO_LOGOUT
logoutAuto = 0;
#endif
}
if (isnew)
made_button = 0;
#endif /* USE_BUTTON_LOGOUT */
if (isnew || last_time != len)
last_time = len;
else
return;
(void) XGetWindowAttributes(dsp, Scr[scr].window, &xgwa);
x = left = timex;
y = timey;
if (timeelapsed) {
if (len < 60)
(void) sprintf(buf,
#ifdef DE
"Seit %d Minute%s gesperrt. \n",
len, len <= 1 ? "" : "n"
#elif defined FR
"%d minute%s <20>coul<75>e%s depuis verrouillage. \n",
len, len <= 1 ? "" : "s", len <= 1 ? "" : "s"
#elif defined NL
"%d minu%s op slot. \n",
len, len <= 1 ? "ut" : "ten"
#elif defined JA
JA_TIME_ELAPSED_MINUTES,
len
#else
"%d minute%s elapsed since locked. \n",
len, len <= 1 ? "" : "s"
#endif
);
else
(void) sprintf(buf,
#ifdef DE
"Seit %d:%02d Stunden gesperrt. \n",
len / 60, len % 60
#elif defined FR
"%d:%02d heures <20>coul<75>e%s depuis verouillage. \n",
len / 60, len % 60, (len / 60) <= 1 ? "" : "s"
#elif defined NL
"%d:%02d uur op slot. \n",
len / 60, len % 60
#elif defined JA
JA_TIME_ELAPSED_HOURS,
len / 60, len % 60
#else
"%d:%02d hour%s elapsed since locked. \n",
len / 60, len % 60, (len / 60) <= 1 ? "" : "s"
#endif
);
putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y);
}
#ifdef USE_BUTTON_LOGOUT
if (enable_button) {
if (logoutButton > len) {
int tmp = logoutButton - len;
if (tmp < 60)
(void) sprintf(buf,
#ifdef DE
"In %d Minute%s erscheint der Auslogger. \n",
tmp, (tmp <= 1) ? "" : "n"
#elif defined FR
"%d minute%s jusqu'<27> apparition du bouton lougout. \n",
tmp, (tmp <= 1) ? "" : "s"
#elif defined NL
"Over %d minu%s verschijnt de logout knop. \n",
tmp, (tmp <= 1) ? "ut" : "ten"
#elif defined JA
JA_BUTTON_MINUTES,
tmp
#else
"%d minute%s until the public logout button appears. \n",
tmp, (tmp <= 1) ? "" : "s"
#endif
);
else
(void) sprintf(buf,
#ifdef DE
"In %d:%02d Stunden erscheint der Auslogger. \n",
#elif defined FR
"%d:%02d heures jusqu'<27> apparition du bouton lougout \n",
#elif defined NL
"Over %d:%02d uur verschijnt de logout knop. \n",
#elif defined JA
JA_BUTTON_HOURS,
#else
"%d:%02d hours until the public logout button appears. \n",
#endif
tmp / 60, tmp % 60);
putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y);
} else {
/* Erase previous logout button message */
putText(dsp, Scr[scr].window, Scr[scr].textgc,
" \n",
False, left, &x, &y);
if (!made_button || (isnew && tried_logout)) {
made_button = 1;
ysave = y;
y += fontheight + 8; /* Leave a gap for validating */
XUnmapWindow(dsp, Scr[scr].button);
XSetForeground(dsp, Scr[scr].gc, Scr[scr].bg_pixel);
XFillRectangle(dsp, Scr[scr].window, Scr[scr].gc, left, y,
xgwa.width - left,
5 + 2 * (fontheight));
XSetForeground(dsp, Scr[scr].gc, Scr[scr].fg_pixel);
if (tried_logout) {
putText(dsp, Scr[scr].window, Scr[scr].textgc, logoutFailedString,
True, left, &x, &y);
} else {
XMoveWindow(dsp, Scr[scr].button, left, y);
XMapWindow(dsp, Scr[scr].button);
XRaiseWindow(dsp, Scr[scr].button);
(void) sprintf(buf, " %s ", logoutButtonLabel);
XSetForeground(dsp, Scr[scr].gc, Scr[scr].white_pixel);
(void) XDrawString(dsp, Scr[scr].button, Scr[scr].gc,
0, font->ascent + 1, buf, strlen(buf));
XSetForeground(dsp, Scr[scr].gc, Scr[scr].fg_pixel);
y += 5 + 2 * fontheight;
putText(dsp, Scr[scr].window, Scr[scr].textgc, logoutButtonHelp,
False, left, &x, &y);
}
y = ysave;
x = left;
}
}
}
#endif /* USE_BUTTON_LOGOUT */
#ifdef USE_AUTO_LOGOUT
if (logoutAuto) {
int tmp = logoutAuto - len;
if (tmp < 60)
(void) sprintf(buf,
#ifdef FR
"%d minute%s jusqu'<27> l'auto-logout. \n",
tmp, (tmp <= 1) ? "" : "s"
#elif defined NL
"%d minu%s tot auto-logout. \n",
tmp, (tmp <= 1) ? "ut" : "ten"
#elif defined JA
JA_AUTOLOGOUT_MINUTES,
tmp
#else
"%d minute%s until auto-logout. \n",
tmp, (tmp <= 1) ? "" : "s"
#endif
);
else
(void) sprintf(buf,
#ifdef FR
"%d:%02d heure%s jusqu'<27> auto-logout. \n",
tmp / 60, tmp % 60, (tmp / 60) <= 1 ? "" : "s"
#elif defined NL
"%d:%02d uur tot auto-logout. \n",
tmp / 60, tmp % 60
#elif defined JA
JA_AUTOLOGOUT_HOURS,
tmp / 60, tmp % 60
#else
"%d:%02d hours until auto-logout. \n",
tmp / 60, tmp % 60
#endif
);
putText(dsp, Scr[scr].window, Scr[scr].textgc, buf, False, left, &x, &y);
}
#endif /* USE_AUTO_LOGOUT */
}
#ifdef USE_AUTO_LOGOUT
static void
checkLogout(Display * display)
{
if (nolock || tried_logout || !logoutAuto)
return;
if (logoutAuto * 60 < (int) (seconds() - start_time)) {
tried_logout = 1;
logoutAuto = 0;
logoutUser(display
#ifdef CLOSEDOWN_LOGOUT
, screens
#endif
);
}
}
#endif /* USE_AUTO_LOGOUT */
#ifndef USE_OLD_EVENT_LOOP
#ifndef WIN32
/* subtract timer t2 from t1, return result in t3. Result is not allowed to
go negative, set to zero if result underflows */
static
void
sub_timers(struct timeval *t1, struct timeval *t2, struct timeval *t3)
{
struct timeval tmp;
int borrow = 0;
if (t1->tv_usec < t2->tv_usec) {
borrow++;
tmp.tv_usec = (1000000 + t1->tv_usec) - t2->tv_usec;
} else {
tmp.tv_usec = t1->tv_usec - t2->tv_usec;
}
/* Be careful here, timeval fields may be unsigned. To avoid
underflow in an unsigned int, add the borrow value to the
subtrahend for the relational test. Same effect, but avoids the
possibility of a negative intermediate value. */
if (t1->tv_sec < (t2->tv_sec + borrow)) {
tmp.tv_usec = tmp.tv_sec = 0;
} else {
tmp.tv_sec = t1->tv_sec - t2->tv_sec - borrow;
}
*t3 = tmp;
}
#endif /* !WIN32 */
/* return 0 on event received, -1 on timeout */
static int
runMainLoop(int maxtime, int iconscreen)
{
#ifndef WIN32
static int lastdelay = -1, lastmaxtime = -1;
int fd = ConnectionNumber(dsp), r;
int poweron=True;
struct timeval sleep_time, first, repeat, elapsed, tmp;
fd_set reads;
unsigned long started;
#ifdef USE_NEW_EVENT_LOOP
struct timeval loopStart, timeSinceLoop;
unsigned long lastIter = 0, desiredIter = 0;
GETTIMEOFDAY(&loopStart);
#endif
first.tv_sec = 0;
first.tv_usec = 0;
elapsed.tv_sec = 0;
elapsed.tv_usec = 0;
repeat.tv_sec = delay / 1000000;
repeat.tv_usec = delay % 1000000;
started = seconds();
for (;;) {
poweron= monitor_powered_on_p(dsp);
if(!poweron) (void) usleep(100000);
if (signalUSR1 || signalUSR2) {
int i;
if (signalUSR1) {
#ifdef DEBUG
(void) printf("switch to mode %s\n", "blank");
#endif
for (i = 0; i < numprocs; i++) {
if (!strcmp(LockProcs[i].cmdline_arg, "blank")) {
set_default_mode(&LockProcs[i]);
break;
}
}
} else {
#ifdef DEBUG
(void) printf("switch to mode %s\n", old_default_mode);
#endif
for (i = 0; i < numprocs; i++) {
if (!strcmp(LockProcs[i].cmdline_arg, old_default_mode)) {
set_default_mode(&LockProcs[i]);
break;
}
}
}
for (screen = startscreen; screen < screens; screen++) {
call_change_hook((LockStruct *) NULL,
mode_info(dsp, screen, Scr[screen].window, False));
}
signalUSR1 = signalUSR2 = 0;
}
if (delay != lastdelay || maxtime != lastmaxtime) {
if (!delay || (maxtime && delay / 1000000 > maxtime)) {
repeat.tv_sec = maxtime;
repeat.tv_usec = 0;
} else {
repeat.tv_sec = delay / 1000000;
repeat.tv_usec = delay % 1000000;
}
first = repeat;
lastdelay = delay;
lastmaxtime = maxtime;
sleep_time = first;
} else {
sleep_time = repeat;
}
/* subtract time spent doing last loop iteration */
sub_timers(&sleep_time, &elapsed, &sleep_time);
/* (void) */ FD_ZERO(&reads);
FD_SET(fd, &reads);
#ifdef VMS
FD_SET(fd + 1, &reads);
#endif
#if DCE_PASSWD
r = _select_sys(fd + 1,
(fd_set *) & reads, (fd_set *) NULL, (fd_set *) NULL,
(struct timeval *) &sleep_time);
#else
#if defined( __cplusplus ) || defined( c_plusplus )
r = select(fd + 1,
(fd_set *) & reads, (fd_set *) NULL, (fd_set *) NULL,
(struct timeval *) &sleep_time);
#else
r = select(fd + 1,
(void *) &reads, (void *) NULL, (void *) NULL,
(struct timeval *) &sleep_time);
#endif
#endif
if (r == 1)
return 0;
if (r > 0 || (r == -1 && errno != EINTR))
(void) fprintf(stderr,
"Unexpected select() return value: %d (errno=%d)\n", r, errno);
GETTIMEOFDAY(&tmp); /* get time before calling mode proc */
#ifdef USE_NEW_EVENT_LOOP
if (delay == 0) {
desiredIter = lastIter + 1;
} else {
sub_timers(&tmp, &loopStart, &timeSinceLoop);
desiredIter =
(timeSinceLoop.tv_usec / delay) +
(((timeSinceLoop.tv_sec % delay) * 1000000) / delay) +
(timeSinceLoop.tv_sec / delay) * 1000000;
}
while (lastIter != desiredIter) {
++lastIter;
#endif
for (screen = startscreen; screen < screens; screen++) {
Window cbwin;
Bool iconic;
ModeInfo *mi;
if (screen == iconscreen) {
cbwin = Scr[screen].icon;
iconic = True;
} else {
cbwin = Scr[screen].window;
iconic = False;
}
if (cbwin != None && poweron) {
mi = mode_info(dsp, screen, cbwin, iconic);
call_callback_hook((LockStruct *) NULL, mi);
}
}
if (poweron)
XSync(dsp, False);
else
(void) usleep(100000);
/* check for events received during the XSync() */
if (QLength(dsp)) {
return 0;
}
if (maxtime && ((int) (seconds() - started) > maxtime)) {
return -1;
}
#ifdef USE_NEW_EVENT_LOOP
}
#endif
/* if (mindelay) (void) usleep(mindelay); */
/* get the time now, figure how long it took */
GETTIMEOFDAY(&elapsed);
sub_timers(&elapsed, &tmp, &elapsed);
}
#else /* WIN32 */
return 0;
#endif /* WIN32 */
}
#endif /* !USE_OLD_EVENT_LOOP */
static int
ReadXString(char *s, int slen, Bool *capsLock
#ifdef GLOBAL_UNLOCK
, Bool pass
#elif defined( USE_PAM )
, Bool PAM_echokeys
#endif
)
{
XEvent event;
char keystr[20];
char c;
int i;
int bp;
int len;
int thisscreen = screen;
char pwbuf[PASSLENGTH];
int first_key = 1;
*capsLock = False;
for (screen = startscreen; screen < screens; screen++)
if (thisscreen == screen) {
call_init_hook((LockStruct *) NULL,
mode_info(dsp, screen, Scr[screen].icon, True));
} else {
call_init_hook((LockStruct *) NULL,
mode_info(dsp, screen, Scr[screen].window, False));
}
statusUpdate(True, thisscreen);
bp = 0;
*s = 0;
for (;;) {
unsigned long lasteventtime = seconds();
KeySym keysym;
while (!XPending(dsp)) {
#ifdef USE_OLD_EVENT_LOOP
for (screen = startscreen; screen < screens; screen++)
if (thisscreen == screen)
call_callback_hook(NULL, mode_info(dsp, screen,
Scr[screen].icon, True));
else
call_callback_hook(NULL, mode_info(dsp, screen,
Scr[screen].window, False));
statusUpdate(False, thisscreen);
XSync(dsp, False);
(void) usleep(delay);
#else
statusUpdate(False, thisscreen);
if (runMainLoop(MIN(timeout, 5), thisscreen) == 0)
break;
#endif
if ((timeout < (int) (seconds() - lasteventtime))) {
screen = thisscreen;
return 1;
}
}
screen = thisscreen;
(void) XNextEvent(dsp, &event);
/*
* This event handling code should be unified with the
* similar code in justDisplay().
*/
switch (event.type) {
case KeyPress:
len = XLookupString((XKeyEvent *) & event,
keystr, 20, /*(KeySym *) NULL,*/
&keysym,
(XComposeStatus *) NULL);
*capsLock = ((event.xkey.state & LockMask) != 0);
for (i = 0; i < len; i++) {
c = keystr[i];
switch (c) {
case 8: /* ^H */
case 127: /* DEL */
if (bp > 0)
bp--;
break;
case 10: /* ^J */
case 13: /* ^M */
if (first_key && usefirst)
break;
s[bp] = '\0';
return 0;
case 21: /* ^U */
bp = 0;
break;
default:
s[bp] = c;
if (bp < slen - 1)
bp++;
else
XSync(dsp, True); /* flush input buffer */
}
}
XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
#ifdef GLOBAL_UNLOCK
if (!pass) {
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
unamex, unamey - font->ascent,
XTextWidth(font, s, slen),
fontheight);
(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
unamex, unamey, s, bp);
} else
#elif defined( USE_PAM )
if (PAM_echokeys) {
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
unamex, unamey - font->ascent,
XTextWidth(font, s, slen),
fontheight);
(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
unamex, unamey, s, bp);
} else
#endif
if (echokeys) {
if (bp > 0 && strcmp("swear", echokey) == 0) {
char swearkeys[] = "@^!$%?#*";
pwbuf[bp - 1] =
swearkeys[NRAND(strlen(swearkeys))];
pwbuf[bp] = '\0';
} else
(void) memset((char *) pwbuf,
echokey[0], slen);
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
passx, passy - font->ascent,
XTextWidth(font, pwbuf, slen),
fontheight);
(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
passx, passy, pwbuf, bp);
}
/* eat all events if there are more than
enough pending... this keeps the Xlib event
buffer from growing larger than all
available memory and crashing xlock. */
if (XPending(dsp) > 100) { /* 100 is arbitrarily
big enough */
register Status status;
do {
status = XCheckMaskEvent(dsp,
KeyPressMask | KeyReleaseMask, &event);
} while (status);
XBell(dsp, 100);
}
break;
case MotionNotify:
if (!mousemotion)
break;
/* fall through on last mouse event */
case ButtonPress:
if (((XButtonEvent *) & event)->window == Scr[screen].icon) {
return 1;
}
#ifdef USE_BUTTON_LOGOUT
if (((XButtonEvent *) & event)->window == Scr[screen].button) {
XSetFunction(dsp, Scr[screen].gc, GXxor);
XSetForeground(dsp, Scr[screen].gc, Scr[screen].fg_pixel);
XFillRectangle(dsp, Scr[screen].button, Scr[screen].gc,
0, 0, 500, 100);
XSync(dsp, False);
tried_logout = 1;
logoutUser(dsp
#ifdef CLOSEDOWN_LOGOUT
, screens
#endif
);
XSetFunction(dsp, Scr[screen].gc, GXcopy);
}
#endif
break;
case Expose:
if (event.xexpose.count != 0)
break;
/* fall through on last expose event */
case VisibilityNotify:
/* next line for -geometry */
if (event.xvisibility.state != VisibilityUnobscured) {
/* window was restacked or exposed */
if (!debug && !inwindow)
XRaiseWindow(dsp, event.xvisibility.window);
call_refresh_hook((LockStruct *) NULL,
mode_info(dsp, screen, Scr[screen].window, False));
#ifndef USE_WINDOW_VISIBILITY
s[0] = '\0';
return 1;
#endif
}
break;
case ConfigureNotify:
/* next line for -geometry */
if (!fullscreen)
break;
/* window config changed */
if (!debug && !inwindow) {
XRaiseWindow(dsp, event.xconfigure.window);
fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors,
saturation, mono, install, inroot, inwindow, verbose);
}
if (window_size_changed(screen, Scr[screen].window)) {
call_init_hook((LockStruct *) NULL,
mode_info(dsp, screen, Scr[screen].window, False));
} else if (install)
/* next line : refresh would be logical. But some modes
* look weird when continuing from an erased screen */
call_refresh_hook((LockStruct *) NULL,
mode_info(dsp, screen, Scr[screen].window, False));
s[0] = '\0';
return 1;
case KeymapNotify:
case KeyRelease:
case ButtonRelease:
case LeaveNotify:
case EnterNotify:
case NoExpose:
case CirculateNotify:
case DestroyNotify:
case GravityNotify:
case MapNotify:
case ReparentNotify:
case UnmapNotify:
break;
default:
(void) fprintf(stderr, "%s: unexpected event: %d\n",
ProgramName, event.type);
break;
}
first_key = 0;
}
}
void
modeDescription(ModeInfo * mi)
{
int left, x, y;
int scrn = MI_SCREEN(mi);
XWindowAttributes xgwa;
(void) XGetWindowAttributes(dsp, Scr[scrn].window, &xgwa);
x = left = Scr[scrn].iconpos.x;
y = Scr[scrn].iconpos.y - fontheight + 2;
XSetForeground(dsp, Scr[scrn].gc, Scr[scrn].bg_pixel);
XFillRectangle(dsp, Scr[scrn].window, Scr[scrn].gc,
x, y - font->ascent,
xgwa.width - x, fontheight + 2);
putText(dsp, Scr[scrn].window, Scr[scrn].textgc, MI_NAME(mi),
True, left, &x, &y);
putText(dsp, Scr[scrn].window, Scr[scrn].textgc, ": ", True, left, &x, &y);
putText(dsp, Scr[scrn].window, Scr[scrn].textgc, MI_DESC(mi),
False, left, &x, &y);
putText(dsp, Scr[scrn].window, Scr[scrn].textgc, "\n", False, left, &x, &y);
}
void
update_plan() /* updates current time in plantext */
{
time_t t;
int i = 0;
t = time(NULL);
(void) strcpy(plantext[0], (char *) ctime(&t));
for (i = 0; i < 29; i++)
if (plantext[0][i] < '\040') { /* Cygwin weirdness */
plantext[0][i] = '\0';
break;
}
plantext[0][29] = '\0'; /* just in case. */
}
/* WIN32 machines handle reading passwords automatically */
#ifndef WIN32
static int
getPassword(void)
{
XWindowAttributes xgwa;
int x, y, left, done, remy;
char buffer[PASSLENGTH];
char **planp;
char *hostbuf = (char *) NULL;
ModeInfo *mi = &modeinfo[screen];
Bool capsLock = False;
#ifdef USE_MB
XFontSet backfontset;
#endif
#ifdef FX
Bool mesa_3Dfx_fullscreen;
char *mesa_3Dfx_env;
mesa_3Dfx_env = getenv("MESA_GLX_FX");
if (mesa_3Dfx_env)
if (tolower(mesa_3Dfx_env[0] == 'f')) {
/* disabling fullscreen HW 3dfx rendering to
allow iconic mode window. */
mesa_3Dfx_fullscreen = True;
unsetenv("MESA_GLX_FX");
}
#endif
#ifdef HAVE_SETPRIORITY
(void) setpriority(0, 0, 0);
#else /* !HAVE_SETPRIORITY */
(void) nice(0);
#endif /* HAVE_SETPRIORITY */
if (!fullscreen)
XConfigureWindow(dsp, Scr[screen].window, sizeconfiguremask,
&(Scr[screen].fullsizeconfigure));
(void) XGetWindowAttributes(dsp, Scr[screen].window, &xgwa);
ChangeGrabbedCursor(dsp, Scr[screen].window,
XCreateFontCursor(dsp, XC_left_ptr));
MI_CLEARWINDOWCOLOR(mi, Scr[screen].bg_pixel);
XMapWindow(dsp, Scr[screen].icon);
XRaiseWindow(dsp, Scr[screen].icon);
if (description)
modeDescription(mi);
x = left = Scr[screen].iconpos.x + iconwidth + font->max_bounds.width;
y = Scr[screen].iconpos.y + font->ascent;
if ((hostbuf = (char *) malloc(strlen(user) + strlen(hostname) +
2)) != NULL) {
#ifdef HAVE_KRB5
if (krb5_valid) {
strcpy(hostbuf, user);
} else
#endif /* HAVE_KRB5 */
(void) sprintf(hostbuf, "%s@%s", user, hostname);
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_user, True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, hostbuf, False, left, &x, &y);
free(hostbuf);
}
if (displayname && displayname[0] != ':') {
char *displaybuf = (char *) NULL;
char *colon = (char *) strchr(displayname, ':');
int n = colon - displayname;
if ((displaybuf = (char *) malloc(n + 1)) != NULL) {
(void) strncpy(displaybuf, displayname, n);
displaybuf[n] = '\0';
if (remote && n
&& strcmp(displaybuf, "unix") != 0
&& strcmp(displaybuf, "localhost") != 0
&& strcmp(displaybuf, hostname) != 0) {
putText(dsp, Scr[screen].window, Scr[screen].textgc, " Display: ", True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, displaybuf, False, left, &x, &y);
}
free(displaybuf);
}
}
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
#ifdef GLOBAL_UNLOCK
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_guser,
True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
False, left, &x, &y);
unamex = x;
unamey = y;
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
#endif
#ifdef SAFEWORD
if (checkDynamic()) {
pb = &pblock;
(void) memset((char *) &pblock, 0, sizeof (pblock));
#if 0
(void) strcpy(pblock.uport, "custpb");
pblock.status = NO_STATUS;
#endif
challx = x;
chally = y;
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n\n",
False, left, &x, &y);
pb->mode = CHALLENGE;
(void) strcpy(pb->id, user);
pbmain(pb);
if (pb->status != GOOD_USER) {
chall[0] = 0;
return 1;
}
if (pb->dynpwdf) {
/* We do not really care if they also got a fixed password... */
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_dpass,
True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
False, left, &x, &y);
passx = x;
passy = y;
} else if (pb->fixpwdf) {
/* In the unlikely event they only got a fixed password... */
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_fpass,
True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
False, left, &x, &y);
passx = x;
passy = y;
}
} else
#endif
{
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_pass, True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, " ", False, left, &x, &y);
passx = x;
passy = y;
}
y += fontheight + 6;
if (y < Scr[screen].iconpos.y + iconheight + font->ascent + 12)
y = Scr[screen].iconpos.y + iconheight + font->ascent + 12;
x = left = Scr[screen].iconpos.x;
#ifdef HAVE_KRB5
if (krb5_valid)
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_krbinfo, False, left, &x, &y);
else
#endif /* HAVE_KRB5 */
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_info, False, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
if (count_failed > 0) {
char * cnt = NULL;
y += fontheight + 6;
if (y < Scr[screen].iconpos.y + iconheight + font->ascent + 12)
y = Scr[screen].iconpos.y + iconheight + font->ascent + 12;
x = left = Scr[screen].iconpos.x;
if ((cnt = (char *) malloc(strlen((count_failed == 1) ? failed_attempt : failed_attempts) + 16)) != NULL) {
(void) sprintf(cnt, "%d%s", count_failed, (count_failed == 1) ? failed_attempt : failed_attempts);
putText(dsp, Scr[screen].window, Scr[screen].textgc, cnt, False, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
free(cnt);
y -= 2 * (fontheight + 2); /* go up */
}
}
timex = x;
timey = y;
#ifdef USE_AUTO_LOGOUT
if (logoutAuto) {
y += fontheight + 2;
}
#endif
#ifdef USE_BUTTON_LOGOUT
if (enable_button) {
y += fontheight + 2;
}
#endif
if (timeelapsed) {
y += fontheight + 2;
}
remy = y;
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
y = Scr[screen].planpos.y;
update_plan();
#ifdef USE_MB
backfontset = fontset;
fontset = planfontset;
#endif
if (*plantext) {
for (planp = plantext; *planp; ++planp) {
y += planfontheight + 2;
(void) XDrawString(dsp, Scr[screen].window,
Scr[screen].plantextgc,
Scr[screen].planpos.x, y,
*planp, strlen(*planp));
}
}
#ifdef USE_MB
fontset = backfontset;
#endif
XFlush(dsp);
if (mailCmd && mailCmd[0]) {
#ifdef ORIGINAL_XPM_PATCH
XpmImage *mbxpm;
mailboxInfo *mbi;
int x, y;
if (system(mailCmd)) {
mbxpm = nomail_xpmimg;
mbi = &Scr[screen].mb.nomail;
} else {
mbxpm = mail_xpmimg;
mbi = &Scr[screen].mb.mail;
}
if (mbxpm) {
x = (DisplayWidth(dsp, screen) - mbxpm->width) / 2;
y = (Scr[screen].planpos.y - 5) - mbxpm->height;
XCopyArea(dsp, mbi->pixmap,
Scr[screen].window, Scr[screen].mb.mbgc,
0, 0,
mbxpm->width, mbxpm->height, x, y);
}
#else
mailboxInfo *mbi;
int mbx, mby;
if (system(mailCmd)) {
mbi = &Scr[screen].mb.nomail;
} else {
mbi = &Scr[screen].mb.mail;
}
if (mbi) {
mbx = (DisplayWidth(dsp, screen) - mbi->width) / 2;
mby = (Scr[screen].planpos.y - 5) - mbi->height;
XSetTSOrigin(dsp, Scr[screen].mb.mbgc, mbx, mby);
XSetStipple(dsp, Scr[screen].mb.mbgc, mbi->pixmap);
XSetFillStyle(dsp, Scr[screen].mb.mbgc, FillOpaqueStippled);
XFillRectangle(dsp, Scr[screen].window, Scr[screen].mb.mbgc,
mbx, mby, mbi->width, mbi->height);
}
#endif
}
done = False;
while (!done) {
#ifdef USE_SOUND
if (sound && !got_invalid) {
playSound(infosound, verbose);
}
got_invalid = 0;
#endif
#ifdef SAFEWORD
pb->mode = CHALLENGE;
(void) strcpy(pb->id, user);
pbmain(pb);
if (pb->status != GOOD_USER) {
chall[0] = 0;
return 1;
}
left = x = challx;
y = chally;
if (strlen(pb->chal) > 0) {
(void) strcpy(chall, pb->chal);
putText(dsp, Scr[screen].window, Scr[screen].textgc, text_chall,
True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
False, left, &x, &y);
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
left + XTextWidth(font, text_chall, strlen(text_chall)),
y - font->ascent, XTextWidth(font, chall, strlen(chall)),
fontheight + 2);
putText(dsp, Scr[screen].window, Scr[screen].textgc, chall,
False, left, &x, &y);
}
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n",
False, left, &x, &y);
if (pb->dynpwdf || pb->fixpwdf) {
/* If they have a dynamic passwd we do not really care about
the fixed password... */
putText(dsp, Scr[screen].window, Scr[screen].textgc,
(pb->dynpwdf) ? text_dpass : text_fpass,
True, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, " ",
False, left, &x, &y);
passx = x;
passy = y;
}
#endif
#ifdef GLOBAL_UNLOCK
if (ReadXString(global_user, PASSLENGTH, (Bool *) NULL, False))
break;
(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
unamex, unamey,
global_user, strlen(global_user));
checkUser(global_user);
#endif
if (ReadXString(buffer, PASSLENGTH, &capsLock
#ifdef GLOBAL_UNLOCK
, True
#elif defined( USE_PAM )
, False
#endif
))
break;
y = remy;
XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
#ifdef SAFEWORD
(void) strcpy(pb->dynpwd, buffer);
pb->mode = EVALUATE_ALL;
pbmain(pb);
done = (pb->status == PASS || pb->status == PASS_MASTER);
pb->mode = UPDATE_LOGS;
pbmain(pb);
#else
{
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
Scr[screen].iconpos.x, y - font->ascent,
2 * XTextWidth(font, text_invalidCapsLock, strlen(text_invalidCapsLock)),
fontheight + 2);
}
(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
Scr[screen].iconpos.x, y, text_valid, strlen(text_valid));
XFlush(dsp);
done = checkPasswd(buffer);
if (!done && !*buffer) {
/* just hit return, and it was not his password */
/* count_failed++; */ /* not really an attempt, is it? */
break;
} else if (!done) {
/* bad password... log it... */
count_failed++;
#if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
(void) printf("failed unlock attempt on user %s\n", user);
syslog(SYSLOG_NOTICE, "%s: failed unlock attempt on user %s\n",
ProgramName, user);
#endif
}
#endif
#ifndef VMS
if (done && pipepassCmd && pipepassCmd[0]) {
FILE *f;
if ((f = (FILE *) popen(pipepassCmd, "w"))) {
/* avoid stdio for this since we don't want to leave
the plaintext password in memory */
char *p = buffer;
int len = strlen(buffer);
while (len > 0) {
int wrote = write(fileno(f), p, len);
if (wrote <= 0) break;
len -= wrote;
p += wrote;
}
(void) pclose(f);
}
}
#endif
/* clear plaintext password so you can not grunge around
/dev/kmem */
(void) memset((char *) buffer, 0, sizeof (buffer));
if (done) {
#ifdef USE_SOUND
if (sound)
playSound(validsound, verbose);
#endif
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
Scr[screen].iconpos.x, y - font->ascent,
2 * XTextWidth(font, text_invalidCapsLock, strlen(text_invalidCapsLock)),
fontheight + 2);
(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
Scr[screen].iconpos.x, y, text_valid, strlen(text_valid));
XFlush(dsp);
if (!fullscreen)
XConfigureWindow(dsp, Scr[screen].window, sizeconfiguremask,
&minisizeconfigure);
return 0;
} else {
char *textInvalid = (capsLock) ? text_invalidCapsLock :
text_invalid;
XSync(dsp, True); /* flush input buffer */
(void) sleep(1);
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
Scr[screen].iconpos.x, y - font->ascent,
XTextWidth(font, text_valid, strlen(text_valid)),
fontheight + 2);
(void) XDrawString(dsp, Scr[screen].window, Scr[screen].textgc,
Scr[screen].iconpos.x, y, textInvalid, strlen(textInvalid));
if (echokeys) /* erase old echo */
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
passx, passy - font->ascent,
xgwa.width - passx,
fontheight);
XSync(dsp, True); /* flush input buffer */
(void) sleep(1);
XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
Scr[screen].iconpos.x, y - font->ascent,
XTextWidth(font, textInvalid, strlen(textInvalid)),
fontheight + 2);
if (count_failed > 0) {
char * cnt = NULL;
y += fontheight + 2;
if (y < Scr[screen].iconpos.y + iconheight + font->ascent + 12)
y = Scr[screen].iconpos.y + iconheight + font->ascent + 12;
x = left = Scr[screen].iconpos.x;
if ((cnt = (char *) malloc(strlen((count_failed == 1) ? failed_attempt : failed_attempts) + 16)) != NULL) {
(void) sprintf(cnt, "%d%s", count_failed, (count_failed == 1) ? failed_attempt : failed_attempts);
putText(dsp, Scr[screen].window, Scr[screen].textgc, cnt, False, left, &x, &y);
putText(dsp, Scr[screen].window, Scr[screen].textgc, "\n", False, left, &x, &y);
free(cnt);
}
}
#ifdef USE_SOUND
if (sound)
playSound(invalidsound, verbose);
got_invalid = 1;
#endif
}
}
ChangeGrabbedCursor(dsp, Scr[screen].window, mycursor);
XUnmapWindow(dsp, Scr[screen].icon);
#ifdef USE_BUTTON_LOGOUT
XUnmapWindow(dsp, Scr[screen].button);
#endif
if (!fullscreen)
XConfigureWindow(dsp, Scr[screen].window, sizeconfiguremask,
&minisizeconfigure);
#ifdef HAVE_SETPRIORITY
(void) setpriority(0, 0, nicelevel);
#else /* !HAVE_SETPRIORITY */
(void) nice(nicelevel);
#endif /* HAVE_SETPRIORITY */
#ifdef FX
if (mesa_3Dfx_fullscreen)
setenv("MESA_GLX_FX", "fullscreen", 0);
#endif
return 1;
}
#endif /* WIN32 */
static int
event_screen(Display * display, Window event_win)
{
int i;
for (i = startscreen; i < screens; i++) {
if (event_win == RootWindow(display, i)) {
return (i);
}
}
return (0);
}
static int
justDisplay(Display * display)
{
int timetodie = False;
int not_done = True;
XEvent event;
#ifdef USE_VTLOCK
/* EL - RCS : lock VT switching */
/*
* I think it has to be done here or 'switch/restore' modes won't
* ever be useful!
*/
if (!nolock && vtlock && !vtlocked)
dovtlock();
#endif
for (screen = startscreen; screen < screens; screen++) {
call_init_hook((LockStruct *) NULL,
mode_info(display, screen, Scr[screen].window, False));
}
while (not_done) {
while (!XPending(display)) {
#ifdef USE_OLD_EVENT_LOOP
(void) usleep(delay);
for (screen = startscreen; screen < screens; screen++)
call_callback_hook((LockStruct *) NULL,
mode_info(display, screen, Scr[screen].window, False));
#ifdef USE_AUTO_LOGOUT
checkLogout(display);
#endif
XSync(display, False);
#else /* !USE_OLD_EVENT_LOOP */
#ifdef USE_AUTO_LOGOUT
if (runMainLoop(30, -1) == 0)
break;
checkLogout(display);
#else
(void) runMainLoop(0, -1);
#endif
#endif /* !USE_OLD_EVENT_LOOP */
}
(void) XNextEvent(display, &event);
/*
* This event handling code should be unified with the
* similar code in ReadXString().
*/
switch (event.type) {
case Expose:
if (event.xexpose.count != 0) {
break;
}
/* fall through on last expose event of the series */
case VisibilityNotify:
if (!debug && !inwindow) {
XRaiseWindow(display, event.xany.window);
}
for (screen = startscreen; screen < screens; screen++) {
call_refresh_hook((LockStruct *) NULL,
mode_info(display, screen, Scr[screen].window, False));
}
break;
case ConfigureNotify:
if (!debug && !inwindow) {
XRaiseWindow(display, event.xconfigure.window);
}
for (screen = startscreen; screen < screens; screen++) {
if (install)
fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors, saturation,
mono, install, inroot, inwindow, verbose);
if (window_size_changed(screen, Scr[screen].window)) {
call_init_hook((LockStruct *) NULL,
mode_info(display, screen, Scr[screen].window, False));
} else if (install)
/* next line : refresh would be logical. But some modes
* look weird when continuing from an erased screen */
call_refresh_hook((LockStruct *) NULL,
mode_info(display, screen, Scr[screen].window, False));
}
break;
case ButtonPress:
if (event.xbutton.button == Button2) {
/* call change hook only for clicked window? */
for (screen = startscreen; screen < screens; screen++) {
call_change_hook((LockStruct *) NULL,
mode_info(display, screen, Scr[screen].window,
False));
}
} else {
screen = event_screen(display, event.xbutton.root);
not_done = False;
}
break;
case MotionNotify:
if (mousemotion) {
screen = event_screen(display, event.xmotion.root);
not_done = False;
}
break;
case KeyPress:
screen = event_screen(display, event.xkey.root);
not_done = False;
break;
}
if (!nolock)
{
if (lock_delay && (lock_delay <= (int) (seconds() - start_time))) {
timetodie = True;
/* not_done = False; */
}
else if (unlockdelay && (unlockdelay > (int) (seconds() - start_time)))
{
not_done = True;
}
}
}
/* KLUDGE SO TVTWM AND VROOT WILL NOT MAKE XLOCK DIE */
if (screen >= screens)
screen = startscreen;
lock_delay = False;
if (usefirst)
(void) XPutBackEvent(display, &event);
return timetodie;
}
#ifdef __cplusplus
extern "C" {
#endif
static void
sigcatch(int signum)
{
#ifndef WIN32
ModeInfo *mi = mode_info(dsp, startscreen, Scr[startscreen].window, False);
const char *name = (mi == NULL) ? "unknown" : MI_NAME(mi);
finish(dsp, True);
(void) sprintf(error_buf,
"Access control list restored.\n%s: caught signal %d while running %s mode (uid %ld).\n",
(strlen(ProgramName) < ERROR_BUF - 120) ?
ProgramName: "xlock", signum,
(strlen(ProgramName) + strlen(name) < ERROR_BUF - 120) ?
name: "?", (long) getuid());
error(error_buf);
#endif /* !WIN32 */
}
#ifdef __cplusplus
}
#endif
#ifndef WIN32
static void
lockDisplay(Display * display, Bool do_display)
{
#ifdef USE_VTLOCK
/* EL - RCS : lock VT switching */
if (!nolock && vtlock && !vtlocked)
dovtlock();
#endif
#if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
syslogStart();
#endif
#ifdef USE_SOUND
if (sound && !inwindow && !inroot && !lockdelay)
playSound(locksound, verbose);
#endif
if (!allowaccess) {
#if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 ) || defined( __CYGWIN__ )
sigset_t oldsigmask;
sigset_t newsigmask;
(void) sigemptyset(&newsigmask);
#ifndef DEBUG
(void) sigaddset(&newsigmask, SIGHUP);
#endif
(void) sigaddset(&newsigmask, SIGINT);
(void) sigaddset(&newsigmask, SIGQUIT);
(void) sigaddset(&newsigmask, SIGTERM);
(void) sigprocmask(SIG_BLOCK, (sigset_t *)&newsigmask, (sigset_t *)&oldsigmask);
#else
int oldsigmask;
#ifndef VMS
oldsigmask = sigblock(
#ifndef DEBUG
sigmask(SIGHUP) |
#endif
sigmask(SIGINT) |
sigmask(SIGQUIT) |
sigmask(SIGTERM));
#endif
#endif
/* (void (*)(int)) sigcatch */
#ifndef DEBUG
(void) signal(SIGHUP, sigcatch);
#endif
(void) signal(SIGINT, sigcatch);
(void) signal(SIGQUIT, sigcatch);
(void) signal(SIGTERM, sigcatch);
/* we should trap ALL signals, especially the deadly ones */
(void) signal(SIGSEGV, sigcatch);
(void) signal(SIGBUS, sigcatch);
(void) signal(SIGFPE, sigcatch);
if (grabserver)
XGrabServer(display);
XGrabHosts(display);
#if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 ) || defined( __CYGWIN__ )
(void) sigprocmask(SIG_SETMASK, &oldsigmask, &oldsigmask);
#else
(void) sigsetmask(oldsigmask);
#endif
}
#if defined( __hpux ) || defined( __apollo )
XHPDisableReset(display);
#endif
do {
if (do_display)
(void) justDisplay(display);
else
do_display = True;
} while (getPassword());
#if defined( __hpux ) || defined( __apollo )
XHPEnableReset(display);
#endif
}
#endif /* !WIN32 */
static void
read_plan(void)
{
FILE *planf = (FILE *) NULL;
char buf[121];
const char *home = getenv("HOME");
char *buffer;
int i, j, len = 0;
if (!home)
home = "";
if ((buffer = (char *) malloc(
#if ( __VMS_VER >= 70000000 )
255
#else
strlen(home) + 32
#endif
)) == NULL) {
error("low memory for plan");
}
#ifdef VMS
(void) sprintf(buffer, "%s%s", home, ".xlocktext");
#else
(void) sprintf(buffer, "%s/%s", home, ".xlocktext");
#endif
planf = my_fopen(buffer, "r");
if (planf == NULL) {
#ifdef VMS
(void) sprintf(buffer, "%s%s", home, ".plan");
#else
(void) sprintf(buffer, "%s/%s", home, ".plan");
#endif
planf = my_fopen(buffer, "r");
}
if (planf == NULL) {
#ifndef VMS
(void) sprintf(buffer, "%s/%s", home, ".signature");
#else
#if ( __VMS_VER >= 70000000 )
/* Get signature file for VMS 7.0 and higher */
char *buffer1;
unsigned int ival;
unsigned long int mail_context = 0;
unsigned short int buflen, buflen1;
struct itmlst_3 item[2], itm_d[1];
if ((buffer1 = (char *) malloc(256)) == NULL) {
error("low memory for signature");
}
itm_d[0].buflen = 0;
itm_d[0].itmcode = 0;
item[0].buflen = 255;
item[0].itmcode = MAIL$_USER_SIGFILE;
item[0].bufadr = buffer1;
item[0].retlen = &buflen1;
item[1].buflen = 255;
item[1].itmcode = MAIL$_USER_FULL_DIRECTORY;
item[1].bufadr = buffer;
item[1].retlen = &buflen;
item[2].buflen = 0;
item[2].itmcode = 0;
ival = mail$user_begin(&mail_context, itm_d, item);
(void) mail$user_end(&mail_context, itm_d, itm_d);
(void) strncat(buffer, buffer1, buflen1);
free(buffer1);
#else
(void) sprintf(buffer, "%s%s", home, ".signature");
#endif
#endif
planf = my_fopen(buffer, "r");
}
if ((plantext[0] = (char *) malloc(30)) == NULL) {
/* this is for the current time */
error("low memory for plan");
} else {
plantext[0][0] = '\0';
}
if (planf != NULL) {
for (i = 0; i < TEXTLINES; i++) {
if (fgets(buf, 120, planf) && (len = strlen(buf)) > 0) {
if (buf[len - 1] == '\n') {
buf[--len] = '\0';
}
/* this expands tabs to 8 spaces */
for (j = 0; j < len; j++) {
if (buf[j] == '\t') {
int k, tab = 8 - (j % 8);
for (k = 120 - tab; k > j; k--) {
buf[k + tab - 1] = buf[k];
}
for (k = j; k < j + tab; k++) {
buf[k] = ' ';
}
len += tab;
if (len > 120)
len = 120;
}
}
if ((plantext[i + 1] = (char *) malloc(strlen(buf) + 1)) == NULL) {
error("low memory for plan");
}
(void) strcpy(plantext[i + 1], buf);
}
}
plantext[i + 1] = (char *) NULL;
(void) fclose(planf);
} else {
plantext[1] = (char *) NULL;
}
free(buffer);
buffer = (char *) NULL;
}
#ifdef USE_MB
static XFontSet
createFontSet(Display * display, char *name)
{
XFontSet xfs;
char *def, **miss;
int miss_count;
#define DEF_FONTSET2 "fixed,-*-14-*"
if ((xfs = XCreateFontSet(display, name, &miss, &miss_count, &def)) == NULL) {
(void) fprintf(stderr, "Could not create FontSet %s\n", name);
if ((xfs = XCreateFontSet(display, DEF_FONTSET2, &miss, &miss_count, &def)) == NULL)
(void) fprintf(stderr, "Could not create FontSet %s\n", DEF_FONTSET2);
}
return xfs;
}
#endif
#ifndef WIN32
#ifdef __cplusplus
extern "C" {
#endif
static void SigUsr2(int sig);
static void
SigUsr1(int sig)
{
#ifdef DEBUG
(void) printf("Signal %d received\n", sig);
#endif
signalUSR1 = 1;
signalUSR2 = 0;
(void) signal(SIGUSR1, SigUsr1);
(void) signal(SIGUSR2, SigUsr2);
}
static void
SigUsr2(int sig)
{
#ifdef DEBUG
(void) printf("Signal %d received\n", sig);
#endif
signalUSR1 = 0;
signalUSR2 = 1;
(void) signal(SIGUSR1, SigUsr1);
(void) signal(SIGUSR2, SigUsr2);
}
#ifdef __cplusplus
}
#endif
int
main(int argc, char **argv)
{
XSetWindowAttributes xswa;
XGCValues xgcv;
XColor nullcolor;
char **planp;
int tmp;
uid_t ruid;
pid_t cmd_pid = 0;
#if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 )
static sigset_t old_sigmask;
#else
static int old_sigmask;
#endif
#ifdef USE_MB
setlocale(LC_ALL, "");
#endif
(void) signal(SIGUSR1, SigUsr1);
(void) signal(SIGUSR2, SigUsr2);
#if defined( __FreeBSD__ ) && !defined( DEBUG )
/* do not exit on FPE */
fpsetmask(0);
#endif
#ifdef OSF1_ENH_SEC
set_auth_parameters(argc, argv);
#endif
ruid = getuid();
rgid = getgid();
#ifdef HAVE_SETEUID
/* save effective uid and gid for later */
euid = geteuid();
egid = getegid();
/* revoke root privs temporarily, to get the correct .Xauthority */
(void) setegid(rgid);
(void) seteuid(ruid);
#else
#ifdef HAVE_SETREUID
/* save effective uid and gid for later */
euid = geteuid();
egid = getegid();
/* revoke root privs temporarily, to get the correct .Xauthority */
(void) setregid(egid, rgid);
(void) setreuid(euid, ruid);
#endif
#endif
ProgramName = strrchr(argv[0], '/');
if (ProgramName)
ProgramName++;
else
ProgramName = argv[0];
start_time = seconds();
#ifdef DEBUG
ProgramPID = getpid(); /* for memcheck.c */
#endif
#if 1
SRAND((long) start_time); /* random mode needs the seed set. */
#else
SRAND((long) ProgramPID);
#endif
getResources(&dsp, argc, argv);
#ifdef HAVE_SETEUID
/* become root to get the password */
(void) setegid(egid);
(void) seteuid(euid);
#else
#ifdef HAVE_SETREUID
/* become root to get the password */
(void) setregid(rgid, egid);
(void) setreuid(ruid, euid);
#endif
#endif
initPasswd();
/* revoke root privs, if there were any */
#ifdef ultrix
/*-
* Potential security problem on ultrix
* Here's the problem. Later on you need setgid to a root group to
* use the crypt program. I do not want to keep the password in memory.
* That means other parts will be running setgid as well.
*/
#if 1
/* Change 1 to 0 */
#error UNTESTED CODE, COMMENT OUT AND SEE IF IT WORKS, PLEASE GET BACK TO ME
#endif
#ifdef HAVE_SETEUID
/* Lets try to dampen it a bit */
(void) setegid(rgid);
#else
#ifdef HAVE_SETREUID
(void) setregid(egid, rgid);
#else
(void) setgid(rgid); /* Forget it */
#endif
#endif
#else
#ifdef BAD_PAM
/* BAD_PAM must have root access to authenticate against shadow passwords */
(void) seteuid(ruid);
/* for BAD_PAM to use shadow passwords, must call seteuid() later */
/* this prevent xlock from dropping privileges when using PAM modules, */
/* that needs root rights (pam_unix e.g.) */
#else
#ifdef USE_VTLOCK
/* In order to lock VT switch we must issue an ioctl on console */
/* (VT_LOCKSWITCH). This ioctl MUST be issued by root. */
/* We need later to be able to do another seteuid(0), so let's */
/* disable the overwrite of saved uid/gid */
if (!vtlock)
#endif
{
(void) setgid(rgid);
(void) setuid(ruid);
}
#endif
#endif
#if 0
/* synchronize -- so I am aware of errors immediately */
/* Too slow only for debugging */
(void) printf("DEBUGGING: XSynchronize version\n");
XSynchronize(dsp, True);
#endif
#ifdef USE_MB
fontset = createFontSet(dsp, fontsetname);
XmbTextExtents(fontset, "Aj", 1, NULL, &mbRect);
planfontset = createFontSet(dsp, planfontsetname);
XmbTextExtents(planfontset, "Aj", 1, NULL, &planmbRect);
#endif
checkResources();
font = XLoadQueryFont(dsp, fontname);
if (font == NULL) {
(void) fprintf(stderr, "%s: can not find font: %s, using %s...\n",
ProgramName, fontname, FALLBACK_FONTNAME);
font = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
if (font == NULL) {
(void) sprintf(error_buf,
"%s: can not even find %s!!!\n",
(strlen(ProgramName) < ERROR_BUF - 80) ?
ProgramName : "xlock",
(strlen(ProgramName) + strlen(FALLBACK_FONTNAME) < ERROR_BUF - 80) ?
FALLBACK_FONTNAME: "a font");
error(error_buf);
}
} {
int flags, x, y;
unsigned int w, h;
#ifdef FX
if (!glgeometry || !*glgeometry) {
glwidth = DEF_GLW;
glheight = DEF_GLH;
} else {
flags = XParseGeometry(glgeometry, &x, &y, &w, &h);
glwidth = flags & WidthValue ? w : DEF_GLW;
glheight = flags & HeightValue ? h : DEF_GLH;
if (glwidth < MINICONW)
glwidth = MINICONW;
if (glheight < MINICONH)
glheight = MINICONH;
}
#endif
if (!icongeometry || !*icongeometry) {
iconwidth = DEF_ICONW;
iconheight = DEF_ICONH;
} else {
flags = XParseGeometry(icongeometry, &x, &y, &w, &h);
iconwidth = flags & WidthValue ? w : DEF_ICONW;
iconheight = flags & HeightValue ? h : DEF_ICONH;
if (iconwidth < MINICONW)
iconwidth = MINICONW;
else if (iconwidth > MAXICONW)
iconwidth = MAXICONW;
if (iconheight < MINICONH)
iconheight = MINICONH;
else if (iconheight > MAXICONH)
iconheight = MAXICONH;
}
if (!geometry || !*geometry) {
fullscreen = True;
} else {
flags = XParseGeometry(geometry, &x, &y, &w, &h);
if (w < MINICONW)
w = MINICONW;
if (h < MINICONH)
h = MINICONH;
minisizeconfigure.x = flags & XValue ? x : 0;
minisizeconfigure.y = flags & YValue ? y : 0;
minisizeconfigure.width = flags & WidthValue ? w : iconwidth;
minisizeconfigure.height = flags & HeightValue ? h : iconheight;
}
}
planfont = XLoadQueryFont(dsp, planfontname);
if (planfont == NULL) {
(void) fprintf(stderr, "%s: can't find font: %s, using %s...\n",
ProgramName, planfontname, FALLBACK_FONTNAME);
planfont = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
if (planfont == NULL) {
(void) sprintf(error_buf,
"%s: can not even find %s!!!\n",
(strlen(ProgramName) < ERROR_BUF - 80) ?
ProgramName : "xlock",
(strlen(ProgramName) + strlen(FALLBACK_FONTNAME) < ERROR_BUF - 80) ?
FALLBACK_FONTNAME: "a font");
error(error_buf);
}
}
read_plan();
screens = ScreenCount(dsp);
if (((modeinfo = (ModeInfo *) calloc(screens,
sizeof (ModeInfo))) == NULL) ||
((Scr = (ScreenInfo *) calloc(screens,
sizeof (ScreenInfo))) == NULL)) {
error("low memory for info");
}
#ifdef FORCESINGLE
/* Safer to keep this after the calloc in case ScreenCount is used */
startscreen = DefaultScreen(dsp);
screens = startscreen + 1;
#endif
#if defined( USE_SOUND ) && defined( USE_ESOUND )
sound = (sound && (init_sound() != -1));
#endif
#ifdef USE_DTSAVER
/* The CDE Session Manager provides the windows for the screen saver
to draw into. */
if (dtsaver) {
Window *saver_wins;
int num_wins;
int this_win;
int this_screen;
XWindowAttributes xgwa;
/* Get the list of requested windows */
if (!DtSaverGetWindows(dsp, &saver_wins, &num_wins)) {
(void) sprintf(error_buf,
"%s: Unable to get screen saver info.\n",
(strlen(ProgramName) < ERROR_BUF - 80) ?
ProgramName : "xlock");
error(error_buf);
}
for (this_win = 0; this_win < num_wins; this_win++) {
(void) XGetWindowAttributes(dsp, saver_wins[this_win], &xgwa);
this_screen = XScreenNumberOfScreen(xgwa.screen);
if (Scr[this_screen].window != None) {
(void) sprintf(error_buf,
"%s: Two windows on screen %d\n",
(strlen(ProgramName) < ERROR_BUF - 80) ?
ProgramName : "xlock", this_screen);
error(error_buf);
}
Scr[this_screen].window = saver_wins[this_win];
}
/* Reduce to the screens that have windows. Avoid problems and */
/* assume that if one fails there is only one good window. */
for (this_screen = startscreen; this_screen < screens; this_screen++) {
if (Scr[this_screen].window == None) {
startscreen = DefaultScreen(dsp);
screens = startscreen + 1;
break;
}
}
} else
#endif
if (inwindow) {
/* Reduce to the last screen requested */
startscreen = DefaultScreen(dsp);
screens = startscreen + 1;
}
for (screen = startscreen; screen < screens; screen++) {
Screen *scr = ScreenOfDisplay(dsp, screen);
Colormap cmap = (Colormap) NULL;
/* Start of MI_ROOT_PIXMAP hack */
Window temp_rw;
XGCValues temp_gcv;
GC temp_gc;
XWindowAttributes temp_xgwa;
temp_rw = (parentSet) ? parent : RootWindowOfScreen(scr);
(void) XGetWindowAttributes(dsp, temp_rw, &temp_xgwa);
temp_gcv.function = GXcopy;
temp_gcv.subwindow_mode = IncludeInferiors;
temp_gc = XCreateGC(dsp, temp_rw, GCFunction|GCSubwindowMode,
&temp_gcv);
Scr[screen].root_pixmap = XCreatePixmap(dsp, temp_rw,
temp_xgwa.width,
temp_xgwa.height,
temp_xgwa.depth);
XCopyArea(dsp, temp_rw, Scr[screen].root_pixmap,
temp_gc, 0, 0, temp_xgwa.width, temp_xgwa.height,
0, 0);
XFreeGC(dsp, temp_gc);
/* End of MI_ROOT_PIXMAP hack */
#ifdef ORIGINAL_XPM_PATCH
if (mailIcon && mailIcon[0]) {
if ((mail_xpmimg = (XpmImage *) malloc(sizeof (XpmImage))))
if (XpmReadFileToXpmImage(mailIcon, mail_xpmimg,
(XpmInfo *) NULL) != XpmSuccess) {
free(mail_xpmimg);
mail_xpmimg = NULL;
}
}
if (nomailIcon && nomailIcon[0]) {
if ((nomail_xpmimg = (XpmImage *) malloc(sizeof (XpmImage))))
if (XpmReadFileToXpmImage(nomailIcon, nomail_xpmimg,
(XpmInfo *) NULL) != XpmSuccess) {
free(nomail_xpmimg);
nomail_xpmimg = NULL;
}
}
#endif
Scr[screen].root = (parentSet) ? parent : RootWindowOfScreen(scr);
defaultVisualInfo(dsp, screen);
/*-
* Some window managers like fvwm and tvtwm do not like it when an application
* thinks it can install a full screen colormap (i.e xlock). It promptly
* deinstalls the colormap and this might lead to white backgrounds if
* CopyFromParent is not used.
* But if CopyFromParent is used one can not change the visual
* and one may get White = Black on PseudoColor (see bug mode).
* There is another spot in xlock.c like this one...
* As far as I can tell, this problem exists only if your using MesaGL.
*/
#if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
Scr[screen].colormap = cmap = xswa.colormap =
XCreateColormap(dsp, Scr[screen].root, Scr[screen].visual, AllocNone);
#else
cmap = DefaultColormapOfScreen(scr);
Scr[screen].colormap = None;
#endif
xswa.override_redirect = True;
xswa.background_pixel = Scr[screen].black_pixel;
xswa.border_pixel = Scr[screen].white_pixel;
xswa.event_mask = KeyPressMask | ButtonPressMask |
VisibilityChangeMask | ExposureMask | StructureNotifyMask;
if (mousemotion)
xswa.event_mask |= MotionNotify;
#ifdef USE_VROOT
if (inroot) {
Scr[screen].window = Scr[screen].root;
XChangeWindowAttributes(dsp, Scr[screen].window, CWBackPixel, &xswa);
/* this gives us these events from the root window */
XSelectInput(dsp, Scr[screen].window,
VisibilityChangeMask | ExposureMask);
} else
#endif
#ifdef USE_DTSAVER
if (!dtsaver)
#endif
{
#define WIDTH (inwindow? WidthOfScreen(scr)/2 : (debug? WidthOfScreen(scr) - 100 : WidthOfScreen(scr)))
#define HEIGHT (inwindow? HeightOfScreen(scr)/2 : (debug? HeightOfScreen(scr) - 100 : HeightOfScreen(scr)))
#if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
#define CWMASK (((debug||inwindow||inroot)? 0 : CWOverrideRedirect) | CWBackPixel | CWBorderPixel | CWEventMask | CWColormap)
#else
#define CWMASK (((debug||inwindow||inroot)? 0 : CWOverrideRedirect) | CWBackPixel | CWBorderPixel | CWEventMask)
#endif
#if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
#define XLOCKWIN_DEPTH (Scr[screen].depth)
#define XLOCKWIN_VISUAL (Scr[screen].visual)
#else
#define XLOCKWIN_DEPTH CopyFromParent
#define XLOCKWIN_VISUAL CopyFromParent
#endif
if (fullscreen) {
Scr[screen].window = XCreateWindow(dsp, Scr[screen].root, 0, 0,
(unsigned int) WIDTH, (unsigned int) HEIGHT, 0,
XLOCKWIN_DEPTH, InputOutput, XLOCKWIN_VISUAL,
CWMASK, &xswa);
} else {
sizeconfiguremask = CWX | CWY | CWWidth | CWHeight;
Scr[screen].fullsizeconfigure.x = 0;
Scr[screen].fullsizeconfigure.y = 0;
Scr[screen].fullsizeconfigure.width = WIDTH;
Scr[screen].fullsizeconfigure.height = HEIGHT;
Scr[screen].window = XCreateWindow(dsp, Scr[screen].root,
(int) minisizeconfigure.x,
(int) minisizeconfigure.y,
(unsigned int) minisizeconfigure.width,
(unsigned int) minisizeconfigure.height,
0, XLOCKWIN_DEPTH, InputOutput, XLOCKWIN_VISUAL,
CWMASK, &xswa);
}
XmbSetWMProperties(dsp, Scr[screen].window,
"xlock","xlock", NULL, 0, NULL, NULL,
&xclasshint);
}
if (use3d) {
XColor C;
#ifdef CALCULATE_BOTH
XColor C2;
#endif
unsigned long planemasks[10];
unsigned long pixels[10];
if (!install || !XAllocColorCells(dsp, cmap, False, planemasks, 2, pixels,
1)) {
/* did not get the needed colours. Use normal 3d view without */
/* color overlapping */
Scr[screen].none_pixel = allocPixel(dsp, cmap, none3d, DEF_NONE3D);
Scr[screen].right_pixel = allocPixel(dsp, cmap, right3d, DEF_RIGHT3D);
Scr[screen].left_pixel = allocPixel(dsp, cmap, left3d, DEF_LEFT3D);
Scr[screen].both_pixel = allocPixel(dsp, cmap, both3d, DEF_BOTH3D);
} else {
/*
* attention: the mixture of colours will only be guaranteed, if
* the right black is used. The problems with BlackPixel would
* be that BlackPixel | left_pixel need not be equal to left_pixel.
* The same holds for rightcol (of course). That is why the right
* black (black3dcol) must be used when GXor is used as put
* function. I have allocated four colors above:
* pixels[0], - 3d black
* pixels[0] | planemasks[0], - 3d right eye color
* pixels[0] | planemasks[1], - 3d left eye color
* pixels[0] | planemasks[0] | planemasks[1] - 3d white
*/
if (!XParseColor(dsp, cmap, none3d, &C))
(void) XParseColor(dsp, cmap, DEF_NONE3D, &C);
Scr[screen].none_pixel = C.pixel = pixels[0];
XStoreColor(dsp, cmap, &C);
if (!XParseColor(dsp, cmap, right3d, &C))
(void) XParseColor(dsp, cmap, DEF_RIGHT3D, &C);
Scr[screen].right_pixel = C.pixel = pixels[0] | planemasks[0];
XStoreColor(dsp, cmap, &C);
#ifdef CALCULATE_BOTH
C2.red = C.red;
C2.green = C.green;
C2.blue = C.blue;
#else
if (!XParseColor(dsp, cmap, left3d, &C))
(void) XParseColor(dsp, cmap, DEF_LEFT3D, &C);
#endif
Scr[screen].left_pixel = C.pixel = pixels[0] | planemasks[1];
XStoreColor(dsp, cmap, &C);
#ifdef CALCULATE_BOTH
C.red |= C2.red; /* or them together... */
C.green |= C2.green;
C.blue |= C2.blue;
#else
if (!XParseColor(dsp, cmap, both3d, &C))
(void) XParseColor(dsp, cmap, DEF_BOTH3D, &C);
#endif
Scr[screen].both_pixel = C.pixel =
pixels[0] | planemasks[0] | planemasks[1];
XStoreColor(dsp, cmap, &C);
}
}
fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors, saturation,
mono, install, inroot, inwindow, verbose);
if (debug || inwindow) {
XWMHints xwmh;
xwmh.flags = InputHint;
xwmh.input = True;
XChangeProperty(dsp, Scr[screen].window,
XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace,
(unsigned char *) &xwmh, sizeof (xwmh) / sizeof (int));
}
if (debug) {
Scr[screen].iconpos.x = (DisplayWidth(dsp, screen) - 100 -
#ifdef HAVE_KRB5
MAX(512, MAX(XTextWidth(font, text_info, strlen(text_info)), XTextWidth(font, text_krbinfo, strlen(text_krbinfo))))) / 2;
#else /* HAVE_KRB5 */
MAX(512, XTextWidth(font, text_info, strlen(text_info)))) / 2;
#endif /* HAVE_KRB5 */
Scr[screen].iconpos.y = (DisplayHeight(dsp, screen) - 100) / 6;
} else {
Scr[screen].iconpos.x = (DisplayWidth(dsp, screen) -
#ifdef HAVE_KRB5
MAX(512, MAX(XTextWidth(font, text_info, strlen(text_info)), XTextWidth(font, text_krbinfo, strlen(text_krbinfo))))) / 2;
#else /* HAVE_KRB5 */
MAX(512, XTextWidth(font, text_info, strlen(text_info)))) / 2;
#endif /* HAVE_KRB5 */
Scr[screen].iconpos.y = DisplayHeight(dsp, screen) / 6;
}
Scr[screen].planpos.x = Scr[screen].planpos.y = 0;
for (planp = plantext; *planp; ++planp) {
tmp = XTextWidth(planfont, *planp, strlen(*planp));
if (tmp > Scr[screen].planpos.x)
Scr[screen].planpos.x = tmp;
++Scr[screen].planpos.y;
}
if (debug) {
Scr[screen].planpos.x = (DisplayWidth(dsp, screen) - 100 -
Scr[screen].planpos.x) / 2;
Scr[screen].planpos.y = DisplayHeight(dsp, screen) - 100 -
(Scr[screen].planpos.y + 4) * (planfontheight + 2);
} else {
Scr[screen].planpos.x = (DisplayWidth(dsp, screen) -
Scr[screen].planpos.x) / 2;
Scr[screen].planpos.y = DisplayHeight(dsp, screen) -
(Scr[screen].planpos.y + 4) * (planfontheight + 2);
}
xswa.border_pixel = Scr[screen].white_pixel;
xswa.background_pixel = Scr[screen].black_pixel;
xswa.event_mask = ButtonPressMask;
#if (defined( USE_GL ) && (!defined( MESA ) || defined( REALGLX ))) || !defined( COMPLIANT_COLORMAP )
#define CIMASK CWBorderPixel | CWBackPixel | CWEventMask | CWColormap
#else
#define CIMASK CWBorderPixel | CWBackPixel | CWEventMask
#endif
if (nolock)
Scr[screen].icon = None;
else {
Scr[screen].icon = XCreateWindow(dsp, Scr[screen].window,
Scr[screen].iconpos.x, Scr[screen].iconpos.y,
iconwidth, iconheight, 1, (int) CopyFromParent,
InputOutput, CopyFromParent,
CIMASK, &xswa);
#ifdef USE_BUTTON_LOGOUT
{
char *buf;
int w, h;
if ((buf = (char *) malloc(strlen(logoutButtonLabel) +
3)) == NULL) {
w = (strlen(logoutButtonLabel) + 5) * 8;
} else {
(void) sprintf(buf, " %s ", logoutButtonLabel);
w = XTextWidth(font, buf, strlen(buf));
free(buf);
}
h = fontheight + 2;
Scr[screen].button = XCreateWindow(dsp, Scr[screen].window,
0, 0, w, h, 1, (int) CopyFromParent,
InputOutput, CopyFromParent,
CIMASK, &xswa);
}
#endif
}
XMapWindow(dsp, Scr[screen].window);
XRaiseWindow(dsp, Scr[screen].window);
#if 0
if (install && cmap != DefaultColormapOfScreen(scr))
setColormap(dsp, Scr[screen].window, cmap, inwindow);
#endif
xgcv.font = font->fid;
xgcv.foreground = Scr[screen].white_pixel;
xgcv.background = Scr[screen].black_pixel;
Scr[screen].gc = XCreateGC(dsp, Scr[screen].window,
GCFont | GCForeground | GCBackground, &xgcv);
xgcv.foreground = Scr[screen].fg_pixel;
xgcv.background = Scr[screen].bg_pixel;
Scr[screen].textgc = XCreateGC(dsp, Scr[screen].window,
GCFont | GCForeground | GCBackground, &xgcv);
xgcv.font = planfont->fid;
Scr[screen].plantextgc = XCreateGC(dsp, Scr[screen].window,
GCFont | GCForeground | GCBackground, &xgcv);
#ifdef ORIGINAL_XPM_PATCH
if (mail_xpmimg) {
XpmAttributes xpm_attr;
xpm_attr.valuemask = 0;
XpmCreatePixmapFromXpmImage(dsp, Scr[screen].window,
mail_xpmimg, &Scr[screen].mb.mail.pixmap,
&Scr[screen].mb.mail.bitmap, &xpm_attr);
}
if (nomail_xpmimg) {
XpmAttributes xpm_attr;
xpm_attr.valuemask = 0;
XpmCreatePixmapFromXpmImage(dsp, Scr[screen].window, nomail_xpmimg,
&Scr[screen].mb.nomail.pixmap,
&Scr[screen].mb.nomail.bitmap, &xpm_attr);
}
if (mail_xpmimg || nomail_xpmimg) {
Scr[screen].mb.mbgc = XCreateGC(dsp, Scr[screen].window,
GCFont | GCForeground | GCBackground,
&xgcv);
}
#else
if (mailCmd && mailCmd[0]) {
pickPixmap(dsp, Scr[screen].window, nomailIcon,
NOMAIL_WIDTH, NOMAIL_HEIGHT, NOMAIL_BITS,
&(Scr[screen].mb.nomail.width),
&(Scr[screen].mb.nomail.height),
&(Scr[screen].mb.nomail.pixmap),
&(Scr[screen].mb.nomail.graphics_format));
pickPixmap(dsp, Scr[screen].window, mailIcon,
MAIL_WIDTH, MAIL_HEIGHT, MAIL_BITS,
&(Scr[screen].mb.mail.width),
&(Scr[screen].mb.mail.height),
&(Scr[screen].mb.mail.pixmap),
&(Scr[screen].mb.mail.graphics_format));
Scr[screen].mb.mbgc = XCreateGC(dsp, Scr[screen].window,
GCFont | GCForeground | GCBackground,
&xgcv);
}
#endif
}
lockc = XCreateBitmapFromData(dsp, Scr[startscreen].root, no_bits, 1, 1);
lockm = XCreateBitmapFromData(dsp, Scr[startscreen].root, no_bits, 1, 1);
mycursor = XCreatePixmapCursor(dsp, lockc, lockm,
&nullcolor, &nullcolor, 0, 0);
XFreePixmap(dsp, lockc);
XFreePixmap(dsp, lockm);
if (!grabmouse || inwindow || inroot) {
nolock = 1;
enablesaver = 1;
} else if (!debug) {
GrabKeyboardAndMouse(dsp, Scr[startscreen].window);
}
if (!nolock) {
XGetScreenSaver(dsp, &sstimeout, &ssinterval,
&ssblanking, &ssexposures);
if (resetsaver)
XResetScreenSaver(dsp); /* make sure not blank now */
if (!enablesaver)
XSetScreenSaver(dsp, 0, 0, 0, 0); /* disable screen saver */
}
#ifdef USE_DPMS
if ((dpmsstandby >= 0) || (dpmssuspend >= 0) || (dpmsoff >= 0))
SetDPMS(dsp, dpmsstandby, dpmssuspend, dpmsoff);
#endif
#ifdef HAVE_SETPRIORITY
(void) setpriority(0, 0, nicelevel);
#else /* !HAVE_SETPRIORITY */
(void) nice(nicelevel);
#endif /* HAVE_SETPRIORITY */
(void) XSetIOErrorHandler(xio_error);
/* start the command startcmd */
if (startCmd && *startCmd) {
if ((cmd_pid = FORK()) == -1) {
(void) fprintf(stderr, "Failed to launch \"%s\"\n", startCmd);
perror(ProgramName);
cmd_pid = 0;
} else if (!cmd_pid) {
#ifndef VMS
(void) setpgid(0, 0);
#endif
#if 0
#if (defined(sun) && defined(__svr4__)) || defined(sgi) || defined(__hpux) || defined(linux)
setsid();
#else
setpgrp(getpid(), getpid());
#endif
#endif
#if defined( SYSV ) || defined( SVR4 ) || ( __VMS_VER >= 70000000 ) || defined( __CYGWIN__ )
(void) sigprocmask(SIG_SETMASK, (sigset_t *)&old_sigmask, (sigset_t *)&old_sigmask);
#else
(void) sigsetmask(old_sigmask);
#endif
(void) system(startCmd);
exit(0);
}
}
lock_delay = lockdelay;
if (nolock) {
(void) justDisplay(dsp);
} else if (lock_delay) {
if (justDisplay(dsp)) {
lockDisplay(dsp, False);
} else
nolock = 1;
} else {
lockDisplay(dsp, True);
}
#if defined( HAVE_SYSLOG_H ) && defined( USE_SYSLOG )
if (!nolock) {
syslogStop(XDisplayString(dsp));
closelog();
}
#endif
#ifdef USE_DPMS
SetDPMS(dsp, -1, -1, -1);
#endif
finish(dsp, True);
if (cmd_pid)
#if defined(NO_KILLPG) || defined(__svr4__) || defined(sgi) || defined(__hpux) || defined(VMS)
kill(-cmd_pid, SIGTERM);
#else
(void) killpg(cmd_pid, SIGTERM);
#endif
if (endCmd && *endCmd) {
if ((cmd_pid = FORK()) == -1) {
(void) fprintf(stderr, "Failed to launch \"%s\"\n", endCmd);
perror(ProgramName);
cmd_pid = 0;
} else if (!cmd_pid) {
(void) system(endCmd);
exit(0);
}
}
#if defined( USE_SOUND ) && defined( USE_ESOUND )
shutdown_sound();
sound = 0;
#endif
#ifdef VMS
return 1;
#else
return 0;
#endif
}
#endif
#ifdef USE_PAM
/* PAM_putText - method to have pam_converse functionality with in XLOCK */
void PAM_putText( const struct pam_message *msg, struct pam_response *resp, Bool PAM_echokeys )
{
int x = 50, y = 50;
int oldX, oldY;
int left;
char buffer[PASSLENGTH];
x = left = Scr[screen].iconpos.x;
y = Scr[screen].iconpos.y + font->ascent + 200;
#ifdef DEBUG
(void) printf( "PAM_putText: message of style %d received: (%s)\n", msg->msg_style, msg->msg );
#endif
if( ( msg->msg_style == PAM_PROMPT_ECHO_ON ) ||
( msg->msg_style == PAM_PROMPT_ECHO_OFF ) )
{
XFlush(dsp);
XSync( dsp, True ); /* Flush Input Buffer */
putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, msg->msg, True, left, &x, &y);
putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, " ", True, left, &x, &y);
unamex = x;
unamey = y;
if( ReadXString(buffer, PASSLENGTH, (Bool *) NULL
#ifdef GLOBAL_UNLOCK
, True
#elif defined( USE_PAM )
, PAM_echokeys
#endif
));
XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
resp->resp = buffer;
resp->resp_retcode = PAM_SUCCESS;
#ifdef DEBUG
(void) printf( "Received Username: (%s)\n", resp->resp );
#endif
}
else
{
XFlush( dsp );
/* Clears three lines of text before displaying the next message */
oldX = x;
oldY = y;
XFillRectangle(dsp, Scr[startscreen].window, Scr[startscreen].gc,
Scr[screen].iconpos.x, y - font->ascent,
XTextWidth(font, msg->msg, strlen(msg->msg)),
(fontheight + 2) * 3);
XSync( dsp, True );
(void) sleep(1);
/* display the message */
putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, msg->msg, True, left, &x, &y);
putText(dsp, Scr[startscreen].window, Scr[startscreen].textgc, " ", True, left, &x, &y);
x = oldX;
y = oldY;
XSync( dsp, True );
(void) sleep(3);
XFlush( dsp );
/* Clears three lines of text before displaying the next message */
XFillRectangle(dsp, Scr[startscreen].window, Scr[startscreen].gc,
Scr[screen].iconpos.x, y - font->ascent,
XTextWidth(font, msg->msg, strlen(msg->msg)),
(fontheight + 2) * 3);
XSync( dsp, True );
}
}
#endif
#if defined( __hpux ) || defined( __apollo )
int
_main(int argc, char **argv)
{
main(argc, argv);
}
#endif
#ifdef HAVE_KRB5
/* like putText, but takes a font argument */
static void
putTextFont(Display * display, Window window, XFontStruct *pfont, GC gc,
const char *string, int bold, int left, int *px, int *py)
/* which window */
/* font */
/* gc */
/* text to write */
/* 1 = make it bold */
/* left edge of text */
/* current x and y, input & return */
{
#define PT_BUFSZ 2048
char buf[PT_BUFSZ], *p, *s;
int x = *px, y = *py, last, len;
(void) strncpy(buf, string, PT_BUFSZ);
buf[PT_BUFSZ - 1] = 0;
p = buf;
last = 0;
for (;;) {
s = p;
for (; *p; ++p)
if (*p == '\n')
break;
if (!*p)
last = 1;
*p = 0;
if ((len = strlen(s))) { /* yes, "=", not "==" */
(void) XDrawImageString(display, window, gc, x, y, s, len);
if (bold)
(void) XDrawString(display, window, gc, x + 1, y, s, len);
}
if (!last) {
y += pfont->ascent + pfont->descent + 2;
x = left;
} else {
if (len)
x += XTextWidth(pfont, s, len);
break;
}
p++;
}
*px = x;
*py = y;
}
/*
* Our Kerberos callback prompter. Note that the widgets aren't exactly
* pretty ... but see if I care. We're assuming there won't be any embedded
* newlines in the prompt strings (but we handle embedded newlines in
* the banner string).
*/
krb5_error_code
xlock_prompter(krb5_context context, void *data, const char *name,
const char *banner, int numprompts, krb5_prompt prompts[])
{
Window parent = Scr[screen].window;
Window win, button;
GC gc;
XGCValues xgcv;
int lines = 0, max = 0, width, i, height, bwidth, bheight, x, y,
leave = 0, cp = 0, count;
XWindowAttributes xgwa;
XSetWindowAttributes xswa;
XEvent event;
KeySym keysym;
char buffer[20];
char *ok = "OK", *c;
const char *b;
struct _promptinfo {
int x;
int y;
int curx;
int rp;
} *pi = NULL;
if (numprompts > 0)
if (!(pi = malloc(sizeof(*pi) * numprompts)))
return ENOMEM;
/*
* Let's see what our longest line is (handle embedded newlines,
* but only in the banner)
*/
if (banner && banner[0] != NULL) {
for (b = banner, c = index(banner, '\n'); c != NULL;
b = c, c = index(c + 1, '\n')) {
width = XTextWidth(planfont, b, c - b);
if (width > max)
max = width;
lines++;
}
width = XTextWidth(planfont, b, strlen(b));
if (width > max)
max = width;
lines++;
}
for (i = 0; i < numprompts; i++) {
/* 32 asterisks for entry should be enough */
width = XTextWidth(planfont, prompts[i].prompt,
strlen(prompts[i].prompt)) +
XTextWidth(planfont,
": ********************************", 34);
if (width > max)
max = width;
lines++;
}
/*
* we're saying a 10 pixel border around the text. We add in
* 40 to the height because of the OK button
*/
height = (lines + 1) * (planfontheight + 2) + 40;
width = max + 20;
(void) XGetWindowAttributes(dsp, Scr[screen].window, &xgwa);
if (width > xgwa.width) {
x = 0;
width = xgwa.width;
} else
x = (xgwa.width - width) / 2;
if (height > xgwa.height) {
y = 0;
height = xgwa.height;
} else
y = (xgwa.height - height) / 2;
xswa.override_redirect = True;
xswa.border_pixel = Scr[screen].white_pixel;
xswa.background_pixel = Scr[screen].white_pixel;
xswa.event_mask = KeyPressMask;
/*
* Create the main dialog window
*/
win = XCreateWindow(dsp, parent, x, y, width, height, 2,
CopyFromParent, CopyFromParent, Scr[screen].visual,
CWOverrideRedirect | CWBackPixel | CWBorderPixel |
CWEventMask, &xswa);
XMapWindow(dsp, win);
XRaiseWindow(dsp, win);
/*
* Create the OK button window
*/
bheight = planfontheight + 10;
bwidth = XTextWidth(planfont, ok, strlen(ok)) + 10;
xswa.border_pixel = Scr[screen].black_pixel;
xswa.event_mask = ButtonPressMask;
button = XCreateWindow(dsp, win, (width - bwidth) / 2,
height - bheight - 5, bwidth, bheight, 2,
CopyFromParent, CopyFromParent,
Scr[screen].visual, CWOverrideRedirect |
CWBackPixel | CWBorderPixel | CWEventMask,
&xswa);
XMapWindow(dsp, button);
XRaiseWindow(dsp, button);
x = 10;
y = 10 + planfont->ascent;
xgcv.font = planfont->fid;
xgcv.foreground = Scr[screen].black_pixel;
xgcv.background = Scr[screen].white_pixel;
gc = XCreateGC(dsp, Scr[screen].window,
GCFont | GCForeground | GCBackground, &xgcv);
if (banner && banner[0] != NULL)
putTextFont(dsp, win, planfont, gc, banner, 1, x, &x, &y);
for (i = 0; i < numprompts; i++) {
x = 10;
y += planfontheight + 2;
putTextFont(dsp, win, planfont, gc, prompts[i].prompt, 1,
x, &x, &y);
putTextFont(dsp, win, planfont, gc, ": ", 1, x, &x, &y);
pi[i].x = pi[i].curx = x;
pi[i].y = y;
pi[i].rp = 0;
memset(prompts[i].reply->data, 0, prompts[i].reply->length);
}
x = 5;
y = 5 + planfont->ascent;
putTextFont(dsp, button, planfont, gc, ok, 1, x, &x, &y);
while (leave == 0) {
XNextEvent(dsp, &event);
switch (event.type) {
case ButtonPress:
if (event.xbutton.window == button)
leave = 1;
break;
case KeyPress:
count = XLookupString((XKeyEvent *) &event, buffer,
sizeof(buffer), &keysym, NULL);
/*
* Try to handle specific keysyms
*/
if (keysym == XK_Return || keysym == XK_KP_Enter ||
keysym == XK_Linefeed) {
if (++cp >= numprompts)
leave = 1;
break;
}
/*
* Ignore modifier keys
*/
if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
break;
/*
* If we don't do any prompts, then we only accept
* Return/Enter/Linefeed
*/
if (numprompts == 0) {
XBell(dsp, 100);
break;
}
/*
* Handle Tab/Shift-Tab
*/
if (keysym == XK_Tab) {
if (!(event.xkey.state & ShiftMask)) {
if (++cp >= numprompts)
cp = 0;
} else {
if (--cp < 0)
cp = numprompts - 1;
}
break;
}
/*
* Handle BS/Delete
*/
if (keysym == XK_BackSpace || keysym == XK_Delete) {
if (pi[cp].rp == 0) {
XBell(dsp, 100);
break;
}
prompts[cp].reply->data[--pi[cp].rp] = '\0';
if (pi[cp].rp < 32) {
pi[cp].curx -= XTextWidth(planfont,
"*", 1);
XClearArea(dsp, win, pi[cp].curx,
pi[cp].y - planfont->ascent,
0, planfont->ascent +
planfont->descent, False);
}
break;
}
/*
* Handle keypresses
*/
for (i = 0; i < count; i++) {
switch (buffer[i]) {
case '\003':
case '\025':
XClearArea(dsp, win, pi[cp].x,
pi[cp].y - planfont->ascent,
0, planfont->ascent +
planfont->descent, False);
memset(prompts[cp].reply->data, 0,
prompts[cp].reply->length);
pi[cp].curx = pi[cp].x;
pi[cp].rp = 0;
break;
default:
if (pi[cp].rp + 1 >=
prompts[cp].reply->length) {
XBell(dsp, 100);
break;
}
prompts[cp].reply->data[pi[cp].rp++] =
buffer[i];
if (pi[cp].rp <= 32) {
putTextFont(dsp, win, planfont,
gc, "*", 1,
pi[cp].curx,
&pi[cp].curx,
&pi[cp].y);
}
break;
}
}
break;
default:
/* Nothing */
break;
}
}
if (pi)
free(pi);
XDestroyWindow(dsp, win);
XFreeGC(dsp, gc);
for (i = 0; i < numprompts; i++)
prompts[i].reply->length = strlen(prompts[i].reply->data);
return 0;
}
#endif /* HAVE_KRB5 */
#ifdef WIN32
#define MAX_TIMES 100
int showtext = 0;
void
hsbramp(double h1, double s1, double b1, double h2, double s2, double b2,
int count, unsigned char *red, unsigned char *green, unsigned char *blue);
static void CalculateColors(int noofcolors, double saturation)
{
/* free any previously allocated colormap */
if (red != NULL)
free(red);
if (green != NULL)
free(green);
if (blue != NULL)
free(blue);
/* create a new colormap */
if ((red = calloc(noofcolors+2, sizeof(unsigned char))) == NULL)
return;
if ((green = calloc(noofcolors+2, sizeof(unsigned char))) == NULL)
return;
if ((blue = calloc(noofcolors+2, sizeof(unsigned char))) == NULL)
return;
/* set the number of colors in the colormap */
colorcount = noofcolors;
/* populate the colormap */
hsbramp(0.0, saturation, 1.0, 1.0, saturation, 1.0, noofcolors,
red, green, blue);
/* store white and black colormap entries */
red[noofcolors] = green[noofcolors] = blue[noofcolors] = 255;
red[noofcolors+1] = green[noofcolors+1] = blue[noofcolors+1] = 0;
}
void xlockmore_set_mode_options(ModeSpecOpt *ms);
/*-
* xlockmore_create
* called when WIN32 event handling issues a create window
*/
unsigned int xlockmore_create(void)
{
int i;
ModeInfo *mi; /* get mode info */
ModeSpecOpt *ms;
/* seeds random number generation */
SRAND((unsigned)time(NULL));
/*#define _DEBUG*/
#ifdef RANDOMMODE
randommode = numprocs-1; /* random */
#else
#ifdef _DEBUG
/* these numbers may not be reliable if any modes were added */
randommode = 49; /* maze */
randommode = 56; /* poly */
randommode = 40; /* life1d */
randommode = 80; /* voters */
randommode = 85; /* xjack */
randommode = 2; /* apollonian */
#else
randommode = NRAND(numprocs);
#endif
#endif
/* set variables */
delay = LockProcs[randommode].def_delay;
count = LockProcs[randommode].def_count;
cycles = LockProcs[randommode].def_cycles;
size = LockProcs[randommode].def_size;
saturation = LockProcs[randommode].def_saturation;
bitmap = LockProcs[randommode].def_bitmap;
/* calculate new color map */
CalculateColors(NUMCOLORS, saturation);
/* allocate mem to the ModeInfo & ScreenInfo structures */
screens = ScreenCount(dsp);
if (((modeinfo = (ModeInfo *) calloc(screens,
sizeof (ModeInfo))) == NULL) ||
((Scr = (ScreenInfo *) calloc(screens,
sizeof (ScreenInfo))) == NULL)) {
error("low memory for info");
}
/* set some WIN32 specific stuff */
mi = mode_info(dsp, 0, (int)hwnd, 0);
MI_COLORMAP_SIZE(mi) = ncolors = mi->screeninfo->npixels = colorcount;
MI_GC(mi) = GCCreate();
MI_NUM_SCREENS(mi) = screens;
for (screen = startscreen; screen < screens; screen++) {
fixColormap(mode_info(dsp, screen, Scr[screen].window, False), ncolors, saturation,
mono, install, inroot, inwindow, verbose);
}
for (i=0; i<NUMCOLORS; i++)
mi->screeninfo->pixels[i] = i;
/* set default options for mode */
ms = LockProcs[randommode].msopt;
xlockmore_set_mode_options(ms);
showtext = 0;
return delay;
}
/*-
* xlockmore_init
* called to initialise a mode
*/
void xlockmore_init(void)
{
call_init_hook(&LockProcs[randommode], mode_info(dsp, 0, (int)hwnd, 0));
}
/*-
* xlockmore_destroy
* called when WIN32 event handling issues a destroy window
*/
void xlockmore_destroy(void)
{
call_release_hook(&LockProcs[randommode], mode_info(dsp, 0, (int)hwnd, 0));
}
#ifdef _DEBUG
static char debug_text[255] = { 0 };
#endif
/*-
* xlockmore_timer
* called when WIN32 event handling issues a timer request
*/
unsigned int xlockmore_timer(void)
{
call_callback_hook(&LockProcs[randommode], mode_info(dsp, 0, (int)hwnd, 0));
#ifndef RANDOMMODE
if (showtext < MAX_TIMES)
{
xlockmore_win32_text(10, 10, LockProcs[randommode].cmdline_arg);
xlockmore_win32_text(10, 30, LockProcs[randommode].desc);
showtext++;
}
#endif
#ifdef _DEBUG
xlockmore_win32_text(10, 60, debug_text);
#endif
return (LockProcs[randommode].def_delay / 1000);
}
/*-
* xlockmore_set_mode_options
* called from create. Sets any default options
*/
void xlockmore_set_mode_options(ModeSpecOpt *ms)
{
int i;
char **varChar;
float *varFloat;
int *varInt;
for (i=0; i < ms->numvarsdesc; i++)
{
switch (ms->vars[i].type)
{
case t_Bool:
varInt = (int *)ms->vars[i].var;
if (strcmp(ms->vars[i].def, "True") == 0)
*varInt = TRUE;
else
*varInt = FALSE;
break;
case t_Float:
varFloat = (float *)ms->vars[i].var;
*varFloat = atof(ms->vars[i].def);
break;
case t_Int:
varInt = (int *)ms->vars[i].var;
*varInt = atoi(ms->vars[i].def);
break;
case t_String:
varChar = (char **)ms->vars[i].var;
*varChar = ms->vars[i].def;
break;
}
}
}
void xlockmore_win32_text(int xloc, int yloc, char *text)
{
RECT rect;
UINT nFlags = SetTextAlign(hdc, TA_RIGHT);
(void) GetClientRect(hwnd, &rect);
TextOut(hdc, rect.right - xloc, yloc, text, strlen(text));
SetTextAlign(hdc, nFlags);
}
// FILE *fp = NULL;
void xlockmore_set_debug(char *text)
{
#ifdef _DEBUG
static FILE *fp = NULL;
strcpy(debug_text, text);
#if 1
if (fp == NULL)
{
fp = fopen("xlock_debug.log", "a");
fprintf(fp, "\n");
}
fprintf(fp, "%s\n", text);
#endif
#endif
}
#endif /* WIN32 */
#endif /* STANDALONE */