1 /*****************************************************************************
2  *
3  * Authors: Michel Eyckmans (MCE) + Stefan De Troch (SDT)
4  *
5  * Content: This file is part of version 2.x of xautolock. It implements
6  *          all option and X resource processing support.
7  *
8  *          Please send bug reports etc. to mce@scarlet.be.
9  *
10  * --------------------------------------------------------------------------
11  *
12  * Copyright 1990, 1992-1999, 2001-2002, 2004, 2007 by  Stefan De Troch and
13  * Michel Eyckmans.
14  *
15  * Versions 2.0 and above of xautolock are available under version 2 of the
16  * GNU GPL. Earlier versions are available under other conditions. For more
17  * information, see the License file.
18  *
19  *****************************************************************************/
20 
21 #include "options.h"
22 #include "state.h"
23 #include "miscutil.h"
24 #include "version.h"
25 
26 /*
27  *  Global option settings. Do not modify outside this file.
28  */
29 const char*  locker = LOCKER;            /* as it says                  */
30 const char*  nowLocker = LOCKER;         /* as it says                  */
31 const char*  notifier = NOTIFIER;        /* as it says                  */
32 const char*  killer = KILLER;            /* as it says                  */
33 time_t       lockTime = LOCK_MINS;       /* as it says                  */
34 time_t       killTime = KILL_MINS;       /* as it says                  */
35 time_t       notifyMargin;               /* as it says                  */
36 Bool         secure = SECURE;            /* as it says                  */
37 int          bellPercent = BELL_PERCENT; /* as it says                  */
38 unsigned     cornerSize = CORNER_SIZE;   /* as it says                  */
39 time_t       cornerDelay = CORNER_DELAY; /* as it says                  */
40 time_t       cornerRedelay;              /* as it says                  */
41 Bool         notifyLock = False;         /* whether to notify the user
42                                             before locking              */
43 Bool         useRedelay = False;         /* as it says                  */
44 cornerAction corners[4] = { ca_ignore, ca_ignore, ca_ignore, ca_ignore };
45                                          /* default cornerActions       */
46 Bool         resetSaver = False;         /* whether to reset the X
47 				            screensaver                 */
48 Bool         noCloseOut = False;         /* whether keep stdout open    */
49 Bool         noCloseErr = False;         /* whether keep stderr open    */
50 message      messageToSend = msg_none;   /* message to send to an
51                                             already running xautolock   */
52 Bool         detectSleep = False;        /* whether to reset the timers
53 					    after a (laptop) sleep,
54 					    i.e. after a big time jump  */
55 
56 #ifdef VMS
57 struct dsc$descriptor lockerDescr;       /* used to fire up the locker  */
58 struct dsc$descriptor nowLockerDescr;    /* used to fire up the locker  */
59 int                   vmsStatus = 1;     /* locker completion status    */
60 #endif /* VMS */
61 
62 Bool         notifierSpecified = False;
63 Bool         killerSpecified = False;
64 
65 /*
66  *  Guess what, these are private.
67  */
68 static Bool killTimeSpecified = False;
69 static Bool redelaySpecified = False;
70 static Bool bellSpecified = False;
71 static Bool dummySpecified;
72 
73 static void usage (int exitCode);
74 
75 /*
76  *  Argument scanning support.
77  */
78 static Bool
getInteger(const char * arg,int * in)79 getInteger (const char* arg, int* in)
80 {
81   char c; /* dummy */
82   return (sscanf (arg, "%d%c", in, &c) == 1);
83 }
84 
85 static Bool
getPositive(const char * arg,int * pos)86 getPositive (const char* arg, int* pos)
87 {
88   return getInteger (arg, pos) && *pos >= 0;
89 }
90 
91 /*
92  *  Option action functions
93  */
94 static Bool
helpAction(Display * d,const char * arg)95 helpAction (Display* d, const char* arg)
96 {
97   usage (EXIT_SUCCESS);
98   return True; /* keep gcc happy */
99 }
100 
101 static Bool
versionAction(Display * d,const char * arg)102 versionAction (Display* d, const char* arg)
103 {
104   error2 ("%s : version %s\n", progName, VERSION);
105   exit (EXIT_SUCCESS);
106   return True; /* keep gcc happy */
107 }
108 
109 static Bool
lockerAction(Display * d,const char * arg)110 lockerAction (Display* d, const char* arg)
111 {
112   nowLocker = locker = arg;
113   return True;
114 }
115 
116 static Bool
nowLockerAction(Display * d,const char * arg)117 nowLockerAction (Display* d, const char* arg)
118 {
119   nowLocker = arg;
120   return True;
121 }
122 
123 static Bool
killerAction(Display * d,const char * arg)124 killerAction (Display* d, const char* arg)
125 {
126   killerSpecified = True;
127   killer = arg;
128   return True;
129 }
130 
131 static Bool
notifierAction(Display * d,const char * arg)132 notifierAction (Display* d, const char* arg)
133 {
134   notifierSpecified = True;
135   notifier = arg;
136   return True;
137 }
138 
139 static Bool
bellAction(Display * d,const char * arg)140 bellAction (Display* d, const char* arg)
141 {
142   bellSpecified = True;
143   return getInteger (arg, &bellPercent);
144 }
145 
146 static Bool
cornerSizeAction(Display * d,const char * arg)147 cornerSizeAction (Display* d, const char* arg)
148 {
149   Bool retVal;
150   int tmp;
151 
152   if ((retVal = getPositive (arg, &tmp))) /* = intended */
153   {
154     cornerSize = tmp;
155   }
156 
157   return retVal;
158 }
159 
160 static Bool
cornersAction(Display * d,const char * arg)161 cornersAction (Display* d, const char* arg)
162 {
163   int c;
164 
165   if (strlen (arg) != 4) return False;
166 
167   for (c = -1; ++c < 4; )
168   {
169     switch (arg[c])
170     {
171       case '0': corners[c] = ca_ignore;    continue;
172       case '-': corners[c] = ca_dontLock;  continue;
173       case '+': corners[c] = ca_forceLock; continue;
174       default:  return False;
175     }
176   }
177 
178   return True;
179 }
180 
181 #define TIME_ACTION(name,nameSpecified)                    \
182 static Bool                                                \
183 name##Action (Display* d, const char* arg)                 \
184 {                                                          \
185   Bool retVal;                                             \
186   int tmp = 0;                                             \
187                                                            \
188   if ((retVal = getPositive (arg, &tmp))) /* = intended */ \
189   {                                                        \
190     name = (time_t) tmp;                                   \
191   }                                                        \
192                                                            \
193   nameSpecified = True;                                    \
194   return retVal;                                           \
195 }                                                          \
196 
TIME_ACTION(lockTime,dummySpecified)197 TIME_ACTION (lockTime     , dummySpecified   )
198 TIME_ACTION (killTime     , killTimeSpecified)
199 TIME_ACTION (cornerDelay  , dummySpecified   )
200 TIME_ACTION (cornerRedelay, redelaySpecified )
201 TIME_ACTION (notifyMargin , notifyLock       )
202 
203 #define notifyAction notifyMarginAction
204 
205 #define MESSAGE_ACTION(name)               \
206 static Bool                                \
207 name##Action (Display* d, const char* arg) \
208 {                                          \
209   if (messageToSend) return False;         \
210   messageToSend = msg_##name;              \
211   return True;                             \
212 }
213 
214 MESSAGE_ACTION (disable  )
215 MESSAGE_ACTION (enable   )
216 MESSAGE_ACTION (toggle   )
217 MESSAGE_ACTION (exit     )
218 MESSAGE_ACTION (lockNow  )
219 MESSAGE_ACTION (unlockNow)
220 MESSAGE_ACTION (restart  )
221 
222 #define BOOL_ACTION(name)                  \
223 static Bool                                \
224 name##Action (Display* d, const char* arg) \
225 {                                          \
226   return name = True;                      \
227 }
228 
229 BOOL_ACTION (secure    )
230 BOOL_ACTION (resetSaver)
231 BOOL_ACTION (noCloseOut)
232 BOOL_ACTION (noCloseErr)
233 BOOL_ACTION (detectSleep)
234 
235 static Bool
236 noCloseAction (Display* d, const char* arg)
237 {
238   (void) noCloseOutAction (d, arg);
239   (void) noCloseErrAction (d, arg);
240   return True;
241 }
242 
243 /*
244  *  Option checking logistics.
245  */
246 #ifndef VMS
247 static void
addExecToCommand(const char ** command)248 addExecToCommand (const char** command)
249 {
250  /*
251   *  On UNIX systems, we dont want to have an extra shell process
252   *  hanging about all the time while the locker is running, so we
253   *  want to insert an `exec' in front of the command. But since
254   *  this obviuosly would fail to work correctly if the command
255   *  actually consists of multiple ones, we need to look for `;'
256   *  characters first. We can only err on the safe side here...
257   */
258   if (!strchr (*command, ';'))
259   {
260     char* tmp;
261     (void) sprintf (tmp = newArray (char, strlen (*command) + 6),
262 		    "exec %s", *command);
263     *command = tmp;
264   }
265 }
266 #endif /* !VMS */
267 
268 static void
lockTimeChecker(Display * d)269 lockTimeChecker (Display* d)
270 {
271   if (lockTime < MIN_LOCK_MINS)
272   {
273     error1 ("Setting lock time to minimum value of %ld minute(s).\n",
274             (long) (lockTime = MIN_LOCK_MINS));
275   }
276   else if (lockTime > MAX_LOCK_MINS)
277   {
278     error1 ("Setting lock time to maximum value of %ld minute(s).\n",
279             (long) (lockTime = MAX_LOCK_MINS));
280   }
281 
282   lockTime *= 60; /* convert to seconds */
283 }
284 
285 static void
killTimeChecker(Display * d)286 killTimeChecker (Display* d)
287 {
288   if (killTimeSpecified && !killerSpecified)
289   {
290     error0 ("Using -killtime without -killer makes no sense.\n");
291     return;
292   }
293 
294   if (killTime < MIN_KILL_MINS)
295   {
296     error1 ("Setting kill time to minimum value of %ld minute(s).\n",
297             (long) (killTime = MIN_KILL_MINS));
298   }
299   else if (killTime > MAX_KILL_MINS)
300   {
301     error1 ("Setting kill time to maximum value of %ld minute(s).\n",
302             (long) (killTime = MAX_KILL_MINS));
303   }
304 
305   killTime *= 60; /* convert to seconds */
306 }
307 
308 static void
lockerChecker(Display * d)309 lockerChecker (Display* d)
310 {
311 #ifndef VMS
312   addExecToCommand (&locker);
313 #else /* VMS */
314  /*
315   *  Translate things to something that VMS knows how to handle.
316   */
317   lockerDescr.dsc$w_length = (unsigned short) strlen (locker);
318   lockerDescr.dsc$b_class = DSC$K_CLASS_S;
319   lockerDescr.dsc$b_dtype = DSC$K_DTYPE_T;
320   lockerDescr.dsc$a_pointer = (char*) locker;
321 #endif /* VMS */
322 }
323 
324 static void
nowLockerChecker(Display * d)325 nowLockerChecker (Display* d)
326 {
327 #ifndef VMS
328   addExecToCommand (&nowLocker);
329 #else /* VMS */
330  /*
331   *  Translate things to something that VMS knows how to handle.
332   */
333   nowLockerDescr.dsc$w_length = (unsigned short) strlen (now_locker);
334   nowLockerDescr.dsc$b_class = DSC$K_CLASS_S;
335   nowLockerDescr.dsc$b_dtype = DSC$K_DTYPE_T;
336   nowLockerDescr.dsc$a_pointer = (char*) nowLocker;
337 #endif /* VMS */
338 }
339 
340 static void
notifierChecker(Display * d)341 notifierChecker (Display* d)
342 {
343   if (strcmp (notifier, ""))
344   {
345     if (!notifyLock)
346     {
347       error0 ("Using -notifier without -notify makes no sense.\n");
348     }
349 #ifndef VMS
350     else
351     {
352      /*
353       *  Add an `&' to the notifier command, so that it always gets
354       *  run as a background process and things will work out properly
355       *  later. The rationale behind this hack is explained elsewhere.
356       */
357       char* tmp;
358       (void) sprintf (tmp = newArray (char, strlen (notifier) + 3),
359 		      "%s &", notifier);
360       notifier = tmp;
361     }
362 #endif /* !VMS */
363   }
364 }
365 
366 static void
killerChecker(Display * d)367 killerChecker (Display* d)
368 {
369 #ifndef VMS
370   if (strcmp (killer, ""))
371   {
372    /*
373     *  Add an `&' to the killer command, so that it always gets
374     *  run as a background process and things will work out properly
375     *  later. The rationale behind this hack is explained elsewhere.
376     */
377     char* tmp;
378     (void) sprintf (tmp = newArray (char, strlen (killer) + 3),
379 		    "%s &", killer);
380     killer = tmp;
381   }
382 #endif /* !VMS */
383 }
384 
385 static void
notifyChecker(Display * d)386 notifyChecker (Display* d)
387 {
388   if (   notifyLock
389       && (   corners[0] == ca_forceLock
390 	  || corners[1] == ca_forceLock
391 	  || corners[2] == ca_forceLock
392 	  || corners[3] == ca_forceLock))
393   {
394     time_t minDelay = MIN (cornerDelay, cornerRedelay);
395 
396     if (notifyMargin > minDelay)
397     {
398       error1 ("Notification time reset to %ld second(s).\n",
399               (long) (notifyMargin = minDelay));
400     }
401 
402     if (notifyMargin > lockTime / 2)
403     {
404       error1 ("Notification time reset to %ld seconds.\n",
405               (long) (notifyMargin = lockTime / 2));
406     }
407   }
408 }
409 
410 static void
bellChecker(Display * d)411 bellChecker (Display* d)
412 {
413   if (bellSpecified)
414   {
415     if (!notifyLock)
416     {
417       error0 ("Using -bell without -notify makes no sense.\n");
418       bellPercent = 0;
419     }
420     else if (notifierSpecified)
421     {
422       error0 ("Using both -bell and -notifier makes no sense.\n");
423       bellPercent = 0;
424     }
425   }
426 
427   if (   bellPercent < -100
428       || bellPercent >  100)
429   {
430     error1 ("Bell percentage reset to %d%%.\n",
431             bellPercent = BELL_PERCENT);
432   }
433 }
434 
435 static void
cornerSizeChecker(Display * d)436 cornerSizeChecker (Display* d)
437 {
438   int      s;
439   Screen*  scr;
440   int      maxCornerSize;
441 
442   for (maxCornerSize = 32000, s = -1; ++s < ScreenCount (d); )
443   {
444     scr = ScreenOfDisplay (d, s);
445 
446     if (   maxCornerSize > WidthOfScreen (scr)  / 4
447         || maxCornerSize > HeightOfScreen (scr) / 4)
448     {
449       maxCornerSize = MIN (WidthOfScreen (scr), HeightOfScreen (scr)) / 4;
450     }
451   }
452 
453   if (cornerSize > maxCornerSize)
454   {
455     error1 ("Corner size reset to %d pixels.\n",
456             cornerSize = maxCornerSize);
457   }
458 }
459 
460 static void
cornerReDelayChecker(Display * d)461 cornerReDelayChecker (Display* d)
462 {
463   if (!redelaySpecified)
464   {
465     cornerRedelay = cornerDelay;
466   }
467 }
468 
469 /*
470  *  The central option table.
471  */
472 typedef Bool (*optAction)  (Display*, const char*);
473 typedef void (*optChecker) (Display*);
474 
475 static struct
476 {
477   const char*   name;    /* as it says              */
478   XrmOptionKind kind;    /* as it says              */
479   caddr_t       value;   /* only for XrmOptionNoArg */
480   optAction     action;  /* as it says              */
481   optChecker    checker; /* as it says              */
482 } options[] =
483 {
484   {"help"              , XrmoptionNoArg , (caddr_t) "",
485     helpAction         , (optChecker) 0            },
486   {"version"           , XrmoptionNoArg , (caddr_t) "",
487     versionAction      , (optChecker) 0            },
488   {"locker"            , XrmoptionSepArg, (caddr_t) 0 ,
489     lockerAction       , lockerChecker             },
490   {"nowlocker"         , XrmoptionSepArg, (caddr_t) 0 ,
491     nowLockerAction    , nowLockerChecker          },
492   {"killer"            , XrmoptionSepArg, (caddr_t) 0 ,
493     killerAction       , killerChecker             },
494   {"notifier"          , XrmoptionSepArg, (caddr_t) 0 ,
495     notifierAction     , notifierChecker           },
496   {"corners"           , XrmoptionSepArg, (caddr_t) 0 ,
497     cornersAction      , (optChecker) 0            },
498   {"cornersize"        , XrmoptionSepArg, (caddr_t) 0 ,
499     cornerSizeAction   , cornerSizeChecker         },
500   {"cornerdelay"       , XrmoptionSepArg, (caddr_t) 0 ,
501     cornerDelayAction  , (optChecker) 0            },
502   {"cornerredelay"     , XrmoptionSepArg, (caddr_t) 0 ,
503     cornerRedelayAction, cornerReDelayChecker      },
504   {"killtime"          , XrmoptionSepArg, (caddr_t) 0 ,
505     killTimeAction     , killTimeChecker           },
506   {"time"              , XrmoptionSepArg, (caddr_t) 0 ,
507     lockTimeAction     , lockTimeChecker           },
508   {"notify"            , XrmoptionSepArg, (caddr_t) 0 ,
509     notifyAction       , notifyChecker             },
510   {"bell"              , XrmoptionSepArg, (caddr_t) 0 ,
511     bellAction         , bellChecker               },
512   {"secure"            , XrmoptionNoArg , (caddr_t) "",
513     secureAction       , (optChecker) 0            },
514   {"enable"            , XrmoptionNoArg , (caddr_t) "",
515     enableAction       , (optChecker) 0            },
516   {"disable"           , XrmoptionNoArg , (caddr_t) "",
517     disableAction      , (optChecker) 0            },
518   {"toggle"            , XrmoptionNoArg , (caddr_t) "",
519     toggleAction       , (optChecker) 0            },
520   {"exit"              , XrmoptionNoArg , (caddr_t) "",
521     exitAction         , (optChecker) 0            },
522   {"locknow"           , XrmoptionNoArg , (caddr_t) "",
523     lockNowAction      , (optChecker) 0            },
524   {"unlocknow"         , XrmoptionNoArg , (caddr_t) "",
525     unlockNowAction    , (optChecker) 0            },
526   {"restart"           , XrmoptionNoArg , (caddr_t) "",
527     restartAction      , (optChecker) 0            },
528   {"resetsaver"        , XrmoptionNoArg , (caddr_t) "",
529     resetSaverAction   , (optChecker) 0            },
530   {"noclose"           , XrmoptionNoArg , (caddr_t) "",
531     noCloseAction      , (optChecker) 0            },
532   {"nocloseout"        , XrmoptionNoArg , (caddr_t) "",
533     noCloseOutAction   , (optChecker) 0            },
534   {"nocloseerr"        , XrmoptionNoArg , (caddr_t) "",
535     noCloseErrAction   , (optChecker) 0            },
536   {"detectsleep"       , XrmoptionNoArg , (caddr_t) "",
537     detectSleepAction  , (optChecker) 0            },
538 }; /* as it says, the order is important! */
539 
540 /*
541  *  Have a guess...
542  */
543 static void
usage(int exitCode)544 usage (int exitCode)
545 {
546  /*
547   *  The relative overhead is enormous here, but who cares.
548   *  I'm a perfectionist and usage() doesn't return anyway.
549   */
550   char*  blanks; /* string full of blanks */
551   size_t len;    /* number of blanks      */
552   len = strlen ("Usage :  ") + strlen (progName);
553   (void) memset (blanks = newArray (char, len + 1), ' ', len);
554   blanks[len] = '\0';
555 
556  /*
557   *  This is where the actual work gets done...
558   */
559   error0 ("\n");
560   error1 ("Usage : %s ", progName);
561   error0 ("[-help][-version][-time mins][-locker locker]\n");
562   error1 ("%s[-killtime mins][-killer killer]\n", blanks);
563   error1 ("%s[-notify margin][-notifier notifier][-bell percent]\n", blanks);
564   error1 ("%s[-corners xxxx][-cornerdelay secs]\n", blanks);
565   error1 ("%s[-cornerredelay secs][-cornersize pixels]\n", blanks);
566   error1 ("%s[-nocloseout][-nocloseerr][-noclose]\n", blanks);
567   error1 ("%s[-enable][-disable][-toggle][-exit][-secure]\n", blanks);
568   error1 ("%s[-locknow][-unlocknow][-nowlocker locker]\n", blanks);
569   error1 ("%s[-restart][-resetsaver][-detectsleep]\n", blanks);
570 
571   error0 ("\n");
572   error0 (" -help               : print this message and exit.\n");
573   error0 (" -version            : print version number and exit.\n");
574   error0 (" -time mins          : time before locking the screen");
575   error2 (" [%d <= mins <= %d].\n", MIN_LOCK_MINS, MAX_LOCK_MINS);
576   error0 (" -locker locker      : program used to lock.\n");
577   error0 (" -nowlocker locker   : program used to lock immediately.\n");
578   error0 (" -killtime killmins  : time after locking at which to run\n");
579   error2 ("                       the killer [%d <= killmins <= %d].\n",
580                                   MIN_KILL_MINS, MAX_KILL_MINS);
581   error0 (" -killer killer      : program used to kill.\n");
582   error0 (" -notify margin      : notify this many seconds before locking.\n");
583   error0 (" -notifier notifier  : program used to notify.\n");
584   error0 (" -bell percent       : loudness of notification beeps.\n");
585   error0 (" -corners xxxx       : corner actions (0, +, -) in this order:\n");
586   error0 ("                       topleft topright bottomleft bottomright\n");
587   error0 (" -cornerdelay secs   : time to lock screen in a `+' corner.\n");
588   error0 (" -cornerredelay secs : time to relock screen in a `+' corner.\n");
589   error0 (" -cornersize pixels  : size of corner areas.\n");
590   error0 (" -nocloseout         : do not close stdout.\n");
591   error0 (" -nocloseerr         : do not close stderr.\n");
592   error0 (" -noclose            : close neither stdout nor stderr.\n");
593   error0 (" -enable             : enable a running xautolock.\n");
594   error0 (" -disable            : disable a running xautolock.\n");
595   error0 (" -toggle             : toggle a running xautolock.\n");
596   error0 (" -locknow            : tell a running xautolock to lock.\n");
597   error0 (" -unlocknow          : tell a running xautolock to unlock.\n");
598   error0 (" -restart            : tell a running xautolock to restart.\n");
599   error0 (" -exit               : kill a running xautolock.\n");
600   error0 (" -secure             : ignore enable, disable, toggle, locknow\n");
601   error0 ("                       unlocknow, and restart messages.\n");
602   error0 (" -resetsaver         : reset the screensaver when starting "
603                                   "the locker.\n");
604   error0 (" -detectsleep        : reset timers when awaking from sleep.\n");
605 
606   error0 ("\n");
607   error0 ("Defaults :\n");
608 
609   error0 ("\n");
610   error1 ("  time          : %d minutes\n"  , LOCK_MINS   );
611   error1 ("  locker        : %s\n"          , LOCKER      );
612   error1 ("  nowlocker     : %s\n"          , LOCKER      );
613   error1 ("  killtime      : %d minutes\n"  , KILL_MINS   );
614   error0 ("  killer        : none\n"                      );
615   error0 ("  notify        : don't notify\n"              );
616   error0 ("  notifier      : none\n"                      );
617   error1 ("  bell          : %d%%\n"        , BELL_PERCENT);
618   error0 ("  corners       : 0000\n"                      );
619   error1 ("  cornerdelay   : %d seconds\n"  , CORNER_DELAY);
620   error1 ("  cornerredelay : %d seconds\n"  , CORNER_DELAY);
621   error1 ("  cornersize    : %d pixels\n"   , CORNER_SIZE );
622 
623   error0 ("\n");
624   error1 ("Version : %s\n", VERSION);
625 
626   error0 ("\n");
627 
628   exit (exitCode);
629 }
630 
631 /*
632  *  Public interface to the above lot.
633  */
634 void
processOpts(Display * d,int argc,char * argv[])635 processOpts (Display* d, int argc, char* argv[])
636 {
637   int                nofOptions = sizeof (options) / sizeof (options[0]);
638                                 /* number of supported options   */
639   int                j;         /* loop counter                  */
640   unsigned           l;         /* temporary storage             */
641   unsigned           maxLen;    /* temporary storage             */
642   char*              dummy;     /* as it says                    */
643   char*              fullname;  /* full resource name            */
644   char*              str;       /* temporary storage             */
645   XrmValue           value;     /* resource value container      */
646   XrmOptionDescList  xoptions;  /* optionslist in Xlib format    */
647   XrmDatabase        rescDb = (XrmDatabase) 0;
648                                 /* resource file database        */
649   XrmDatabase        cmdlDb = (XrmDatabase) 0;
650                                 /* command line options database */
651 
652  /*
653   *  Collect defaults from various places except the command line into one
654   *  resource database, then parse the command line options into an other.
655   *  Both databases are not merged, because we want to know where exactly
656   *  each resource value came from.
657   *
658   *  One day I might extend this stuff to fully cover *all* possible
659   *  resource value sources, but... One of the problems is that various
660   *  pieces of documentation make conflicting claims with respect to the
661   *  proper order in which resource value sources should be accessed.
662   */
663   XrmInitialize ();
664 
665   if (XResourceManagerString (d))
666   {
667     XrmMergeDatabases (XrmGetStringDatabase (XResourceManagerString (d)),
668 		       &rescDb);
669   }
670   else if ((str = getenv ("XENVIRONMENT"))) /* = intended */
671   {
672     XrmMergeDatabases (XrmGetFileDatabase (str), &rescDb);
673   }
674 #if defined (ReadXdefaultsFile) && !defined (VMS)
675   else
676   {
677    /*
678     *  In general, the following is a not a good idea. Who is to say that
679     *  the user's .Xdefaults file matches the screen being used? And who
680     *  says we shouldn't run the file through cpp first? Using which
681     *  options, by the way?
682     *
683     *  Fortunately, chances are pretty small that anyone will actually run
684     *  xautolock remotely. And even if someone does, the same .Xdefaults
685     *  file will most likely be involved on both sides of the link. Also,
686     *  we only do this of we failed to get our resources from the standard
687     *  places. People who have .Xdefaults files that need to be fed to cpp,
688     *  will run the appropriate xrdb command on login anyway, such that we
689     *  never get here.
690     *
691     *  Having said that, I'm only keeping this stuff around because of the
692     *  desire to be backward compatible for those who originally convinced
693     *  me to include it, or who since became to depend on it. If I could
694     *  live my life over again, this wouldn't get added in the first place.
695     */
696     XrmDatabase Xdefaults;
697     struct passwd *passwd;
698     const char* home;
699     char* path;
700 
701     passwd = getpwuid (getuid ());
702 
703     if (passwd)
704     {
705       home = passwd->pw_dir;
706     }
707     else
708     {
709       home = getenv ("HOME");
710       if (!home) home = ".";
711     }
712 
713     path = newArray (char, strlen (home) + strlen ("/.Xdefaults") + 1);
714     (void) sprintf (path, "%s/.Xdefaults", home);
715     Xdefaults = XrmGetFileDatabase (path);
716     if (Xdefaults) XrmMergeDatabases (Xdefaults, &rescDb);
717 
718     free (path);
719   }
720 #endif /* ReadXdefaultsFile && !VMS */
721 
722   xoptions = newArray (XrmOptionDescRec, nofOptions);
723 
724   for (j = -1, maxLen = 0; ++j < nofOptions; )
725   {
726     l = strlen (options[j].name) + 1;
727     maxLen = MAX (maxLen, l);
728 
729     (void) sprintf (xoptions[j].option = newArray (char, l + 1),
730 	            "-%s", options[j].name);
731     (void) sprintf (xoptions[j].specifier = newArray (char, l + 1),
732                     ".%s", options[j].name);
733     xoptions[j].argKind = options[j].kind;
734     xoptions[j].value = options[j].value;
735   }
736 
737   XrmParseCommand (&cmdlDb, xoptions, nofOptions, progName, &argc, argv);
738 
739   if (--argc) usage (EXIT_FAILURE);
740 
741  /*
742   *  Let's be perfect...
743   */
744   {
745     unsigned classLen = strlen (APPLIC_CLASS);
746     unsigned progLen  = strlen (progName);
747 
748     fullname = newArray (char, MAX (progLen, classLen) + maxLen + 1);
749   }
750 
751  /*
752   *  Call the action functions.
753   */
754   for (j = -1; ++j < nofOptions; )
755   {
756     (void) sprintf (fullname, "%s%s", progName, xoptions[j].specifier);
757 
758     if (   XrmGetResource (cmdlDb, fullname, DUMMY_RES_CLASS,
759                            &dummy, &value)
760         == True)
761     {
762       if (!(*(options[j].action)) (d, value.addr))
763       {
764 	usage (EXIT_FAILURE);
765       }
766     }
767     else if (   XrmGetResource (rescDb, fullname, DUMMY_RES_CLASS,
768                                 &dummy, &value)
769              == True)
770     {
771       if (!(*(options[j].action)) (d, value.addr))
772       {
773         error2 ("Can't interprete \"%s\" for \"%s\", using default.\n",
774                 value.addr, fullname);
775       }
776     }
777     else
778     {
779       (void) sprintf (fullname, "%s%s", APPLIC_CLASS, xoptions[j].specifier);
780 
781       if (   (   XrmGetResource (rescDb, fullname, DUMMY_RES_CLASS,
782                                  &dummy, &value)
783               == True)
784           && !(*(options[j].action)) (d, value.addr))
785       {
786         error2 ("Can't interprete \"%s\" for \"%s\", using default.\n",
787                 value.addr, fullname);
788       }
789     }
790   }
791 
792  /*
793   *  Call the consistency checkers.
794   */
795   for (j = -1; ++j < nofOptions; )
796   {
797     if (options[j].checker != (optChecker) NULL)
798     {
799       (*(options[j].checker)) (d);
800     }
801   }
802 
803  /*
804   *  General clean up.
805   */
806   XrmDestroyDatabase (cmdlDb);
807   XrmDestroyDatabase (rescDb);
808 
809   for (j = -1; ++j < nofOptions; )
810   {
811     free (xoptions[j].option);
812     free (xoptions[j].specifier);
813   }
814 
815   free (xoptions);
816   free (fullname);
817 }
818