2
0

HelpUtil.c 77 KB

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