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