1 /* $TOG: HelpUtil.c /main/19 1998/04/09 17:43:30 mgreess $ */
2 /************************************<+>*************************************
3 ****************************************************************************
7 ** Project: Rivers Project
12 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
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.
19 ****************************************************************************
20 ************************************<+>*************************************/
23 #include <sys/param.h>
27 #include <unistd.h> /* R_OK */
30 #include <sys/types.h>
31 #define X_INCLUDE_PWD_H
32 #define XOS_USE_XT_LOCKING
33 #include <X11/Xos_r.h>
37 #include <Xm/MwmUtil.h>
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>
45 /* private includes */
48 #include "DisplayAreaI.h"
53 #include "StringFuncsI.h"
54 #include "HelpDialogI.h"
55 #include "HelpDialogP.h"
56 #include "HelpUtilI.h"
58 #include "MessagesP.h"
59 #include "HelpQuickD.h"
62 #include "HelpAccessI.h"
63 #include "FileUtilsI.h"
64 #include "HourGlassI.h"
67 #include <Dt/DtNlUtils.h>
69 /******* global variables *******/
70 char _DtHelpDefaultHelp4HelpVolume[] = "Help4Help";
71 char _DtHelpDefaultLocationId[] = "_HOMETOPIC";
73 /**** Help Util Error message Defines ****/
75 #define UtilMessage0 _DtHelpMsg_0010
76 #define UtilMessage2 _DtHelpMsg_0011
79 static void _DtMessageClose(
81 XtPointer client_data,
83 static void CloseDefBoxCB(
85 XtPointer client_data,
88 /* Macro for finding a point within a gadget.
89 * Its used for item help
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))))
98 /******** useful constants ********/
100 #define DIR_SLASH '/'
102 #define HUSET 8 /* message catalog set */
104 /******** static variables ********/
105 static char DirSlash[] = "/";
107 /******** data structures ********/
108 typedef struct ExecContext
111 XtPointer pDisplayArea;
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};
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};
149 #if 0 /* XPM format */
150 static char * onitem32_xpm[] = {
151 /* width height ncolors cpp [x_hot y_hot] */
154 " s iconColor1 m black c black",
155 ". s background m black c #969696969696",
156 "X s iconColor2 m white c white",
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 "............... ................"};
196 #define NO_CONDITION 0
197 #define MISMATCHING_HOME_DIRS 1
199 /* ------------------------------------------------------------ *
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.
210 ** True - if the help volume IS Trusted
211 ** False - if the help volume is NOT Trusted
213 ** ------------------------------------------------------------ */
214 static Boolean trusted (char *hv_path) /* Full path to the help volume */
219 if ( (stat (hv_path, &buf)) == -1)
223 /* S_IWGRP */ /* write group */
224 /* S_IWOTH */ /* write other */
226 /** ---------------------------------------------------------------------- *
227 ** The help volume MUST be owned by root, bin, or sys to be trusted.
228 ** ---------------------------------------------------------------------- */
230 if ( buf.st_uid != ROOT_USER &&
231 buf.st_uid != BIN_USER &&
232 buf.st_uid != SYS_USER)
237 /** ----------------------------------------------------------------------- *
238 ** The help volume MUST not be writable by group or others to be trusted.
239 ** ----------------------------------------------------------------------- */
241 writable = (((buf.st_mode & S_IWGRP) == 0) && (buf.st_mode & S_IWOTH) == 0) ?
249 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
250 /**** API Error Dialog Support Functions *****/
251 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
254 /************************************************************************
255 * Function: _DtMessageClose
257 * Close the error/info message box.
259 ************************************************************************/
260 static void _DtMessageClose(
262 XtPointer client_data,
265 /* NOTE: ExecuteContextCB() is dependent on this code */
266 if (event->type == UnmapNotify)
268 XtRemoveEventHandler (XtParent (client_data), StructureNotifyMask,
269 True, (XtEventHandler) _DtMessageClose, client_data);
271 XtUnmanageChild (client_data);
272 XtDestroyWidget (client_data);
276 /************************************************************************
277 * Function: ExecuteContextCB
279 * Execute an execution context
281 ************************************************************************/
282 static void ExecuteContextCB(
284 XtPointer client_data,
287 ExecContext * ec = (ExecContext *) client_data;
289 if (ec && ec->command && ec->pDisplayArea)
291 _DtHelpExecProcedure(ec->pDisplayArea,ec->command);
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 */
302 /*****************************************************************************
303 * Function: CreateErrorDialog
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.
309 *****************************************************************************/
316 Widget messageDialog;
320 XmString label_string;
324 /* Setup the message string and dialog title */
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"));
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",
339 XtSetArg(args[0], XmNmwmDecorations,
340 MWM_DECOR_BORDER | MWM_DECOR_TITLE);
341 XtSetArg(args[1], XmNuseAsyncGeometry, True);
342 XtSetValues(XtParent(messageDialog), args, 2);
344 XmStringFree (label_string);
345 XmStringFree (ok_string);
346 XtFree(title_string);
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);
354 /* StructureNotifyMask gets Circulate, Configure, Destroy,
355 Gravity, Map, Reparent, & Unmap events */
356 XtAddEventHandler(XtParent(messageDialog),
357 StructureNotifyMask,True,
358 (XtEventHandler) _DtMessageClose, (XtPointer) messageDialog);
360 return messageDialog; /* RETURN */
364 /*****************************************************************************
365 * Function: CreateExecErrorDlg
370 *****************************************************************************/
375 Boolean invalidAlias,
376 _DtHelpCommonHelpStuff * pHelpStuff,
380 DtHelpListStruct *pHelpInfo;
386 /* handle the error case */
389 msg = (char *)_DTGETMESSAGE(HUSET, 12,
390 "The help volume wanted to execute a command alias.\n"
391 "The alias '%s' is not defined.");
394 else if (condition == MISMATCHING_HOME_DIRS)
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"
402 "The command is: \"%s\"\n\n"
404 "Note: to avoid this in the future:\n"
405 " execute \"su - root\" rather than \"su root\".\n");
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");
415 fullmsg = (char *) malloc(strlen(msg)+strlen(cmdStr)+30);
418 if (condition == MISMATCHING_HOME_DIRS)
419 sprintf(fullmsg, msg, current_hd, cmdStr);
421 sprintf(fullmsg,msg,cmdStr);
426 /* create an error dialog, but don't manage it yet */
427 msgDlg = CreateErrorDialog(XtParent(helpWidget),fullmsg);
429 if (msg != fullmsg) free(fullmsg);
431 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_HELP_BUTTON);
432 XtManageChild (btn); /* re-manage the button */
434 /* add the HelpOnHelp callback */
435 pHelpInfo = _DtHelpListAdd(DtHELP_ExecutionPolicy_STR,
436 helpWidget, pHelpStuff, &pHelpStuff->pHelpListHead);
437 XtAddCallback(btn, XmNactivateCallback, _DtHelpCB, (XtPointer) pHelpInfo);
442 /*****************************************************************************
443 * Function: _DtHelpErrorDialog
448 *****************************************************************************/
449 void _DtHelpErrorDialog(
453 Widget messageDialog;
455 messageDialog = CreateErrorDialog(parent,message);
457 /* Display help window. This used to be before the call
458 to add a StructureNotify event handler */
459 XtManageChild (messageDialog);
463 /*****************************************************************************
464 * Function: _DtHelpFilterExecCmdStr
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
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.
483 * ret_invalidAlias will be True if the alias was undefined and
484 * no default command was given.
486 * ret_execPermitted will be True if executionPolicy is DtHELP_EXECUTE_ALL
487 * or DtHELP_EXECUTE_QUERY_xxx and ret_cmdStr is valid
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).
495 * True: if execPermitted and a valid command string
496 * False: if if execPermitted is False or invalid command string
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.
503 * command string must be writable; it is written, but left
504 * unchanged when the function exits.
506 *****************************************************************************/
507 Boolean _DtHelpFilterExecCmdStr(
509 unsigned char executionPolicy,
510 const char * commandStr,
512 Boolean * ret_invalidAlias,
513 Boolean * ret_execPermitted,
514 Boolean * ret_queryNeeded,
515 char * hv_path) /* Path to the Help Volume */
520 char * aliasCommand = NULL;
523 #define RN_execAlias "executionAlias"
524 #define RC_execAlias "ExecutionAlias"
525 #define ExecAliasCmd "DtHelpExecAlias"
529 *ret_invalidAlias = False;
530 *ret_execPermitted = False;
531 *ret_queryNeeded = False;
533 if (NULL == commandStr)
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 ** ------------------------------------------------------------- */
543 if (DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy)
545 if ( ! (trusted (hv_path)))
546 *ret_queryNeeded = True; /* Query ALL non-trusted help volumes */
549 *ret_queryNeeded = (DtHELP_EXECUTE_QUERY_ALL == executionPolicy);
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;
557 *ret_execPermitted = False;
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;
566 if ( NULL == token || _DtHelpCeStrCaseCmpLatin1(token, ExecAliasCmd) != 0 )
568 /*** the command is not an alias; proceed using execution Policy ***/
570 *tokenEnd = tokenEndChar; /* restore the string */
572 *ret_cmdStr = strdup(commandStr);
573 ret = *ret_execPermitted;
575 return ret; /* RETURN ret */
579 /**** It's an alias; get it , look it up, and return it ****/
581 *tokenEnd = tokenEndChar; /* restore the string */
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;
591 Display * dpy = XtDisplay(helpWidget);
592 XrmDatabase appDb = XrmGetDatabase(dpy);
594 String appname, appclass;
596 char *rsrc_name, *rsrc_class;
598 rsrc_name = XtMalloc(200);
599 rsrc_class = XtMalloc(200);
601 XtGetApplicationNameAndClass(dpy,&appname,&appclass);
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);
610 /* Get alias command */
611 if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
612 aliasCommand = value.addr;
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);
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;
624 if (rsrc_name) XtFree(rsrc_name);
625 if (rsrc_class) XtFree(rsrc_class);
626 } /* if alias token */
632 if (tokenEnd) *tokenEnd = tokenEndChar; /* restore the string */
634 /* alias was defined */
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;
643 else /* the alias wasn't defined */
645 char * aliasToken = token; /* token currently pts to alias */
647 /* look for a default command */
648 /* get the next token */
649 token = tokenEnd + DtStrspn(tokenEnd, " \t");
650 tokenEnd = token + DtStrcspn(token, " \t");
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 */
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;
668 return ret; /* RETURN ret */
671 /*********************************************************************
672 * _DtHelpCeWaitAndProcessEvents
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.
681 * This function should only be used on modal dialogs.
683 *********************************************************************/
686 _DtHelpCeWaitAndProcessEvents (
688 _DtHelpCeWaitProc waitProc,
695 app = XtWidgetToApplicationContext(w);
699 XtAppNextEvent(app,&event);
700 XtDispatchEvent(&event);
704 while (!(mask = XtAppPending(app)))
705 ; /* Busy waiting - so we don't lose our Lock! */
707 if (mask & XtIMXEvent) /* We have an XEvent */
709 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
710 would also process timers/alternate inputs.
712 XtAppNextEvent(app, &event); /* No blocking, since an event is ready */
713 XtDispatchEvent(&event);
715 else /* Not a XEvent, it's an alternate input/timer event */
717 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
719 #endif /* XTHREADS */
720 /* check to see if we're done waiting */
721 waitFlag = (*waitProc)(w, clientData);
725 /*****************************************************************************
726 * Function: WaitForBtnActivatedCB
729 * Treats the 'clientData' as a pointer to an integer
730 * and turns its value into a Boolean
732 * Returns: *(int *)clientData < 0
733 *****************************************************************************/
735 WaitForBtnActivatedCB(
739 return (*(int *)clientData < 0);
740 /* True=keep waiting; False= wait no longer */
744 typedef struct ModalMsgDlgCBStruct
751 } ModalMsgDlgCBStruct;
753 /*****************************************************************************
754 * Function: IdentifyActivatedBtnCB
757 * Treats the 'clientData' as a pointer to an integer.
758 * Waits for the value pointed to by clientData to be >= 0.
760 *****************************************************************************/
762 IdentifyActivatedBtnCB(
764 XtPointer clientData,
767 ModalMsgDlgCBStruct * pMd = (ModalMsgDlgCBStruct *) clientData;
769 /* w must be a XmMessageDialog widget */
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 */
780 /*****************************************************************************
781 * Function: _DtHelpFilterExecCmd
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
792 * 0: no error; filteredCmdStr can be exec'd
793 * -1: error: either internal or executionPolicy denies exec;
794 * filteredCmdStr is NULL
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.
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.
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.
816 * command string must be writable; it is written, but left
817 * unchanged whent the function exits.
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.
824 *****************************************************************************/
825 int _DtHelpFilterExecCmd(
827 const char * commandStr,
828 unsigned char executionPolicy,
829 Boolean useQueryDialog,
830 _DtHelpCommonHelpStuff * pHelpStuff,
831 char * * ret_filteredCmdStr,
834 ModalMsgDlgCBStruct msgDlgCBStruct;
836 Boolean invalidAlias;
837 Boolean execPermitted;
840 char * filteredCmdStr = NULL;
843 XmString labelString;
844 XmString labelString2;
849 goodCmd = _DtHelpFilterExecCmdStr(helpWidget, executionPolicy,
850 commandStr, &filteredCmdStr, &invalidAlias,
851 &execPermitted, &queryNeeded, hv_path);
853 /* if permissions allow immediate execution, do so */
854 if (execPermitted && False == queryNeeded)
856 *ret_filteredCmdStr = filteredCmdStr;
857 return 0; /* RETURN ok */
860 if (False == useQueryDialog)
862 *ret_filteredCmdStr = NULL;
863 return -1; /* RETURN error */
866 /* create the dialog, but don't yet manage it */
867 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr,
868 invalidAlias,pHelpStuff, NO_CONDITION, "");
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)
874 XtManageChild(msgDlg); /* manage modeless dialog */
875 *ret_filteredCmdStr = NULL; /* don't execute */
876 XtFree(filteredCmdStr);
877 return -1; /* RETURN error */
880 /* if got this far, query is needed;make the dialog include
881 Execute Anyway and Don't Execute buttons */
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")));
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);
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);
903 execBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
904 XtManageChild (execBtn); /* re-manage the button */
905 XtAddCallback(execBtn, XmNactivateCallback,
906 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
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;
914 /* Display message dialog */
915 XtManageChild (msgDlg);
918 * turn on the modal dialog indicator
920 _DtHelpTurnOnNoEnter(helpWidget);
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);
928 * turn off the modal dialog indicator
930 _DtHelpTurnOffNoEnter(helpWidget);
932 /* no need to destroy msgDlg; it has a closeCallback to do that */
934 /* act based on which button was activated */
935 if (msgDlgCBStruct.activatedBtnId == XmDIALOG_OK_BUTTON)
937 *ret_filteredCmdStr = filteredCmdStr; /* do execute command */
938 return 0; /* RETURN ok */
942 *ret_filteredCmdStr = NULL; /* don't execute */
943 XtFree(filteredCmdStr);
944 return -1; /* RETURN error */
948 /*****************************************************************************
949 * Function: _DtHelpExecFilteredCmd
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
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.
964 * command string must be writable; it is written, but left
965 * unchanged whent the function exits.
967 * At the moment, the helpLocationId is ignored, and the
968 * help location is hardwired to DtHELP_ExecutionPolicy_STR
969 * in CreateExecErrorDialog().
971 *****************************************************************************/
972 void _DtHelpExecFilteredCmd(
975 char * helpLocationId,
976 _DtHelpDisplayWidgetStuff * pDisplayStuff,
977 _DtHelpCommonHelpStuff * pHelpStuff)
980 Boolean invalidAlias;
981 Boolean execPermitted;
983 char * filteredCmdStr = NULL;
984 ExecContext * execContext;
985 DtHelpListStruct *pHelpInfo;
986 XmString labelString;
987 XmString labelString2;
996 Boolean diff_home_dirs=False; /* True ==> $HOME is different from */
997 /* root user's $HOME directory */
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
1005 _Xgetpwparams pwd_buf;
1006 struct passwd * pwd_ret;
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
1015 ** -------------------------------------------------------------- */
1017 if ( (user=getuid()) == ROOT_USER)
1019 home_dir = getenv ("HOME");
1021 if (home_dir != NULL && strlen(home_dir) >= (size_t) 1)
1023 if (((pwd_ret = _XGetpwuid(user, pwd_buf)) != NULL)
1024 && (strcmp(home_dir, pwd_ret->pw_dir)))
1026 diff_home_dirs = True;
1031 hv_path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, pDisplayStuff->helpVolume,
1032 _DtHelpFileSuffixList, False, R_OK);
1034 /* The desired and intended behaviour is to use _DtHelpFilterExecCmdStr(), but
1035 the other code is left here, should a change be wished. */
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);
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 */
1051 (( pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_ALL)
1052 || (pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_UNALIASED))
1056 /* if permissions allow immediate execution, do so */
1057 if (execPermitted && False == queryNeeded && diff_home_dirs == False)
1059 (void) _DtHelpExecProcedure (pHelpStuff->pDisplayArea, filteredCmdStr);
1060 free(filteredCmdStr);
1061 return; /* RETURN */
1064 /* this traps bad cmds and also use of the synchronous filter call */
1065 if (NULL == filteredCmdStr) return; /* RETURN */
1067 /*** Create a modeless dialog to inform the user of the problem
1068 and possibly allow them to execute the command anyway. ***/
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 );
1075 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1079 /*** setup ExecuteAnyway and Help buttons ***/
1081 if ( (diff_home_dirs == True)
1083 (queryNeeded && execPermitted) )
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")));
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);
1098 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
1099 XtManageChild (btn); /* re-manage the button */
1101 /* add the ExecuteContextCB() client-data and callback */
1102 execContext = malloc(sizeof(ExecContext));
1105 execContext->command = filteredCmdStr;
1106 execContext->pDisplayArea = pHelpStuff->pDisplayArea;
1107 XtAddCallback(btn, XmNactivateCallback,
1108 ExecuteContextCB, (XtPointer) execContext);
1112 free(filteredCmdStr);
1114 } /* cmd wasn't an alias */
1117 free(filteredCmdStr);
1120 /* Display message dialog */
1121 XtManageChild (msgDlg);
1128 /*****************************************************************************
1129 * Function: LocateWidgetId()
1134 *****************************************************************************/
1135 static Widget LocateWidgetId(
1142 static Cursor DfltOnItemCursor = NULL;
1145 CompositeWidget comp_widget;
1157 Boolean notDone=TRUE;
1160 /* Make the target cursor */
1161 if (cursorIn != NULL)
1165 cursor = XCreateFontCursor (dpy, XC_question_arrow);
1168 _DtHelpProcessLock();
1169 if (NULL == DfltOnItemCursor)
1174 unsigned int height;
1175 unsigned int xHotspot;
1176 unsigned int yHotspot;
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;
1188 pixmap = XCreateBitmapFromData (dpy,
1189 RootWindowOfScreen(XtScreen(shellWidget)), bits,
1193 maskPixmap = XCreateBitmapFromData (dpy,
1194 RootWindowOfScreen(XtScreen(shellWidget)), maskBits,
1197 xcolors[0].pixel = BlackPixelOfScreen(ScreenOfDisplay(dpy, screen));
1198 xcolors[1].pixel = WhitePixelOfScreen(ScreenOfDisplay(dpy, screen));
1201 DefaultColormapOfScreen(ScreenOfDisplay(dpy, screen)),
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 */
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)
1223 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 3,
1224 "Internal Error: Could not grab the mouse\nDtHelpReturnSelectedWidget aborted.\n"));
1225 *statusRet = DtHELP_SELECT_ERROR;
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)
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;
1244 /* We are ok so let the user select a window... */
1247 XtAppContext app = XtWidgetToApplicationContext(shellWidget);
1248 /* allow one more event */
1250 XtAppNextEvent(app, &event);
1254 while (!(mask = XtAppPending(app)))
1255 ; /* Busy waiting - so we don't lose our Lock! */
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 */
1261 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
1262 would also process timers/alternate inputs.
1264 XtAppNextEvent(app, &event);
1265 #endif /* XTHREADS */
1266 widget = XtWindowToWidget(dpy, event.xany.window);
1268 switch (event.type) {
1275 /* Look for ESC key press and stop if we get one */
1276 if (event.xkey.state & ShiftMask)
1281 keySym = XLookupKeysym((XKeyEvent *)&event, offset);
1282 if (keySym == XK_Escape)
1284 XtUngrabKeyboard (shellWidget, CurrentTime);
1285 XtUngrabPointer (shellWidget, CurrentTime);
1286 *statusRet = DtHELP_SELECT_ABORT;
1290 XtDispatchEvent(&event);
1297 XtUngrabKeyboard (shellWidget, CurrentTime); /* Done with keyboard */
1298 XtUngrabPointer (shellWidget, CurrentTime); /* Done with pointer */
1300 /* If its null then the user selected some area outside our window(s) */
1301 if (widget == shellWidget)
1303 *statusRet = DtHELP_SELECT_INVALID;
1306 if (!XtIsComposite (widget))
1308 *statusRet = DtHELP_SELECT_VALID;
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;
1318 XTranslateCoordinates(dpy, parent, target_win, x, y,
1319 &new_x, &new_y, &sub);
1323 comp_widget = (CompositeWidget)widget;
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))
1332 *statusRet = DtHELP_SELECT_VALID;
1337 *statusRet = DtHELP_SELECT_VALID;
1344 /*****************************************************************************
1345 * Function: Boolean RememberDir(String path)
1347 * Parameters: path Specifies the path to check.
1349 * Return Value: Boolean if the path name is good.
1351 * Description: Use the directory caching mechanism to improve performance
1352 * by remembering the directories that have already been
1355 *****************************************************************************/
1357 RememberDir(String path)
1363 if (path == NULL || *path == '\0')
1366 if (_DtHelpCeStrrchr(path, "/", MB_CUR_MAX, &ptr) == 0 && ptr != path)
1369 result = _DtHelpCeCheckAndCacheDir(path);
1372 if (result == 0 && access(path, R_OK) == 0 &&
1373 stat(path, &buf) == 0 && S_ISREG(buf.st_mode))
1379 /*****************************************************************************
1380 * Function: Boolean _DtHelpResolvePathname(
1385 * Return Value: Boolean.
1388 * Description: _DtHelpResolvePathname attempts to validate and expand a path
1389 * to a Cache Creek help access file.
1391 *****************************************************************************/
1392 Boolean _DtHelpResolvePathname(
1394 char * * io_fileName,
1395 _DtHelpVolumeHdl * io_volumeHandle,
1396 char * sysVolumeSearchPath,
1397 char * userVolumeSearchPath)
1399 String newPath = NULL;
1401 /* try to locate file and its entry, if present */
1402 newPath = _DtHelpFileLocate(DtHelpVOLUME_TYPE, *io_fileName,
1403 _DtHelpFileSuffixList,False,R_OK);
1405 /* If we found a valid file let's do some set up here */
1407 if (newPath != NULL) /* We have a valid volume file so open it */
1409 /* Close the current one if we have one open */
1410 if (*io_volumeHandle != NULL)
1411 _DtHelpCloseVolume(*io_volumeHandle);
1413 /* Open the help volume file and save the handle id */
1414 if (_DtHelpOpenVolume(newPath,io_volumeHandle) >= 0)
1416 /* Copy the expanded file location path */
1417 XtFree(*io_fileName);
1418 *io_fileName = newPath;
1424 /* ERROR; leave io_fileName untouched on error
1425 * We used to set it to null here now we just return what came in
1427 /* later NOTE: this seems strange, since we have closed the
1428 old volume, invalidating io_fileName */
1430 XmeWarning(widget,(char*)UtilMessage2);
1434 else /* We have a non-valid path */
1436 /* ERROR; leave io_fileName untouched on error
1437 * We used to set it to null here now we just return what came in
1440 XmeWarning(widget,(char*)UtilMessage0);
1450 /*****************************************************************************
1451 * Function: Boolean _DtHelpExpandHelpVolume(DtHelpDialogWidget nw);
1454 * Parameters: nw Specifies the current help dialog widget.
1456 * Return Value: Boolean.
1459 * Description: _DtHelpExpandHelpVolume looks for a $LANG variable in the
1460 * helpAccesFile string and if found, replaces it with the
1461 * current lang variable.
1463 *****************************************************************************/
1464 Boolean _DtHelpExpandHelpVolume(
1466 _DtHelpDisplayWidgetStuff * display,
1467 _DtHelpCommonHelpStuff * help,
1468 _DtHelpPrintStuff * print)
1470 Boolean validTopic = FALSE;
1471 Boolean validPath = FALSE;
1474 /* Free the old, and Copy the new volumeHandle to printVolume varialbe */
1475 if (print->printVolume != NULL)
1476 XtFree(print->printVolume);
1478 print->printVolume = XtNewString(display->helpVolume);
1480 validPath = _DtHelpResolvePathname((Widget)w,
1481 &print->printVolume,
1482 &display->volumeHandle,
1483 help->sysVolumeSearchPath,
1484 help->userVolumeSearchPath);
1487 /* Check to see that we resolved our path correctly */
1489 return (FALSE); /* RETURN */
1493 /* The following routine will malloc memory for the topLevelId
1494 * variable, so we must free our current version first.
1496 XtFree(help->topLevelId);
1498 /* Assign our top level topic for this help access file */
1499 validTopic = _DtHelpCeGetTopTopicId(display->volumeHandle, &topLevelId);
1503 /* Bad top level topic */
1504 help->topLevelId = NULL;
1509 /* recall that the topLevelId/File vars are malloc'd */
1510 help->topLevelId = topLevelId;
1517 /*****************************************************************************
1518 * Function: char *_DtHelpParseIdString(char * specification);
1521 * Parameters: specification Specifies an author defined help topic.
1523 * Return Value: Void.
1525 * Description: This function copies the locationId portion of the
1526 * specification and returns it to the calling routine.
1528 *****************************************************************************/
1529 char *_DtHelpParseIdString(
1530 char *specification)
1533 char *pAccessFile = NULL;
1535 char *returnStr=NULL;
1538 tmpSpec = XtNewString(specification);
1541 /* First look for a blank in the specification. This will signify that
1542 * we have a HelpAccessFile as part of the specification.
1545 /* The first call will return true, with the first string */
1546 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1547 returnStr = XtNewString(pAccessFile);
1549 /* The second call will return true only if we have another string */
1550 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1552 if (pAccessFile != NULL)
1554 /* We have a helpAccessFile in our specification */
1558 returnStr = XtNewString(pAccessFile);
1565 /* We don't have a helpAccessFile as part of the specificaiton
1566 * so we just return our locationId.
1576 /*****************************************************************************
1577 * Function: char *_DtHelpParseAccessFile(char * specification);
1580 * Parameters: specification Specifies an author defined help topic.
1582 * Return Value: Void.
1584 * Description: This function copies the helpAccessFile portion of the
1585 * specification and returns it to the calling routine.
1587 *****************************************************************************/
1588 char *_DtHelpParseAccessFile(
1589 char *specification)
1591 char *pAccessFile = NULL;
1593 char *returnStr=NULL;
1596 tmpSpec = XtNewString(specification);
1599 /* First look for a blank in the specification. This will signify that
1600 * we have a HelpAccessFile as part of the specification.
1603 /* The first call will return true, with the first string */
1604 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1605 returnStr = XtNewString(pAccessFile);
1607 /* The second call will return true only if we have another string */
1608 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1610 if (pAccessFile != NULL)
1612 /* We have a helpAccessFile in our specification */
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.
1624 /* We don't have a helpAccessFile as part of the specificaiton
1641 /*****************************************************************************
1642 * Function: DtHelpReturnSelectedWidgetId
1644 * Parameters: parent Specifies the widget ID to use as the bases of
1645 * interaction, usually a top level shell.
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
1652 * widget This is the return value (e.g. the selected
1653 * widget). A value of NULL is returned on error.
1655 * Return Value: Status: (-1,0 or 1).
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
1662 *****************************************************************************/
1663 int DtHelpReturnSelectedWidgetId(
1672 Widget selectedItem;
1673 int status=DtHELP_SELECT_ERROR;
1676 _DtHelpWidgetToAppContext(parent);
1678 _DtHelpAppLock(app);
1679 /* Setup some needed variables */
1680 dpy = XtDisplay(parent);
1681 retScr = XtScreen(parent);
1683 screen = XScreenNumberOfScreen(retScr);
1685 /* refresh the display */
1686 XmUpdateDisplay(parent);
1688 /* Change the curser to let the user select the desired widget */
1689 selectedItem = LocateWidgetId(dpy, screen, &status, parent, cursor);
1693 case DtHELP_SELECT_VALID:
1694 *widget = selectedItem;
1695 result = DtHELP_SELECT_VALID;
1698 case DtHELP_SELECT_ABORT:
1700 result = DtHELP_SELECT_ABORT;
1703 case DtHELP_SELECT_ERROR:
1705 result = DtHELP_SELECT_ERROR;
1708 case DtHELP_SELECT_INVALID:
1711 result = DtHELP_SELECT_INVALID;
1715 _DtHelpAppUnlock(app);
1726 /*****************************************************************************
1727 * Function: void _DtHelpTopicListAddToHead(
1731 * DtTopicListStruct *pHead,
1732 * DtTopicListStruct *pTale,
1738 * Return Value: Void.
1740 * Purpose: Adds an element to the top of the given topicList.
1742 *****************************************************************************/
1743 void _DtHelpTopicListAddToHead(
1745 XmString topicTitle,
1749 DtTopicListStruct **pHead,
1750 DtTopicListStruct **pTale,
1754 DtTopicListStruct *pTemp=NULL;
1756 /* add the new topic to the top */
1757 pTemp = (DtTopicListStruct *) XtMalloc((sizeof(DtTopicListStruct)));
1759 pTemp->pNext = (*pHead);
1760 pTemp->pPrevious = NULL;
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;
1771 /* Add locationId as first element if pHead = NULL */
1774 /* Assign our tale pointer */
1775 (*pTale) = (*pHead);
1777 /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
1781 { /* We have a list so add the new topic to the top */
1783 (*pHead)->pPrevious = pTemp;
1785 /* Assign our tale pointer only the first time in this block */
1786 if (*totalNodes == 1)
1787 (*pTale) = (*pHead);
1789 /* Re-Assign our head pointer to point to the new head of the list */
1791 /* Bump our totalNode count */
1792 *totalNodes = *totalNodes +1;
1795 /* set the head to the current entry */
1798 /* If we have reached our maxNodes remove a node from the end of our list */
1799 if (*totalNodes > maxNodes)
1802 (*pTale) = (*pTale)->pPrevious;
1803 (*pTale)->pNext = NULL;
1804 pTemp->pPrevious = NULL;
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);
1812 /* Now, free the whole node */
1813 XtFree((char*)pTemp);
1815 /* Bump back our total node counter */
1816 *totalNodes = *totalNodes -1;
1824 /*****************************************************************************
1825 * Function: void _DtHelpTopicListDeleteHead(
1826 * DtTopicListStruct *pHead,
1827 * DtTopicListStruct *pTale,
1833 * Return Value: Void.
1835 * Purpose: Delets an element from the top of the given topicList.
1837 *****************************************************************************/
1838 void _DtHelpTopicListDeleteHead(
1839 DtTopicListStruct **pHead,
1840 DtTopicListStruct **pTale,
1843 DtTopicListStruct *pTemp=NULL;
1845 /* Delete the top node in our topic list */
1849 if(pTemp != (*pTale)) /* (e.g. more than one node in list) */
1851 (*pHead) = pTemp->pNext;
1852 pTemp->pNext = NULL;
1853 (*pHead)->pPrevious = NULL;
1855 /* Free the id String and accessPath elements */
1856 XtFree(pTemp->locationId);
1857 XtFree(pTemp->helpVolume);
1859 /* Now, free the whole node */
1860 XtFree((char*)pTemp);
1862 /* Bump back our total node counter */
1863 *totalNodes = *totalNodes -1;
1873 /*****************************************************************************
1874 * Function: void _DtHelpMapCB()
1878 * Parameters: client_data is the widget in reference to
1879 * which widget w is placed
1881 * Return Value: Void.
1883 * Purpose: Determins where a new child dialog should be mapped in
1884 * relation to its parent.
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.
1891 *****************************************************************************/
1892 XtCallbackProc _DtHelpMapCB(
1894 XtPointer client_data,
1895 XtPointer call_data )
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 */
1907 parent = (Widget)client_data;
1908 display = XtDisplay(w);
1909 screen = XtScreen(w);
1910 screenNumber = XScreenNumberOfScreen(screen);
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);
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
1929 /* first try left right placement */
1930 bestY = pY + pHeight/2 - myHeight/2;
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;
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;
1946 /* otherwise, center vertically and on the right */
1947 bestX = maxX - myWidth;
1952 XtSetArg(args[0], XmNx, bestX);
1953 XtSetArg(args[1], XmNy, bestY);
1954 XtSetValues(w, args, 2);
1956 return((XtCallbackProc) NULL);
1965 /*****************************************************************************
1966 * Function: void _DtHelpMapCenteredCB(
1972 * Return Value: Void.
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.
1977 *****************************************************************************/
1978 XtCallbackProc _DtHelpMapCenteredCB(
1980 XtPointer client_data,
1981 XtPointer call_data )
1985 Position newX, newY, pY, pX;
1986 Dimension pHeight, myHeight, pWidth, myWidth;
1988 parent = (Widget)client_data;
1992 pHeight = XtHeight(parent);
1993 pWidth = XtWidth(parent);
1994 myHeight = XtHeight(w);
1995 myWidth = XtWidth(w);
1998 newY = ((Position)(pHeight - myHeight) / 2) + pY;
1999 newX = ((Position)(pWidth - myWidth) / 2) + pX;
2001 XtSetArg(args[0], XmNx, newX);
2002 XtSetArg(args[1], XmNy, newY);
2003 XtSetValues(w, args, 2);
2005 return((XtCallbackProc) NULL);
2012 /*****************************************************************************
2013 * Function: void _DtHelpDisplayDefinitionBox(
2015 * Widget definitionBox,
2017 * char * locationId);
2023 * Purpose: This routine will create and post the definition box.
2024 * (e.g. the Quick Help Dialog widget)
2026 ****************************************************************************/
2027 void _DtHelpDisplayDefinitionBox(
2029 Widget **definitionBox,
2036 Widget printWidget, helpWidget, backWidget;
2037 XmString closeString;
2040 /* get the title from the main help dialog and use it here for */
2042 XtSetArg (args[n], XmNtitle, &(title)); ++n;
2043 XtGetValues (XtParent(parent), args, n);
2046 if (*definitionBox == NULL)
2049 /* Create the QuickHelpDialog widget to use as the definition box */
2050 closeString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
2051 (HUSET, 2,"Close")));
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++;
2059 (Widget *)DtCreateHelpQuickDialog(parent, "definitionBox",
2061 XmStringFree(closeString);
2063 /* Catch the close callback so we can destroy the widget */
2064 XtAddCallback((Widget)*definitionBox, DtNcloseCallback,
2065 CloseDefBoxCB, (XtPointer) NULL);
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);
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);
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);
2086 /* Adjust the decorations for the dialog shell of the dialog */
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);
2093 /* Add the popup position callback to our history dialog */
2094 XtAddCallback (XtParent(*definitionBox), XmNpopupCallback,
2095 (XtCallbackProc)_DtHelpMapCenteredCB, (XtPointer)XtParent(parent));
2102 /* We already have one so lets use it. */
2104 /* Set the proper title */
2106 XtSetArg (args[n], XmNtitle, title); ++n;
2107 XtSetValues (XtParent(*definitionBox), args, n);
2109 /* Set the proper contents. */
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);
2119 /* Display the dialog */
2120 XtManageChild((Widget)*definitionBox);
2121 XtMapWidget(XtParent((Widget)*definitionBox));
2126 /*****************************************************************************
2127 * Function: static void CloseDefBoxCB(
2129 * XtPointer client_data,
2130 * XtPointer call_data);
2136 * Purpose: This routine closes and destroys the Definition Box
2137 * Dialog Widget that we create.
2139 ****************************************************************************/
2140 static void CloseDefBoxCB(
2142 XtPointer client_data,
2143 XtPointer call_data )
2155 /*****************************************************************************
2156 * Function: void _DtHelpDisplayFormatError()
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.
2166 ****************************************************************************/
2167 void _DtHelpDisplayFormatError(
2168 XtPointer displayArea,
2173 XtPointer topicHandle;
2175 /* Set the string to the current help dialog */
2176 (void) _DtHelpFormatAsciiStringDynamic(displayArea, userError, &topicHandle);
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
2182 _DtHelpDisplayAreaSetList (displayArea, topicHandle, FALSE, -1);
2184 if (systemError != NULL)
2185 XmeWarning((Widget)widget, systemError);
2191 /*****************************************************************************
2192 * Function: void _DtHelpCommonHelpInit()
2198 * Purpose: This routine inits common help stuff
2200 ****************************************************************************/
2201 void _DtHelpCommonHelpInit(
2202 _DtHelpCommonHelpStuff * help)
2204 help->topLevelId = NULL;
2205 help->currentHelpFile = NULL;
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 */
2216 /* get the search paths used by the widget */
2217 help->userVolumeSearchPath = _DtHelpGetUserSearchPath();
2218 help->sysVolumeSearchPath = _DtHelpGetSystemSearchPath();
2223 /*****************************************************************************
2224 * Function: void _DtHelpCommonHelpClean()
2230 * Purpose: This routine cleans up common help stuff
2232 ****************************************************************************/
2233 void _DtHelpCommonHelpClean(
2234 _DtHelpCommonHelpStuff * help,
2237 free(help->topLevelId);
2238 XtFree(help->currentHelpFile);
2240 help->topLevelId = NULL;
2241 help->currentHelpFile = NULL;
2245 if (help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2246 XtFree(help->helpOnHelpVolume);
2248 /* Free all the info we saved for our help callbacks */
2249 _DtHelpListFree(&help->pHelpListHead);
2251 XtFree(help->userVolumeSearchPath);
2252 XtFree(help->sysVolumeSearchPath);
2254 memset(help,0,sizeof(_DtHelpCommonHelpStuff));
2258 /* Set our display area to a null starting vlaues */
2259 _DtHelpDisplayAreaClean(help->pDisplayArea);
2265 /*****************************************************************************
2266 * Function: void _DtHelpSetDlgButtonsWidth
2272 * Purpose: This routine cleans up common help stuff
2274 ****************************************************************************/
2275 void _DtHelpSetButtonPositions(
2278 Dimension minFormWidth,
2279 Dimension btnMargins,
2280 Dimension minBetweenBtnSpace)
2281 { /* position buttons */
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;
2297 Dimension maxBtnWidth = 0;
2299 XmFontList fontList = NULL;
2304 if (numBtns <= 0 || NULL == btnList[0]) return;
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 */
2312 /* cycle through all buttons */
2313 for (i=0; i<numBtns && NULL!=btnList[i]; i++)
2315 XmString labelString;
2317 /* get the label from the button */
2318 XtSetArg (args[0], XmNlabelString, &labelString);
2319 XtGetValues (btnList[i], args, 1);
2321 btnWidth = XmStringWidth(fontList,labelString) + borderWidth + btnMargins;
2322 if (btnWidth > maxBtnWidth) maxBtnWidth = btnWidth;
2324 XmStringFree(labelString);
2325 } /* for calcing widths */
2326 numBtns = i; /* number of valid buttons */
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));
2334 /* scale pixels to percent */
2335 scale = 100.0 / (float) minFormWidth;
2337 /* set the positions of each button */
2338 leftPos = spaceWidth;
2339 for ( i=0; i<numBtns; i++ )
2341 rightPos = leftPos + maxBtnWidth;
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);
2350 leftPos = rightPos + spaceWidth + spaceWidth;
2351 } /* setup the positions for all buttons */
2352 } /* _DtHelpSetDlgButtonsWidth */
2356 /*****************************************************************************
2357 * Function: _DtHelpXmFontListGetPropertyMax
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
2365 * True: got at least one value
2366 * False: unable to get any value; ret_propertyValue unchanged
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.
2373 ****************************************************************************/
2375 _DtHelpXmFontListGetPropertyMax(
2376 XmFontList fontList,
2378 unsigned long *ret_propertyValue)
2380 Boolean gotValue = False;
2381 XmFontContext context;
2382 XmFontListEntry entry;
2385 if (NULL == fontList) return False; /* RETURN on error */
2387 /* walk through the fontList entries and add them in */
2388 XmFontListInitFontContext(&context,fontList);
2389 for ( entry = XmFontListNextEntry(context);
2391 entry = XmFontListNextEntry(context) )
2393 unsigned long value;
2396 fontData = XmFontListEntryGetFont(entry,&type);
2397 if (XmFONT_IS_FONT == type)
2399 XFontStruct * fontStruct;
2401 /* cast according to type */
2402 fontStruct = (XFontStruct *) fontData;
2404 if(XGetFontProperty(fontStruct, atom, &value) == TRUE)
2406 if(gotValue == False) /* haven't gotten any prop value yet */
2408 *ret_propertyValue = value;
2411 else /* have a good prop value already...get the max one */
2413 if(value > *ret_propertyValue)
2414 *ret_propertyValue = value;
2416 } /* if the getproperty call was good */
2418 else /* XmFONT_IS_FONTSET */
2421 XFontStruct **font_list;
2426 /* cast according to type */
2427 fontSet = (XFontSet) fontData;
2429 numfont=XFontsOfFontSet(fontSet,&font_list,&name_list);
2430 for(i = 0; i < numfont; i++)
2432 if(XGetFontProperty(font_list[i], atom, &value) == TRUE)
2434 if(gotValue == False) /* haven't gotten any prop value yet */
2436 *ret_propertyValue = value;
2439 else /* have a good prop value already...get the max one */
2441 if(value > *ret_propertyValue)
2442 *ret_propertyValue = value;
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);