~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/programs/xkbevd/xkbevd.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Xorg: xkbevd.c,v 1.4 2000/08/17 19:54:49 cpqbld Exp $ */
 
2
/************************************************************
 
3
 Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
 
4
 
 
5
 Permission to use, copy, modify, and distribute this
 
6
 software and its documentation for any purpose and without
 
7
 fee is hereby granted, provided that the above copyright
 
8
 notice appear in all copies and that both that copyright
 
9
 notice and this permission notice appear in supporting
 
10
 documentation, and that the name of Silicon Graphics not be 
 
11
 used in advertising or publicity pertaining to distribution 
 
12
 of the software without specific prior written permission.
 
13
 Silicon Graphics makes no representation about the suitability 
 
14
 of this software for any purpose. It is provided "as is"
 
15
 without any express or implied warranty.
 
16
 
 
17
 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 
 
18
 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 
 
19
 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
 
20
 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
 
21
 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 
 
22
 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
 
23
 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
 
24
 THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
25
 
 
26
 ********************************************************/
 
27
/* $XFree86: xc/programs/xkbevd/xkbevd.c,v 3.9 2001/07/25 15:05:25 dawes Exp $ */
 
28
 
 
29
#define DEBUG_VAR xkbevdDebug
 
30
#include <X11/Xosdefs.h>
 
31
#include <stdlib.h>
 
32
#include "xkbevd.h"
 
33
 
 
34
 
 
35
#define lowbit(x)       ((x) & (-(x)))
 
36
 
 
37
/***====================================================================***/
 
38
 
 
39
#ifndef DFLT_XKBEVD_CONFIG
 
40
#define DFLT_XKBEVD_CONFIG "%s/.xkb/xkbevd.cf"
 
41
#endif /* DFLT_XKBEVD_CONFIG */
 
42
 
 
43
#ifndef DFLT_XKB_CONFIG_ROOT
 
44
#define DFLT_XKB_CONFIG_ROOT "/usr/X11R6/lib/xkb"
 
45
#endif
 
46
 
 
47
#ifndef DFLT_SYS_XKBEVD_CONFIG
 
48
#define DFLT_SYS_XKBEVD_CONFIG "%s/xkbevd.cf"
 
49
#endif /* DFLT_SYS_XKBEVD_CONFIG */
 
50
 
 
51
#ifndef DFLT_SOUND_CMD
 
52
#define DFLT_SOUND_CMD "/usr/sbin/sfplay -q"
 
53
#endif /* DFLT_SOUND_CMD */
 
54
 
 
55
#ifndef DFLT_SOUND_DIR
 
56
#define DFLT_SOUND_DIR "/usr/share/data/sounds/prosonus/"
 
57
#endif /* DFLT_SOUND_DIR */
 
58
 
 
59
/***====================================================================***/
 
60
 
 
61
char *          dpyName=        NULL;
 
62
Display *       dpy=            NULL;
 
63
char *          cfgFileName=    NULL;
 
64
int             xkbOpcode=      0;
 
65
int             xkbEventCode=   0;
 
66
Bool            detectableRepeat= False;
 
67
 
 
68
CfgEntryPtr     config=         NULL;
 
69
unsigned long   eventMask=      0;
 
70
 
 
71
Bool            synch=          False;
 
72
int             verbose=        0;
 
73
Bool            background=     False;
 
74
 
 
75
char *          soundCmd=       NULL;
 
76
char *          soundDir=       NULL;
 
77
 
 
78
XkbDescPtr      xkb=            NULL;
 
79
 
 
80
/***====================================================================***/
 
81
 
 
82
#define M(m)    fprintf(stderr,(m))
 
83
#define M1(m,a) fprintf(stderr,(m),(a))
 
84
 
 
85
static void
 
86
Usage(int argc, char *argv[])
 
87
{
 
88
    M1("Usage: %s [options]...\n",argv[0]);
 
89
    M("Legal options:\n");
 
90
    M("-?,-help             Print this message\n");
 
91
    M("-cfg <file>          Specify a config file\n");
 
92
    M("-sc <cmd>            Specify the command to play sounds\n");
 
93
    M("-sd <dir>            Specify the root directory for sound files\n");
 
94
    M("-d[isplay] <dpy>     Specify the display to watch\n");
 
95
    M("-bg                  Run in background\n");
 
96
    M("-synch               Force synchronization\n");
 
97
    M("-v                   Print verbose messages\n");
 
98
    return;
 
99
}
 
100
 
 
101
/***====================================================================***/
 
102
 
 
103
static Bool
 
104
parseArgs(int argc, char *argv[])
 
105
{
 
106
register int i;
 
107
 
 
108
    for (i=1;i<argc;i++) {
 
109
        if (strcmp(argv[i],"-bg")==0) {
 
110
            background= True;
 
111
        }
 
112
        else if (strcmp(argv[i],"-cfg")==0) {
 
113
            if (i>=(argc-1)) {
 
114
                uError("No configuration file specified on command line\n");
 
115
                uAction("Trailing %s argument ignored\n",argv[i]);
 
116
            }
 
117
            else {
 
118
                char *name= argv[++i];
 
119
                if (cfgFileName!=NULL) {
 
120
                    if (uStringEqual(cfgFileName,name)) 
 
121
                        uWarning("Config file \"%s\" specified twice!\n");
 
122
                    else {
 
123
                        uWarning("Multiple config files on command line\n");
 
124
                        uAction("Using \"%s\", ignoring \"%s\"\n",name,
 
125
                                                                cfgFileName);
 
126
                    }
 
127
                }
 
128
                cfgFileName= name;
 
129
            }
 
130
        }
 
131
        else if ((strcmp(argv[i],"-d")==0)||(strcmp(argv[i],"-display")==0)) {
 
132
            if (i>=(argc-1)) {
 
133
                uError("No display specified on command line\n");
 
134
                uAction("Trailing %s argument ignored\n",argv[i]);
 
135
            }
 
136
            else {
 
137
                char *name= argv[++i];
 
138
                if (dpyName!=NULL) {
 
139
                    if (uStringEqual(dpyName,name)) 
 
140
                        uWarning("Display \"%s\" specified twice!\n");
 
141
                    else {
 
142
                        uWarning("Multiple displays on command line\n");
 
143
                        uAction("Using \"%s\", ignoring \"%s\"\n",name,
 
144
                                                                dpyName);
 
145
                    }
 
146
                }
 
147
                dpyName= name;
 
148
            }
 
149
        }
 
150
        else if (strcmp(argv[i],"-sc")==0) {
 
151
            if (i>=(argc-1)) {
 
152
                uError("No sound command specified on command line\n");
 
153
                uAction("Trailing %s argument ignored\n",argv[i]);
 
154
            }
 
155
            else {
 
156
                char *name= argv[++i];
 
157
                if (soundCmd!=NULL) {
 
158
                    if (uStringEqual(soundCmd,name)) 
 
159
                        uWarning("Sound command \"%s\" specified twice!\n");
 
160
                    else {
 
161
                        uWarning("Multiple sound commands on command line\n");
 
162
                        uAction("Using \"%s\", ignoring \"%s\"\n",name,
 
163
                                                                soundCmd);
 
164
                    }
 
165
                }
 
166
                soundCmd= name;
 
167
            }
 
168
        }
 
169
        else if (strcmp(argv[i],"-sd")==0) {
 
170
            if (i>=(argc-1)) {
 
171
                uError("No sound directory specified on command line\n");
 
172
                uAction("Trailing %s argument ignored\n",argv[i]);
 
173
            }
 
174
            else {
 
175
                char *name= argv[++i];
 
176
                if (soundDir!=NULL) {
 
177
                    if (uStringEqual(soundDir,name)) 
 
178
                        uWarning("Sound directory \"%s\" specified twice!\n");
 
179
                    else {
 
180
                        uWarning("Multiple sound dirs on command line\n");
 
181
                        uAction("Using \"%s\", ignoring \"%s\"\n",name,
 
182
                                                                soundDir);
 
183
                    }
 
184
                }
 
185
                soundDir= name;
 
186
            }
 
187
        }
 
188
        else if ((strcmp(argv[i],"-synch")==0)||(strcmp(argv[i],"-s")==0)) {
 
189
            synch= True;
 
190
        }
 
191
        else if (strcmp(argv[i],"-v")==0) {
 
192
            verbose++;
 
193
        }
 
194
        else if ((strcmp(argv[i],"-?")==0)||(strcmp(argv[i],"-help")==0)) {
 
195
            Usage(argc,argv);
 
196
            exit(0);
 
197
        }
 
198
        else {
 
199
            uError("Unknown flag \"%s\" on command line\n",argv[i]);
 
200
            Usage(argc,argv);
 
201
            return False;
 
202
        }
 
203
    }
 
204
    return True;
 
205
}
 
206
 
 
207
static Display *
 
208
GetDisplay(char *program, char *dpyName, int *opcodeRtrn, int *evBaseRtrn)
 
209
{
 
210
int     mjr,mnr,error;
 
211
Display *dpy;
 
212
 
 
213
    mjr= XkbMajorVersion;
 
214
    mnr= XkbMinorVersion;
 
215
    dpy= XkbOpenDisplay(dpyName,evBaseRtrn,NULL,&mjr,&mnr,&error);
 
216
    if (dpy==NULL) {
 
217
        switch (error) {
 
218
            case XkbOD_BadLibraryVersion:
 
219
                uInformation("%s was compiled with XKB version %d.%02d\n",
 
220
                                program,XkbMajorVersion,XkbMinorVersion);
 
221
                uError("X library supports incompatible version %d.%02d\n",
 
222
                                mjr,mnr);
 
223
                break;
 
224
            case XkbOD_ConnectionRefused:
 
225
                uError("Cannot open display \"%s\"\n",dpyName);
 
226
                break;
 
227
            case XkbOD_NonXkbServer:
 
228
                uError("XKB extension not present on %s\n",dpyName);
 
229
                break;
 
230
            case XkbOD_BadServerVersion:
 
231
                uInformation("%s was compiled with XKB version %d.%02d\n",
 
232
                                program,XkbMajorVersion,XkbMinorVersion);
 
233
                uError("Server %s uses incompatible version %d.%02d\n",
 
234
                                dpyName,mjr,mnr);
 
235
                break;
 
236
            default:
 
237
                uInternalError("Unknown error %d from XkbOpenDisplay\n",error);
 
238
        }
 
239
    }
 
240
    else if (synch)
 
241
        XSynchronize(dpy,True);
 
242
    if (opcodeRtrn)
 
243
        XkbQueryExtension(dpy,opcodeRtrn,evBaseRtrn,NULL,&mjr,&mnr);
 
244
    return dpy;
 
245
}
 
246
 
 
247
/***====================================================================***/
 
248
 
 
249
void
 
250
InterpretConfigs(CfgEntryPtr cfg)
 
251
{
 
252
char *          name;
 
253
unsigned        priv= 0;
 
254
 
 
255
    config= cfg;
 
256
    while (cfg!=NULL) {
 
257
        name= cfg->name.str;
 
258
        if (cfg->entry_type==VariableDef) {
 
259
            if (uStrCaseEqual(name,"sounddirectory")||
 
260
                                        uStrCaseEqual(name,"sounddir")) {
 
261
                if (soundDir==NULL) {
 
262
                    soundDir= cfg->action.text;
 
263
                    cfg->name.str= NULL;
 
264
                    cfg->action.text= NULL;
 
265
                }
 
266
            }
 
267
            else if (uStrCaseEqual(name,"soundcommand")||
 
268
                                uStrCaseEqual(name,"soundcmd")) {
 
269
                if (soundCmd==NULL) {
 
270
                    soundCmd= cfg->action.text;
 
271
                    cfg->name.str= NULL;
 
272
                    cfg->action.text= NULL;
 
273
                }
 
274
            }
 
275
            else {
 
276
                uWarning("Assignment to unknown variable \"%s\"\n",cfg->name);
 
277
                uAction("Ignored\n");
 
278
            }
 
279
        }
 
280
        else if (cfg->entry_type==EventDef) switch (cfg->event_type) {
 
281
            case XkbBellNotify:
 
282
                if (name!=NULL) cfg->name.atom= XInternAtom(dpy,name,False);
 
283
                else            cfg->name.atom= None;
 
284
                if (name) uFree(name);
 
285
                break;
 
286
            case XkbAccessXNotify:
 
287
                priv= 0;
 
288
                if (name==NULL)         
 
289
                     priv= XkbAllNewKeyboardEventsMask;
 
290
                else if (uStrCaseEqual(name,"skpress")) 
 
291
                     priv= XkbAXN_SKPressMask;
 
292
                else if (uStrCaseEqual(name,"skaccept"))
 
293
                     priv= XkbAXN_SKAcceptMask;
 
294
                else if (uStrCaseEqual(name,"skreject"))
 
295
                     priv= XkbAXN_SKRejectMask;
 
296
                else if (uStrCaseEqual(name,"skrelease"))
 
297
                     priv= XkbAXN_SKReleaseMask;
 
298
                else if (uStrCaseEqual(name,"bkaccept"))
 
299
                     priv= XkbAXN_BKAcceptMask;
 
300
                else if (uStrCaseEqual(name,"bkreject"))
 
301
                     priv= XkbAXN_BKRejectMask;
 
302
                else if (uStrCaseEqual(name,"warning"))
 
303
                     priv= XkbAXN_AXKWarningMask;
 
304
                if (name)       uFree(name);
 
305
                cfg->name.priv= priv;
 
306
                break;
 
307
            case XkbActionMessage:
 
308
                /* nothing to do */
 
309
                break;
 
310
        }
 
311
        eventMask|= (1L<<cfg->event_type);
 
312
        cfg= cfg->next;
 
313
    }
 
314
    while ((config)&&(config->entry_type!=EventDef)) {
 
315
        CfgEntryPtr next;
 
316
        if (config->name.str)           uFree(config->name.str);
 
317
        if (config->action.text)        uFree(config->action.text);
 
318
        config->name.str=       NULL;
 
319
        config->action.text=    NULL;
 
320
        next=                   config->next;
 
321
        uFree(config);
 
322
        config= next;
 
323
    }
 
324
    cfg= config;
 
325
    while ((cfg!=NULL)&&(cfg->next!=NULL)) {
 
326
        CfgEntryPtr next;
 
327
        next= cfg->next;
 
328
        if (next->entry_type!=EventDef) {
 
329
            if (next->name.str)         uFree(config->name.str);
 
330
            if (next->action.text)      uFree(config->action.text);
 
331
            next->name.str=             NULL;
 
332
            next->action.text=          NULL;
 
333
            cfg->next=                  next->next;
 
334
            next->next=                 NULL;
 
335
            uFree(next);
 
336
        }
 
337
        else cfg= next;
 
338
    }
 
339
    return;
 
340
}
 
341
 
 
342
static CfgEntryPtr
 
343
FindMatchingConfig(XkbEvent *ev)
 
344
{
 
345
CfgEntryPtr     cfg,dflt;
 
346
 
 
347
    dflt= NULL;
 
348
    for (cfg= config;(cfg!=NULL);cfg=cfg->next) {
 
349
        if ((ev->type!=xkbEventCode)||(cfg->event_type!=ev->any.xkb_type))
 
350
            continue;
 
351
        switch (ev->any.xkb_type) {
 
352
           case XkbBellNotify:
 
353
                if (ev->bell.name==cfg->name.atom)
 
354
                    return cfg;
 
355
                else if ((cfg->name.atom==None)&&(dflt==NULL))
 
356
                    dflt= cfg;
 
357
                break;
 
358
            case XkbAccessXNotify:
 
359
                if (cfg->name.priv&(1L<<ev->accessx.detail))
 
360
                    return cfg;
 
361
                break;
 
362
            case XkbActionMessage:
 
363
                if (cfg->name.str==NULL)
 
364
                    dflt= cfg;
 
365
                else if (strncmp(cfg->name.str,ev->message.message,
 
366
                                                XkbActionMessageLength)==0)
 
367
                    return cfg;
 
368
                break;
 
369
           default:
 
370
                uInternalError("Can't handle type %d XKB events yet, Sorry.\n");
 
371
                break;
 
372
        }
 
373
    }
 
374
    return dflt;
 
375
}
 
376
 
 
377
static Bool
 
378
ProcessMatchingConfig(XkbEvent *ev)
 
379
{
 
380
CfgEntryPtr     cfg;
 
381
char            buf[1024],*cmd;
 
382
int             ok;
 
383
 
 
384
    cfg= FindMatchingConfig(ev);
 
385
    if (!cfg)
 
386
        return False;
 
387
    if (cfg->action.type==UnknownAction) {
 
388
        if (cfg->action.text==NULL)
 
389
            cfg->action.type= NoAction;
 
390
        else if (cfg->action.text[0]=='!') {
 
391
            char *tmp;
 
392
            cfg->action.type= ShellAction;
 
393
            tmp= uStringDup(&cfg->action.text[1]);
 
394
            uFree(cfg->action.text);
 
395
            cfg->action.text= tmp;
 
396
        }
 
397
        else cfg->action.type= SoundAction;
 
398
    }
 
399
    switch (cfg->action.type) {
 
400
        case NoAction:
 
401
            return True;
 
402
        case EchoAction:
 
403
            if (cfg->action.text!=NULL) {
 
404
                sprintf(buf,cfg->action.text);
 
405
                cmd= SubstituteEventArgs(buf,ev);
 
406
                printf("%s",cmd);
 
407
            }
 
408
            return True;
 
409
        case PrintEvAction:
 
410
            PrintXkbEvent(stdout,ev);
 
411
            return True;
 
412
        case ShellAction:
 
413
            if (cfg->action.text==NULL) {
 
414
                uWarning("Empty shell command!\n");
 
415
                uAction("Ignored\n");
 
416
                return True;
 
417
            }
 
418
            cmd= cfg->action.text;
 
419
            break;
 
420
        case SoundAction:
 
421
            if (cfg->action.text==NULL) {
 
422
                uWarning("Empty sound command!\n");
 
423
                uAction("Ignored\n");
 
424
                return True;
 
425
            }
 
426
            sprintf(buf,"%s %s%s",soundCmd,soundDir,cfg->action.text);
 
427
            cmd= buf;
 
428
            break;
 
429
        default:
 
430
            uInternalError("Unknown error action type %d\n",cfg->action.type);
 
431
            return False;
 
432
    }
 
433
    cmd= SubstituteEventArgs(cmd,ev);
 
434
    if (verbose)
 
435
        uInformation("Executing shell command \"%s\"\n",cmd);
 
436
    ok= (system(cmd)==0);
 
437
    return ok;
 
438
}
 
439
 
 
440
/***====================================================================***/
 
441
 
 
442
int
 
443
main(int argc, char *argv[])
 
444
{
 
445
FILE    *       file;
 
446
static char     buf[1024];
 
447
XkbEvent        ev;
 
448
Bool            ok;
 
449
 
 
450
 
 
451
    yyin = stdin;
 
452
    uSetEntryFile(NullString);
 
453
    uSetDebugFile(NullString);
 
454
    uSetErrorFile(NullString);
 
455
 
 
456
    if (!parseArgs(argc,argv))
 
457
        exit(1);
 
458
    file= NULL;
 
459
    XkbInitAtoms(NULL);
 
460
    if (cfgFileName==NULL) {
 
461
        char *home;
 
462
        home= (char *)getenv("HOME");
 
463
        sprintf(buf,DFLT_XKBEVD_CONFIG,(home?home:""));
 
464
        cfgFileName= buf;
 
465
    }
 
466
    if (uStringEqual(cfgFileName,"-")) {
 
467
        static char *in= "stdin";
 
468
        file= stdin;
 
469
        cfgFileName= in;
 
470
    }
 
471
    else {
 
472
        file= fopen(cfgFileName,"r");
 
473
        if (file==NULL) { /* no personal config, try for a system one */
 
474
            if (cfgFileName!=buf) { /* user specified a file.  bail */
 
475
                uError("Can't open config file \"%s\n",cfgFileName);
 
476
                uAction("Exiting\n");
 
477
                exit(1);
 
478
            }
 
479
            sprintf(buf,DFLT_SYS_XKBEVD_CONFIG,DFLT_XKB_CONFIG_ROOT);
 
480
            file= fopen(cfgFileName,"r");
 
481
            if (file==NULL) {
 
482
                if (verbose) {
 
483
                    uError("Couldn't find a config file anywhere\n");
 
484
                    uAction("Exiting\n");
 
485
                    exit(1);
 
486
                }
 
487
                exit(0);
 
488
            }
 
489
        }
 
490
    }
 
491
 
 
492
    if (background) {
 
493
        if (fork()!=0) {
 
494
            if (verbose) 
 
495
                uInformation("Running in the background\n");
 
496
            exit(0);
 
497
        }
 
498
    }
 
499
    dpy= GetDisplay(argv[0],dpyName,&xkbOpcode,&xkbEventCode);
 
500
    if (!dpy)
 
501
        goto BAILOUT;
 
502
    ok= True;
 
503
    setScanState(cfgFileName,1);
 
504
    CFGParseFile(file);
 
505
    if (!config) {
 
506
        uError("No configuration specified in \"%s\"\n",cfgFileName);
 
507
        goto BAILOUT;
 
508
    }
 
509
    if (eventMask==0) {
 
510
        uError("No events to watch in \"%s\"\n",cfgFileName);
 
511
        goto BAILOUT;
 
512
    }
 
513
    if (!XkbSelectEvents(dpy,XkbUseCoreKbd,eventMask,eventMask)) {
 
514
        uError("Couldn't select desired XKB events\n");
 
515
        goto BAILOUT;
 
516
    }
 
517
    xkb= XkbGetKeyboard(dpy,XkbGBN_AllComponentsMask,XkbUseCoreKbd);
 
518
    if (eventMask&XkbBellNotifyMask) {
 
519
        unsigned ctrls,vals;
 
520
        if (verbose)
 
521
           uInformation("Temporarily disabling the audible bell\n");
 
522
        if (!XkbChangeEnabledControls(dpy,XkbUseCoreKbd,XkbAudibleBellMask,0)) {
 
523
            uError("Couldn't disable audible bell\n");
 
524
            goto BAILOUT;
 
525
        }
 
526
        ctrls= vals= XkbAudibleBellMask;
 
527
        if (!XkbSetAutoResetControls(dpy,XkbAudibleBellMask,&ctrls,&vals)) {
 
528
            uWarning("Couldn't configure audible bell to reset on exit\n");
 
529
            uAction("Audible bell might remain off\n");
 
530
        }
 
531
    }
 
532
    if (soundCmd==NULL) soundCmd= DFLT_SOUND_CMD;
 
533
    if (soundDir==NULL) soundDir= DFLT_SOUND_DIR;
 
534
    XkbStdBellEvent(dpy,None,0,XkbBI_ImAlive);
 
535
    while (1) {
 
536
        XNextEvent(dpy,&ev.core);
 
537
        if ((!ProcessMatchingConfig(&ev))&&(ev.type==xkbEventCode)&&
 
538
                                        (ev.any.xkb_type==XkbBellNotify)) {
 
539
            XkbForceDeviceBell(dpy,ev.bell.device,
 
540
                                ev.bell.bell_class,ev.bell.bell_id,
 
541
                                ev.bell.percent);
 
542
        }
 
543
    }
 
544
 
 
545
    XCloseDisplay(dpy);
 
546
    return (ok==0);
 
547
BAILOUT:
 
548
    uAction("Exiting\n");
 
549
    if (dpy!=NULL)
 
550
        XCloseDisplay(dpy);
 
551
    exit(1);
 
552
}