2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: HelpUtil.c /main/19 1998/04/09 17:43:30 mgreess $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 ** Project: Rivers Project
34 ** (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
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.
41 ****************************************************************************
42 ************************************<+>*************************************/
45 #include <sys/param.h>
49 #include <unistd.h> /* R_OK */
52 #include <sys/types.h>
53 #define X_INCLUDE_PWD_H
54 #define XOS_USE_XT_LOCKING
55 #include <X11/Xos_r.h>
59 #include <Xm/MwmUtil.h>
61 #include <Xm/MessageB.h>
62 #include <X11/Shell.h>
63 #include <X11/Intrinsic.h>
64 #include <X11/cursorfont.h>
66 /* private includes */
69 #include "DisplayAreaI.h"
74 #include "StringFuncsI.h"
75 #include "HelpDialogI.h"
76 #include "HelpDialogP.h"
77 #include "HelpUtilI.h"
79 #include "MessagesP.h"
80 #include "HelpQuickD.h"
83 #include "HelpAccessI.h"
84 #include "FileUtilsI.h"
85 #include "HourGlassI.h"
88 #include <Dt/DtNlUtils.h>
90 /******* global variables *******/
91 char _DtHelpDefaultHelp4HelpVolume[] = "Help4Help";
92 char _DtHelpDefaultLocationId[] = "_HOMETOPIC";
94 /**** Help Util Error message Defines ****/
96 #define UtilMessage0 _DtHelpMsg_0010
97 #define UtilMessage2 _DtHelpMsg_0011
100 static void _DtMessageClose(
102 XtPointer client_data,
104 static void CloseDefBoxCB(
106 XtPointer client_data,
107 XtPointer call_data);
109 /* Macro for finding a point within a gadget.
110 * Its used for item help
112 #define PT_IN_CHILD(X, Y, CHILD) \
113 ((((int)(X)) >= ((int) (CHILD)->core.x)) && \
114 (((int)(X)) <= ((int)((CHILD)->core.x + (CHILD)->core.width))) && \
115 (((int)(Y)) >= ((int) (CHILD)->core.y)) && \
116 (((int)(Y)) <= ((int)((CHILD)->core.y + (CHILD)->core.height))))
119 /******** useful constants ********/
121 #define DIR_SLASH '/'
123 #define HUSET 8 /* message catalog set */
125 /******** static variables ********/
128 /******** data structures ********/
129 typedef struct ExecContext
132 XtPointer pDisplayArea;
135 /******** The onitem cursor (32x32, xbm format) ********/
136 #define onitem32_width 32
137 #define onitem32_height 32
138 #define onitem32_x_hot 0
139 #define onitem32_y_hot 0
140 static unsigned char onitem32_bits[] = {
141 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0x1f, 0xfc, 0xf9, 0xff, 0xe7, 0xf3,
142 0xf1, 0xff, 0xfb, 0xef, 0xe1, 0xff, 0xfd, 0xdf, 0xc1, 0xff, 0xfd, 0xdf,
143 0x83, 0xff, 0xfe, 0xbf, 0x03, 0xff, 0x7e, 0x7e, 0x03, 0xfe, 0xbe, 0x7d,
144 0x03, 0xfc, 0xbe, 0x7d, 0x03, 0xf0, 0xc1, 0x7d, 0x03, 0xe0, 0xff, 0x7e,
145 0x07, 0xc0, 0x7f, 0xbf, 0x07, 0x80, 0xbf, 0xbf, 0x07, 0x00, 0xde, 0xdf,
146 0x07, 0x00, 0xdc, 0xef, 0x07, 0x00, 0xdf, 0xf7, 0x07, 0x80, 0xdf, 0xfb,
147 0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0xc0, 0xdf, 0xfb, 0x0f, 0x81, 0xdf, 0xfb,
148 0xcf, 0x83, 0x3f, 0xfc, 0xef, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff,
149 0xff, 0x0f, 0x3e, 0xfc, 0xff, 0x0f, 0xde, 0xfb, 0xff, 0x1f, 0xdc, 0xfb,
150 0xff, 0x1f, 0xdc, 0xfb, 0xff, 0x3f, 0xd8, 0xfb, 0xff, 0x3f, 0x3c, 0xfc,
151 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
153 #define onitem32_m_width 32
154 #define onitem32_m_height 32
155 #define onitem32_m_x_hot 0
156 #define onitem32_m_y_hot 0
157 static unsigned char onitem32_m_bits[] = {
158 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0x03, 0x0f, 0x00, 0xf8, 0x0f,
159 0x1f, 0x00, 0xfc, 0x1f, 0x3f, 0x00, 0xfe, 0x3f, 0x7f, 0x00, 0xfe, 0x3f,
160 0xfe, 0x00, 0xff, 0x7f, 0xfe, 0x01, 0xff, 0xff, 0xfe, 0x03, 0x7f, 0xfe,
161 0xfe, 0x0f, 0x7f, 0xfe, 0xfe, 0x1f, 0x3e, 0xfe, 0xfe, 0x3f, 0x00, 0xff,
162 0xfc, 0x7f, 0x80, 0x7f, 0xfc, 0xff, 0xc1, 0x7f, 0xfc, 0xff, 0xe3, 0x3f,
163 0xfc, 0xff, 0xe7, 0x1f, 0xfc, 0xff, 0xe3, 0x0f, 0xfc, 0xff, 0xe0, 0x07,
164 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0xff, 0xe0, 0x07,
165 0xf8, 0xfe, 0xc0, 0x03, 0x38, 0xfc, 0x01, 0x00, 0x18, 0xfc, 0x01, 0x00,
166 0x00, 0xf8, 0xc3, 0x03, 0x00, 0xf8, 0xe3, 0x07, 0x00, 0xf0, 0xe7, 0x07,
167 0x00, 0xf0, 0xe7, 0x07, 0x00, 0xe0, 0xef, 0x07, 0x00, 0xe0, 0xc7, 0x03,
168 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x00, 0x00};
170 #if 0 /* XPM format */
171 static char * onitem32_xpm[] = {
172 /* width height ncolors cpp [x_hot y_hot] */
175 " s iconColor1 m black c black",
176 ". s background m black c #969696969696",
177 "X s iconColor2 m white c white",
179 " ..............................",
180 " X ..................XXXXX......",
181 " XX ...............XX XX....",
182 " XXX .............X X...",
183 " XXXX ...........X X..",
184 " XXXXX ..........X X..",
185 ". XXXXX ........X X.",
186 ". XXXXXX .......X XX X",
187 ". XXXXXXX ......X X..X X",
188 ". XXXXXXXX ....X X..X X",
189 ". XXXXXXXXXX ....XXXXX...X X",
190 ". XXXXXXXXXXX ..........X X",
191 ".. XXXXXXXXXXX ........X X.",
192 ".. XXXXXXXXXXXX .....X X.",
193 ".. XXXXXXXXXXXXXX ...X X..",
194 ".. XXXXXXXXXXXXXXX ..X X...",
195 ".. XXXXXXXXXXXXX ...X X....",
196 ".. XXXXXXXXXXXX .....X X.....",
197 "... XXXXXXXXXX ......X X.....",
198 "... XXXXXXXXXX ......X X.....",
199 "... XXXX XXXXXX .....X X.....",
200 "... XX . XXXXX ......XXXX......",
201 "... X .... XXXXX ...............",
202 "... ..... XXXXX ...............",
203 "........... XXXXX ....XXXX......",
204 "........... XXXXX ...X X.....",
205 "............ XXXXX ..X X.....",
206 "............ XXXXX ..X X.....",
207 "............. XXXXX .X X.....",
208 "............. XXXX ...XXXX......",
209 ".............. X ..............",
210 "............... ................"};
217 #define NO_CONDITION 0
218 #define MISMATCHING_HOME_DIRS 1
220 /* ------------------------------------------------------------ *
224 ** Purpose Determines if the passed help volume is a
225 ** "trusted" help volume or not. We call it
226 ** trusted if it meets the following conditions:
227 ** 1. File Owner is root, bin, or system.
228 ** 2. File is NOT writable by group or others.
231 ** True - if the help volume IS Trusted
232 ** False - if the help volume is NOT Trusted
234 ** ------------------------------------------------------------ */
235 static Boolean trusted (char *hv_path) /* Full path to the help volume */
240 if ( (stat (hv_path, &buf)) == -1)
244 /* S_IWGRP */ /* write group */
245 /* S_IWOTH */ /* write other */
247 /** ---------------------------------------------------------------------- *
248 ** The help volume MUST be owned by root, bin, or sys to be trusted.
249 ** ---------------------------------------------------------------------- */
251 if ( buf.st_uid != ROOT_USER &&
252 buf.st_uid != BIN_USER &&
253 buf.st_uid != SYS_USER)
258 /** ----------------------------------------------------------------------- *
259 ** The help volume MUST not be writable by group or others to be trusted.
260 ** ----------------------------------------------------------------------- */
262 writable = (((buf.st_mode & S_IWGRP) == 0) && (buf.st_mode & S_IWOTH) == 0) ?
270 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
271 /**** API Error Dialog Support Functions *****/
272 /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
275 /************************************************************************
276 * Function: _DtMessageClose
278 * Close the error/info message box.
280 ************************************************************************/
281 static void _DtMessageClose(
283 XtPointer client_data,
286 /* NOTE: ExecuteContextCB() is dependent on this code */
287 if (event->type == UnmapNotify)
289 XtRemoveEventHandler (XtParent (client_data), StructureNotifyMask,
290 True, (XtEventHandler) _DtMessageClose, client_data);
292 XtUnmanageChild (client_data);
293 XtDestroyWidget (client_data);
297 /************************************************************************
298 * Function: ExecuteContextCB
300 * Execute an execution context
302 ************************************************************************/
303 static void ExecuteContextCB(
305 XtPointer client_data,
308 ExecContext * ec = (ExecContext *) client_data;
310 if (ec && ec->command && ec->pDisplayArea)
312 _DtHelpExecProcedure(ec->pDisplayArea,ec->command);
317 /* unmap, rather than unmanage and destroy, because of the code
318 in _DtMessageClose(). _DtMessageClose() is notified when
319 the widget unmaps and it destroys the widget. */
320 XtUnmapWidget(w); /* w is the message dialog */
323 /*****************************************************************************
324 * Function: CreateErrorDialog
326 * Creates an XmMessageDialog with the message and all buttons
327 * except the 'Close' (OK) button unmanaged.
328 * Also adds a callback that destroys the widget when the dialog is closed.
330 *****************************************************************************/
337 Widget messageDialog;
341 XmString label_string;
345 /* Setup the message string and dialog title */
347 ok_string = XmStringCreateLocalized(((char *)_DTGETMESSAGE
348 (HUSET, 2,"Close")));
349 label_string = XmStringCreateLocalized(message);
350 title_string = XtNewString((char *)_DTGETMESSAGE
351 (HUSET, 5,"Help Error"));
354 XtSetArg (args[n], XmNmessageString, label_string); n++;
355 XtSetArg (args[n], XmNtitle,title_string); n++;
356 XtSetArg (args[n], XmNcancelLabelString, ok_string); n++;
357 XtSetArg (args[n], XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON); n++;
358 messageDialog = XmCreateErrorDialog (parent, "errorDialog",
360 XtSetArg(args[0], XmNmwmDecorations,
361 MWM_DECOR_BORDER | MWM_DECOR_TITLE);
362 XtSetArg(args[1], XmNuseAsyncGeometry, True);
363 XtSetValues(XtParent(messageDialog), args, 2);
365 XmStringFree (label_string);
366 XmStringFree (ok_string);
367 XtFree(title_string);
369 /* unmanage or define the other buttons */
370 button = XmMessageBoxGetChild (messageDialog, XmDIALOG_OK_BUTTON);
371 XtUnmanageChild (button);
372 button = XmMessageBoxGetChild (messageDialog, XmDIALOG_HELP_BUTTON);
373 XtUnmanageChild (button);
375 /* StructureNotifyMask gets Circulate, Configure, Destroy,
376 Gravity, Map, Reparent, & Unmap events */
377 XtAddEventHandler(XtParent(messageDialog),
378 StructureNotifyMask,True,
379 (XtEventHandler) _DtMessageClose, (XtPointer) messageDialog);
381 return messageDialog; /* RETURN */
385 /*****************************************************************************
386 * Function: CreateExecErrorDlg
391 *****************************************************************************/
396 Boolean invalidAlias,
397 _DtHelpCommonHelpStuff * pHelpStuff,
401 DtHelpListStruct *pHelpInfo;
407 /* handle the error case */
410 msg = (char *)_DTGETMESSAGE(HUSET, 12,
411 "The help volume wanted to execute a command alias.\n"
412 "The alias '%s' is not defined.");
415 else if (condition == MISMATCHING_HOME_DIRS)
417 msg = (char *)_DTGETMESSAGE(HUSET, 14,
418 "The help volume wanted to execute a command as the root user, but the\n"
419 "home directory of \"%s\" ($HOME) does not match the root\n"
420 "user's home directory. This could result in executing unexpected\n"
423 "The command is: \"%s\"\n\n"
425 "Note: to avoid this in the future:\n"
426 " execute \"su - root\" rather than \"su root\".\n");
431 msg = (char *)_DTGETMESSAGE(HUSET, 13,
432 "The help volume wanted to execute a command.\n"
433 "For security reasons, automatic command execution is turned off.\n"
434 "The command is: %s");
436 fullmsg = (char *) malloc(strlen(msg)+strlen(cmdStr)+30);
439 if (condition == MISMATCHING_HOME_DIRS)
440 sprintf(fullmsg, msg, current_hd, cmdStr);
442 sprintf(fullmsg,msg,cmdStr);
447 /* create an error dialog, but don't manage it yet */
448 msgDlg = CreateErrorDialog(XtParent(helpWidget),fullmsg);
450 if (msg != fullmsg) free(fullmsg);
452 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_HELP_BUTTON);
453 XtManageChild (btn); /* re-manage the button */
455 /* add the HelpOnHelp callback */
456 pHelpInfo = _DtHelpListAdd(DtHELP_ExecutionPolicy_STR,
457 helpWidget, pHelpStuff, &pHelpStuff->pHelpListHead);
458 XtAddCallback(btn, XmNactivateCallback, _DtHelpCB, (XtPointer) pHelpInfo);
463 /*****************************************************************************
464 * Function: _DtHelpErrorDialog
469 *****************************************************************************/
470 void _DtHelpErrorDialog(
474 Widget messageDialog;
476 messageDialog = CreateErrorDialog(parent,message);
478 /* Display help window. This used to be before the call
479 to add a StructureNotify event handler */
480 XtManageChild (messageDialog);
484 /*****************************************************************************
485 * Function: _DtHelpFilterExecCmdStr
488 * helpWidget: help widget requesting to exec the command
489 * pDisplayStuff: ptr to the DisplayWidget stuff of the help widget
490 * commandStr: command string to execute
491 * ret_cmdStr: the screened & possibly rewritten command is put here
492 * ret_invalidAlias: was the command an invalid alias?
493 * ret_execPermitted: if executionPolicy permit exec & ret_cmdStr is valid
494 * ret_queryNeeded: if executionPolicy requires a query before exec
497 * ret_cmdStr gets memory owned by the calling function; it should be
498 * freed when no longer needed. The string will be the same as the
499 * commandStr if commandStr was not an alias. If the commandStr
500 * is an alias and if the alias is defined, the ret_cmdStr will be the
501 * value of the alias. If the alias isn't defined, the ret_cmdStr will
502 * be the default command if available, or the alias name otherwise.
504 * ret_invalidAlias will be True if the alias was undefined and
505 * no default command was given.
507 * ret_execPermitted will be True if executionPolicy is DtHELP_EXECUTE_ALL
508 * or DtHELP_EXECUTE_QUERY_xxx and ret_cmdStr is valid
510 * ret_queryNeeded will be True if executionPoilcy is
511 * DtHELP_EXECUTE_QUERY_ALL or if it is DtHELP_EXECUTE_QUERY_UNALIASED
512 * and ret_cmdStr did not derive from an alias (i.e. was hardcoded
513 * in the help volume, not retrieved from a resource).
516 * True: if execPermitted and a valid command string
517 * False: if if execPermitted is False or invalid command string
520 * This code is written such that we don't need nor want to know
521 * whether it is a general or quick help widget.
524 * command string must be writable; it is written, but left
525 * unchanged when the function exits.
527 *****************************************************************************/
528 Boolean _DtHelpFilterExecCmdStr(
530 unsigned char executionPolicy,
531 const char * commandStr,
533 Boolean * ret_invalidAlias,
534 Boolean * ret_execPermitted,
535 Boolean * ret_queryNeeded,
536 char * hv_path) /* Path to the Help Volume */
541 char * aliasCommand = NULL;
544 #define RN_execAlias "executionAlias"
545 #define RC_execAlias "ExecutionAlias"
546 #define ExecAliasCmd "DtHelpExecAlias"
550 *ret_invalidAlias = False;
551 *ret_execPermitted = False;
552 *ret_queryNeeded = False;
554 if (NULL == commandStr)
557 /** ------------------------------------------------------------- *
558 ** If the executionPolicy is query all unaliased (query for all
559 ** execution links that have no execution alias defined), we
560 ** make an exception: only query the user for help volumes
561 ** deemed NOT "trusted".
562 ** ------------------------------------------------------------- */
564 if (DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy)
566 if ( ! (trusted (hv_path)))
567 *ret_queryNeeded = True; /* Query ALL non-trusted help volumes */
570 *ret_queryNeeded = (DtHELP_EXECUTE_QUERY_ALL == executionPolicy);
572 /* get whether exec permitted */
573 if ( DtHELP_EXECUTE_ALL == executionPolicy
574 || DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
575 || DtHELP_EXECUTE_QUERY_ALL == executionPolicy)
576 *ret_execPermitted = True;
578 *ret_execPermitted = False;
580 /* parse apart the command string, looking for DtHelpExecAlias */
581 /* The first call will return true, with the first string */
582 token = (char *) commandStr + DtStrspn((char *)commandStr, " \t");
583 tokenEnd = token + DtStrcspn(token, " \t");
584 tokenEndChar = *tokenEnd;
585 if (tokenEnd) *tokenEnd = EOS;
587 if ( NULL == token || _DtHelpCeStrCaseCmpLatin1(token, ExecAliasCmd) != 0 )
589 /*** the command is not an alias; proceed using execution Policy ***/
591 *tokenEnd = tokenEndChar; /* restore the string */
593 *ret_cmdStr = strdup(commandStr);
594 ret = *ret_execPermitted;
596 return ret; /* RETURN ret */
600 /**** It's an alias; get it , look it up, and return it ****/
602 *tokenEnd = tokenEndChar; /* restore the string */
604 /* get the next token */
605 token = tokenEnd + DtStrspn(tokenEnd, " \t");
606 tokenEnd = token + DtStrcspn(token, " \t");
607 tokenEndChar = *tokenEnd;
608 if (tokenEnd) *tokenEnd = EOS;
612 Display * dpy = XtDisplay(helpWidget);
613 XrmDatabase appDb = XrmGetDatabase(dpy);
615 String appname, appclass;
617 char *rsrc_name, *rsrc_class;
619 rsrc_name = XtMalloc(200);
620 rsrc_class = XtMalloc(200);
622 XtGetApplicationNameAndClass(dpy,&appname,&appclass);
624 /* query the application's database for the alias command */
625 /* build alias resource class and resource */
626 /* e.g. App.executionAlias.<alias> */
627 sprintf(rsrc_name,"%s.%s.%s",appclass, RN_execAlias,token);
628 /* e.g. App.ExecutionAlias.<alias> */
629 sprintf(rsrc_class,"%s.%s.%s",appclass, RC_execAlias,token);
631 /* Get alias command */
632 if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
633 aliasCommand = value.addr;
635 /* build alias resource name and resource */
636 /* e.g. app.executionAlias.<alias> */
637 sprintf(rsrc_name,"%s.%s.%s",appname, RN_execAlias,token);
638 /* e.g. app.ExecutionAlias.<alias> */
639 sprintf(rsrc_class,"%s.%s.%s",appname, RC_execAlias,token);
641 /* Get alias command and override class with instance, if defined */
642 if (XrmGetResource(appDb,rsrc_name,rsrc_class,&reptype,&value) == True)
643 aliasCommand = value.addr;
645 if (rsrc_name) XtFree(rsrc_name);
646 if (rsrc_class) XtFree(rsrc_class);
647 } /* if alias token */
653 if (tokenEnd) *tokenEnd = tokenEndChar; /* restore the string */
655 /* alias was defined */
658 *ret_cmdStr = strdup(aliasCommand);
659 /* see if query needed; is not if policy is query_unaliased or all */
660 *ret_queryNeeded = !( DtHELP_EXECUTE_QUERY_UNALIASED == executionPolicy
661 || DtHELP_EXECUTE_ALL == executionPolicy);
662 ret = *ret_execPermitted;
664 else /* the alias wasn't defined */
666 char * aliasToken = token; /* token currently pts to alias */
668 /* look for a default command */
669 /* get the next token */
670 token = tokenEnd + DtStrspn(tokenEnd, " \t");
671 tokenEnd = token + DtStrcspn(token, " \t");
673 if (token == tokenEnd)
674 { /* alias wasn't defined and no default command */
675 *ret_cmdStr = strdup(aliasToken);
676 *ret_invalidAlias = True;
677 *ret_queryNeeded = False; /* no query needed on invalid alias, ever */
678 *ret_execPermitted = False; /* can't exec an invalid alias */
682 { /* alias wasn't defined but a default command */
683 /* query is whatever was determined earlier */
684 *ret_cmdStr = strdup(token);
685 ret = *ret_execPermitted;
689 return ret; /* RETURN ret */
692 /*********************************************************************
693 * _DtHelpCeWaitAndProcessEvents
696 * _DtHelpCeWaitAndProcessEvents will process events and call
697 * the waitProc until waitProc returns False. This function
698 * is useful to put up modal dialogs that must be reponded to
699 * in the midst of executing code that must remain on the call stack.
702 * This function should only be used on modal dialogs.
704 *********************************************************************/
707 _DtHelpCeWaitAndProcessEvents (
709 _DtHelpCeWaitProc waitProc,
716 app = XtWidgetToApplicationContext(w);
720 XtAppNextEvent(app,&event);
721 XtDispatchEvent(&event);
725 while (!(mask = XtAppPending(app)))
726 ; /* Busy waiting - so we don't lose our Lock! */
728 if (mask & XtIMXEvent) /* We have an XEvent */
730 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
731 would also process timers/alternate inputs.
733 XtAppNextEvent(app, &event); /* No blocking, since an event is ready */
734 XtDispatchEvent(&event);
736 else /* Not a XEvent, it's an alternate input/timer event */
738 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
740 #endif /* XTHREADS */
741 /* check to see if we're done waiting */
742 waitFlag = (*waitProc)(w, clientData);
746 /*****************************************************************************
747 * Function: WaitForBtnActivatedCB
750 * Treats the 'clientData' as a pointer to an integer
751 * and turns its value into a Boolean
753 * Returns: *(int *)clientData < 0
754 *****************************************************************************/
756 WaitForBtnActivatedCB(
760 return (*(int *)clientData < 0);
761 /* True=keep waiting; False= wait no longer */
765 typedef struct ModalMsgDlgCBStruct
772 } ModalMsgDlgCBStruct;
774 /*****************************************************************************
775 * Function: IdentifyActivatedBtnCB
778 * Treats the 'clientData' as a pointer to an integer.
779 * Waits for the value pointed to by clientData to be >= 0.
781 *****************************************************************************/
783 IdentifyActivatedBtnCB(
785 XtPointer clientData,
788 ModalMsgDlgCBStruct * pMd = (ModalMsgDlgCBStruct *) clientData;
790 /* w must be a XmMessageDialog widget */
792 { pMd->activatedBtnId = XmDIALOG_OK_BUTTON; return; /* RETURN */ }
793 if (pMd->cancelBtn == w)
794 { pMd->activatedBtnId = XmDIALOG_CANCEL_BUTTON; return; /* RETURN */ }
795 if (pMd->helpBtn == w)
796 { pMd->activatedBtnId = XmDIALOG_HELP_BUTTON; return; /* RETURN */ }
797 pMd->activatedBtnId = -1; /* unknown button */
801 /*****************************************************************************
802 * Function: _DtHelpFilterExecCmd
805 * helpWidget: help widget requesting to exec the command
806 * command: command string to execute
807 * execPolicy: current policy setting
808 * useQueryDialog: use a dialog to query user whether to exec, if not allowed
809 * pHelpStuff: ptr to the HelpStuff structure of the help widget
810 * ret_filteredCmdStr: filtered command string
813 * 0: no error; filteredCmdStr can be exec'd
814 * -1: error: either internal or executionPolicy denies exec;
815 * filteredCmdStr is NULL
818 * This function filters an execution command string. This can
819 * occur in several ways. In all cases, the command string is
820 * supports command alias replacement. If the final outcome
821 * is that execution is permitted, the returned string is
822 * is the command string to execute. If execution is not
823 * permitted, the return string is a NULL pointer.
825 * Filtering of the command occurs as follows.
826 * If executionPolicy permits execution, only alias replacement occurs.
827 * If executionPolicy does restrict execution and a
828 * dialog is requested, then a modal dialog is posted and the
829 * user can decide whether to execute or not.
830 * If a dialog is not requested, the return string is NULL.
833 * This code is written such that we don't need nor want to know
834 * whether it is a general or quick help widget.
837 * command string must be writable; it is written, but left
838 * unchanged whent the function exits.
840 * This operation is synchronous, meaning that, if a dialog is
841 * posted, it is a modal dialog and the function won't return
842 * until the user selects a button.
845 *****************************************************************************/
846 int _DtHelpFilterExecCmd(
848 const char * commandStr,
849 unsigned char executionPolicy,
850 Boolean useQueryDialog,
851 _DtHelpCommonHelpStuff * pHelpStuff,
852 char * * ret_filteredCmdStr,
855 ModalMsgDlgCBStruct msgDlgCBStruct;
857 Boolean invalidAlias;
858 Boolean execPermitted;
861 char * filteredCmdStr = NULL;
864 XmString labelString;
865 XmString labelString2;
869 goodCmd = _DtHelpFilterExecCmdStr(helpWidget, executionPolicy,
870 commandStr, &filteredCmdStr, &invalidAlias,
871 &execPermitted, &queryNeeded, hv_path);
873 /* if permissions allow immediate execution, do so */
874 if (execPermitted && False == queryNeeded)
876 *ret_filteredCmdStr = filteredCmdStr;
877 return 0; /* RETURN ok */
880 if (False == useQueryDialog)
882 *ret_filteredCmdStr = NULL;
883 return -1; /* RETURN error */
886 /* create the dialog, but don't yet manage it */
887 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr,
888 invalidAlias,pHelpStuff, NO_CONDITION, "");
890 /* if a bad alias or no exec permitted,
891 don't need to wait for a response; dlg has close & Help */
892 if (False == execPermitted || False == queryNeeded)
894 XtManageChild(msgDlg); /* manage modeless dialog */
895 *ret_filteredCmdStr = NULL; /* don't execute */
896 XtFree(filteredCmdStr);
897 return -1; /* RETURN error */
900 /* if got this far, query is needed;make the dialog include
901 Execute Anyway and Don't Execute buttons */
903 /* give the right title to the buttons */
904 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
905 (HUSET, 10,"Execute Anyway")));
906 /* give the right title to the Cancel button */
907 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
908 (HUSET, 11,"Don't Execute")));
910 XtSetArg (args[n], XmNokLabelString, labelString); n++;
911 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
912 XtSetArg (args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); n++;
913 XtSetValues(msgDlg,args,n);
914 XmStringFree(labelString);
915 XmStringFree(labelString2);
917 /* We put an activate callback on the DontExecute and ExecuteAnyway buttons
918 and wait until a button is pressed. */
919 noexecBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_CANCEL_BUTTON);
920 XtAddCallback(noexecBtn, XmNactivateCallback,
921 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
923 execBtn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
924 XtManageChild (execBtn); /* re-manage the button */
925 XtAddCallback(execBtn, XmNactivateCallback,
926 IdentifyActivatedBtnCB, (XtPointer) &msgDlgCBStruct);
928 /* fill out the CB information structure used by IdentifyActivatedBtnCB */
929 msgDlgCBStruct.msgDlg = msgDlg;
930 msgDlgCBStruct.okBtn = execBtn;
931 msgDlgCBStruct.cancelBtn = noexecBtn;
932 msgDlgCBStruct.activatedBtnId = -1;
934 /* Display message dialog */
935 XtManageChild (msgDlg);
938 * turn on the modal dialog indicator
940 _DtHelpTurnOnNoEnter(helpWidget);
942 /* wait until 'msgDlgCBStruct.activatedBtnId' has a value >= 0 */
943 /* this occurs when the user responds to the msg dialog */
944 _DtHelpCeWaitAndProcessEvents(msgDlg,
945 WaitForBtnActivatedCB, &msgDlgCBStruct.activatedBtnId);
948 * turn off the modal dialog indicator
950 _DtHelpTurnOffNoEnter(helpWidget);
952 /* no need to destroy msgDlg; it has a closeCallback to do that */
954 /* act based on which button was activated */
955 if (msgDlgCBStruct.activatedBtnId == XmDIALOG_OK_BUTTON)
957 *ret_filteredCmdStr = filteredCmdStr; /* do execute command */
958 return 0; /* RETURN ok */
962 *ret_filteredCmdStr = NULL; /* don't execute */
963 XtFree(filteredCmdStr);
964 return -1; /* RETURN error */
968 /*****************************************************************************
969 * Function: _DtHelpExecFilteredCmd
972 * helpWidget: help widget requesting to exec the command
973 * command: command string to execute
974 * modal: is the execution modal (sync) or modeless (async)
975 * helpLocationId: helpOnHelp file location for Help btn in error dialog
976 * pDisplayStuff: ptr to the DisplayWidget stuff of the help widget
977 * pHelpStuff: ptr to the CommonHelp stuff of the help widget
980 * This code is written such that we don't need nor want to know
981 * whether it is a general or quick help widget.
984 * command string must be writable; it is written, but left
985 * unchanged whent the function exits.
987 * At the moment, the helpLocationId is ignored, and the
988 * help location is hardwired to DtHELP_ExecutionPolicy_STR
989 * in CreateExecErrorDialog().
991 *****************************************************************************/
992 void _DtHelpExecFilteredCmd(
995 char * helpLocationId,
996 _DtHelpDisplayWidgetStuff * pDisplayStuff,
997 _DtHelpCommonHelpStuff * pHelpStuff)
1000 Boolean invalidAlias;
1001 Boolean execPermitted;
1002 Boolean queryNeeded;
1003 char * filteredCmdStr = NULL;
1004 ExecContext * execContext;
1005 XmString labelString;
1006 XmString labelString2;
1015 Boolean diff_home_dirs=False; /* True ==> $HOME is different from */
1016 /* root user's $HOME directory */
1018 getpw{uid,nam}_r routines fail on IBM platform when search password info
1019 via NIS (yellow pages). However, in the case of root, we'll assume that
1020 the password info is in /etc/passwd. If this is not the case, the
1021 following code can fail on IBM platform when XTHREADS and XUSE_MTSAFE_API
1025 _Xgetpwparams pwd_buf;
1027 struct passwd * pwd_ret;
1029 /** -------------------------------------------------------------- *
1030 ** If we're running as the root user
1031 ** o check if the value of the HOME env var matches
1032 ** root's home directory (defined by /etc/passwd).
1033 ** o If they do not match, then present a dialog
1034 ** alerting the user of this, along with the command to
1036 ** -------------------------------------------------------------- */
1038 if ( (user=getuid()) == ROOT_USER)
1040 home_dir = getenv ("HOME");
1042 if (home_dir != NULL && strlen(home_dir) >= (size_t) 1)
1044 if (((pwd_ret = _XGetpwuid(user, pwd_buf)) != NULL)
1045 && (strcmp(home_dir, pwd_ret->pw_dir)))
1047 diff_home_dirs = True;
1052 hv_path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, pDisplayStuff->helpVolume,
1053 _DtHelpFileSuffixList, False, R_OK);
1055 /* The desired and intended behaviour is to use _DtHelpFilterExecCmdStr(), but
1056 the other code is left here, should a change be wished. */
1058 /* This function runs a filter for policy and alias but posts no dialog */
1059 goodCmd=_DtHelpFilterExecCmdStr(helpWidget,
1060 pDisplayStuff->executionPolicy, commandStr,
1061 &filteredCmdStr, &invalidAlias, &execPermitted, &queryNeeded, hv_path);
1063 /* This function does an synchronous filter; i.e. the code runs a filter
1064 for policy and alias, and if policy denies exec and the command is
1065 valid, then posts a modal dialog and waits for the user to decide
1066 what to do before returning. */
1067 goodCmd = _DtHelpFilterExecCmd(helpWidget, commandStr,
1068 pDisplayStuff->executionPolicy, True,
1069 pHelpStuff, &filteredCmdStr, hv_path);
1070 execPermitted = (goodCmd == 0); /* convert an error int into a Boolean */
1072 (( pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_ALL)
1073 || (pDisplayStuff->executionPolicy==DtHELP_EXECUTE_QUERY_UNALIASED))
1077 /* if permissions allow immediate execution, do so */
1078 if (execPermitted && False == queryNeeded && diff_home_dirs == False)
1080 (void) _DtHelpExecProcedure (pHelpStuff->pDisplayArea, filteredCmdStr);
1081 free(filteredCmdStr);
1082 return; /* RETURN */
1085 /* this traps bad cmds and also use of the synchronous filter call */
1086 if (NULL == filteredCmdStr) return; /* RETURN */
1088 /*** Create a modeless dialog to inform the user of the problem
1089 and possibly allow them to execute the command anyway. ***/
1091 /* create the dialog, but don't yet manage it */
1092 if ( diff_home_dirs == True)
1093 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1094 MISMATCHING_HOME_DIRS, home_dir );
1096 msgDlg = CreateExecErrorDlg(helpWidget,filteredCmdStr, invalidAlias,pHelpStuff,
1100 /*** setup ExecuteAnyway and Help buttons ***/
1102 if ( (diff_home_dirs == True)
1104 (queryNeeded && execPermitted) )
1106 /* give the right title to the buttons */
1107 labelString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1108 (HUSET, 10,"Execute Anyway")));
1109 /* give the right title to the Cancel button */
1110 labelString2 = XmStringCreateLocalized(((char *)_DTGETMESSAGE
1111 (HUSET, 11,"Don't Execute")));
1113 XtSetArg (args[n], XmNokLabelString, labelString); n++;
1114 XtSetArg (args[n], XmNcancelLabelString, labelString2); n++;
1115 XtSetValues(msgDlg,args,n);
1116 XmStringFree(labelString);
1117 XmStringFree(labelString2);
1119 btn = XmMessageBoxGetChild (msgDlg, XmDIALOG_OK_BUTTON);
1120 XtManageChild (btn); /* re-manage the button */
1122 /* add the ExecuteContextCB() client-data and callback */
1123 execContext = malloc(sizeof(ExecContext));
1126 execContext->command = filteredCmdStr;
1127 execContext->pDisplayArea = pHelpStuff->pDisplayArea;
1128 XtAddCallback(btn, XmNactivateCallback,
1129 ExecuteContextCB, (XtPointer) execContext);
1133 free(filteredCmdStr);
1135 } /* cmd wasn't an alias */
1138 free(filteredCmdStr);
1141 /* Display message dialog */
1142 XtManageChild (msgDlg);
1149 /*****************************************************************************
1150 * Function: LocateWidgetId()
1155 *****************************************************************************/
1156 static Widget LocateWidgetId(
1163 static Cursor DfltOnItemCursor = 0;
1166 CompositeWidget comp_widget;
1178 Boolean notDone=TRUE;
1181 /* Make the target cursor */
1186 cursor = XCreateFontCursor (dpy, XC_question_arrow);
1189 _DtHelpProcessLock();
1190 if (0 == DfltOnItemCursor)
1195 unsigned int height;
1196 unsigned int xHotspot;
1197 unsigned int yHotspot;
1202 width = onitem32_width;
1203 height = onitem32_height;
1204 bits = (char *) onitem32_bits;
1205 maskBits = (char *) onitem32_m_bits;
1206 xHotspot = onitem32_x_hot;
1207 yHotspot = onitem32_y_hot;
1209 pixmap = XCreateBitmapFromData (dpy,
1210 RootWindowOfScreen(XtScreen(shellWidget)), bits,
1214 maskPixmap = XCreateBitmapFromData (dpy,
1215 RootWindowOfScreen(XtScreen(shellWidget)), maskBits,
1218 xcolors[0].pixel = BlackPixelOfScreen(ScreenOfDisplay(dpy, screen));
1219 xcolors[1].pixel = WhitePixelOfScreen(ScreenOfDisplay(dpy, screen));
1222 DefaultColormapOfScreen(ScreenOfDisplay(dpy, screen)),
1226 DfltOnItemCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
1227 &(xcolors[0]), &(xcolors[1]),
1228 xHotspot, yHotspot);
1229 XFreePixmap (dpy, pixmap);
1230 XFreePixmap (dpy, maskPixmap);
1231 } /* if dflt cursor not yet created */
1232 cursor = DfltOnItemCursor;
1233 _DtHelpProcessUnlock();
1234 } /* if to use the standard cursor */
1238 /* Grab the pointer using target cursor, letting it roam all over */
1239 status = XtGrabPointer (shellWidget, TRUE,
1240 ButtonPressMask|ButtonReleaseMask, GrabModeAsync,
1241 GrabModeAsync, None, cursor, CurrentTime);
1242 if (status != GrabSuccess)
1244 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 3,
1245 "Internal Error: Could not grab the mouse\nDtHelpReturnSelectedWidget aborted.\n"));
1246 *statusRet = DtHELP_SELECT_ERROR;
1252 /* Grab the Keyboard so we can catch the ESC button press */
1253 status = XtGrabKeyboard(shellWidget, False,
1254 GrabModeAsync, GrabModeAsync, CurrentTime);
1255 if (status != GrabSuccess)
1258 XtUngrabPointer (shellWidget, CurrentTime);
1259 XmeWarning(shellWidget,(char *)_DTGETMESSAGE(HUSET, 4,
1260 "Internal Error: Could not grab the keyboard\nDtHelpReturnSelectedWidget() aborted.\n"));
1261 *statusRet = DtHELP_SELECT_ERROR;
1265 /* We are ok so let the user select a window... */
1268 XtAppContext app = XtWidgetToApplicationContext(shellWidget);
1269 /* allow one more event */
1271 XtAppNextEvent(app, &event);
1275 while (!(mask = XtAppPending(app)))
1276 ; /* Busy waiting - so we don't lose our Lock! */
1278 if (!(mask & XtIMXEvent)) /* Not a XEvent, it's an alternate input/timer event */
1279 XtAppProcessEvent(app, mask); /* No blocking, since an event is ready */
1280 else /* We have an XEvent */
1282 /* Get the XEvent - we know it's there! Note that XtAppNextEvent
1283 would also process timers/alternate inputs.
1285 XtAppNextEvent(app, &event);
1286 #endif /* XTHREADS */
1287 widget = XtWindowToWidget(dpy, event.xany.window);
1289 switch (event.type) {
1296 /* Look for ESC key press and stop if we get one */
1297 if (event.xkey.state & ShiftMask)
1302 keySym = XLookupKeysym((XKeyEvent *)&event, offset);
1303 if (keySym == XK_Escape)
1305 XtUngrabKeyboard (shellWidget, CurrentTime);
1306 XtUngrabPointer (shellWidget, CurrentTime);
1307 *statusRet = DtHELP_SELECT_ABORT;
1311 XtDispatchEvent(&event);
1318 XtUngrabKeyboard (shellWidget, CurrentTime); /* Done with keyboard */
1319 XtUngrabPointer (shellWidget, CurrentTime); /* Done with pointer */
1321 /* If its null then the user selected some area outside our window(s) */
1322 if (widget == shellWidget)
1324 *statusRet = DtHELP_SELECT_INVALID;
1327 if (!XtIsComposite (widget))
1329 *statusRet = DtHELP_SELECT_VALID;
1333 /* Get the x and y and parent relative to the current window */
1334 parent = RootWindow(dpy, screen);
1335 target_win = XtWindow(widget);
1336 x = event.xbutton.x_root;
1337 y = event.xbutton.y_root;
1339 XTranslateCoordinates(dpy, parent, target_win, x, y,
1340 &new_x, &new_y, &sub);
1344 comp_widget = (CompositeWidget)widget;
1346 /* look for gadgets at this point */
1347 for (i = 0; i < comp_widget->composite.num_children; i++) {
1348 child = comp_widget->composite.children[i];
1349 /* put in check for only managed widgets here */
1350 if(XtIsManaged(child))
1351 if (PT_IN_CHILD (x, y, child))
1353 *statusRet = DtHELP_SELECT_VALID;
1358 *statusRet = DtHELP_SELECT_VALID;
1365 /*****************************************************************************
1366 * Function: Boolean RememberDir(String path)
1368 * Parameters: path Specifies the path to check.
1370 * Return Value: Boolean if the path name is good.
1372 * Description: Use the directory caching mechanism to improve performance
1373 * by remembering the directories that have already been
1376 *****************************************************************************/
1378 RememberDir(String path)
1384 if (path == NULL || *path == '\0')
1387 if (_DtHelpCeStrrchr(path, "/", MB_CUR_MAX, &ptr) == 0 && ptr != path)
1390 result = _DtHelpCeCheckAndCacheDir(path);
1393 if (result == 0 && access(path, R_OK) == 0 &&
1394 stat(path, &buf) == 0 && S_ISREG(buf.st_mode))
1400 /*****************************************************************************
1401 * Function: Boolean _DtHelpResolvePathname(
1406 * Return Value: Boolean.
1409 * Description: _DtHelpResolvePathname attempts to validate and expand a path
1410 * to a Cache Creek help access file.
1412 *****************************************************************************/
1413 Boolean _DtHelpResolvePathname(
1415 char * * io_fileName,
1416 _DtHelpVolumeHdl * io_volumeHandle,
1417 char * sysVolumeSearchPath,
1418 char * userVolumeSearchPath)
1420 String newPath = NULL;
1422 /* try to locate file and its entry, if present */
1423 newPath = _DtHelpFileLocate(DtHelpVOLUME_TYPE, *io_fileName,
1424 _DtHelpFileSuffixList,False,R_OK);
1426 /* If we found a valid file let's do some set up here */
1428 if (newPath != NULL) /* We have a valid volume file so open it */
1430 /* Close the current one if we have one open */
1431 if (*io_volumeHandle != NULL)
1432 _DtHelpCloseVolume(*io_volumeHandle);
1434 /* Open the help volume file and save the handle id */
1435 if (_DtHelpOpenVolume(newPath,io_volumeHandle) >= 0)
1437 /* Copy the expanded file location path */
1438 XtFree(*io_fileName);
1439 *io_fileName = newPath;
1445 /* ERROR; leave io_fileName untouched on error
1446 * We used to set it to null here now we just return what came in
1448 /* later NOTE: this seems strange, since we have closed the
1449 old volume, invalidating io_fileName */
1451 XmeWarning(widget,(char*)UtilMessage2);
1455 else /* We have a non-valid path */
1457 /* ERROR; leave io_fileName untouched on error
1458 * We used to set it to null here now we just return what came in
1461 XmeWarning(widget,(char*)UtilMessage0);
1471 /*****************************************************************************
1472 * Function: Boolean _DtHelpExpandHelpVolume(DtHelpDialogWidget nw);
1475 * Parameters: nw Specifies the current help dialog widget.
1477 * Return Value: Boolean.
1480 * Description: _DtHelpExpandHelpVolume looks for a $LANG variable in the
1481 * helpAccesFile string and if found, replaces it with the
1482 * current lang variable.
1484 *****************************************************************************/
1485 Boolean _DtHelpExpandHelpVolume(
1487 _DtHelpDisplayWidgetStuff * display,
1488 _DtHelpCommonHelpStuff * help,
1489 _DtHelpPrintStuff * print)
1491 Boolean validTopic = FALSE;
1492 Boolean validPath = FALSE;
1495 /* Free the old, and Copy the new volumeHandle to printVolume varialbe */
1496 if (print->printVolume != NULL)
1497 XtFree(print->printVolume);
1499 print->printVolume = XtNewString(display->helpVolume);
1501 validPath = _DtHelpResolvePathname((Widget)w,
1502 &print->printVolume,
1503 &display->volumeHandle,
1504 help->sysVolumeSearchPath,
1505 help->userVolumeSearchPath);
1508 /* Check to see that we resolved our path correctly */
1510 return (FALSE); /* RETURN */
1514 /* The following routine will malloc memory for the topLevelId
1515 * variable, so we must free our current version first.
1517 XtFree(help->topLevelId);
1519 /* Assign our top level topic for this help access file */
1520 validTopic = _DtHelpCeGetTopTopicId(display->volumeHandle, &topLevelId);
1524 /* Bad top level topic */
1525 help->topLevelId = NULL;
1530 /* recall that the topLevelId/File vars are malloc'd */
1531 help->topLevelId = topLevelId;
1538 /*****************************************************************************
1539 * Function: char *_DtHelpParseIdString(char * specification);
1542 * Parameters: specification Specifies an author defined help topic.
1544 * Return Value: Void.
1546 * Description: This function copies the locationId portion of the
1547 * specification and returns it to the calling routine.
1549 *****************************************************************************/
1550 char *_DtHelpParseIdString(
1551 char *specification)
1554 char *pAccessFile = NULL;
1556 char *returnStr=NULL;
1559 tmpSpec = XtNewString(specification);
1562 /* First look for a blank in the specification. This will signify that
1563 * we have a HelpAccessFile as part of the specification.
1566 /* The first call will return true, with the first string */
1567 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1568 returnStr = XtNewString(pAccessFile);
1570 /* The second call will return true only if we have another string */
1571 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1573 if (pAccessFile != NULL)
1575 /* We have a helpAccessFile in our specification */
1579 returnStr = XtNewString(pAccessFile);
1586 /* We don't have a helpAccessFile as part of the specificaiton
1587 * so we just return our locationId.
1597 /*****************************************************************************
1598 * Function: char *_DtHelpParseAccessFile(char * specification);
1601 * Parameters: specification Specifies an author defined help topic.
1603 * Return Value: Void.
1605 * Description: This function copies the helpAccessFile portion of the
1606 * specification and returns it to the calling routine.
1608 *****************************************************************************/
1609 char *_DtHelpParseAccessFile(
1610 char *specification)
1612 char *pAccessFile = NULL;
1614 char *returnStr=NULL;
1617 tmpSpec = XtNewString(specification);
1620 /* First look for a blank in the specification. This will signify that
1621 * we have a HelpAccessFile as part of the specification.
1624 /* The first call will return true, with the first string */
1625 pAccessFile = DtStrtok_r(tmpSpec, " ", &strtok_ptr);
1626 returnStr = XtNewString(pAccessFile);
1628 /* The second call will return true only if we have another string */
1629 pAccessFile = DtStrtok_r(NULL, " ", &strtok_ptr);
1631 if (pAccessFile != NULL)
1633 /* We have a helpAccessFile in our specification */
1636 /* If we have an accessFile, but it's not a full path, then we
1637 * must get the full path from the reg file.
1645 /* We don't have a helpAccessFile as part of the specificaiton
1662 /*****************************************************************************
1663 * Function: DtHelpReturnSelectedWidgetId
1665 * Parameters: parent Specifies the widget ID to use as the bases of
1666 * interaction, usually a top level shell.
1668 * cursor Specifies the cursor to be used for the pointer
1669 * during the interaction. If a value of NULL is
1670 * used this function will use a default cursor
1673 * widget This is the return value (e.g. the selected
1674 * widget). A value of NULL is returned on error.
1676 * Return Value: Status: (-1,0 or 1).
1678 * Purpose: Allows developers to get the widget ID for any widget in their UI
1679 * that the user has selected via the pointer. This function will
1680 * cause the cursor to change and allow a user to select an item in
1683 *****************************************************************************/
1684 int DtHelpReturnSelectedWidgetId(
1693 Widget selectedItem;
1694 int status=DtHELP_SELECT_ERROR;
1697 _DtHelpWidgetToAppContext(parent);
1699 _DtHelpAppLock(app);
1700 /* Setup some needed variables */
1701 dpy = XtDisplay(parent);
1702 retScr = XtScreen(parent);
1704 screen = XScreenNumberOfScreen(retScr);
1706 /* refresh the display */
1707 XmUpdateDisplay(parent);
1709 /* Change the curser to let the user select the desired widget */
1710 selectedItem = LocateWidgetId(dpy, screen, &status, parent, cursor);
1714 case DtHELP_SELECT_VALID:
1715 *widget = selectedItem;
1716 result = DtHELP_SELECT_VALID;
1719 case DtHELP_SELECT_ABORT:
1721 result = DtHELP_SELECT_ABORT;
1724 case DtHELP_SELECT_ERROR:
1726 result = DtHELP_SELECT_ERROR;
1729 case DtHELP_SELECT_INVALID:
1732 result = DtHELP_SELECT_INVALID;
1736 _DtHelpAppUnlock(app);
1747 /*****************************************************************************
1748 * Function: void _DtHelpTopicListAddToHead(
1752 * DtTopicListStruct *pHead,
1753 * DtTopicListStruct *pTale,
1759 * Return Value: Void.
1761 * Purpose: Adds an element to the top of the given topicList.
1763 *****************************************************************************/
1764 void _DtHelpTopicListAddToHead(
1766 XmString topicTitle,
1770 DtTopicListStruct **pHead,
1771 DtTopicListStruct **pTale,
1775 DtTopicListStruct *pTemp=NULL;
1777 /* add the new topic to the top */
1778 pTemp = (DtTopicListStruct *) XtMalloc((sizeof(DtTopicListStruct)));
1780 pTemp->pNext = (*pHead);
1781 pTemp->pPrevious = NULL;
1783 /* Assign the passed in values to our first element */
1784 pTemp->locationId = XtNewString(locationId);
1785 pTemp->topicTitleLbl = NULL;
1786 if (topicTitle != NULL)
1787 pTemp->topicTitleLbl= XmStringCopy(topicTitle);
1788 pTemp->topicType = topicType;
1789 pTemp->helpVolume = XtNewString(accessPath);
1790 pTemp->scrollPosition = scrollPosition;
1792 /* Add locationId as first element if pHead = NULL */
1795 /* Assign our tale pointer */
1796 (*pTale) = (*pHead);
1798 /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
1802 { /* We have a list so add the new topic to the top */
1804 (*pHead)->pPrevious = pTemp;
1806 /* Assign our tale pointer only the first time in this block */
1807 if (*totalNodes == 1)
1808 (*pTale) = (*pHead);
1810 /* Re-Assign our head pointer to point to the new head of the list */
1812 /* Bump our totalNode count */
1813 *totalNodes = *totalNodes +1;
1816 /* set the head to the current entry */
1819 /* If we have reached our maxNodes remove a node from the end of our list */
1820 if (*totalNodes > maxNodes)
1823 (*pTale) = (*pTale)->pPrevious;
1824 (*pTale)->pNext = NULL;
1825 pTemp->pPrevious = NULL;
1827 /* Free the id String and AccessPath elements */
1828 XtFree(pTemp->locationId);
1829 XtFree(pTemp->helpVolume);
1830 if (pTemp->topicTitleLbl != NULL)
1831 XmStringFree(pTemp->topicTitleLbl);
1833 /* Now, free the whole node */
1834 XtFree((char*)pTemp);
1836 /* Bump back our total node counter */
1837 *totalNodes = *totalNodes -1;
1845 /*****************************************************************************
1846 * Function: void _DtHelpTopicListDeleteHead(
1847 * DtTopicListStruct *pHead,
1848 * DtTopicListStruct *pTale,
1854 * Return Value: Void.
1856 * Purpose: Delets an element from the top of the given topicList.
1858 *****************************************************************************/
1859 void _DtHelpTopicListDeleteHead(
1860 DtTopicListStruct **pHead,
1861 DtTopicListStruct **pTale,
1864 DtTopicListStruct *pTemp=NULL;
1866 /* Delete the top node in our topic list */
1870 if(pTemp != (*pTale)) /* (e.g. more than one node in list) */
1872 (*pHead) = pTemp->pNext;
1873 pTemp->pNext = NULL;
1874 (*pHead)->pPrevious = NULL;
1876 /* Free the id String and accessPath elements */
1877 XtFree(pTemp->locationId);
1878 XtFree(pTemp->helpVolume);
1880 /* Now, free the whole node */
1881 XtFree((char*)pTemp);
1883 /* Bump back our total node counter */
1884 *totalNodes = *totalNodes -1;
1894 /*****************************************************************************
1895 * Function: void _DtHelpMapCB()
1899 * Parameters: client_data is the widget in reference to
1900 * which widget w is placed
1902 * Return Value: Void.
1904 * Purpose: Determins where a new child dialog should be mapped in
1905 * relation to its parent.
1907 * Algorithm: 1. attempt left or right placement with no overlap
1908 * 2. if fails, attempt up or down placement with no overlap
1909 * 3. if fails, determines location with least
1910 * amount of overlap, and places there.
1912 *****************************************************************************/
1913 XtCallbackProc _DtHelpMapCB(
1915 XtPointer client_data,
1916 XtPointer call_data )
1920 Position centeredY, bestX, bestY, pX, pY;
1921 Dimension pHeight, myHeight, pWidth, myWidth;
1922 Dimension maxX, maxY;
1923 int rhsX, lhsX, topY, botY; /* needs to be int, not Dimension */
1928 parent = (Widget)client_data;
1929 display = XtDisplay(w);
1930 screen = XtScreen(w);
1931 screenNumber = XScreenNumberOfScreen(screen);
1937 pHeight = XtHeight(parent);
1938 pWidth = XtWidth(parent);
1939 myHeight = XtHeight(w);
1940 myWidth = XtWidth(w);
1941 maxX = XDisplayWidth(display,screenNumber);
1942 maxY = XDisplayHeight(display,screenNumber);
1945 * 1. attempt left or right placement with no overlap
1946 * 2. if fails, attempt up or down placement with no overlap
1947 * 3. if fails, places on the right in the middle
1950 /* first try left right placement */
1951 bestY = pY + pHeight/2 - myHeight/2;
1954 lhsX = pX - myWidth - 8; /* 8: account for border */
1955 if ( ((int)(rhsX + myWidth)) < ((int) maxX) ) bestX = rhsX;
1956 else if ( lhsX > 0 ) bestX = lhsX;
1959 /* then try up down placement */
1960 bestX = pX + pWidth/2 - myWidth/2;
1961 botY = pY + pHeight;
1962 topY = pY - myHeight - 44; /* 44: account for menu border */
1963 if ( ((int)(botY + myWidth)) < ((int) maxY) ) bestY = botY;
1964 else if ( topY > 0 ) bestY = topY;
1967 /* otherwise, center vertically and on the right */
1968 bestX = maxX - myWidth;
1973 XtSetArg(args[0], XmNx, bestX);
1974 XtSetArg(args[1], XmNy, bestY);
1975 XtSetValues(w, args, 2);
1977 return((XtCallbackProc) NULL);
1986 /*****************************************************************************
1987 * Function: void _DtHelpMapCenteredCB(
1993 * Return Value: Void.
1995 * Purpose: Determins where the center of our help dialog is and sets
1996 * where new child dialog should be mapped such that its centered.
1998 *****************************************************************************/
1999 XtCallbackProc _DtHelpMapCenteredCB(
2001 XtPointer client_data,
2002 XtPointer call_data )
2006 Position newX, newY, pY, pX;
2007 Dimension pHeight, myHeight, pWidth, myWidth;
2009 parent = (Widget)client_data;
2013 pHeight = XtHeight(parent);
2014 pWidth = XtWidth(parent);
2015 myHeight = XtHeight(w);
2016 myWidth = XtWidth(w);
2019 newY = ((Position)(pHeight - myHeight) / 2) + pY;
2020 newX = ((Position)(pWidth - myWidth) / 2) + pX;
2022 XtSetArg(args[0], XmNx, newX);
2023 XtSetArg(args[1], XmNy, newY);
2024 XtSetValues(w, args, 2);
2026 return((XtCallbackProc) NULL);
2033 /*****************************************************************************
2034 * Function: void _DtHelpDisplayDefinitionBox(
2036 * Widget definitionBox,
2038 * char * locationId);
2044 * Purpose: This routine will create and post the definition box.
2045 * (e.g. the Quick Help Dialog widget)
2047 ****************************************************************************/
2048 void _DtHelpDisplayDefinitionBox(
2050 Widget **definitionBox,
2057 Widget printWidget, helpWidget, backWidget;
2058 XmString closeString;
2061 /* get the title from the main help dialog and use it here for */
2063 XtSetArg (args[n], XmNtitle, &(title)); ++n;
2064 XtGetValues (XtParent(parent), args, n);
2067 if (*definitionBox == NULL)
2070 /* Create the QuickHelpDialog widget to use as the definition box */
2071 closeString = XmStringCreateLocalized(((char *)_DTGETMESSAGE
2072 (HUSET, 2,"Close")));
2074 XtSetArg (args[n], DtNhelpVolume, path); n++;
2075 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2076 XtSetArg (args[n], DtNlocationId, locationId); n++;
2077 XtSetArg (args[n], DtNcloseLabelString, closeString); n++;
2078 XtSetArg (args[n], XmNtitle, title); n++;
2080 (Widget *)DtCreateHelpQuickDialog(parent, "definitionBox",
2082 XmStringFree(closeString);
2084 /* Catch the close callback so we can destroy the widget */
2085 XtAddCallback((Widget)*definitionBox, DtNcloseCallback,
2086 CloseDefBoxCB, (XtPointer) NULL);
2089 /* We do not want a print button for now so we unmap it */
2090 printWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2091 DtHELP_QUICK_PRINT_BUTTON);
2092 XtUnmanageChild (printWidget);
2094 /* We do not want a help button for now so we unmap it */
2095 helpWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2096 DtHELP_QUICK_HELP_BUTTON);
2097 XtUnmanageChild (helpWidget);
2100 /* We do not want a BACK button for now so we unmap it */
2101 backWidget = DtHelpQuickDialogGetChild ((Widget)*definitionBox,
2102 DtHELP_QUICK_BACK_BUTTON);
2103 XtUnmanageChild (backWidget);
2107 /* Adjust the decorations for the dialog shell of the dialog */
2109 XtSetArg(args[n], XmNmwmFunctions, MWM_FUNC_RESIZE | MWM_FUNC_MOVE); n++;
2110 XtSetArg (args[n], XmNmwmDecorations,
2111 MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH); n++;
2112 XtSetValues (XtParent(*definitionBox), args, n);
2114 /* Add the popup position callback to our history dialog */
2115 XtAddCallback (XtParent(*definitionBox), XmNpopupCallback,
2116 (XtCallbackProc)_DtHelpMapCenteredCB, (XtPointer)XtParent(parent));
2123 /* We already have one so lets use it. */
2125 /* Set the proper title */
2127 XtSetArg (args[n], XmNtitle, title); ++n;
2128 XtSetValues (XtParent(*definitionBox), args, n);
2130 /* Set the proper contents. */
2132 XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
2133 XtSetArg (args[n], DtNhelpVolume, path); n++;
2134 XtSetArg (args[n], DtNlocationId, locationId); n++;
2135 XtSetValues ((Widget)*definitionBox, args, n);
2140 /* Display the dialog */
2141 XtManageChild((Widget)*definitionBox);
2142 XtMapWidget(XtParent((Widget)*definitionBox));
2147 /*****************************************************************************
2148 * Function: static void CloseDefBoxCB(
2150 * XtPointer client_data,
2151 * XtPointer call_data);
2157 * Purpose: This routine closes and destroys the Definition Box
2158 * Dialog Widget that we create.
2160 ****************************************************************************/
2161 static void CloseDefBoxCB(
2163 XtPointer client_data,
2164 XtPointer call_data )
2176 /*****************************************************************************
2177 * Function: void _DtHelpDisplayFormatError()
2183 * Purpose: This routine generate and display the proper errror
2184 * message to the display area as well as send the proper
2185 * error to XmWarning() function.
2187 ****************************************************************************/
2188 void _DtHelpDisplayFormatError(
2189 XtPointer displayArea,
2194 XtPointer topicHandle;
2196 /* Set the string to the current help dialog */
2197 (void) _DtHelpFormatAsciiStringDynamic(displayArea, userError, &topicHandle);
2199 /* We ignor the status return here, because if we error out here we are
2200 * in big trouble because this is an error routine
2203 _DtHelpDisplayAreaSetList (displayArea, topicHandle, FALSE, -1);
2205 if (systemError != NULL)
2206 XmeWarning((Widget)widget, systemError);
2212 /*****************************************************************************
2213 * Function: void _DtHelpCommonHelpInit()
2219 * Purpose: This routine inits common help stuff
2221 ****************************************************************************/
2222 void _DtHelpCommonHelpInit(
2223 _DtHelpCommonHelpStuff * help)
2225 help->topLevelId = NULL;
2226 help->currentHelpFile = NULL;
2228 /* for help on help */
2229 if ( help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2230 help->helpOnHelpVolume = XtNewString(help->helpOnHelpVolume);
2231 if ( NULL == help->helpOnHelpVolume )
2232 help->helpOnHelpVolume = (char *)_DtHelpDefaultHelp4HelpVolume;
2233 help->pHelpListHead = NULL; /* Help List Pointer */
2234 help->onHelpDialog = NULL; /* help on help dialog */
2235 help->pDisplayArea = NULL; /* Display widget handle */
2237 /* get the search paths used by the widget */
2238 help->userVolumeSearchPath = _DtHelpGetUserSearchPath();
2239 help->sysVolumeSearchPath = _DtHelpGetSystemSearchPath();
2244 /*****************************************************************************
2245 * Function: void _DtHelpCommonHelpClean()
2251 * Purpose: This routine cleans up common help stuff
2253 ****************************************************************************/
2254 void _DtHelpCommonHelpClean(
2255 _DtHelpCommonHelpStuff * help,
2258 free(help->topLevelId);
2259 XtFree(help->currentHelpFile);
2261 help->topLevelId = NULL;
2262 help->currentHelpFile = NULL;
2266 if (help->helpOnHelpVolume != _DtHelpDefaultHelp4HelpVolume)
2267 XtFree(help->helpOnHelpVolume);
2269 /* Free all the info we saved for our help callbacks */
2270 _DtHelpListFree(&help->pHelpListHead);
2272 XtFree(help->userVolumeSearchPath);
2273 XtFree(help->sysVolumeSearchPath);
2275 memset(help,0,sizeof(_DtHelpCommonHelpStuff));
2279 /* Set our display area to a null starting vlaues */
2280 _DtHelpDisplayAreaClean(help->pDisplayArea);
2286 /*****************************************************************************
2287 * Function: void _DtHelpSetDlgButtonsWidth
2293 * Purpose: This routine cleans up common help stuff
2295 ****************************************************************************/
2296 void _DtHelpSetButtonPositions(
2299 Dimension minFormWidth,
2300 Dimension btnMargins,
2301 Dimension minBetweenBtnSpace)
2302 { /* position buttons */
2304 /* This code adds up the sizes of the buttons to go into
2305 the bottom row and calculates the form position percentages.
2306 All buttons are the same size, and are able to hold all
2307 the strings that may be dynamically placed in them.
2308 All buttons are 5% apart. */
2309 /* This code is specifically written to handle 3 buttons
2310 and assumes that the first 3 strings are to the ActionBtn */
2311 Dimension minWidthWithSpace = 0;
2312 Dimension borderWidth = 0;
2313 Dimension sumWidth = 0;
2314 Dimension leftPos = 0;
2315 Dimension rightPos = 0;
2316 Dimension spaceWidth = 0;
2318 Dimension maxBtnWidth = 0;
2320 XmFontList fontList = NULL;
2325 if (numBtns <= 0 || NULL == btnList[0]) return;
2327 /* get the fontList for the button */
2328 XtSetArg (args[0], XmNborderWidth, &borderWidth);
2329 XtSetArg (args[1], XmNfontList, &fontList);
2330 XtGetValues (btnList[0], args, 2);
2331 /* assumption: the fontList that is returned is not owned by me; don't free */
2333 /* cycle through all buttons */
2334 for (i=0; i<numBtns && NULL!=btnList[i]; i++)
2336 XmString labelString;
2338 /* get the label from the button */
2339 XtSetArg (args[0], XmNlabelString, &labelString);
2340 XtGetValues (btnList[i], args, 1);
2342 btnWidth = XmStringWidth(fontList,labelString) + borderWidth + btnMargins;
2343 if (btnWidth > maxBtnWidth) maxBtnWidth = btnWidth;
2345 XmStringFree(labelString);
2346 } /* for calcing widths */
2347 numBtns = i; /* number of valid buttons */
2349 /* calc the space */
2350 sumWidth = maxBtnWidth * numBtns;
2351 minWidthWithSpace = sumWidth + minBetweenBtnSpace * (numBtns * 2);
2352 if (minWidthWithSpace > minWidthWithSpace) minFormWidth = minWidthWithSpace;
2353 spaceWidth = ((int)(minFormWidth - sumWidth) / (numBtns * 2));
2355 /* scale pixels to percent */
2356 scale = 100.0 / (float) minFormWidth;
2358 /* set the positions of each button */
2359 leftPos = spaceWidth;
2360 for ( i=0; i<numBtns; i++ )
2362 rightPos = leftPos + maxBtnWidth;
2365 XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
2366 XtSetArg (args[n], XmNleftPosition, (Dimension) (((float) leftPos)*scale)); n++;
2367 XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2368 XtSetArg (args[n], XmNrightPosition,(Dimension) (((float) rightPos)*scale)); n++;
2369 XtSetValues (btnList[i], args, n);
2371 leftPos = rightPos + spaceWidth + spaceWidth;
2372 } /* setup the positions for all buttons */
2373 } /* _DtHelpSetDlgButtonsWidth */
2377 /*****************************************************************************
2378 * Function: _DtHelpXmFontListGetPropertyMax
2381 * fontList: an XmFontList
2382 * atom: an XA_xxx value (see Vol 1, chpt 6.2.9)
2383 * ret_propertyValue: ptr to long value that will hold the max value
2386 * True: got at least one value
2387 * False: unable to get any value; ret_propertyValue unchanged
2390 * This function returns the max value of XGetFontProperty calls
2391 * for each font in the XmFontList
2392 * If there is an error, ret_propertyValue is left unchanged.
2394 ****************************************************************************/
2396 _DtHelpXmFontListGetPropertyMax(
2397 XmFontList fontList,
2399 unsigned long *ret_propertyValue)
2401 Boolean gotValue = False;
2402 XmFontContext context;
2403 XmFontListEntry entry;
2406 if (NULL == fontList) return False; /* RETURN on error */
2408 /* walk through the fontList entries and add them in */
2409 XmFontListInitFontContext(&context,fontList);
2410 for ( entry = XmFontListNextEntry(context);
2412 entry = XmFontListNextEntry(context) )
2414 unsigned long value;
2417 fontData = XmFontListEntryGetFont(entry,&type);
2418 if (XmFONT_IS_FONT == type)
2420 XFontStruct * fontStruct;
2422 /* cast according to type */
2423 fontStruct = (XFontStruct *) fontData;
2425 if(XGetFontProperty(fontStruct, atom, &value) == TRUE)
2427 if(gotValue == False) /* haven't gotten any prop value yet */
2429 *ret_propertyValue = value;
2432 else /* have a good prop value already...get the max one */
2434 if(value > *ret_propertyValue)
2435 *ret_propertyValue = value;
2437 } /* if the getproperty call was good */
2439 else /* XmFONT_IS_FONTSET */
2442 XFontStruct **font_list;
2447 /* cast according to type */
2448 fontSet = (XFontSet) fontData;
2450 numfont=XFontsOfFontSet(fontSet,&font_list,&name_list);
2451 for(i = 0; i < numfont; i++)
2453 if(XGetFontProperty(font_list[i], atom, &value) == TRUE)
2455 if(gotValue == False) /* haven't gotten any prop value yet */
2457 *ret_propertyValue = value;
2460 else /* have a good prop value already...get the max one */
2462 if(value > *ret_propertyValue)
2463 *ret_propertyValue = value;
2465 } /* if the getproperty call was good */
2466 } /* for all fonts in the font set */
2467 } /* this entry uses a font set */
2468 } /* for all font entries in the font list */
2469 XmFontListFreeFontContext(context);