8637c2fffbb2231b99ce8d1ed7e1320621b9aaf7
[oweals/cde.git] / cde / lib / DtHelp / HelpUtil.c
1 /* $TOG: HelpUtil.c /main/19 1998/04/09 17:43:30 mgreess $ */
2 /************************************<+>*************************************
3  ****************************************************************************
4  **
5  **   File:        HelpUtil.c
6  **
7  **   Project:     Rivers Project
8  **
9  **   Description: 
10  ** 
11  **
12  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
13  **
14  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
15  **  (c) Copyright 1993, 1994 International Business Machines Corp.
16  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
17  **  (c) Copyright 1993, 1994 Novell, Inc.
18  **
19  ****************************************************************************
20  ************************************<+>*************************************/
21
22
23 #include <sys/param.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>  /* R_OK */
28 #include <sys/stat.h>
29
30 #include <sys/types.h>
31 #define X_INCLUDE_PWD_H
32 #define XOS_USE_XT_LOCKING
33 #include <X11/Xos_r.h>
34
35 #include <Xm/Xm.h>
36 #include <Xm/XmP.h>
37 #include <Xm/MwmUtil.h>
38
39 #include <Xm/MessageB.h>
40 #include <X11/keysymdef.h>
41 #include <X11/Shell.h>
42 #include <X11/Intrinsic.h>
43 #include <X11/cursorfont.h>
44
45 /* private includes */
46 #include "Access.h"
47 #include "bufioI.h"
48 #include "DisplayAreaI.h"
49
50 #include <Dt/Help.h>
51 #include "HelpI.h"
52 #include "HelpP.h"
53 #include "StringFuncsI.h"
54 #include "HelpDialogI.h"
55 #include "HelpDialogP.h"
56 #include "HelpUtilI.h"
57 #include "HelposI.h"
58 #include "MessagesP.h"
59 #include "HelpQuickD.h"
60 #include "SetListI.h"
61 #include "DestroyI.h"
62 #include "HelpAccessI.h"
63 #include "FileUtilsI.h"
64 #include "HourGlassI.h"
65 #include "Lock.h"
66
67 #include <Dt/DtNlUtils.h>
68
69 /******* global variables *******/
70 char _DtHelpDefaultHelp4HelpVolume[] = "Help4Help";
71 char _DtHelpDefaultLocationId[] = "_HOMETOPIC";
72
73 /**** Help Util Error message Defines ****/
74
75 #define UtilMessage0    _DtHelpMsg_0010
76 #define UtilMessage2    _DtHelpMsg_0011
77
78
79 static void _DtMessageClose(
80     Widget w,
81     XtPointer client_data,
82     XEvent *event);
83 static void  CloseDefBoxCB(
84     Widget w,
85     XtPointer client_data,
86     XtPointer call_data);
87
88 /* Macro for finding a point within a gadget.
89  * Its used for item help 
90  */
91 #define  PT_IN_CHILD(X, Y, CHILD) \
92          ((((int)(X)) >= ((int) (CHILD)->core.x)) && \
93           (((int)(X)) <= ((int)((CHILD)->core.x + (CHILD)->core.width))) && \
94           (((int)(Y)) >= ((int) (CHILD)->core.y)) && \
95           (((int)(Y)) <= ((int)((CHILD)->core.y + (CHILD)->core.height))))
96
97
98 /******** useful constants ********/
99 #define EOS  '\0'
100 #define DIR_SLASH '/'
101
102 #define HUSET 8     /* message catalog set */
103
104 /******** static variables ********/
105 static char DirSlash[] = "/";
106
107 /******** data structures ********/
108 typedef struct ExecContext 
109 {
110    char * command;
111    XtPointer pDisplayArea;
112 } ExecContext;
113
114 /******** The onitem cursor (32x32, xbm format) ********/
115 #define onitem32_width 32
116 #define onitem32_height 32
117 #define onitem32_x_hot 0
118 #define onitem32_y_hot 0
119 static unsigned char onitem32_bits[] = {
120    0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x1f, 0xfc, 0xf9, 0xff, 0xe7, 0xf3,
121    0xf1, 0xff, 0xfb, 0xef, 0xe1, 0xff, 0xfd, 0xdf, 0xc1, 0xff, 0xfd, 0xdf,
122    0x83, 0xff, 0xfe, 0xbf, 0x03, 0xff, 0x7e, 0x7e, 0x03, 0xfe, 0xbe, 0x7d,
123    0x03, 0xfc, 0xbe, 0x7d, 0x03, 0xf0, 0xc1, 0x7d, 0x03, 0xe0, 0xff, 0x7e,
124    0x07, 0xc0, 0x7f, 0xbf, 0x07, 0x80, 0xbf, 0xbf, 0x07, 0x00, 0xde, 0xdf,
125    0x07, 0x00, 0xdc, 0xef, 0x07, 0x00, 0xdf, 0xf7, 0x07, 0x80, 0xdf, 0xfb,
126    0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0x81, 0xdf, 0xfb,
127    0xcf, 0x83, 0x3f, 0xfc, 0xef, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff,
128    0xff, 0x0f, 0x3e, 0xfc, 0xff, 0x0f, 0xde, 0xfb, 0xff, 0x1f, 0xdc, 0xfb,
129    0xff, 0x1f, 0xdc, 0xfb, 0xff, 0x3f, 0xd8, 0xfb, 0xff, 0x3f, 0x3c, 0xfc,
130    0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
131
132 #define onitem32_m_width 32
133 #define onitem32_m_height 32
134 #define onitem32_m_x_hot 0
135 #define onitem32_m_y_hot 0
136 static unsigned char onitem32_m_bits[] = {
137    0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0x03, 0x0f, 0x00, 0xf8, 0x0f,
138    0x1f, 0x00, 0xfc, 0x1f, 0x3f, 0x00, 0xfe, 0x3f, 0x7f, 0x00, 0xfe, 0x3f,
139    0xfe, 0x00, 0xff, 0x7f, 0xfe, 0x01, 0xff, 0xff, 0xfe, 0x03, 0x7f, 0xfe,
140    0xfe, 0x0f, 0x7f, 0xfe, 0xfe, 0x1f, 0x3e, 0xfe, 0xfe, 0x3f, 0x00, 0xff,
141    0xfc, 0x7f, 0x80, 0x7f, 0xfc, 0xff, 0xc1, 0x7f, 0xfc, 0xff, 0xe3, 0x3f,
142    0xfc, 0xff, 0xe7, 0x1f, 0xfc, 0xff, 0xe3, 0x0f, 0xfc, 0xff, 0xe0, 0x07,
143    0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0xff, 0xe0, 0x07,
144    0xf8, 0xfe, 0xc0, 0x03, 0x38, 0xfc, 0x01, 0x00, 0x18, 0xfc, 0x01, 0x00,
145    0x00, 0xf8, 0xc3, 0x03, 0x00, 0xf8, 0xe3, 0x07, 0x00, 0xf0, 0xe7, 0x07,
146    0x00, 0xf0, 0xe7, 0x07, 0x00, 0xe0, 0xef, 0x07, 0x00, 0xe0, 0xc7, 0x03,
147    0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x00, 0x00};
148
149 #if 0 /* XPM format */
150 static char * onitem32_xpm[] = {
151 /* width height ncolors cpp [x_hot y_hot] */
152 "32 32 3 1 0 0",
153 /* colors */
154 "       s iconColor1    m black c black",
155 ".      s background    m black c #969696969696",
156 "X      s iconColor2    m white c white",
157 /* pixels */
158 "  ..............................",
159 " X ..................XXXXX......",
160 " XX ...............XX     XX....",
161 " XXX .............X         X...",
162 " XXXX ...........X           X..",
163 " XXXXX ..........X           X..",
164 ". XXXXX ........X             X.",
165 ". XXXXXX .......X      XX      X",
166 ". XXXXXXX ......X     X..X     X",
167 ". XXXXXXXX  ....X     X..X     X",
168 ". XXXXXXXXXX ....XXXXX...X     X",
169 ". XXXXXXXXXXX ..........X      X",
170 ".. XXXXXXXXXXX ........X      X.",
171 ".. XXXXXXXXXXXX  .....X       X.",
172 ".. XXXXXXXXXXXXXX ...X       X..",
173 ".. XXXXXXXXXXXXXXX ..X      X...",
174 ".. XXXXXXXXXXXXX  ...X     X....",
175 ".. XXXXXXXXXXXX .....X    X.....",
176 "... XXXXXXXXXX ......X    X.....",
177 "... XXXXXXXXXX ......X    X.....",
178 "... XXXX XXXXXX .....X    X.....",
179 "... XX  . XXXXX ......XXXX......",
180 "... X .... XXXXX ...............",
181 "...  ..... XXXXX ...............",
182 "........... XXXXX ....XXXX......",
183 "........... XXXXX ...X    X.....",
184 "............ XXXXX ..X    X.....",
185 "............ XXXXX ..X    X.....",
186 "............. XXXXX .X    X.....",
187 "............. XXXX ...XXXX......",
188 ".............. X  ..............",
189 "............... ................"};
190 #endif
191
192 #define ROOT_USER 0
193 #define BIN_USER  2
194 #define SYS_USER  3
195
196 #define NO_CONDITION           0
197 #define MISMATCHING_HOME_DIRS  1
198
199 /* ------------------------------------------------------------ *
200 **
201 **  Function     trusted
202 **
203 **  Purpose      Determines if the passed help volume is a 
204 **               "trusted"  help volume or not.  We call it 
205 **               trusted if it meets the following conditions:
206 **                  1. File Owner is root, bin, or system. 
207 **                  2. File is NOT writable by group or others.
208 **                     
209 **  Returns
210 **               True   -  if the help volume IS Trusted
211 **              False   -  if the help volume is NOT Trusted
212 **
213 ** ------------------------------------------------------------ */
214 static Boolean trusted (char *hv_path)  /* Full path to the help volume */
215 {
216    struct stat buf;
217    Boolean     writable;
218
219    if ( (stat (hv_path, &buf)) == -1)
220       return False;
221
222
223 /* S_IWGRP */   /* write group */
224 /* S_IWOTH */   /* write other */
225
226   /** ---------------------------------------------------------------------- *
227    **  The help volume MUST be owned by root, bin, or sys to be trusted.
228    ** ---------------------------------------------------------------------- */
229
230    if ( buf.st_uid != ROOT_USER &&
231         buf.st_uid != BIN_USER  &&
232         buf.st_uid != SYS_USER)
233    {
234       return False;
235    }
236
237   /** ----------------------------------------------------------------------- *
238    **  The help volume MUST not be writable by group or others to be trusted.
239    ** ----------------------------------------------------------------------- */
240
241    writable = (((buf.st_mode & S_IWGRP) == 0) && (buf.st_mode & S_IWOTH) == 0) ?  
242               True : False;
243
244    return writable;
245
246 }
247
248
249 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
250 /****       API Error Dialog Support Functions       *****/
251 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
252
253
254 /************************************************************************
255  * Function: _DtMessageClose
256  *
257  *      Close the error/info message box.
258  *
259  ************************************************************************/ 
260 static void _DtMessageClose(
261     Widget w,
262     XtPointer client_data,
263     XEvent *event )
264 {                        
265    /* NOTE: ExecuteContextCB() is dependent on this code */
266    if (event->type == UnmapNotify)
267    {
268       XtRemoveEventHandler (XtParent (client_data), StructureNotifyMask, 
269                             True, (XtEventHandler) _DtMessageClose, client_data);
270
271       XtUnmanageChild (client_data);
272       XtDestroyWidget (client_data);
273    }
274 }
275
276 /************************************************************************
277  * Function: ExecuteContextCB
278  *
279  *      Execute an execution context
280  *
281  ************************************************************************/ 
282 static void ExecuteContextCB(
283     Widget w,
284     XtPointer client_data,
285     XtPointer callData )
286 {
287     ExecContext * ec = (ExecContext *) client_data;
288
289     if (ec && ec->command && ec->pDisplayArea)
290     {
291         _DtHelpExecProcedure(ec->pDisplayArea,ec->command);
292         free(ec->command);
293     }
294     XtFree((char *) ec);
295
296     /* unmap, rather than unmanage and destroy, because of the code
297        in _DtMessageClose().  _DtMessageClose() is notified when 
298        the widget unmaps and it destroys the widget. */
299     XtUnmapWidget(w);       /* w is the message dialog */
300 }
301
302 /*****************************************************************************
303  * Function: CreateErrorDialog
304  *
305  *  Creates an XmMessageDialog with the message and all buttons
306  *  except the 'Close' (OK) button unmanaged.
307  *  Also adds a callback that destroys the widget when the dialog is closed.
308  * 
309  *****************************************************************************/
310 static Widget 
311 CreateErrorDialog(
312     Widget                   parent,
313     char *                   message)
314 {     
315    Widget       button;
316    Widget       messageDialog;
317    Arg          args[10];
318    int          n;
319  
320    XmString     label_string;
321    XmString      ok_string;
322    char          *title_string; 
323  
324    /* Setup the message string and dialog title */
325  
326    ok_string = XmStringCreateLocalized(((char *)_DTGETMESSAGE
327                                (HUSET, 2,"Close")));
328    label_string = XmStringCreateLocalized(message);
329    title_string = XtNewString((char *)_DTGETMESSAGE
330                               (HUSET, 5,"Help Error"));
331  
332    n = 0;
333    XtSetArg (args[n], XmNmessageString, label_string);  n++;
334    XtSetArg (args[n], XmNtitle,title_string); n++;
335    XtSetArg (args[n], XmNcancelLabelString, ok_string); n++;
336    XtSetArg (args[n], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); n++;
337    messageDialog = XmCreateErrorDialog (parent, "errorDialog",
338                                                args, n);
339    XtSetArg(args[0], XmNmwmDecorations,
340                               MWM_DECOR_BORDER | MWM_DECOR_TITLE);
341    XtSetArg(args[1], XmNuseAsyncGeometry, True);
342    XtSetValues(XtParent(messageDialog), args, 2);
343  
344    XmStringFree (label_string);
345    XmStringFree (ok_string);
346    XtFree(title_string);
347  
348    /* unmanage or define the other buttons */
349    button = XmMessageBoxGetChild (messageDialog, XmDIALOG_OK_BUTTON);
350    XtUnmanageChild (button);
351    button = XmMessageBoxGetChild (messageDialog, XmDIALOG_HELP_BUTTON);
352    XtUnmanageChild (button);
353  
354    /* StructureNotifyMask gets Circulate, Configure, Destroy, 
355       Gravity, Map, Reparent, & Unmap events */
356    XtAddEventHandler(XtParent(messageDialog),
357                      StructureNotifyMask,True,
358                      (XtEventHandler) _DtMessageClose, (XtPointer) messageDialog);
359  
360    return messageDialog;           /* RETURN */
361
362 }
363
364 /*****************************************************************************
365  * Function: CreateExecErrorDlg
366  *
367  * 
368  * 
369  * Called by:
370  *****************************************************************************/
371 static Widget
372 CreateExecErrorDlg(
373       Widget   helpWidget,
374       const char *  cmdStr,
375       Boolean  invalidAlias,
376       _DtHelpCommonHelpStuff * pHelpStuff,
377       int        condition,
378       char     * current_hd)
379 {
380    DtHelpListStruct *pHelpInfo;
381    Widget msgDlg;
382    Widget btn;
383    char *  msg;
384    char *  fullmsg;
385
386    /* handle the error case */
387    if (invalidAlias)
388    {
389       msg = (char *)_DTGETMESSAGE(HUSET, 12,
390                "The help volume wanted to execute a command alias.\n"
391                "The alias '%s' is not defined.");
392    }
393
394    else if (condition == MISMATCHING_HOME_DIRS)
395    {
396       msg = (char *)_DTGETMESSAGE(HUSET, 14,
397 "The help volume wanted to execute a command as the root user, but the\n"
398 "home directory of  \"%s\"  ($HOME) does not match the root\n"
399 "user's home directory.  This could result in executing unexpected\n"
400 "commands.\n\n"
401
402 "The command is:  \"%s\"\n\n"
403
404 "Note:  to avoid this in the future:\n"
405 "  execute \"su - root\"  rather than \"su root\".\n");
406    }
407
408    else
409    {
410       msg = (char *)_DTGETMESSAGE(HUSET, 13,
411              "The help volume wanted to execute a command.\n"
412              "For security reasons, automatic command execution is turned off.\n"
413              "The command is:  %s");
414    }
415    fullmsg = (char *) malloc(strlen(msg)+strlen(cmdStr)+30);
416    if (fullmsg) 
417    {
418       if (condition == MISMATCHING_HOME_DIRS)
419          sprintf(fullmsg, msg, current_hd, cmdStr);
420       else
421          sprintf(fullmsg,msg,cmdStr);
422    }
423    else 
424       fullmsg = msg;
425
426    /* create an error dialog, but don't manage it yet */
427    msgDlg = CreateErrorDialog(XtParent(helpWidget),fullmsg);
428    
429    if (msg != fullmsg) free(fullmsg);
430
431    btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_HELP_BUTTON);
432    XtManageChild (btn);           /* re-manage the button */
433
434    /* add the HelpOnHelp callback */
435    pHelpInfo = _DtHelpListAdd(DtHELP_ExecutionPolicy_STR,
436                         helpWidget, pHelpStuff, &pHelpStuff->pHelpListHead);
437    XtAddCallback(btn, XmNactivateCallback, _DtHelpCB, (XtPointer) pHelpInfo);
438
439    return msgDlg;
440 }
441  
442 /*****************************************************************************
443  * Function: _DtHelpErrorDialog
444  *
445  * 
446  * 
447  * Called by:
448  *****************************************************************************/
449 void _DtHelpErrorDialog(
450     Widget                   parent,
451     char *                   message)
452 {     
453   Widget messageDialog;
454
455   messageDialog = CreateErrorDialog(parent,message);
456
457   /* Display help window. This used to be before the call 
458      to add a StructureNotify event handler */
459   XtManageChild (messageDialog);
460 }
461
462
463 /*****************************************************************************
464  * Function: _DtHelpFilterExecCmdStr
465  *
466  *   Args:
467  *    helpWidget:       help widget requesting to exec the command
468  *    pDisplayStuff:    ptr to the DisplayWidget stuff of the help widget
469  *    commandStr:       command string to execute
470  *    ret_cmdStr:       the screened & possibly rewritten command is put here
471  *    ret_invalidAlias:  was the command an invalid alias?
472  *    ret_execPermitted: if executionPolicy permit exec & ret_cmdStr is valid
473  *    ret_queryNeeded:  if executionPolicy requires a query before exec
474  *
475  * Description:
476  *    ret_cmdStr gets memory owned by the calling function; it should be
477  *    freed when no longer needed.  The string will be the same as the
478  *    commandStr if commandStr was not an alias.  If the commandStr
479  *    is an alias and if the alias is defined, the ret_cmdStr will be the
480  *    value of the alias.  If the alias isn't defined, the ret_cmdStr will
481  *    be the default command if available, or the alias name otherwise.
482  * 
483  *    ret_invalidAlias will be True if the alias was undefined and
484  *    no default command was given.
485  *
486  *    ret_execPermitted will be True if executionPolicy is DtHELP_EXECUTE_ALL
487  *    or DtHELP_EXECUTE_QUERY_xxx and ret_cmdStr is valid
488  *
489  *    ret_queryNeeded will be True if executionPoilcy is 
490  *    DtHELP_EXECUTE_QUERY_ALL or if it is DtHELP_EXECUTE_QUERY_UNALIASED 
491  *    and ret_cmdStr did not derive from an alias (i.e. was hardcoded
492  *    in the help volume, not retrieved from a resource).
493  *
494  * Returns:
495  *    True:  if execPermitted and a valid command string
496  *    False: if if execPermitted is False or invalid command string
497  *
498  * Comments:
499  *    This code is written such that we don't need nor want to know
500  *    whether it is a general or quick help widget.
501  * 
502  * Warning:
503  *    command string must be writable; it is written, but left
504  *    unchanged when the function exits.
505  *
506  *****************************************************************************/
507 Boolean _DtHelpFilterExecCmdStr(
508     Widget                   helpWidget,
509     unsigned char            executionPolicy,
510     const char *             commandStr,
511     char * *                 ret_cmdStr,
512     Boolean *                ret_invalidAlias,
513     Boolean *                ret_execPermitted,
514     Boolean *                ret_queryNeeded,
515     char *                   hv_path)     /* Path to the Help Volume */
516 {     
517    char * token;
518    char * tokenEnd;
519    char   tokenEndChar;
520    char * aliasCommand = NULL;
521    Boolean ret;
522
523 #define RN_execAlias "executionAlias"
524 #define RC_execAlias "ExecutionAlias"
525 #define ExecAliasCmd "DtHelpExecAlias"
526
527    /* default values */
528    *ret_cmdStr = NULL;
529    *ret_invalidAlias = False;
530    *ret_execPermitted = False;
531    *ret_queryNeeded = False;
532
533    if (NULL == commandStr) 
534       return False;
535
536   /** ------------------------------------------------------------- *
537    **  If the executionPolicy is query all unaliased (query for all
538    **  execution links that have no execution alias defined), we 
539    **  make an exception:  only query the user for help volumes 
540    **  deemed NOT "trusted".
541    ** ------------------------------------------------------------- */
542
543    if (DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy)
544    {
545       if ( ! (trusted (hv_path)))
546          *ret_queryNeeded = True;   /* Query ALL non-trusted help volumes */
547    }
548    else
549       *ret_queryNeeded = (DtHELP_EXECUTE_QUERY_ALL == executionPolicy);
550
551    /* get whether exec permitted */
552    if (   DtHELP_EXECUTE_ALL == executionPolicy 
553        || DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
554        || DtHELP_EXECUTE_QUERY_ALL == executionPolicy)
555       *ret_execPermitted = True;
556    else
557       *ret_execPermitted = False;
558
559    /* parse apart the command string, looking for DtHelpExecAlias */
560    /* The first call will return true, with the first string */
561    token = (char *) commandStr + DtStrspn((char *)commandStr, " \t");
562    tokenEnd = token + DtStrcspn(token, " \t");
563    tokenEndChar = *tokenEnd;
564    if (tokenEnd) *tokenEnd = EOS;
565
566    if ( NULL == token || _DtHelpCeStrCaseCmpLatin1(token, ExecAliasCmd) != 0 )
567    {
568       /*** the command is not an alias; proceed using execution Policy ***/
569    
570       *tokenEnd = tokenEndChar;       /* restore the string */
571    
572       *ret_cmdStr = strdup(commandStr);
573       ret = *ret_execPermitted;
574
575       return ret;                             /* RETURN ret */
576    }
577
578
579    /**** It's an alias; get it , look it up, and return it ****/
580
581    *tokenEnd = tokenEndChar;       /* restore the string */
582
583    /* get the next token */
584    token = tokenEnd + DtStrspn(tokenEnd, " \t");
585    tokenEnd = token + DtStrcspn(token, " \t");
586    tokenEndChar = *tokenEnd;
587    if (tokenEnd) *tokenEnd = EOS;
588
589    if ( token )
590    {
591       Display * dpy = XtDisplay(helpWidget);
592       XrmDatabase appDb = XrmGetDatabase(dpy);
593       XrmValue value;
594       String appname, appclass;
595       char * reptype;
596       char *rsrc_name, *rsrc_class;
597
598       rsrc_name = XtMalloc(200);
599       rsrc_class = XtMalloc(200);
600
601       XtGetApplicationNameAndClass(dpy,&appname,&appclass);
602
603       /* query the application's database for the alias command */
604       /* build alias resource class and resource */
605       /* e.g. App.executionAlias.<alias> */
606       sprintf(rsrc_name,"%s.%s.%s",appclass, RN_execAlias,token);
607       /* e.g. App.ExecutionAlias.<alias> */
608       sprintf(rsrc_class,"%s.%s.%s",appclass, RC_execAlias,token);
609
610       /* Get alias command */
611       if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
612          aliasCommand = value.addr;
613
614       /* build alias resource name and resource */
615       /* e.g. app.executionAlias.<alias> */
616       sprintf(rsrc_name,"%s.%s.%s",appname, RN_execAlias,token);
617       /* e.g. app.ExecutionAlias.<alias> */
618       sprintf(rsrc_class,"%s.%s.%s",appname, RC_execAlias,token);
619
620       /* Get alias command and override class with instance, if defined */
621       if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
622          aliasCommand = value.addr;
623
624       if (rsrc_name) XtFree(rsrc_name);
625       if (rsrc_class) XtFree(rsrc_class);
626    }  /* if alias token */
627    else 
628    {
629       token = "";
630    }
631
632    if (tokenEnd) *tokenEnd = tokenEndChar; /* restore the string */
633
634    /* alias was defined */
635    if (aliasCommand) 
636    {
637       *ret_cmdStr = strdup(aliasCommand);
638       /* see if query needed; is not if policy is query_unaliased or all */
639       *ret_queryNeeded = !(   DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
640                            || DtHELP_EXECUTE_ALL == executionPolicy);
641       ret = *ret_execPermitted;
642    }
643    else /* the alias wasn't defined */
644    {
645       char * aliasToken = token;   /* token currently pts to alias */
646
647       /* look for a default command */
648       /* get the next token */
649       token = tokenEnd + DtStrspn(tokenEnd, " \t");
650       tokenEnd = token + DtStrcspn(token, " \t");
651
652       if (token == tokenEnd)
653       {  /* alias wasn't defined and no default command */
654          *ret_cmdStr = strdup(aliasToken);
655          *ret_invalidAlias = True;
656          *ret_queryNeeded = False;  /* no query needed on invalid alias, ever */
657          *ret_execPermitted = False; /* can't exec an invalid alias */
658          ret = False;
659       }
660       else 
661       {  /* alias wasn't defined but a default command */
662          /* query is whatever was determined earlier */
663          *ret_cmdStr = strdup(token);
664          ret = *ret_execPermitted;
665       }
666    }
667
668    return ret;                          /* RETURN ret */
669 }
670
671 /*********************************************************************
672  * _DtHelpCeWaitAndProcessEvents
673  *
674  *  Purpose:
675  *    _DtHelpCeWaitAndProcessEvents will process events and call
676  *    the waitProc until waitProc returns False.   This function
677  *    is useful to put up modal dialogs that must be reponded to 
678  *    in the midst of executing code that must remain on the call stack.
679  *
680  *  Warning:
681  *    This function should only be used on modal dialogs.
682  *
683  *********************************************************************/
684
685 void
686 _DtHelpCeWaitAndProcessEvents (
687     Widget             w,
688     _DtHelpCeWaitProc  waitProc,
689     void *             clientData)
690 {
691     Boolean waitFlag;
692     XEvent   event;
693     XtAppContext app;
694
695     app = XtWidgetToApplicationContext(w);
696     do 
697     {
698 #ifndef XTHREADS
699         XtAppNextEvent(app,&event);
700         XtDispatchEvent(&event);
701 #else
702         XtInputMask mask;
703
704         while (!(mask = XtAppPending(app)))
705           ;   /* Busy waiting - so we don't lose our Lock! */
706         
707         if (mask & XtIMXEvent)         /* We have an XEvent */
708           {
709             /* Get the XEvent - we know it's there! Note that XtAppNextEvent
710                would also process timers/alternate inputs.
711              */
712             XtAppNextEvent(app, &event);  /* No blocking, since an event is ready */
713             XtDispatchEvent(&event);
714           }
715         else   /* Not a XEvent, it's an alternate input/timer event */
716           {
717             XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
718           }
719 #endif /* XTHREADS */
720         /* check to see if we're done waiting */
721         waitFlag = (*waitProc)(w, clientData); 
722     } while (waitFlag);
723 }
724
725 /*****************************************************************************
726 * Function: WaitForBtnActivatedCB
727 *
728 * Purpose:
729 *    Treats the 'clientData' as a pointer to an integer
730 *    and turns its value into a Boolean
731 *
732 * Returns:  *(int *)clientData < 0
733 *****************************************************************************/
734 static Boolean 
735 WaitForBtnActivatedCB(
736     Widget w,
737     void * clientData)
738 {
739     return (*(int *)clientData < 0);
740    /* True=keep waiting; False= wait no longer */
741 }
742
743
744 typedef struct ModalMsgDlgCBStruct
745 {
746   Widget msgDlg;
747   Widget okBtn;
748   Widget cancelBtn;
749   Widget helpBtn;
750   int    activatedBtnId;
751 } ModalMsgDlgCBStruct;
752
753 /*****************************************************************************
754 * Function: IdentifyActivatedBtnCB
755 *
756 * Purpose:
757 *    Treats the 'clientData' as a pointer to an integer.
758 *    Waits for the value pointed to by clientData to be >= 0.
759 *
760 *****************************************************************************/
761 static void 
762 IdentifyActivatedBtnCB(
763     Widget w,
764     XtPointer clientData,
765     XtPointer callData)
766 {
767    ModalMsgDlgCBStruct * pMd = (ModalMsgDlgCBStruct *) clientData;
768     
769    /* w must be a XmMessageDialog widget */
770    if (pMd->okBtn == w) 
771       { pMd->activatedBtnId = XmDIALOG_OK_BUTTON; return; /* RETURN */ }
772    if (pMd->cancelBtn == w) 
773       { pMd->activatedBtnId = XmDIALOG_CANCEL_BUTTON; return; /* RETURN */ }
774    if (pMd->helpBtn == w) 
775       { pMd->activatedBtnId = XmDIALOG_HELP_BUTTON; return; /* RETURN */ }
776    pMd->activatedBtnId = -1;      /* unknown button */
777 }
778     
779
780 /*****************************************************************************
781  * Function: _DtHelpFilterExecCmd
782  *
783  *   Args:
784  *    helpWidget:       help widget requesting to exec the command
785  *    command:          command string to execute
786  *    execPolicy:       current policy setting
787  *    useQueryDialog:   use a dialog to query user whether to exec, if not allowed
788  *    pHelpStuff:       ptr to the HelpStuff structure of the help widget
789  *    ret_filteredCmdStr: filtered command string
790  * 
791  * Returns:
792  *    0: no error; filteredCmdStr can be exec'd
793  *   -1: error: either internal or executionPolicy denies exec; 
794  *       filteredCmdStr is NULL
795  *
796  * Purpose:
797  *    This function filters an execution command string.  This can
798  *    occur in several ways.  In all cases, the command string is
799  *    supports command alias replacement.  If the final outcome
800  *    is that execution is permitted, the returned string is
801  *    is the command string to execute.  If execution is not
802  *    permitted, the return string is a NULL pointer. 
803  *
804  *    Filtering of the command occurs as follows.
805  *    If executionPolicy permits execution, only alias replacement occurs.
806  *    If executionPolicy does restrict execution and a
807  *    dialog is requested, then a modal dialog is posted and the
808  *    user can decide whether to execute or not.
809  *    If a dialog is not requested, the return string is NULL.
810  *
811  * Comments:
812  *    This code is written such that we don't need nor want to know
813  *    whether it is a general or quick help widget.
814  * 
815  * Warning:
816  *    command string must be writable; it is written, but left
817  *    unchanged whent the function exits.
818  *
819  *    This operation is synchronous, meaning that, if a dialog is
820  *    posted, it is a modal dialog and the function won't return 
821  *    until the user selects a button.
822  *
823  * Called by:
824  *****************************************************************************/
825 int _DtHelpFilterExecCmd(
826     Widget        helpWidget,
827     const char *  commandStr,
828     unsigned char executionPolicy,
829     Boolean       useQueryDialog,
830     _DtHelpCommonHelpStuff * pHelpStuff,
831     char * *      ret_filteredCmdStr,
832     char *                   hv_path)
833 {     
834    ModalMsgDlgCBStruct msgDlgCBStruct;
835    Boolean goodCmd;
836    Boolean invalidAlias;
837    Boolean execPermitted;
838    Boolean queryNeeded;
839    Widget  msgDlg;
840    char *  filteredCmdStr = NULL;
841    Arg     args[5];
842    int     n;
843    XmString labelString;
844    XmString labelString2;
845    Widget  noexecBtn;
846    Widget  execBtn;
847    Cursor  cursor;
848
849    goodCmd = _DtHelpFilterExecCmdStr(helpWidget, executionPolicy, 
850                  commandStr, &filteredCmdStr, &invalidAlias, 
851                  &execPermitted, &queryNeeded, hv_path);
852
853    /* if permissions allow immediate execution, do so */
854    if (execPermitted && False == queryNeeded)
855    {
856       *ret_filteredCmdStr = filteredCmdStr;
857       return 0;                           /* RETURN ok */
858    }
859
860    if (False == useQueryDialog)
861    {
862       *ret_filteredCmdStr = NULL;
863       return -1;                          /* RETURN error */
864    }
865
866    /* create the dialog, but don't yet manage it */
867    msgDlg =  CreateExecErrorDlg(helpWidget,filteredCmdStr,
868                         invalidAlias,pHelpStuff, NO_CONDITION, "");
869
870    /* if a bad alias or no exec permitted, 
871       don't need to wait for a response; dlg has close & Help */
872    if (False == execPermitted || False == queryNeeded)  
873    {
874       XtManageChild(msgDlg);                 /* manage modeless dialog */
875       *ret_filteredCmdStr = NULL;            /* don't execute */
876       XtFree(filteredCmdStr);
877       return -1;                            /* RETURN error */
878    }
879
880    /* if got this far, query is needed;make the dialog include 
881       Execute Anyway and Don't Execute buttons */
882
883    /* give the right title to the buttons */
884    labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
885                    (HUSET, 10,"Execute Anyway")));
886    /* give the right title to the Cancel button */
887    labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
888                    (HUSET, 11,"Don't Execute")));
889    n = 0;
890    XtSetArg (args[n], XmNokLabelString, labelString);   n++;
891    XtSetArg (args[n], XmNcancelLabelString, labelString2);              n++;
892    XtSetArg (args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
893    XtSetValues(msgDlg,args,n);
894    XmStringFree(labelString);
895    XmStringFree(labelString2);
896
897    /* We put an activate callback on the DontExecute and ExecuteAnyway buttons 
898       and wait until a button is pressed.  */
899    noexecBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_CANCEL_BUTTON);
900    XtAddCallback(noexecBtn, XmNactivateCallback, 
901                              IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
902
903    execBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
904    XtManageChild (execBtn);           /* re-manage the button */
905    XtAddCallback(execBtn, XmNactivateCallback, 
906                              IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
907    
908    /* fill out the CB information structure used by IdentifyActivatedBtnCB */
909    msgDlgCBStruct.msgDlg = msgDlg;
910    msgDlgCBStruct.okBtn = execBtn;
911    msgDlgCBStruct.cancelBtn = noexecBtn;
912    msgDlgCBStruct.activatedBtnId = -1;
913
914    /* Display message dialog */
915    XtManageChild (msgDlg);
916
917    /*
918     * turn on the modal dialog indicator
919     */
920    _DtHelpTurnOnNoEnter(helpWidget);
921
922    /* wait until 'msgDlgCBStruct.activatedBtnId' has a value >= 0 */
923    /* this occurs when the user responds to the msg dialog */
924    _DtHelpCeWaitAndProcessEvents(msgDlg, 
925               WaitForBtnActivatedCB, &msgDlgCBStruct.activatedBtnId);
926
927    /*
928     * turn off the modal dialog indicator
929     */
930    _DtHelpTurnOffNoEnter(helpWidget);
931
932    /* no need to destroy msgDlg; it has a closeCallback to do that */
933
934    /* act based on which button was activated */
935    if (msgDlgCBStruct.activatedBtnId == XmDIALOG_OK_BUTTON)
936    {
937       *ret_filteredCmdStr = filteredCmdStr;  /* do execute command */
938       return 0;                             /* RETURN ok */
939    }
940    else
941    {
942       *ret_filteredCmdStr = NULL;            /* don't execute */
943       XtFree(filteredCmdStr);
944       return -1;                            /* RETURN error */
945    }
946 }
947
948 /*****************************************************************************
949  * Function: _DtHelpExecFilteredCmd
950  *
951  *   Args:
952  *    helpWidget:       help widget requesting to exec the command
953  *    command:          command string to execute
954  *    modal:            is the execution modal (sync) or modeless (async)
955  *    helpLocationId:   helpOnHelp file location for Help btn in error dialog
956  *    pDisplayStuff:    ptr to the DisplayWidget stuff of the help widget
957  *    pHelpStuff:       ptr to the CommonHelp stuff of the help widget
958  * 
959  * Comments:
960  *    This code is written such that we don't need nor want to know
961  *    whether it is a general or quick help widget.
962  * 
963  * Warning:
964  *    command string must be writable; it is written, but left
965  *    unchanged whent the function exits.
966  *
967  *    At the moment, the helpLocationId is ignored, and the
968  *    help location is hardwired to DtHELP_ExecutionPolicy_STR
969  *    in CreateExecErrorDialog().
970  * Called by:
971  *****************************************************************************/
972 void _DtHelpExecFilteredCmd(
973     Widget                   helpWidget,
974     char *                   commandStr,
975     char *                   helpLocationId,
976     _DtHelpDisplayWidgetStuff * pDisplayStuff,
977     _DtHelpCommonHelpStuff * pHelpStuff)
978 {     
979    Boolean goodCmd;
980    Boolean invalidAlias;
981    Boolean execPermitted;
982    Boolean queryNeeded;
983    char *  filteredCmdStr = NULL;
984    ExecContext * execContext;
985    DtHelpListStruct *pHelpInfo;
986    XmString labelString;
987    XmString labelString2;
988    Widget   msgDlg;
989    Widget   btn;
990    int     n;   
991    Arg     args[5];
992    char    *hv_path=NULL;
993
994    uid_t         user;
995    char          *home_dir;
996    Boolean        diff_home_dirs=False; /* True ==> $HOME is different from */
997                                         /* root user's $HOME directory      */
998 /*
999    getpw{uid,nam}_r routines fail on IBM platform when search password info
1000    via NIS (yellow pages). However, in the case of root, we'll assume that
1001    the password info is in /etc/passwd. If this is not the case, the
1002    following code can fail on IBM platform when XTHREADS and XUSE_MTSAFE_API
1003    are defined.
1004 */
1005    _Xgetpwparams pwd_buf;
1006    struct passwd * pwd_ret;
1007
1008   /** -------------------------------------------------------------- *
1009    **  If we're running as the root user
1010    **   o check if the value of the HOME env var matches 
1011    **     root's home directory (defined by /etc/passwd).
1012    **   o If they do not match, then present a dialog 
1013    **     alerting the user of this, along with the command to 
1014    **     invoke.
1015    ** -------------------------------------------------------------- */
1016
1017    if ( (user=getuid()) == ROOT_USER)
1018    {
1019       home_dir = getenv ("HOME");
1020
1021       if (home_dir != NULL && strlen(home_dir) >= (size_t) 1)
1022       {
1023          if (((pwd_ret = _XGetpwuid(user, pwd_buf)) != NULL)
1024                          && (strcmp(home_dir, pwd_ret->pw_dir)))
1025          {
1026             diff_home_dirs = True;
1027          }
1028       }
1029    }
1030
1031    hv_path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, pDisplayStuff->helpVolume,
1032                                _DtHelpFileSuffixList, False, R_OK);
1033
1034    /* The desired and intended behaviour is to use _DtHelpFilterExecCmdStr(), but
1035       the other code is left here, should a change be wished. */
1036 #if 1
1037    /* This function runs a filter for policy and alias but posts no dialog  */
1038    goodCmd=_DtHelpFilterExecCmdStr(helpWidget, 
1039               pDisplayStuff->executionPolicy, commandStr, 
1040                &filteredCmdStr, &invalidAlias, &execPermitted, &queryNeeded, hv_path);
1041 #else
1042     /* This function does an synchronous filter; i.e. the code runs a filter
1043        for policy and alias, and if policy denies exec and the command is
1044        valid, then posts a modal dialog and waits for the user to decide
1045        what to do before returning. */
1046    goodCmd = _DtHelpFilterExecCmd(helpWidget, commandStr, 
1047                                   pDisplayStuff->executionPolicy, True, 
1048                                   pHelpStuff, &filteredCmdStr, hv_path);
1049    execPermitted = (goodCmd == 0);  /* convert an error int into a Boolean */
1050    queryNeeded =    
1051           ((   pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_ALL)
1052             || (pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_UNALIASED))
1053        && goodCmd;
1054 #endif
1055
1056    /* if permissions allow immediate execution, do so */
1057    if (execPermitted && False == queryNeeded  && diff_home_dirs == False)
1058    {
1059       (void) _DtHelpExecProcedure (pHelpStuff->pDisplayArea, filteredCmdStr);
1060       free(filteredCmdStr);
1061       return;                           /* RETURN */
1062    }
1063
1064    /* this traps bad cmds and also use of the synchronous filter call */
1065    if (NULL == filteredCmdStr) return;       /* RETURN */
1066
1067    /*** Create a modeless dialog to inform the user of the problem
1068         and possibly allow them to execute the command anyway. ***/
1069
1070    /* create the dialog, but don't yet manage it */
1071    if ( diff_home_dirs == True)
1072      msgDlg =  CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff, 
1073                                   MISMATCHING_HOME_DIRS, home_dir );
1074    else
1075      msgDlg =  CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff, 
1076                                   NO_CONDITION, "");
1077
1078
1079    /*** setup ExecuteAnyway and Help buttons ***/
1080
1081    if ( (diff_home_dirs == True)  
1082                      ||
1083         (queryNeeded && execPermitted) )
1084    {
1085       /* give the right title to the buttons */
1086       labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1087                          (HUSET, 10,"Execute Anyway")));
1088       /* give the right title to the Cancel button */
1089       labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1090                       (HUSET, 11,"Don't Execute")));
1091       n = 0;
1092       XtSetArg (args[n], XmNokLabelString, labelString);        n++;
1093       XtSetArg (args[n], XmNcancelLabelString, labelString2);   n++;
1094       XtSetValues(msgDlg,args,n);
1095       XmStringFree(labelString);
1096       XmStringFree(labelString2);
1097    
1098       btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
1099       XtManageChild (btn);           /* re-manage the button */
1100    
1101       /* add the ExecuteContextCB() client-data and callback */
1102       execContext = malloc(sizeof(ExecContext));
1103       if (execContext) 
1104       { 
1105          execContext->command = filteredCmdStr;
1106          execContext->pDisplayArea = pHelpStuff->pDisplayArea;
1107          XtAddCallback(btn, XmNactivateCallback, 
1108                              ExecuteContextCB, (XtPointer) execContext);
1109       }
1110       else
1111       {
1112          free(filteredCmdStr);
1113       }
1114    }  /* cmd wasn't an alias */
1115    else
1116    {
1117       free(filteredCmdStr);
1118    }
1119
1120    /* Display message dialog */
1121    XtManageChild (msgDlg);
1122
1123    /* RETURN */
1124 }
1125
1126
1127
1128 /*****************************************************************************
1129  * Function: LocateWidgetId()
1130  *
1131  *   
1132  *
1133  * Called by: 
1134  *****************************************************************************/
1135 static Widget  LocateWidgetId(
1136     Display          *dpy,
1137     int              screen,
1138     int             *statusRet,
1139     Widget           shellWidget,
1140     Cursor           cursorIn)
1141 {
1142     static Cursor    DfltOnItemCursor = NULL;
1143     Widget           widget;
1144     Widget           child;
1145     CompositeWidget  comp_widget;
1146     int              status;
1147     Cursor           cursor;
1148     XEvent           event;
1149     int              x,y;
1150     int              i;
1151     Window           parent;
1152     Window           sub;
1153     Window           target_win;
1154     int              new_x, new_y;
1155     int              offset;
1156     KeySym           keySym;
1157     Boolean          notDone=TRUE;
1158
1159  
1160     /* Make the target cursor */
1161     if (cursorIn != NULL)
1162         cursor = cursorIn;
1163     else
1164 #if 0
1165         cursor = XCreateFontCursor (dpy, XC_question_arrow);
1166 #else
1167     {
1168         _DtHelpProcessLock();
1169         if (NULL == DfltOnItemCursor)
1170         {
1171             char        *bits;
1172             char        *maskBits;
1173             unsigned int width;
1174             unsigned int height;
1175             unsigned int xHotspot;
1176             unsigned int yHotspot;
1177             Pixmap       pixmap;
1178             Pixmap       maskPixmap;
1179             XColor       xcolors[2];
1180    
1181             width    = onitem32_width;
1182             height   = onitem32_height;
1183             bits     = (char *) onitem32_bits;
1184             maskBits = (char *) onitem32_m_bits;
1185             xHotspot = onitem32_x_hot;
1186             yHotspot = onitem32_y_hot;
1187     
1188             pixmap = XCreateBitmapFromData (dpy,
1189                          RootWindowOfScreen(XtScreen(shellWidget)), bits,
1190                          width, height);
1191     
1192     
1193             maskPixmap = XCreateBitmapFromData (dpy,
1194                          RootWindowOfScreen(XtScreen(shellWidget)), maskBits,
1195                          width, height);
1196     
1197             xcolors[0].pixel = BlackPixelOfScreen(ScreenOfDisplay(dpy, screen));
1198             xcolors[1].pixel = WhitePixelOfScreen(ScreenOfDisplay(dpy, screen));
1199     
1200             XQueryColors(dpy,
1201                          DefaultColormapOfScreen(ScreenOfDisplay(dpy, screen)), 
1202                          xcolors, 
1203                          2);
1204     
1205             DfltOnItemCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
1206                                           &(xcolors[0]), &(xcolors[1]),
1207                                           xHotspot, yHotspot);
1208             XFreePixmap (dpy, pixmap);
1209             XFreePixmap (dpy, maskPixmap);
1210         }  /* if dflt cursor not yet created */
1211         cursor = DfltOnItemCursor;
1212         _DtHelpProcessUnlock();
1213     }  /* if to use the standard cursor */
1214 #endif
1215
1216
1217     /* Grab the pointer using target cursor, letting it roam all over */
1218     status = XtGrabPointer (shellWidget, TRUE,
1219                            ButtonPressMask|ButtonReleaseMask, GrabModeAsync,
1220                            GrabModeAsync, None, cursor, CurrentTime);
1221     if (status != GrabSuccess)
1222       {
1223         XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 3,
1224               "Internal Error: Could not grab the mouse\nDtHelpReturnSelectedWidget aborted.\n"));
1225         *statusRet = DtHELP_SELECT_ERROR;
1226         return(NULL);
1227       }
1228
1229
1230
1231     /* Grab the Keyboard so we can catch the ESC button press */
1232     status = XtGrabKeyboard(shellWidget, False,
1233                            GrabModeAsync, GrabModeAsync, CurrentTime);
1234     if (status != GrabSuccess)
1235       {
1236         
1237         XtUngrabPointer (shellWidget, CurrentTime);
1238         XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 4,
1239         "Internal Error: Could not grab the keyboard\nDtHelpReturnSelectedWidget() aborted.\n"));
1240         *statusRet = DtHELP_SELECT_ERROR;
1241         return(NULL);
1242       }
1243
1244     /* We are ok so let the user select a window... */
1245     while (notDone)
1246     {
1247       XtAppContext app = XtWidgetToApplicationContext(shellWidget);
1248       /* allow one more event */
1249 #ifndef XTHREADS
1250       XtAppNextEvent(app, &event);
1251 #else
1252       XtInputMask mask;
1253
1254       while (!(mask = XtAppPending(app)))
1255           ;   /* Busy waiting - so we don't lose our Lock! */
1256         
1257       if (!(mask & XtIMXEvent)) /* Not a XEvent, it's an alternate input/timer event */
1258             XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
1259       else   /* We have an XEvent */
1260         {
1261             /* Get the XEvent - we know it's there! Note that XtAppNextEvent
1262                would also process timers/alternate inputs.
1263              */
1264             XtAppNextEvent(app, &event);
1265 #endif /* XTHREADS */
1266       widget = XtWindowToWidget(dpy, event.xany.window);
1267       
1268       switch (event.type) {
1269             case ButtonPress:
1270                 break;
1271             case ButtonRelease:
1272                 notDone = FALSE;
1273                 break;
1274             case KeyPress:
1275                 /* Look for ESC key press and stop if we get one */
1276                 if (event.xkey.state & ShiftMask)
1277                   offset = 1;
1278                 else
1279                   offset = 0;
1280                 
1281                 keySym = XLookupKeysym((XKeyEvent *)&event, offset);
1282                 if (keySym == XK_Escape)
1283                   {
1284                     XtUngrabKeyboard (shellWidget, CurrentTime);
1285                     XtUngrabPointer (shellWidget, CurrentTime);
1286                     *statusRet = DtHELP_SELECT_ABORT;
1287                     return(NULL);
1288                   }
1289             default:
1290                   XtDispatchEvent(&event);
1291       }
1292 #ifdef XTHREADS
1293         }    /* if */
1294 #endif
1295     } 
1296
1297     XtUngrabKeyboard (shellWidget, CurrentTime);      /* Done with keyboard */
1298     XtUngrabPointer (shellWidget, CurrentTime);      /* Done with pointer */
1299
1300     /* If its null then the user selected some area outside our window(s) */
1301     if (widget == shellWidget)
1302       {
1303         *statusRet = DtHELP_SELECT_INVALID;
1304         return (NULL);
1305       }
1306     if (!XtIsComposite (widget))
1307       {
1308         *statusRet = DtHELP_SELECT_VALID;
1309         return (widget);
1310       }
1311     
1312     /* Get the x and y and parent relative to the current window */
1313     parent = RootWindow(dpy, screen);
1314     target_win = XtWindow(widget);
1315     x = event.xbutton.x_root;
1316     y = event.xbutton.y_root;
1317
1318     XTranslateCoordinates(dpy, parent, target_win, x, y,
1319                              &new_x, &new_y, &sub);
1320     x = new_x;
1321     y = new_y;
1322
1323     comp_widget = (CompositeWidget)widget;
1324
1325     /*  look for gadgets at this point  */
1326     for (i = 0; i < comp_widget->composite.num_children; i++) {
1327         child = comp_widget->composite.children[i];
1328         /* put in check for only managed widgets here */
1329          if(XtIsManaged(child))
1330            if (PT_IN_CHILD (x, y, child))
1331               {
1332                 *statusRet = DtHELP_SELECT_VALID;
1333                 return (child);
1334               }
1335     }
1336
1337     *statusRet = DtHELP_SELECT_VALID;
1338     return (widget);
1339 }
1340
1341
1342
1343 \f
1344 /*****************************************************************************
1345  * Function:       Boolean RememberDir(String path)
1346  *
1347  * Parameters:          path            Specifies the path to check.
1348  *
1349  * Return Value:        Boolean         if the path name is good.
1350  *
1351  * Description: Use the directory caching mechanism to improve performance
1352  *              by remembering the directories that have already been
1353  *              stat'ed.
1354  *
1355  *****************************************************************************/
1356 static  Boolean
1357 RememberDir(String path)
1358 {
1359     int          result = 0;
1360     char        *ptr;
1361     struct stat  buf;
1362
1363     if (path == NULL || *path == '\0')
1364         return False;
1365
1366     if (_DtHelpCeStrrchr(path, "/", MB_CUR_MAX, &ptr) == 0 && ptr != path)
1367       {
1368         *ptr   = '\0';
1369         result = _DtHelpCeCheckAndCacheDir(path);
1370         *ptr   = '/';
1371       }
1372     if (result == 0 && access(path, R_OK) == 0 &&
1373                                 stat(path, &buf) == 0 && S_ISREG(buf.st_mode))
1374         return True;
1375
1376     return False;
1377 }
1378
1379 /*****************************************************************************
1380  * Function:       Boolean _DtHelpResolvePathname(
1381  *
1382  *
1383  * Parameters:     
1384  *
1385  * Return Value:    Boolean.
1386  *
1387  *
1388  * Description: _DtHelpResolvePathname attempts to validate and expand a path
1389  *              to a Cache Creek help access file.
1390  *
1391  *****************************************************************************/
1392 Boolean _DtHelpResolvePathname(
1393    Widget       widget,
1394    char * *     io_fileName,
1395    _DtHelpVolumeHdl * io_volumeHandle,
1396    char *       sysVolumeSearchPath,
1397    char *       userVolumeSearchPath)
1398 {
1399    String           newPath = NULL;
1400
1401    /* try to locate file and its entry, if present */
1402    newPath = _DtHelpFileLocate(DtHelpVOLUME_TYPE, *io_fileName,
1403                                   _DtHelpFileSuffixList,False,R_OK);
1404
1405    /* If we found a valid file let's do some set up here */
1406
1407    if (newPath != NULL)       /* We have a valid volume file so open it */
1408    {
1409        /* Close the current one if we have one open */
1410        if (*io_volumeHandle != NULL)
1411            _DtHelpCloseVolume(*io_volumeHandle);
1412
1413        /* Open the help volume file and save the handle id */
1414        if (_DtHelpOpenVolume(newPath,io_volumeHandle) >= 0)
1415        {
1416            /* Copy the expanded file location path */
1417            XtFree(*io_fileName);
1418            *io_fileName = newPath;
1419
1420            return(TRUE);
1421        }
1422        else
1423        {
1424            /* ERROR; leave io_fileName untouched on error
1425             * We used to set it to null here now we just return what came in
1426             */
1427            /* later NOTE: this seems strange, since we have closed the
1428               old volume, invalidating io_fileName */
1429            XtFree(newPath);
1430            XmeWarning(widget,(char*)UtilMessage2); 
1431            return (FALSE);
1432        }      
1433    }
1434    else                       /* We have a non-valid path */
1435    {
1436        /* ERROR; leave io_fileName untouched on error
1437         * We used to set it to null here now we just return what came in
1438         */
1439
1440        XmeWarning(widget,(char*)UtilMessage0);        
1441        return (FALSE);
1442    }
1443
1444 }
1445
1446
1447
1448
1449 \f
1450 /*****************************************************************************
1451  * Function:       Boolean _DtHelpExpandHelpVolume(DtHelpDialogWidget nw);
1452  *
1453  *
1454  * Parameters:     nw  Specifies the current help dialog widget.
1455  *
1456  * Return Value:    Boolean.
1457  *
1458
1459  * Description: _DtHelpExpandHelpVolume looks for a $LANG variable in the 
1460  *              helpAccesFile string and if found, replaces it with the 
1461  *              current lang variable.
1462  *
1463  *****************************************************************************/
1464 Boolean _DtHelpExpandHelpVolume(
1465    Widget                      w,
1466    _DtHelpDisplayWidgetStuff * display,
1467    _DtHelpCommonHelpStuff *    help,
1468    _DtHelpPrintStuff *         print)
1469 {
1470   Boolean validTopic = FALSE;
1471   Boolean validPath  = FALSE;
1472   char  *topLevelId;
1473
1474   /* Free the old, and Copy the new volumeHandle to printVolume varialbe */
1475   if (print->printVolume != NULL)
1476      XtFree(print->printVolume);
1477
1478   print->printVolume = XtNewString(display->helpVolume);     
1479
1480   validPath = _DtHelpResolvePathname((Widget)w,
1481                                 &print->printVolume,
1482                                 &display->volumeHandle,
1483                                 help->sysVolumeSearchPath,
1484                                 help->userVolumeSearchPath);
1485
1486  
1487   /* Check to see that we resolved our path correctly */
1488   if (!validPath)
1489     return (FALSE);                     /* RETURN */
1490   else
1491     {
1492
1493        /* The following routine will malloc memory for the topLevelId
1494         * variable, so we must free our current version first.
1495         */
1496        XtFree(help->topLevelId);
1497
1498        /* Assign our top level topic for this help access file */
1499        validTopic = _DtHelpCeGetTopTopicId(display->volumeHandle, &topLevelId);
1500
1501        if (!validTopic)
1502          {
1503            /* Bad top level topic */
1504            help->topLevelId = NULL;
1505            return(FALSE);
1506          }
1507        else   
1508          {
1509             /* recall that the topLevelId/File vars are malloc'd */
1510             help->topLevelId = topLevelId;
1511             return(TRUE); 
1512          }
1513     }
1514 }
1515
1516 \f
1517 /*****************************************************************************
1518  * Function:       char *_DtHelpParseIdString(char * specification);
1519  *
1520  *
1521  * Parameters:     specification  Specifies an author defined help topic.
1522  *
1523  * Return Value:    Void.
1524  *
1525  * Description:   This function copies the locationId portion of the 
1526  *                specification and returns it to the calling routine.
1527  *
1528  *****************************************************************************/
1529 char *_DtHelpParseIdString(
1530    char *specification)
1531 {
1532
1533   char *pAccessFile = NULL;
1534   char *tmpSpec=NULL;
1535   char *returnStr=NULL;
1536   char *strtok_ptr;
1537
1538   tmpSpec = XtNewString(specification);
1539
1540   
1541   /* First look for a blank in the specification.  This will signify that
1542    * we have a HelpAccessFile as part of the specification.
1543    */
1544   
1545   /* The first call will return true, with the first string */
1546   pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1547   returnStr = XtNewString(pAccessFile);
1548
1549   /* The second call will return true only if we have another string */
1550   pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1551
1552   if (pAccessFile != NULL)
1553     {
1554       /* We have a helpAccessFile in our specification */
1555            
1556       XtFree(returnStr);
1557    
1558       returnStr = XtNewString(pAccessFile);
1559       XtFree(tmpSpec);
1560       return(returnStr);
1561
1562     }
1563   else
1564     {
1565       /* We don't have a helpAccessFile as part of the specificaiton
1566        * so we just return our locationId.
1567        */
1568        XtFree(tmpSpec);
1569        return (returnStr);
1570      }
1571
1572 }
1573
1574
1575 \f
1576 /*****************************************************************************
1577  * Function:       char *_DtHelpParseAccessFile(char * specification);
1578  *
1579  *
1580  * Parameters:     specification  Specifies an author defined help topic.
1581  *
1582  * Return Value:    Void.
1583  *
1584  * Description:   This function copies the helpAccessFile portion of the 
1585  *                specification and returns it to the calling routine.
1586  *
1587  *****************************************************************************/
1588 char *_DtHelpParseAccessFile(
1589    char *specification)
1590 {
1591   char *pAccessFile = NULL;
1592   char *tmpSpec=NULL;
1593   char *returnStr=NULL;
1594   char *strtok_ptr;
1595
1596   tmpSpec = XtNewString(specification);
1597
1598   
1599   /* First look for a blank in the specification.  This will signify that
1600    * we have a HelpAccessFile as part of the specification.
1601    */
1602   
1603   /* The first call will return true, with the first string */
1604   pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1605   returnStr = XtNewString(pAccessFile);
1606
1607   /* The second call will return true only if we have another string */
1608   pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1609
1610   if (pAccessFile != NULL)
1611     {
1612       /* We have a helpAccessFile in our specification */
1613            
1614
1615       /* If we have an accessFile, but it's not a full path, then we
1616        * must get the full path from the reg file.
1617        */
1618       XtFree(tmpSpec);
1619       return(returnStr);
1620
1621     }
1622   else
1623     {
1624       /* We don't have a helpAccessFile as part of the specificaiton
1625        * so return NULL.
1626        */
1627        XtFree(returnStr);
1628        XtFree(tmpSpec);
1629        return (NULL);
1630      }
1631
1632 }
1633
1634
1635
1636
1637
1638
1639
1640
1641 /*****************************************************************************
1642  * Function:     DtHelpReturnSelectedWidgetId 
1643  *
1644  * Parameters:   parent      Specifies the widget ID to use as the bases of 
1645  *                           interaction, usually a top level shell.
1646  *
1647  *               cursor      Specifies the cursor to be used for the pointer
1648  *                           during the interaction.  If a value of NULL is 
1649  *                           used this function will use a default cursor
1650  *                           value.
1651  *
1652  *               widget      This is the return value (e.g. the selected 
1653  *                           widget).  A value of NULL is returned on error.
1654  *
1655  * Return Value:  Status: (-1,0 or 1).
1656  *
1657  * Purpose: Allows developers to get the widget ID for any widget in their UI
1658  *          that the user has selected via the pointer.  This function will
1659  *          cause the cursor to change and allow a user to select an item in 
1660  *          the UI.
1661  *
1662  *****************************************************************************/
1663 int DtHelpReturnSelectedWidgetId(
1664     Widget parent,
1665     Cursor cursor,
1666     Widget  *widget)
1667 {
1668
1669
1670  Display   *dpy;
1671  int       screen;  
1672  Widget    selectedItem;
1673  int       status=DtHELP_SELECT_ERROR;
1674  Screen    *retScr;
1675  int       result;
1676  _DtHelpWidgetToAppContext(parent);
1677
1678   _DtHelpAppLock(app);
1679   /* Setup some needed variables */
1680   dpy = XtDisplay(parent);
1681   retScr = XtScreen(parent);
1682  
1683   screen = XScreenNumberOfScreen(retScr);
1684  
1685   /* refresh the display */
1686   XmUpdateDisplay(parent);
1687
1688   /* Change the curser to let the user select the desired widget */
1689   selectedItem = LocateWidgetId(dpy, screen, &status, parent, cursor);
1690   
1691   switch (status)
1692     {
1693       case DtHELP_SELECT_VALID:
1694         *widget = selectedItem;
1695         result = DtHELP_SELECT_VALID;
1696         break;
1697      
1698       case DtHELP_SELECT_ABORT:
1699         *widget = NULL;
1700         result = DtHELP_SELECT_ABORT;
1701         break;
1702
1703       case DtHELP_SELECT_ERROR:
1704         *widget = NULL;
1705         result = DtHELP_SELECT_ERROR;
1706         break;
1707  
1708       case DtHELP_SELECT_INVALID:
1709       default:
1710         *widget = NULL;
1711         result = DtHELP_SELECT_INVALID;
1712         break;
1713     }
1714
1715   _DtHelpAppUnlock(app);
1716   return result;
1717 }
1718
1719
1720
1721
1722
1723
1724
1725 \f
1726 /*****************************************************************************
1727  * Function:        void _DtHelpTopicListAddToHead(
1728  *                                       char *locationId,
1729  *                                       int topicType,
1730  *                                       int maxNodex,
1731  *                                       DtTopicListStruct *pHead,
1732  *                                       DtTopicListStruct *pTale,
1733  *                                       totalNodes) 
1734  *                            
1735  *
1736  * Parameters:  
1737  *
1738  * Return Value:    Void.
1739  *
1740  * Purpose:         Adds an element to the top of the given topicList.
1741  *
1742  *****************************************************************************/
1743 void _DtHelpTopicListAddToHead(
1744     char *locationId,
1745     XmString topicTitle,
1746     int topicType,
1747     int maxNodes,
1748     char *accessPath,
1749     DtTopicListStruct **pHead,
1750     DtTopicListStruct **pTale,
1751     int *totalNodes,
1752     int scrollPosition)
1753 {
1754   DtTopicListStruct *pTemp=NULL;
1755
1756   /* add the new topic to the top */
1757   pTemp = (DtTopicListStruct *) XtMalloc((sizeof(DtTopicListStruct)));
1758
1759   pTemp->pNext            = (*pHead);
1760   pTemp->pPrevious        = NULL;
1761
1762   /* Assign the passed in values to our first element */
1763   pTemp->locationId       = XtNewString(locationId);
1764   pTemp->topicTitleLbl    = NULL;
1765   if (topicTitle != NULL)
1766       pTemp->topicTitleLbl= XmStringCopy(topicTitle);
1767   pTemp->topicType        = topicType;
1768   pTemp->helpVolume       = XtNewString(accessPath);
1769   pTemp->scrollPosition   = scrollPosition; 
1770
1771   /* Add locationId as first element if pHead = NULL */
1772   if (*pHead == NULL)
1773     {
1774       /* Assign our tale pointer */
1775       (*pTale) = (*pHead);
1776
1777       /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
1778       *totalNodes = 1;
1779     }
1780   else 
1781     {  /* We have a list so add the new topic to the top */
1782     
1783      (*pHead)->pPrevious     = pTemp;
1784
1785      /* Assign our tale pointer only the first time in this block */
1786      if (*totalNodes == 1)
1787        (*pTale) = (*pHead);
1788
1789      /* Re-Assign our head pointer to point to the new head of the list */
1790
1791      /* Bump our totalNode count */
1792      *totalNodes = *totalNodes +1;
1793     }
1794
1795   /* set the head to the current entry */
1796   (*pHead) = pTemp;
1797
1798    /* If we have reached our maxNodes remove a node from the end of our list */
1799    if (*totalNodes > maxNodes)
1800      {
1801        pTemp            = (*pTale);
1802        (*pTale)         = (*pTale)->pPrevious;
1803        (*pTale)->pNext  = NULL;
1804        pTemp->pPrevious = NULL;
1805                
1806        /* Free the id String and AccessPath elements */
1807        XtFree(pTemp->locationId);
1808        XtFree(pTemp->helpVolume);
1809        if (pTemp->topicTitleLbl != NULL)
1810            XmStringFree(pTemp->topicTitleLbl);
1811
1812        /* Now, free the whole node */
1813        XtFree((char*)pTemp);
1814
1815        /* Bump back our total node counter */
1816        *totalNodes = *totalNodes -1;
1817
1818      }
1819 }
1820
1821
1822
1823 \f
1824 /*****************************************************************************
1825  * Function:        void _DtHelpTopicListDeleteHead(
1826  *                                       DtTopicListStruct *pHead,
1827  *                                       DtTopicListStruct *pTale,
1828  *                                       totalNodes) 
1829  *                            
1830  *
1831  * Parameters:  
1832  *
1833  * Return Value:    Void.
1834  *
1835  * Purpose:         Delets an element from the top of the given topicList.
1836  *
1837  *****************************************************************************/
1838 void _DtHelpTopicListDeleteHead(
1839     DtTopicListStruct **pHead,
1840     DtTopicListStruct **pTale,
1841     int *totalNodes)
1842 {
1843   DtTopicListStruct *pTemp=NULL;
1844
1845   /* Delete the top node in our topic list */
1846   if (*pHead != NULL)
1847     {
1848       pTemp = (*pHead);
1849       if(pTemp != (*pTale))        /* (e.g. more than one node in list) */
1850         {
1851            (*pHead)            = pTemp->pNext;
1852            pTemp->pNext        = NULL; 
1853            (*pHead)->pPrevious = NULL;
1854
1855            /* Free the id String and accessPath elements */
1856            XtFree(pTemp->locationId);
1857            XtFree(pTemp->helpVolume);
1858
1859            /* Now, free the whole node */
1860            XtFree((char*)pTemp);
1861
1862            /* Bump back our total node counter */
1863            *totalNodes = *totalNodes -1;
1864          } 
1865     }
1866 }
1867
1868
1869
1870
1871
1872 \f
1873 /*****************************************************************************
1874  * Function:        void _DtHelpMapCB()
1875  *                   
1876  *                            
1877  *
1878  * Parameters:      client_data is the widget in reference to
1879  *                  which widget w is placed
1880  *
1881  * Return Value:    Void.
1882  *
1883  * Purpose:         Determins where a new child dialog should be mapped in
1884  *                  relation to its parent.
1885  *
1886  * Algorithm:       1. attempt left or right placement with no overlap
1887  *                  2. if fails, attempt up or down placement with no overlap
1888  *                  3. if fails, determines location with least
1889  *                     amount of overlap, and places there.
1890  *
1891  *****************************************************************************/
1892 XtCallbackProc _DtHelpMapCB(
1893     Widget w,
1894     XtPointer client_data,
1895     XtPointer call_data )
1896 {
1897     Arg         args[2];
1898     Widget      parent;
1899     Position    centeredY, bestX, bestY, pX, pY; 
1900     Dimension   pHeight, myHeight, pWidth, myWidth;
1901     Dimension   maxX, maxY;
1902     int         rhsX, lhsX, topY, botY;   /* needs to be int, not Dimension */
1903     Display *   display;
1904     Screen *    screen;
1905     int         screenNumber;
1906
1907     parent = (Widget)client_data;
1908     display = XtDisplay(w);
1909     screen = XtScreen(w);
1910     screenNumber = XScreenNumberOfScreen(screen);
1911
1912     pX = XtX(parent);
1913     pY = XtY(parent);
1914     if (pX < 0) pX = 0;
1915     if (pY < 0) pY = 0;
1916     pHeight = XtHeight(parent);
1917     pWidth = XtWidth(parent);
1918     myHeight = XtHeight(w);
1919     myWidth = XtWidth(w);
1920     maxX = XDisplayWidth(display,screenNumber);
1921     maxY = XDisplayHeight(display,screenNumber);
1922
1923     /* algorithm 
1924      * 1. attempt left or right placement with no overlap
1925      * 2. if fails, attempt up or down placement with no overlap
1926      * 3. if fails, places on the right in the middle
1927      */
1928     
1929     /* first try left right placement */
1930     bestY = pY + pHeight/2 - myHeight/2;
1931     centeredY = bestY;
1932     rhsX = pX + pWidth;
1933     lhsX = pX - myWidth - 8;     /* 8: account for border */
1934     if ( ((int)(rhsX + myWidth)) < ((int) maxX) ) bestX = rhsX;
1935     else if ( lhsX > 0 ) bestX = lhsX;
1936     else
1937     {
1938         /* then try up down placement */
1939         bestX = pX + pWidth/2 - myWidth/2;
1940         botY = pY + pHeight;
1941         topY = pY - myHeight - 44;     /* 44: account for menu border */
1942         if ( ((int)(botY + myWidth)) < ((int) maxY) ) bestY = botY;
1943         else if ( topY > 0 ) bestY = topY;
1944         else
1945         {
1946             /* otherwise, center vertically and on the right */
1947             bestX = maxX - myWidth;
1948             bestY = centeredY;
1949         }
1950     }
1951
1952     XtSetArg(args[0], XmNx, bestX);
1953     XtSetArg(args[1], XmNy,  bestY);
1954     XtSetValues(w, args, 2);
1955
1956     return((XtCallbackProc) NULL);
1957
1958 }
1959
1960
1961
1962
1963
1964 \f
1965 /*****************************************************************************
1966  * Function:      void _DtHelpMapCenteredCB(
1967  *
1968  *
1969  *
1970  * Parameters:
1971  *
1972  * Return Value:    Void.
1973  *
1974  * Purpose:       Determins where the center of our help dialog is and sets
1975  *                  where new child dialog should be mapped such that its centered.
1976  *
1977  *****************************************************************************/
1978 XtCallbackProc _DtHelpMapCenteredCB(
1979     Widget w,
1980     XtPointer client_data,
1981     XtPointer call_data )
1982 {
1983     Arg         args[2];
1984     Widget      parent;
1985     Position newX, newY, pY, pX;
1986     Dimension pHeight, myHeight, pWidth, myWidth;
1987
1988     parent = (Widget)client_data;
1989
1990     pX = XtX(parent);
1991     pY = XtY(parent);
1992     pHeight = XtHeight(parent);
1993     pWidth = XtWidth(parent);
1994     myHeight = XtHeight(w);
1995     myWidth = XtWidth(w);
1996
1997
1998     newY = ((Position)(pHeight - myHeight) / 2) + pY;
1999     newX = ((Position)(pWidth - myWidth) / 2) + pX;
2000
2001     XtSetArg(args[0], XmNx, newX);
2002     XtSetArg(args[1], XmNy, newY);
2003     XtSetValues(w, args, 2);
2004
2005     return((XtCallbackProc) NULL);
2006
2007 }
2008
2009
2010
2011 \f
2012 /*****************************************************************************
2013  * Function:       void _DtHelpDisplayDefinitionBox(
2014  *                            Widget new,   
2015  *                            Widget definitionBox,
2016  *                            char * path,
2017  *                            char * locationId);
2018  *       
2019  * Parameters:   
2020  *
2021  * Return Value:    
2022  *
2023  * Purpose:        This routine will create and post the definition box.
2024  *                 (e.g. the Quick Help Dialog widget)
2025  *
2026  ****************************************************************************/
2027 void _DtHelpDisplayDefinitionBox(
2028     Widget parent,  
2029     Widget **definitionBox, 
2030     char * path,
2031     char * locationId)
2032 {
2033
2034   Arg  args[10];
2035   int    n;
2036   Widget printWidget, helpWidget, backWidget;
2037   XmString closeString;
2038   char *title;
2039
2040   /* get the title from the main help dialog and use it here for */
2041   n = 0;
2042   XtSetArg (args[n], XmNtitle, &(title));  ++n;
2043   XtGetValues (XtParent(parent), args, n);
2044
2045
2046   if (*definitionBox == NULL)
2047     {
2048
2049       /* Create the QuickHelpDialog widget to use as the definition box */
2050       closeString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
2051                               (HUSET, 2,"Close")));
2052       n =0;
2053       XtSetArg (args[n], DtNhelpVolume, path);            n++; 
2054       XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++; 
2055       XtSetArg (args[n], DtNlocationId, locationId);      n++;
2056       XtSetArg (args[n], DtNcloseLabelString, closeString);  n++;
2057       XtSetArg (args[n], XmNtitle, title);                n++;
2058       *definitionBox = 
2059            (Widget *)DtCreateHelpQuickDialog(parent, "definitionBox", 
2060                                                args, n);
2061       XmStringFree(closeString);
2062
2063       /* Catch the close callback so we can destroy the widget */
2064       XtAddCallback((Widget)*definitionBox, DtNcloseCallback,
2065                     CloseDefBoxCB, (XtPointer) NULL);
2066
2067
2068       /* We do not want a print button for now so we unmap it */     
2069       printWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox, 
2070                                         DtHELP_QUICK_PRINT_BUTTON);
2071       XtUnmanageChild (printWidget);
2072   
2073       /* We do not want a help button for now so we unmap it */     
2074       helpWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox, 
2075                                        DtHELP_QUICK_HELP_BUTTON);
2076       XtUnmanageChild (helpWidget);
2077
2078
2079       /* We do not want a BACK button for now so we unmap it */     
2080       backWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox, 
2081                                            DtHELP_QUICK_BACK_BUTTON);
2082       XtUnmanageChild (backWidget);
2083
2084
2085   
2086       /*  Adjust the decorations for the dialog shell of the dialog  */
2087       n = 0;
2088       XtSetArg(args[n], XmNmwmFunctions, MWM_FUNC_RESIZE | MWM_FUNC_MOVE); n++;
2089       XtSetArg (args[n], XmNmwmDecorations, 
2090                 MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH); n++;
2091       XtSetValues (XtParent(*definitionBox), args, n);
2092     
2093       /* Add the popup position callback to our history dialog */
2094       XtAddCallback (XtParent(*definitionBox), XmNpopupCallback,
2095                     (XtCallbackProc)_DtHelpMapCenteredCB, (XtPointer)XtParent(parent));
2096
2097
2098
2099     }
2100   else
2101     {
2102        /* We already have one so lets use it. */
2103
2104        /* Set the proper title */
2105        n = 0;
2106        XtSetArg (args[n], XmNtitle, title);  ++n;
2107        XtSetValues (XtParent(*definitionBox), args, n);
2108    
2109        /* Set the proper contents. */
2110        n = 0;
2111        XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++; 
2112        XtSetArg (args[n], DtNhelpVolume, path);             n++; 
2113        XtSetArg (args[n], DtNlocationId, locationId);       n++;
2114        XtSetValues ((Widget)*definitionBox, args, n);
2115   
2116     }
2117  
2118
2119   /* Display the dialog */
2120   XtManageChild((Widget)*definitionBox);     
2121   XtMapWidget(XtParent((Widget)*definitionBox));
2122  
2123 }
2124
2125 \f
2126 /*****************************************************************************
2127  * Function:       static void CloseDefBoxCB(
2128  *                            Widget w,   
2129  *                            XtPointer client_data,
2130  *                            XtPointer call_data);
2131  *       
2132  * Parameters:   
2133  *
2134  * Return Value:    
2135  *
2136  * Purpose:        This routine closes and destroys the Definition Box
2137  *                 Dialog Widget that we create.
2138  *
2139  ****************************************************************************/
2140 static void  CloseDefBoxCB(
2141     Widget w,
2142     XtPointer client_data,
2143     XtPointer call_data )
2144 {
2145
2146    XtUnmanageChild(w);
2147
2148
2149 }
2150
2151
2152
2153
2154 \f
2155 /*****************************************************************************
2156  * Function:       void _DtHelpDisplayFormatError()
2157   *       
2158  * Parameters:   
2159  *
2160  * Return Value:    
2161  *
2162  * Purpose:        This routine generate and display the proper errror 
2163  *                 message to the display area as well as send the proper 
2164  *                 error to XmWarning() function.
2165  *
2166  ****************************************************************************/
2167 void _DtHelpDisplayFormatError(
2168     XtPointer displayArea,
2169     Widget widget,   
2170     char *userError,
2171     char *systemError)
2172 {
2173    XtPointer  topicHandle;
2174
2175    /* Set the string to the current help dialog */
2176    (void) _DtHelpFormatAsciiStringDynamic(displayArea, userError, &topicHandle);
2177          
2178    /* We ignor the status return here, because if we error out here we are
2179     * in big trouble because this is an error routine
2180     */
2181    
2182    _DtHelpDisplayAreaSetList (displayArea, topicHandle, FALSE, -1);
2183
2184    if (systemError != NULL)  
2185      XmeWarning((Widget)widget, systemError);
2186   
2187 }
2188
2189  
2190 \f
2191 /*****************************************************************************
2192  * Function:       void _DtHelpCommonHelpInit()
2193   *       
2194  * Parameters:   
2195  *
2196  * Return Value:    
2197  *
2198  * Purpose:        This routine inits common help stuff
2199  *
2200  ****************************************************************************/
2201 void _DtHelpCommonHelpInit(
2202     _DtHelpCommonHelpStuff * help)
2203 {
2204    help->topLevelId          = NULL;
2205    help->currentHelpFile     = NULL;
2206
2207    /* for help on help */
2208    if ( help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2209        help->helpOnHelpVolume = XtNewString(help->helpOnHelpVolume);
2210    if ( NULL == help->helpOnHelpVolume ) 
2211        help->helpOnHelpVolume = (char *)_DtHelpDefaultHelp4HelpVolume;
2212    help->pHelpListHead = NULL;          /* Help List Pointer */
2213    help->onHelpDialog = NULL;           /* help on help dialog */
2214    help->pDisplayArea = NULL;           /* Display widget handle */
2215
2216    /* get the search paths used by the widget */
2217    help->userVolumeSearchPath = _DtHelpGetUserSearchPath();
2218    help->sysVolumeSearchPath = _DtHelpGetSystemSearchPath();
2219 }
2220
2221  
2222 \f
2223 /*****************************************************************************
2224  * Function:       void _DtHelpCommonHelpClean()
2225   *       
2226  * Parameters:   
2227  *
2228  * Return Value:    
2229  *
2230  * Purpose:        This routine cleans up common help stuff
2231  *
2232  ****************************************************************************/
2233 void _DtHelpCommonHelpClean(
2234     _DtHelpCommonHelpStuff * help,
2235     Boolean                 destroy)
2236 {
2237    free(help->topLevelId);
2238    XtFree(help->currentHelpFile);
2239
2240    help->topLevelId          = NULL;
2241    help->currentHelpFile     = NULL;
2242
2243    if (destroy)
2244    {
2245       if (help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2246          XtFree(help->helpOnHelpVolume);
2247
2248       /* Free all the info we saved for our help callbacks */
2249       _DtHelpListFree(&help->pHelpListHead);
2250
2251       XtFree(help->userVolumeSearchPath);
2252       XtFree(help->sysVolumeSearchPath);
2253
2254       memset(help,0,sizeof(_DtHelpCommonHelpStuff));
2255    }
2256    else
2257    {
2258       /* Set our display area to a null starting vlaues */
2259       _DtHelpDisplayAreaClean(help->pDisplayArea);
2260    }
2261 }
2262
2263  
2264 \f
2265 /*****************************************************************************
2266  * Function:       void _DtHelpSetDlgButtonsWidth
2267  *       
2268  * Parameters:   
2269  *
2270  * Return Value:    
2271  *
2272  * Purpose:        This routine cleans up common help stuff
2273  *
2274  ****************************************************************************/
2275 void _DtHelpSetButtonPositions(
2276     Widget     btnList[],
2277     int        numBtns,
2278     Dimension  minFormWidth,
2279     Dimension  btnMargins,
2280     Dimension  minBetweenBtnSpace)
2281 { /* position buttons */
2282
2283       /* This code adds up the sizes of the buttons to go into
2284          the bottom row and calculates the form position percentages.
2285          All buttons are the same size, and are able to hold all
2286          the strings that may be dynamically placed in them.
2287          All buttons are 5% apart. */
2288       /* This code is specifically written to handle 3 buttons
2289          and assumes that the first 3 strings are to the ActionBtn */
2290    Dimension minWidthWithSpace = 0;
2291    Dimension borderWidth = 0;
2292    Dimension sumWidth = 0;
2293    Dimension leftPos = 0;
2294    Dimension rightPos = 0;
2295    Dimension spaceWidth = 0;
2296    Dimension btnWidth;
2297    Dimension maxBtnWidth = 0;
2298    float scale = 0.0;
2299    XmFontList fontList = NULL;
2300    int        i;
2301    int        n;
2302    Arg        args[5];
2303
2304    if (numBtns <= 0 || NULL == btnList[0]) return;
2305
2306    /* get the fontList for the button */
2307    XtSetArg (args[0], XmNborderWidth, &borderWidth);
2308    XtSetArg (args[1], XmNfontList, &fontList);
2309    XtGetValues (btnList[0], args, 2);
2310    /* assumption: the fontList that is returned is not owned by me; don't free */
2311
2312    /* cycle through all buttons */
2313    for (i=0; i<numBtns && NULL!=btnList[i]; i++)
2314    {
2315       XmString labelString;
2316
2317       /* get the label from the button */
2318       XtSetArg (args[0], XmNlabelString, &labelString);
2319       XtGetValues (btnList[i], args, 1);
2320
2321       btnWidth = XmStringWidth(fontList,labelString) + borderWidth + btnMargins;
2322       if (btnWidth > maxBtnWidth) maxBtnWidth = btnWidth;
2323
2324       XmStringFree(labelString);
2325    } /* for calcing widths */
2326    numBtns = i;  /* number of valid buttons */
2327
2328    /* calc the space */
2329    sumWidth = maxBtnWidth * numBtns;
2330    minWidthWithSpace = sumWidth + minBetweenBtnSpace * (numBtns * 2);
2331    if (minWidthWithSpace > minWidthWithSpace) minFormWidth = minWidthWithSpace;
2332    spaceWidth = ((int)(minFormWidth - sumWidth) / (numBtns * 2));
2333
2334    /* scale pixels to percent */
2335    scale = 100.0 / (float) minFormWidth;
2336
2337    /* set the positions of each button */
2338    leftPos = spaceWidth;
2339    for ( i=0; i<numBtns; i++ )
2340    {
2341       rightPos = leftPos + maxBtnWidth;
2342    
2343       n = 0;
2344       XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION);            n++;
2345       XtSetArg (args[n], XmNleftPosition, (Dimension) (((float) leftPos)*scale)); n++;
2346       XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION);           n++;
2347       XtSetArg (args[n], XmNrightPosition,(Dimension) (((float) rightPos)*scale)); n++;
2348       XtSetValues (btnList[i], args, n);
2349    
2350       leftPos = rightPos + spaceWidth + spaceWidth;
2351    }  /* setup the positions for all buttons */
2352 }  /* _DtHelpSetDlgButtonsWidth */
2353
2354
2355 \f
2356 /*****************************************************************************
2357  * Function:       _DtHelpXmFontListGetPropertyMax
2358  *       
2359  * Parameters:   
2360  *     fontList:  an XmFontList
2361  *     atom:      an XA_xxx value (see Vol 1, chpt 6.2.9)
2362  *     ret_propertyValue: ptr to long value that will hold the max value
2363  *
2364  * Return Value:    
2365  *     True: got at least one value
2366  *     False: unable to get any value; ret_propertyValue unchanged
2367  *
2368  * Purpose:
2369  *    This function returns the max value of XGetFontProperty calls 
2370  *    for each font in the XmFontList
2371  *    If there is an error, ret_propertyValue is left unchanged.
2372  *
2373  ****************************************************************************/
2374 Boolean
2375 _DtHelpXmFontListGetPropertyMax(
2376         XmFontList fontList,
2377         Atom atom,
2378         unsigned long *ret_propertyValue)
2379 {
2380     Boolean gotValue = False;
2381     XmFontContext context;
2382     XmFontListEntry entry;
2383     XtPointer fontData;
2384
2385     if (NULL == fontList) return False;           /* RETURN on error */
2386
2387     /* walk through the fontList entries and add them in */
2388     XmFontListInitFontContext(&context,fontList);
2389     for ( entry = XmFontListNextEntry(context);
2390           NULL != entry;
2391           entry = XmFontListNextEntry(context) )
2392     {
2393        unsigned long value;
2394        XmFontType type;
2395
2396        fontData = XmFontListEntryGetFont(entry,&type);
2397        if (XmFONT_IS_FONT == type)
2398        {
2399           XFontStruct * fontStruct;
2400
2401           /* cast according to type */
2402           fontStruct = (XFontStruct *) fontData;
2403
2404           if(XGetFontProperty(fontStruct, atom, &value) == TRUE) 
2405           {
2406              if(gotValue == False) /* haven't gotten any prop value yet */
2407              {
2408                  *ret_propertyValue = value;
2409                  gotValue = True;
2410              }
2411              else   /* have a good prop value already...get the max one */
2412              {
2413                  if(value > *ret_propertyValue)
2414                      *ret_propertyValue = value;
2415              }
2416           } /* if the getproperty call was good */
2417        }
2418        else  /* XmFONT_IS_FONTSET */
2419        {
2420           XFontSet fontSet;
2421           XFontStruct **font_list;
2422           char **name_list;
2423           int numfont;
2424           int i;
2425
2426           /* cast according to type */
2427           fontSet = (XFontSet) fontData;
2428  
2429           numfont=XFontsOfFontSet(fontSet,&font_list,&name_list);
2430           for(i = 0; i < numfont; i++) 
2431           {
2432               if(XGetFontProperty(font_list[i], atom, &value) == TRUE) 
2433               {
2434                   if(gotValue == False) /* haven't gotten any prop value yet */
2435                   {
2436                       *ret_propertyValue = value;
2437                       gotValue = True;
2438                   }
2439                   else   /* have a good prop value already...get the max one */
2440                   {
2441                       if(value > *ret_propertyValue)
2442                           *ret_propertyValue = value;
2443                   }
2444               } /* if the getproperty call was good */
2445           } /* for all fonts in the font set */
2446        } /* this entry uses a font set */
2447     } /* for all font entries in the font list */
2448     XmFontListFreeFontContext(context);
2449
2450     return(gotValue);
2451 }