Merge branch 'coverity_dtsession'
[oweals/cde.git] / cde / programs / dtsession / SmRestore.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: SmRestore.c /main/26 1998/12/14 20:13:07 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30 /*************************************<+>*************************************
31  *****************************************************************************
32  **
33  **  File:        SmRestore.c
34  **
35  **  Project:     HP DT Session Manager (dtsession)
36  **
37  **  Description:
38  **  -----------
39  **  This file contains functions that are in charge of restoring state.
40  **  When the session manager is first started, it restores the state that
41  **  was either last saved (home state), or last exited (current state).  The
42  **  state restored depends on values the user has configured.
43  **
44  **
45  **
46  *******************************************************************
47  **  (c) Copyright Hewlett-Packard Company, 1990.  All rights are  
48  **  reserved.  Copying or other reproduction of this program      
49  **  except for archival purposes is prohibited without prior      
50  **  written consent of Hewlett-Packard Company.                     
51  ********************************************************************
52  **
53  **
54  **
55  *****************************************************************************
56  *************************************<+>*************************************/
57
58 #include <stdio.h>
59 #include <fcntl.h>
60 #include <unistd.h>
61 #include <string.h>
62 #ifdef _SUN_OS   /* to get the define for NOFILE */
63 #include <sys/param.h>
64 #endif /* _SUN_OS */
65 #include <sys/types.h>
66 #include <stdlib.h>
67 #ifdef __apollo
68 #include <X11/apollosys.h>        /* for pid_t struct in hp-ux sys/types.h */
69 #endif
70 #include <sys/socket.h>
71 #include <sys/wait.h>
72 #include <netinet/in.h>
73 #include <netdb.h>
74 #include <errno.h>
75 #include <ctype.h>
76
77 #include <X11/Intrinsic.h>
78 #include <X11/Xutil.h>
79 #include <X11/Xatom.h>
80 #include <X11/StringDefs.h>
81 #include <X11/keysymdef.h>
82 #include <X11/SM/SMlib.h>
83 #include <Xm/Xm.h>
84
85 # include <stdarg.h>
86 # define Va_start(a,b) va_start(a,b)
87
88 #include <Dt/DtP.h>
89 #include <Dt/Message.h>
90 #include <Dt/CommandM.h>
91 #include <Dt/Connect.h>
92 #include <Dt/Wsm.h>
93 #include <Dt/WsmP.h>
94 #include <Dt/UserMsg.h>
95 #include <Dt/SessionM.h>
96 #include <Dt/EnvControlP.h>
97 #include <Dt/Utility.h>
98 #include <Dt/MsgLog.h>
99 #include <bms/spc.h>
100 #include <Dt/CmdInv.h>
101 #include <Dt/ActionUtilP.h>
102
103 #include "Sm.h"
104 #include "SmResource.h"
105 #include "SmError.h"
106 #include "SmCommun.h"
107 #include "SmRestore.h"
108 #include "SmProtocol.h"
109 #include "SmConMgmt.h"
110 #include "SmSave.h"
111 #include "SmUI.h"
112 #include "SmGlobals.h"
113 #include "SmXSMP.h"
114 #include "SmDB.h"
115 #include "SmProp.h"
116
117 #ifndef __osf__
118 #include <X11/Xlibint.h>
119 #endif /* __osf__ */
120
121 /*
122  * Local variables
123  */
124 static const char * DISPLAY_NAME_EQUAL  = "DISPLAY=";
125 static const char * DISPLAY_NAME        = "DISPLAY";
126 static char * savedDisplay = NULL;
127
128 /*
129  * #define statements
130  */
131 #define MAXLINE     1024
132 #define MAXPATHSM   1023
133 #define MAX_QUOTE_DEPTH 10
134
135 #define SM_MAX_ARGS MAXLINE
136
137 #if defined (SVR4) || defined (__osf__)
138 #define REMOTE_CMD_STRING "rsh %s -n %s &"
139 #else
140 #define REMOTE_CMD_STRING "remsh %s -n %s &"
141 #endif
142
143
144 /*
145  * typedef statements
146  */
147 typedef struct
148 {
149     unsigned char *hostPtr;
150     unsigned char *cmdPtr;
151 } RemoteReq;
152
153 /*
154  * Variables global to this module only
155  */
156 static XtResource settingsResources[] =
157 {
158    {SmNaccelNum, SmCaccelNum, XtRInt, sizeof(int),
159      XtOffset(SessionSettingsPtr, accelNum),
160      XtRImmediate, (XtPointer) -1},
161    {SmNaccelDenom, SmCaccelDenom, XtRInt, sizeof(int),
162      XtOffset(SessionSettingsPtr, accelDenom),
163      XtRImmediate, (XtPointer) -1},
164    {SmNthreshold, SmCthreshold, XtRInt, sizeof(int),
165      XtOffset(SessionSettingsPtr, threshold),
166      XtRImmediate, (XtPointer) -1},
167
168    {SmNtimeout, SmCtimeout, XtRInt, sizeof(int),
169      XtOffset(SessionSettingsPtr, timeout),
170      XtRImmediate, (XtPointer) -1},
171    {SmNinterval, SmCinterval, XtRInt, sizeof(int),
172      XtOffset(SessionSettingsPtr, interval),
173      XtRImmediate, (XtPointer) -1},
174    {SmNpreferBlank, SmCpreferBlank, XtRInt, sizeof(int),
175      XtOffset(SessionSettingsPtr, preferBlank),
176      XtRImmediate, (XtPointer) 0},   
177    {SmNallowExp, SmCallowExp, XtRInt, sizeof(int),
178      XtOffset(SessionSettingsPtr, allowExp),
179      XtRImmediate, (XtPointer) 0},
180    
181    {SmNfontPath, SmCfontPath, XtRString, sizeof(String),
182          XtOffset(SessionSettingsPtr, fontDirs), XtRString, (XtPointer) ""},
183    
184    {SmNkeyClick, SmCkeyClick, XtRInt, sizeof(int),
185         XtOffset(SessionSettingsPtr, kbdState.key_click_percent),
186         XtRImmediate, (XtPointer) -1}, 
187    {SmNbellPercent, SmCbellPercent, XtRInt, sizeof(int),
188         XtOffset(SessionSettingsPtr, kbdState.bell_percent),
189         XtRImmediate, (XtPointer) -1}, 
190    {SmNbellPitch, SmCbellPitch, XtRInt, sizeof(int),
191         XtOffset(SessionSettingsPtr, kbdState.bell_pitch),
192         XtRImmediate, (XtPointer) -1},
193    {SmNbellDuration, SmCbellDuration, XtRInt, sizeof(int),
194         XtOffset(SessionSettingsPtr, kbdState.bell_duration),
195         XtRImmediate, (XtPointer) -1},
196    {SmNledMask, SmCledMask, XtRInt, sizeof(int),
197         XtOffset(SessionSettingsPtr, kbdState.led_mask),
198         XtRImmediate, (XtPointer) 0},
199    {SmNglobalRepeats, SmCglobalRepeats, XtRInt, sizeof(int),
200         XtOffset(SessionSettingsPtr, kbdState.global_auto_repeat),
201         XtRImmediate, (XtPointer) 2},
202    {SmNautoRepeats, SmCautoRepeats, XtRString, sizeof(String),
203         XtOffset(SessionSettingsPtr, autoRepeats), XtRString, (XtPointer) ""},
204    
205    {SmNbuttonMap, SmCbuttonMap, XtRString, sizeof(String),
206          XtOffset(SessionSettingsPtr, buttonMap), XtRString, (XtPointer) ""},
207    
208    {SmNnumKeyCode, SmCnumKeyCode, XtRInt, sizeof(int),
209         XtOffset(SessionSettingsPtr, numKeyCode), XtRImmediate, (XtPointer) 0},
210    {SmNkeySymsPerKey, SmCkeySymsPerKey, XtRInt, sizeof(int),
211         XtOffset(SessionSettingsPtr, keySymPerCode),
212         XtRImmediate, (XtPointer) 0},
213    {SmNkeySyms, SmCkeySyms, XtRString, sizeof(String),
214         XtOffset(SessionSettingsPtr, keySyms), XtRString, (XtPointer) ""},
215
216    {SmNmaxKeyPerMod, SmCmaxKeyPerMod, XtRInt, sizeof(int),
217         XtOffset(SessionSettingsPtr, maxKeyPerMod),
218         XtRImmediate, (XtPointer) 0},
219    {SmNmodMap, SmCmodMap, XtRString, sizeof(String),
220         XtOffset(SessionSettingsPtr, modSyms),
221         XtRString, (XtPointer) ""}, 
222
223    {SmNdidQuerySettings, SmCdidQuerySettings, XtRBoolean, sizeof(Boolean),
224      XtOffset(SessionSettingsPtr, didQuery),
225      XtRImmediate, (XtPointer) False},
226    {SmNshutDownState, SmCshutDownState, XtRInt, sizeof(int),
227      XtOffset(SessionSettingsPtr, confirmMode),
228      XtRImmediate, (XtPointer) 1},
229    {SmNshutDownMode, SmCshutDownMode, XtRInt, sizeof(int),
230      XtOffset(SessionSettingsPtr, startState),
231      XtRImmediate, (XtPointer) 4},
232 };
233
234 /*
235  * Variables used for parsing code
236  */
237
238 static unsigned char  fallBackLine[MAXLINE+2]; /* line buffer */
239 static unsigned char  *line;  /* line buffer */
240 static FILE *cfileP = NULL;   /* fopen'ed configuration file or NULL */
241 static int   linec = 0;       /* line counter for parser */
242 static unsigned char *parseP = NULL;   /* pointer to parse string */
243 static int fileSize = 0;
244 char **smExecArray = NULL;
245
246 /*
247  * Variables used for remote execution
248  */
249 static int      numRemoteExecs = 0;
250 unsigned char   *remoteBuf[MAX_SCREENS_SAVED];
251 unsigned int    actRemoteSize[MAX_SCREENS_SAVED];
252 RemoteReq       remoteBufPtr[MAX_REMOTE_CLIENTS];
253 static char     localHost[MAXHOSTNAMELEN];
254 static char     ** ignoreEnvPtr = NULL;
255
256 /*
257  * Timeout for workspace manager handshake
258  */
259 static Boolean  wmTimeout;
260
261 /* 
262  * These lines were added to support the builtin
263  * panacomm dtwm.
264  */
265
266 char   tmpExecWmFile[MAXPATHSM+1];
267 static Boolean  localWmLaunched = False;
268
269 /* 
270  *     ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  
271  * End of  lines were added to support the builtin
272  * panacomm dtwm.
273  */
274
275 /*
276  * Fonts
277  */
278 char *fonttype[] = {
279         "*systemFont",
280         "*userFont",
281         "*FontList",
282         "*buttonFontList",
283         "*labelFontList",
284         "*textFontList",
285         "*XmText*FontList",
286         "*XmTextField*FontList",
287         "*DtEditor*textFontList",
288         "*Font",
289         "*FontSet"
290 };
291
292 static char *fontclass[] = {
293         "*SystemFont",
294         "*UserFont",
295         "*FontList",
296         "*ButtonFontList",
297         "*LabelFontList",
298         "*TextFontList",
299         "*XmText*FontList",
300         "*XmTextField*FontList",
301         "*DtEditor*textFontList",
302         "*Font",
303         "*FontSet"
304 };
305
306 /*
307  * Local functions
308  */
309
310 static int RestoreSettings( void ) ;
311 static int RestoreClients( void ) ;
312 static unsigned char * GetNextLine( void ) ;
313 static unsigned int PeekAhead( unsigned char *, unsigned int ) ;
314 static unsigned char * GetSmartString( unsigned char **) ;
315 static void ForkWM( void ) ;
316 static int FillCmdBuf( unsigned char *, unsigned char **, 
317                         unsigned int *, unsigned int *, 
318                         unsigned int, unsigned int *) ;
319 static int FillRemoteBuf( unsigned char *, unsigned char *, 
320                           unsigned char *, unsigned char **,
321                           unsigned int *, unsigned int *, unsigned int) ;
322 static int FillHintBuf(unsigned char *, unsigned char **,
323                        unsigned int  *, unsigned int  *,
324                        unsigned int, unsigned int *);
325 static void WaitForWM( void ) ;
326 static void HandleWMClientMessage(Widget smWidget, XtPointer dummy,
327                                 XEvent *event);
328 static void WaitWMTimeout( XtPointer , XtIntervalId *) ;
329 static void FixEnvironmentData( void ) ;
330 static void ResetScreenInfo(unsigned char **,
331                             int *, unsigned int *,
332                             Boolean *, char *,
333                             char *);
334 static void RemoteRequestFailed(char *, void *);
335 static void RemoteRequestSucceeded(char *, void *);
336
337 static void SetTemporaryDisplay (
338         int                     screenNum);
339
340 int RestorePreferences(char *filename);
341
342 static void RestoreDisplay (
343         int                     screenNum);
344
345 static Boolean StartLocalClient (
346         char                    * program, 
347         char                    ** argv, 
348         char                    * cwd,
349         char                    ** envp, 
350         Boolean                 doChdir,
351         Boolean                 useIgnoreEnvResource);
352
353 static Boolean StartRemoteClient (
354         char                    * program, 
355         char                    ** argv, 
356         char                    * hostName, 
357         char                    * cwd,
358         char                    ** envp, 
359         Boolean                 useIgnoreEnvResource);
360
361 static Boolean CheckRequiredProperties (
362         XSMPClientDBRecPtr      pDbRec,
363         char                    * databaseName);
364
365 static Boolean CheckRequiredFields (
366         ProxyClientDBRecPtr     pDbRec,
367         char                    * databaseName,
368         int                     clientNum);
369
370 static void LogXSMPOpenDatabaseFailure (
371         char                    * databaseName,
372         DtMsgLogType            msgType,
373         int                     errorNum);
374
375 static void LogMissingPropertyMessage (
376         XSMPClientDBRecPtr      pDbRec,
377         char                    * propName,
378         char                    * databaseName,
379         DtMsgLogType            msgType);
380
381 static void LogCWDMessage (
382         char                    * badDir,
383         char                    * appName,
384         char                    * goodDir);
385
386 static char ** RemoveEnvironmentVars (
387         char                    **envp);
388
389 static void MarkFileDescriptors (
390         int                     start_fd,
391         int                     cmd,
392         int                     data);
393
394 \f
395 /*************************************<->*************************************
396  *
397  *  SetCompatState ()
398  *
399  *
400  *  Description:
401  *  -----------
402  *  Sets _DT_SM_STATE_INFO for dtstyle indicating compatibility mode
403  *
404  *
405  *  Inputs:
406  *  ------
407  *
408  * 
409  *  Outputs:
410  *  -------
411  *
412  *
413  *  Comments:
414  *  --------
415  *  The only thing dtstyle should be looking at is the compatMode
416  * 
417  *************************************<->***********************************/
418 int 
419 SetCompatState( void )
420 {
421     SmStateInfo state;
422
423     /*
424      * BEFORE any clients are started
425      * set a property on the top level window
426      * which lets the style manager know what state the sm is in
427      */
428     state.flags = SM_STATE_ALL;
429     state.smStartState = 0;
430     state.smConfirmMode = 0;
431     state.smCompatMode = True;
432     state.smSendSettings = False;
433     state.smCoverScreen = True;
434     state.smLockOnTimeoutStatus = smGD.lockOnTimeoutStatus;
435     state.smCycleTimeout = 0;
436     state.smLockTimeout = 0;
437     state.smSaverTimeout = 0;
438     state.smRandom = 0;
439     state.smDisplaySpecific = smGD.displaySpecific;
440
441     _DtSetSmState(smGD.display, smGD.topLevelWindow, &state);
442
443     XFlush(smGD.display);
444
445     return(0);
446
447 } /* END OF FUNCTION SetCompatState */
448
449 \f
450 /*************************************<->*************************************
451  *
452  *  SystemCmd (pchCmd)
453  *
454  *
455  *  Description:
456  *  -----------
457  *  This function fiddles with our signal handling and calls the
458  *  system() function to invoke a unix command.
459  *
460  *
461  *  Inputs:
462  *  ------
463  *  pchCmd = string with the command we want to exec.
464  *
465  *  Outputs:
466  *  -------
467  *
468  *
469  *  Comments:
470  *  --------
471  *  The system() command is touchy about the SIGCLD behavior. Restore
472  *  the default SIGCLD handler during the time we run system().
473  *
474  *************************************<->***********************************/
475
476 void
477 SystemCmd (char *pchCmd)
478 {
479     void (*signalHandler) ();
480
481     signalHandler = (void (*)())signal (SIGCHLD, SIG_DFL);
482
483     system (pchCmd);
484
485     signal (SIGCHLD, signalHandler);
486 } /* END OF FUNTION SystemCmd */
487
488
489 \f
490 /*************************************<->*************************************
491  *
492  *  RestoreState ()
493  *
494  *
495  *  Description:
496  *  -----------
497  *
498  *  Inputs:
499  *  ------
500  *
501  *  Outputs:
502  *  -------
503  *
504  *  Comments:
505  *  --------
506  *  When this routine is finished, all settings and resources will be restored.
507  *  Clients may not be, as they are actually restored by different processes.
508  * 
509  *************************************<->***********************************/
510 int 
511 RestoreState( void )
512 {
513     SmStateInfo state;
514     SmSaverInfo saver;
515     char convertCommand[MAXPATHSM+1];
516     int status;
517     Boolean fixedBuffer = False;
518     struct stat                 buf;
519     char *pchar;
520     Boolean useXrmDB = False;
521
522     /*
523      * Restore all the X settings which were active at the time of shutdown
524      */
525     RestoreSettings();
526
527     if (smGD.sessionType == HOME_SESSION)
528         smSettings.startState = DtSM_HOME_STATE;
529     else
530         smSettings.startState = DtSM_CURRENT_STATE;
531
532     /*
533      * BEFORE any clients are started
534      * set a property on the top level window
535      * which lets the style manager know what state the sm is in
536      */
537     state.flags = SM_STATE_ALL;
538     state.smStartState = smSettings.startState;
539     state.smConfirmMode = smSettings.confirmMode;
540     state.smCompatMode = smGD.compatMode;
541     state.smSendSettings = !smRes.querySettings;
542     state.smLockOnTimeoutStatus = smGD.lockOnTimeoutStatus;
543     state.smCycleTimeout = smSaverRes.cycleTimeout;
544     state.smLockTimeout = smSaverRes.lockTimeout;
545     state.smSaverTimeout = smSaverRes.saverTimeout;
546     state.smRandom = smSaverRes.random;
547     state.smDisplaySpecific = smGD.displaySpecific;
548
549     _DtSetSmState(smGD.display, smGD.topLevelWindow, &state);
550
551     saver.saverList = smGD.saverList;
552     _DtSetSmSaver(smGD.display, smGD.topLevelWindow, &saver);
553
554     /*
555      * Set up the Property telling all applications what session is being
556      * restored
557      */
558     XaSmRestoreMode = XInternAtom(smGD.display, _XA_DT_RESTORE_MODE, False);
559     XChangeProperty(smGD.display, RootWindow(smGD.display, 0),
560                     XaSmRestoreMode, XA_STRING, 8, PropModeReplace,
561                     (unsigned char *)smGD.restoreSession, strlen(smGD.restoreSession));
562     XFlush(smGD.display);
563
564     /*
565      * Check the session database and either parse it as an
566      * Xrm-database or the CDE1.0 format
567      */
568     if ((pchar = strrchr (smGD.clientPath, '/')) != NULL) 
569     {
570          pchar ++;
571          if ((*pchar != '\0') && (!strcmp (pchar, SM_CLIENT_FILE2)))
572              useXrmDB = True;
573     }
574
575     if (useXrmDB)
576     {
577         return (StartXSMPSession (smGD.clientPath));
578
579     } else {
580           /*
581            * Malloc line for parsing.
582            */
583           status = stat(smGD.clientPath, &buf);
584           if(status != -1)
585           {
586               fileSize = buf.st_size;
587           }
588
589           if (fileSize < MAXLINE + 1)
590           {
591               fileSize = MAXLINE + 1;
592           }
593
594           line = malloc(fileSize + 1);
595           if (line == NULL)
596           {
597               line = fallBackLine;
598               fileSize = MAXLINE + 1;
599               fixedBuffer = True;
600           }
601           cfileP = fopen(smGD.clientPath, "r");
602           if (cfileP == NULL)
603           {
604               PrintErrnoError(DtError, smNLS.cantOpenFileString);
605               if (!fixedBuffer && line)
606               {
607                   SM_FREE((char *)line);
608               }
609
610               return(-1);
611           }
612           RestoreClients();
613
614           if (!fixedBuffer && line)
615           {
616               SM_FREE((char *)line);
617           }
618     }
619
620     return(0);
621 }
622
623
624 \f
625 /*************************************<->*************************************
626  *
627  *  StartWM ()
628  *
629  *
630  *  Description:
631  *  -----------
632  *  Start up the window manager.  The default is to start dtmwm unless
633  *  another one is specified in a resource.
634  *
635  *
636  *  Inputs:
637  *  ------
638  *
639  * 
640  *  Outputs:
641  *  -------
642  *
643  *
644  *  Comments:
645  *  --------
646  *  When this routine is finished, all settings and resources will be restored.
647  *  Clients may not be, as they are actually restored by different processes.
648  * 
649  *************************************<->***********************************/
650 int 
651 StartWM( void )
652 {
653     char wmStartupErrorString[(2 * MAXPATHSM) + 1];
654     char localWmErrorString[(2 * MAXPATHSM) + 1];
655     Boolean goodWmStartup = True;
656     int status;
657   
658     if((smGD.wmStartup == NULL) || (*smGD.wmStartup == 0))
659     {
660         ForkWM();
661     }
662     else
663     {
664         CreateExecString(smGD.wmStartup);
665
666         /*
667          * check to see if the wmStartup string exists and is
668          * executable.
669          */
670         status = access(smExecArray[0], F_OK | X_OK);
671         if(status == -1)
672         {
673             goodWmStartup = False;
674             CreateExecString(CDE_INSTALLATION_TOP "/bin/dtwm");     
675         }
676         
677         if(smExecArray[0] != NULL)
678         {
679             (void) StartClient(smExecArray[0], smExecArray, NULL, NULL, 
680                                 NULL, False, False, -1);
681         }
682     }
683     
684     /*
685      * We used to start the message server before the window
686      * manager and then if the message server did not start
687      * we would exit.  Now we start the window manager, then
688      * start the message server and then wait for the window
689      * manager.  This seems to improve performance.
690      */
691
692     StartMsgServer();
693     
694     if (goodWmStartup == False)
695     {
696         sprintf(wmStartupErrorString, GETMESSAGE(16, 7,
697           "The wmStartupCommand resource is set to:\n\n"
698           "%s\n\n"
699           "This file does not exist or is not executable.\n"
700           CDE_INSTALLATION_TOP "/bin/dtwm will be started "
701           "instead.\n"),
702           smGD.wmStartup);
703         PrintError(DtError, wmStartupErrorString);
704     }
705
706     WaitForWM();
707
708     /* 
709      * These lines were added to support the builtin
710      * panacomm dtwm.
711      */
712
713     if (localWmLaunched && wmTimeout)
714     {
715         if (!smGD.userSetWaitWmTimeout)
716         {
717             smRes.waitWmTimeout = smGD.savedWaitWmTimeout;
718         }
719
720         localWmLaunched = False;
721         /*
722          * A special version of a built-in Xterminal dtwm
723          * was attempted and failed.
724          * Try to launch .../dt/bin/dtwm instead
725          */
726         
727         CreateExecString(CDE_INSTALLATION_TOP "/bin/dtwm");         
728         if(smExecArray[0] != NULL)
729         {
730             (void) StartClient(smExecArray[0], smExecArray, NULL, 
731                                 NULL, NULL, False, False, -1);
732         }
733         WaitForWM();
734         sprintf(localWmErrorString, GETMESSAGE(16, 9,
735           "The following window manager did not start:\n\n"
736           "      %s\n\n"
737           "This message indicates you tried to start a\n"
738           "window manager that is built into an X terminal.\n"
739           "This will only work with X terminals that support this protocol.\n"
740           CDE_INSTALLATION_TOP "/bin/dtwm will be started instead.\n"),
741           tmpExecWmFile);
742         PrintError(DtError, localWmErrorString);
743     }
744     /* 
745      *     ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  
746      * End of  lines were added to support the builtin
747      * panacomm dtwm.
748      */
749
750     
751     return(0);
752 }
753
754 \f
755 /*************************************<->*************************************
756  *
757  *  ReloadResources ()
758  *
759  *
760  *  Description:
761  *  -----------
762  *  Reloads RESOURCE_MANAGER during running session
763  *
764  *
765  *  Inputs:
766  *  ------
767  *
768  *  Outputs:
769  *  -------
770  *
771  *  Comments:
772  *  --------
773  *
774  *************************************<->***********************************/
775
776 void
777 ReloadResources(void)
778 {
779  /*
780   * Load sys.resources and .Xdefaults
781   */
782   RestoreResources(True,
783                    "-load",
784                    "-system",
785                    "-xdefaults",
786                    NULL);
787
788  /*
789   * Merge _DT_SM_PREFERENCES
790   */
791   RestorePreferences(NULL);
792
793   SetSystemReady();
794 }
795
796 \f
797 /*************************************<->*************************************
798  *
799  *  RestoreResources (errorHandlerInstalled, options ... )
800  *
801  *
802  *  Description:
803  *  -----------
804  *  Calls routines responsible for restoring resources.
805  *  Resources are restored by a fork and exec of dtsession_res.
806  *
807  *
808  *  Inputs:
809  *  ------
810  *
811  * 
812  *  Outputs:
813  *  -------
814  *
815  *
816  *  Comments:
817  *  --------
818  *  When this routine is finished, all settings and resources will be restored.
819  *  Clients may not be, as they are actually restored by different processes.
820  * 
821  *************************************<->***********************************/
822
823 int 
824 RestoreResources( Boolean errorHandlerInstalled, ... )
825 {
826     pid_t  forkrc;
827     int    childStatus, execStatus, i;
828     char *pgrm, *p;
829     char *argv[20]; 
830     va_list  args;
831
832 #if 0
833     /* JET - this seems like a bad (and unused) idea */
834     /*
835      * Check for alternate resource loader.
836      */
837      if ((pgrm = getenv("DTLOADRESOURCES")) == NULL)
838      {
839        pgrm = CDE_INSTALLATION_TOP "/bin/dtsession_res";
840      }
841 #else
842        pgrm = CDE_INSTALLATION_TOP "/bin/dtsession_res";
843 #endif
844
845     /*
846      * By convention, exec() wants arg0 to be the program name. Ex: if pgrm
847      * is /usr/dt/bin/dtsession_res, the program name is dtsession_res.
848      * If all else fails, use pgrm.
849      */
850      argv[0] = (p = strrchr(pgrm, '/')) != NULL && *(p+1) != '\0' ? p+1 : pgrm;
851
852      i = 0;
853      Va_start(args,errorHandlerInstalled);
854      do
855      {
856        i++;
857        argv[i] = va_arg(args, char *);
858      }
859      while(argv[i]);
860      va_end(args);
861
862     /*
863      * if an error handler is installed - remove it
864      */
865     if(errorHandlerInstalled)
866     {
867         sigaction(SIGCHLD, &smGD.defvec, (struct sigaction *) NULL);
868     }
869     
870     /*
871      * Fork and exec the xrdb process to load in the file created by
872      * writing out the resource manager string generated by the last
873      * session termination.
874      */
875
876     for(i = 0;(i < 10) && ((forkrc = vfork()) < 0);i++)
877     {
878         if(errno != EAGAIN)
879         {
880             break;
881         }
882         sleep(2);
883     }
884
885     if(forkrc < 0)
886     {
887         PrintErrnoError(DtError, smNLS.cantForkClientString);
888         return(-1);
889     }
890         
891     /*
892      * Fork succeeded - now do the exec
893      */
894     if(forkrc == 0)
895     {
896         SetSIGPIPEToDefault ();
897
898 #ifndef __hpux
899         /*
900          * Set the gid of the process back from bin
901          */
902 #ifndef SVR4
903         setregid(smGD.runningGID, smGD.runningGID);
904 #else
905         setgid(smGD.runningGID);
906         setegid(smGD.runningGID);
907 #endif
908 #endif
909 #if defined(__osf__) || defined(CSRG_BASED)
910         setsid();
911 #else
912         (void) setpgrp();
913 #endif /* __osf__ */
914
915         MarkFileDescriptors (3, F_SETFD, 1);
916
917         execStatus = execv(pgrm, argv);
918
919         if(execStatus != 0)
920         {
921             char   clientMessage[MAXPATHLEN + 256];
922
923             memset(clientMessage, 0, MAXPATHLEN + 256);
924             snprintf(clientMessage, (MAXPATHLEN + 256) - 1,
925                      ((char *)GETMESSAGE(16, 1, "Unable to exec process %s.  No session resources will be restored.")), pgrm);
926             PrintErrnoError(DtError, clientMessage);
927             SM_EXIT(-1);
928         }
929     }
930
931     while(wait(&childStatus) != forkrc);
932
933     /*
934      * if an error handler is installed - remove it
935      */
936     if(errorHandlerInstalled)
937     {
938         sigaction(SIGCHLD, &smGD.childvec, (struct sigaction *) NULL);
939     }
940
941     return(0);
942 }
943
944 \f
945 /*************************************<->*************************************
946  *
947  *  RestorePreferences ( filename)
948  *
949  *
950  *  Description:
951  *  -----------
952  *  
953  *  This routine has two roles:
954  * 
955  *  1) If 'filename' specified, the content of filename is read, and
956  *     _DT_SM_PREFERENCES is populated with its content. This is used
957  *     at session startup to set the initial state of _DT_SM_PREFERENCES.
958  *
959  *  2) If 'filename' is NULL, the content of _DT_SM_PREFERENCES is
960  *     merged into RESOURCE_MANAGER. This is used when resources are
961  *     reloaded at user request during a session.
962  *
963  *  Inputs:
964  *  ------
965  *
966  * 
967  *  Outputs:
968  *  -------
969  *
970  *
971  *  Comments:
972  *  --------
973  * 
974  *************************************<->***********************************/
975
976 int 
977 RestorePreferences( 
978         char *filename )
979 {
980   char *data;
981
982   if (filename)
983   {
984     FILE *fp;
985     int size;
986     struct stat statinfo;
987
988     if(access(filename,R_OK) != 0)
989     {
990       return(0);
991     }
992
993    /*
994     * Determine size of file.
995     */
996     if (stat(filename, &statinfo) == -1)
997     {
998       return(0);
999     }
1000
1001    /*
1002     * Get some memory.
1003     */
1004     if ((data = (char *)SM_MALLOC(statinfo.st_size + 1)) == NULL)
1005     {
1006       return(0);
1007     }
1008
1009    /*
1010     * Read file into memory.
1011     */
1012     if ((fp = fopen(filename, "r")) == NULL)
1013     {
1014       SM_FREE(data);
1015       return(0);
1016     }
1017
1018     size = fread(data, 1, statinfo.st_size, fp);
1019
1020     if (size == statinfo.st_size)
1021     {
1022      /*
1023       * Merge .Xdefaults string into RESOURCE_MANAGER database, and
1024       * also convert to Xrm database form for later subtraction.
1025       */
1026       data[size] = '\0';
1027       _DtAddResString(smGD.display, data, _DT_ATR_PREFS);
1028     }
1029     fclose(fp);
1030     SM_FREE(data);
1031   }
1032   else
1033   {
1034    /*
1035     * Read string from _DT_SM_PREFERENCES
1036     */
1037     data = _DtGetResString(smGD.display, _DT_ATR_PREFS);
1038   
1039    /*
1040     * Merge string into RESOURCE_MANAGER
1041     */
1042     _DtAddResString(smGD.display, data, _DT_ATR_RESMGR);
1043     XFree(data);
1044   }
1045   return(0);
1046 }
1047
1048
1049
1050 \f
1051 /*************************************<->*************************************
1052  *
1053  *  RestoreSettings ()
1054  *
1055  *
1056  *  Description:
1057  *  -----------
1058  *  In charge of restoring all settings.  Settings are stored in resource
1059  *  format so it gets the values by getting the resource values stored in
1060  *  a resource file that was created by the session manager.
1061  *
1062  *
1063  *  Inputs:
1064  *  ------
1065  *  smGD.settingPath = path that points to the settings resource file.
1066  *
1067  * 
1068  *  Outputs:
1069  *  -------
1070  *
1071  *
1072  *  Comments:
1073  *  --------
1074  *  This routine messes with the actual strings returned by the resource
1075  *  manager by tokenizing them, so these session settings resources should
1076  *  not be accessed again.
1077  * 
1078  *************************************<->***********************************/
1079 static int 
1080 RestoreSettings( void )
1081 {
1082     XrmDatabase         smBase = NULL;
1083     XKeyboardControl    kbdControl;
1084     int                 kbdControlMask;
1085     char                **restorePtrArray, **tmpRestore;
1086     char                *restoreCharArray;
1087     int                 numArgs, ptrSize, charSize;
1088     int                 i;
1089     char                *tmpKey;
1090     KeySym              *tmpSyms, codeSym;
1091     int                 symSize;
1092     KeyCode             *tmpCode;
1093     XModifierKeymap     restoreMod;
1094
1095     ptrSize = 50;
1096     charSize = 5000;
1097     restorePtrArray = (char **) SM_MALLOC (ptrSize * sizeof(char *));
1098     restoreCharArray = (char *) SM_MALLOC (charSize * sizeof(char));
1099     if((restorePtrArray == NULL) || (restoreCharArray == NULL))
1100     {
1101         PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1102
1103         if(restorePtrArray != NULL)
1104         {
1105             SM_FREE((char *) restorePtrArray);
1106         }
1107         else
1108         {
1109             if(restoreCharArray != NULL)
1110             {
1111                 SM_FREE(restoreCharArray);
1112             }
1113         }
1114         return(-1);
1115     }
1116
1117     /*
1118      * Load the resources from the SM database file
1119      */
1120     if (smGD.settingPath[0] != 0)
1121     {
1122        smBase = XrmGetFileDatabase(smGD.settingPath);
1123
1124        if(smBase == NULL)
1125        {
1126            PrintError(DtError, GETMESSAGE(16, 2, "Invalid client settings file.  No settings restored."));
1127            return(-1);
1128        }
1129        else
1130        {
1131            XrmMergeDatabases(smBase, &(smGD.display->db));
1132        }
1133     }
1134
1135     /*
1136      * Retrieve the session settings file from the database
1137      */
1138     XtGetApplicationResources(smGD.topLevelWid, (XtPointer) &smSettings,
1139                               settingsResources, XtNumber(settingsResources),
1140                               NULL, 0);
1141
1142     /*
1143      * Copy any string resources since they may be overwritten in
1144      * Xrm calls.
1145      */
1146     smGD.fontDirs  = SmNewString(smSettings.fontDirs);
1147     smGD.autoRepeats  = SmNewString(smSettings.autoRepeats);
1148     smGD.buttonMap  = SmNewString(smSettings.buttonMap);
1149     smGD.keySyms  = SmNewString(smSettings.keySyms);
1150     smGD.modSyms  = SmNewString(smSettings.modSyms);
1151
1152
1153     /*
1154      * This is provided for backward compatibility sake.  The values that
1155      * confirmMode can take have changed
1156      */
1157     if(smSettings.confirmMode == DtSM_ASK_STATE)
1158     {
1159         smSettings.confirmMode = DtSM_VERBOSE_MODE;
1160     }
1161
1162     /*
1163      * If the user has previously used the "query" method, and now wishes
1164      * to use "only what I've customized" method, then we have to start
1165      * from scratch.  So don't set anything until customizer tells me to
1166      */
1167     if((smSettings.didQuery == True) && (smRes.querySettings == False))
1168     {
1169         SM_FREE((char *) restorePtrArray);
1170         SM_FREE(restoreCharArray);
1171         return(0);
1172     }
1173     
1174     /*
1175      * Restore pointer control settings
1176      */
1177     if((smSettings.accelNum > -1 ) || (smSettings.threshold > -1))
1178     {
1179         XChangePointerControl(smGD.display, True, True,
1180                               smSettings.accelNum,
1181                               smSettings.accelDenom,
1182                               smSettings.threshold);
1183         smToSet.pointerChange = True;
1184     }
1185     else
1186     {
1187         smToSet.pointerChange = False;
1188     }
1189
1190     /*
1191      * Restore screen saver settings if any are set to non-default
1192      * values.
1193      */
1194     if ((smSettings.timeout > -1) || (smSettings.interval > -1) ||
1195         (smSaverRes.saverTimeout > -1) || (smSaverRes.lockTimeout > -1) ||
1196         (smSaverRes.cycleTimeout > -1))
1197     {
1198
1199         /* 
1200          * For the time between Screen Savers, use the cycleTimeout 
1201          * if the user has set this value.  Otherwise, use the interval 
1202          * value that was set when the session was saved.
1203          */
1204         if (smSaverRes.cycleTimeout < 0)
1205         {
1206             screenSaverVals.smInterval = smSettings.interval;
1207         }
1208         else
1209         {
1210             screenSaverVals.smInterval = smSaverRes.cycleTimeout;
1211         }
1212
1213         /* 
1214          * For the screen saver time, use the minimum of the values set for
1215          * saverTimeout or lockTimeout if the user has set one of these
1216          * values.
1217          *
1218          * Otherwise, use the Timeout value that was set when the
1219          * session was saved.
1220          *
1221          * If it is not set, then use the minimum of the values set for 
1222          * saverTimeout or lockTimeout.  Set timeout to the Timeout value 
1223          * that was saved.
1224          */
1225         if ((smSaverRes.saverTimeout > -1) ||
1226             (smSaverRes.lockTimeout  > -1))
1227         {
1228             if (smSaverRes.saverTimeout > -1)
1229             {
1230                 if ((smSaverRes.lockTimeout > -1) &&
1231                     (smSaverRes.lockTimeout < smSaverRes.saverTimeout))
1232                 {
1233                     screenSaverVals.smTimeout = smSaverRes.lockTimeout;
1234                 }
1235                 else
1236                 {
1237                     screenSaverVals.smTimeout = smSaverRes.saverTimeout;
1238                 }
1239             }
1240             else
1241             {
1242                 screenSaverVals.smTimeout = smSaverRes.lockTimeout;
1243             }
1244         }
1245         else
1246         {
1247             screenSaverVals.smTimeout = smSettings.timeout;
1248         }
1249         screenSaverVals.smPreferBlank = smSettings.preferBlank;
1250         screenSaverVals.smAllowExp = smSettings.allowExp;
1251
1252         /* Notify X of the new screen saver values */
1253         XSetScreenSaver(smGD.display, screenSaverVals.smTimeout,
1254                         screenSaverVals.smInterval,
1255                         screenSaverVals.smPreferBlank,
1256                         screenSaverVals.smAllowExp);
1257
1258         /* 
1259          * If using timeout or interval values that were
1260          * previously saved, then set flag to indicate that they
1261          * should be saved again when the state for the session
1262          * is saved.
1263          */
1264         if ((smSettings.timeout > -1) || (smSettings.interval > -1))
1265         {
1266             smToSet.screenSavChange = True;
1267         }
1268         else
1269         {
1270             smToSet.screenSavChange = False;
1271         }
1272
1273     }
1274     else
1275     {
1276         smToSet.screenSavChange = False;
1277     }
1278
1279     /*
1280      * Get the font path.  Then set it.
1281      */
1282     tmpRestore = restorePtrArray;
1283     numArgs = 0;
1284     *tmpRestore = strtok(smGD.fontDirs, ",");
1285
1286     while(*tmpRestore != NULL)
1287     {
1288         numArgs++; tmpRestore++;
1289         *tmpRestore = strtok(NULL, ",");
1290         if((numArgs >= ptrSize) && (*tmpRestore != NULL))
1291         {
1292             ptrSize += 50;
1293             restorePtrArray = (char **)SM_REALLOC((char *)
1294                                                   restorePtrArray, ptrSize *
1295                                                   sizeof(char *));
1296             if(restorePtrArray == NULL)
1297             {
1298                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1299                 SM_FREE(restoreCharArray);
1300                 return(-1);
1301             }
1302         }
1303     }
1304
1305     if(numArgs > 0)
1306     {
1307         XSetFontPath(smGD.display, restorePtrArray, numArgs);
1308     }
1309
1310     /*
1311      * Restore the keyboard control information.  In order for it
1312      * to be restored it has to be changed from a XKeyboardState
1313      * format to an XKeyboardControl format.
1314      */
1315     if((smSettings.kbdState.key_click_percent > -1) ||
1316        (smSettings.kbdState.bell_percent > -1) ||
1317        (smSettings.kbdState.bell_pitch > -1) ||
1318        (smSettings.kbdState.bell_duration > -1))
1319     {
1320         
1321         kbdControlMask = 0;
1322         if((smSettings.kbdState.bell_percent > -1) ||
1323            (smSettings.kbdState.bell_pitch > -1) ||
1324            (smSettings.kbdState.bell_duration > -1))
1325         {
1326             kbdControl.bell_percent = smSettings.kbdState.bell_percent;
1327             kbdControl.bell_pitch = smSettings.kbdState.bell_pitch;
1328             kbdControl.bell_duration = smSettings.kbdState.bell_duration;
1329             kbdControlMask |= (KBBellPercent | KBBellPitch | KBBellDuration);
1330             smToSet.audioChange = True;
1331             audioVals.smBellPercent = smSettings.kbdState.bell_percent;
1332             audioVals.smBellPitch = smSettings.kbdState.bell_pitch;
1333             audioVals.smBellDuration = smSettings.kbdState.bell_duration;
1334         }
1335         else
1336         {
1337             smToSet.audioChange = False;
1338         }
1339
1340         if((smSettings.kbdState.key_click_percent > -1) ||
1341            (smSettings.kbdState.global_auto_repeat != AutoRepeatModeOn))
1342         {
1343             kbdControl.key_click_percent =
1344                 smSettings.kbdState.key_click_percent;
1345             kbdControlMask |= KBKeyClickPercent;
1346             smToSet.keyboardChange = True;
1347             keyboardVals.smKeyClickPercent =  kbdControl.key_click_percent;
1348         }
1349         else
1350         {
1351             smToSet.keyboardChange = False;
1352         }
1353         
1354
1355         /*
1356          * NOTICE THAT THE LED'S DON'T GET RESET.  THIS IS BECAUSE LED STUFF
1357          * IS MACHINE DEPENDENT.
1358          */
1359         /*
1360          * Set the auto repeat stuff
1361          */
1362         tmpKey = strtok(smGD.autoRepeats, ",");
1363         if((tmpKey == NULL) &&
1364             ((smSettings.kbdState.global_auto_repeat == AutoRepeatModeOff) ||
1365              (smSettings.kbdState.global_auto_repeat == AutoRepeatModeOn)))
1366         {
1367             smToSet.keyboardChange = True;
1368             kbdControl.auto_repeat_mode =
1369                 smSettings.kbdState.global_auto_repeat;
1370             kbdControlMask |= KBAutoRepeatMode;
1371             XChangeKeyboardControl(smGD.display, kbdControlMask, &kbdControl);
1372             keyboardVals.smGlobalAutoRepeat =
1373                 smSettings.kbdState.global_auto_repeat;
1374         }
1375         else
1376         {
1377             if(tmpKey != NULL)
1378             {
1379                 smToSet.keyboardChange = True;
1380                 kbdControl.auto_repeat_mode = smSettings.kbdState.global_auto_repeat;
1381                 kbdControlMask |= KBAutoRepeatMode;
1382                 XChangeKeyboardControl(smGD.display,
1383                                        kbdControlMask, &kbdControl);
1384                 kbdControl.auto_repeat_mode = AutoRepeatModeOn;
1385                 kbdControlMask = KBAutoRepeatMode | KBKey;
1386                 /*
1387                  * This is only involked when there is auto repeats set for
1388                  * specific keys only.  It is VERY SLOW code so unless you
1389                  * have to save off auto repeats for single keys - DONT
1390                  */
1391                 while(tmpKey != NULL)
1392                 {
1393                     kbdControl.key = atoi(tmpKey);
1394                     XChangeKeyboardControl(smGD.display,
1395                                            kbdControlMask, &kbdControl);
1396                     tmpKey = strtok(NULL, ",");
1397                 }
1398             }
1399             else
1400             {
1401                 if(kbdControlMask != 0)
1402                 {
1403                     XChangeKeyboardControl(smGD.display,
1404                                            kbdControlMask, &kbdControl);
1405                 }
1406             }
1407         }
1408     }
1409     else
1410     {
1411         smToSet.audioChange = False;
1412         smToSet.keyboardChange = False;
1413     }
1414
1415     /*
1416      * Restore the button mappings
1417      */
1418     numArgs = 0;
1419     tmpKey = strtok(smGD.buttonMap, ",");
1420     
1421     if(tmpKey != NULL)
1422     {
1423         smToSet.pointerMapChange = True;
1424     }
1425     else
1426     {
1427         smToSet.pointerMapChange = False;
1428     }
1429         
1430     while(tmpKey != NULL)
1431     {
1432         restoreCharArray[numArgs] = (char) atoi(tmpKey);
1433         numArgs++;
1434         tmpKey = strtok(NULL, ",");
1435         if((numArgs >= charSize) && (tmpKey != NULL))
1436         {
1437             charSize += 500;
1438             restoreCharArray = (char *) SM_REALLOC(restoreCharArray,
1439                                                 charSize * sizeof(char));
1440             if(restoreCharArray == NULL)
1441             {
1442                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1443                 SM_FREE((char *)restorePtrArray);
1444                 return(-1);
1445             }
1446         }
1447     }
1448     
1449     if(numArgs > 0)
1450     {
1451         XSetPointerMapping(smGD.display, (unsigned char *)restoreCharArray, numArgs);
1452
1453         /*
1454          * Copy the pointer map into the saved map for logout
1455          */
1456          smToSet.numButton = ((numArgs > 5) ? 5  : numArgs);
1457         for(i = 0; i < smToSet.numButton;i++)
1458         {
1459             smToSet.pointerMap[i] = restoreCharArray[i];
1460         }
1461     }
1462
1463     /*
1464      * Restore the key mappings
1465      */
1466     if(smSettings.numKeyCode > 0)
1467     {
1468         tmpSyms = (KeySym *) restoreCharArray;
1469         symSize = (charSize * sizeof(char)) / sizeof(KeySym);
1470         tmpKey = strtok(smGD.keySyms, ",");
1471         for(i = 0;tmpKey != NULL;i++)
1472         {
1473             tmpSyms[i] = (KeySym) atol(tmpKey);
1474             tmpKey = strtok(NULL, ",");
1475             numArgs = i + 1;
1476             if((numArgs >= symSize) && (tmpKey != NULL))
1477             {
1478                 charSize += 1000;
1479                 symSize = (charSize * sizeof(char))/sizeof(KeySym);
1480                 restoreCharArray = (char *) SM_REALLOC(restoreCharArray,
1481                                      (charSize * sizeof(char)));
1482                 if(restoreCharArray == NULL)
1483                 {
1484                     PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1485                     SM_FREE((char *) restorePtrArray);
1486                     return(-1);
1487                 }
1488                 tmpSyms = (KeySym *) restoreCharArray;
1489             }
1490         }
1491         numArgs /= smSettings.keySymPerCode;
1492         XChangeKeyboardMapping(smGD.display, (KeyCode)
1493                                smGD.display->min_keycode,
1494                                smSettings.keySymPerCode, tmpSyms,
1495                                numArgs);
1496     }
1497     
1498     /*
1499      * Restore the modifier mappings
1500      */
1501     tmpCode = (KeyCode *) restoreCharArray; 
1502     tmpKey = strtok(smGD.modSyms, ",");
1503     if(tmpKey != NULL)
1504     {
1505         for(i = 0;i < (8 * smSettings.maxKeyPerMod);i++)
1506         {
1507             if(tmpKey != NULL)
1508             {
1509                 codeSym = (KeySym) atol(tmpKey);
1510                 if(codeSym != 0)
1511                 {
1512                     tmpCode[i] = XKeysymToKeycode(smGD.display, codeSym);
1513                 }
1514                 else
1515                 {
1516                     tmpCode[i] = (KeyCode) 0;
1517                 }
1518             }
1519             else
1520             {
1521                 tmpCode[i] = (KeyCode) 0;
1522             }
1523             tmpKey = strtok(NULL, ",");
1524         }
1525         restoreMod.max_keypermod = smSettings.maxKeyPerMod;
1526         restoreMod.modifiermap = tmpCode;
1527         XSetModifierMapping(smGD.display, &restoreMod);
1528     }
1529
1530     SM_FREE((char *) restorePtrArray);
1531     SM_FREE(restoreCharArray);
1532
1533     return(0);    
1534 }
1535
1536
1537 \f
1538 /*************************************<->*************************************
1539  *
1540  *  RestoreIndependentResources ()
1541  *
1542  *
1543  *  Description:
1544  *  -----------
1545  *  In charge of restoring the resources that help make the session more
1546  *  resolution and language independent - only restored if they are
1547  *  necessary (lang || resolution has changed) and exist
1548  *
1549  *
1550  *  Inputs:
1551  *  ------
1552  *  smResources = global pointer to the resources to be restored by the SM
1553  *
1554  * 
1555  *  Outputs:
1556  *  -------
1557  *
1558  *
1559  *  Comments:
1560  *  --------
1561  * 
1562  *************************************<->***********************************/
1563 void 
1564 RestoreIndependentResources( void )
1565 {
1566     Atom        actualType;
1567     int         actualFormat;
1568     unsigned long   nitems, leftover;
1569     unsigned char   *data = NULL;
1570     XrmDatabase         smBase;
1571     XrmValue            fontResourceReturn;
1572     char *currentLangPtr, *resValRet, *sessionType;
1573     float fltYRes;
1574     int   intYRes[2], status,i;
1575     char  *sessionRes;
1576     struct stat buf;
1577     Boolean resIndep = False, resRet;
1578     char *resdata;
1579
1580     if(((smGD.sessionLang == NULL) || (*smGD.sessionLang == 0)) &&
1581        (smRes.displayResolution == 0))
1582     {
1583         /*
1584          * No saved info to draw from - nothing new is added
1585          */
1586         return;
1587     }
1588     
1589     currentLangPtr = getenv("LANG");
1590
1591     fltYRes = ((float) DisplayHeight(smGD.display, 0) /
1592                (float) DisplayHeightMM(smGD.display, 0)) * 1000;
1593
1594     if(fltYRes < MED_RES_Y_RES) 
1595     {
1596         intYRes[0] = LOW_RES_Y_RES;
1597         sessionRes = SM_LOW_RES_EXT;
1598     }
1599     else
1600     {
1601         if(fltYRes >= HIGH_RES_Y_RES)
1602         {
1603             intYRes[0] = HIGH_RES_Y_RES;
1604             sessionRes = SM_HIGH_RES_EXT;
1605         }
1606         else
1607         {
1608             intYRes[0] = MED_RES_Y_RES;
1609             sessionRes = SM_MED_RES_EXT;
1610         }
1611     }
1612
1613     if(smRes.displayResolution < MED_RES_Y_RES)
1614     {
1615         intYRes[1] = LOW_RES_Y_RES;
1616     }
1617     else
1618     {
1619         if(smRes.displayResolution >= HIGH_RES_Y_RES)
1620         {
1621             intYRes[1] = HIGH_RES_Y_RES;
1622         }
1623         else
1624         {
1625             intYRes[1] = MED_RES_Y_RES;
1626         }
1627     }
1628
1629     /*
1630      * If the resolution or the language has changed -
1631      * load the language/resolution independent fonts if
1632      * they exist in the users home directory or in the system
1633      */
1634     if((strcmp(currentLangPtr, smGD.sessionLang)) ||
1635        (intYRes[0] != intYRes[1]))
1636     {
1637         char    *fontPath = SM_MALLOC(MAXPATHLEN + 1);
1638
1639         if(smGD.sessionType == HOME_SESSION)
1640         {
1641             sessionType = SM_HOME_FONT_DIRECTORY;
1642         }
1643         else
1644         {
1645             sessionType = SM_CURRENT_FONT_DIRECTORY;
1646         }
1647
1648         memset(fontPath, 0, MAXPATHLEN + 1);
1649         snprintf(fontPath, MAXPATHLEN, "%s/%s/%s/%s.%s",
1650                  smGD.savePath, sessionType,
1651                  currentLangPtr, SM_FONT_FILE, sessionRes);
1652         status = stat(fontPath, &buf);
1653         if(status == -1)
1654         {
1655             /*
1656              * User has nothing there - look in the system defaults
1657              * first in the language dep -then in lang independent
1658              */
1659             memset(fontPath, 0, MAXPATHLEN + 1);
1660
1661             if((currentLangPtr != NULL) && (*currentLangPtr != 0))
1662             {
1663                 strcat(fontPath, "/");
1664                 strncat(fontPath, currentLangPtr, MAXPATHLEN);
1665             }
1666
1667             strncat(fontPath, "/", MAXPATHLEN);
1668             strncat(fontPath, SM_SYSTEM_FONT_FILE, MAXPATHLEN);
1669
1670             FixPath(fontPath);
1671
1672             status = stat(fontPath, &buf);
1673             if(status == -1)
1674             {
1675                 if((currentLangPtr != NULL) && (*currentLangPtr != 0) &&
1676                    (strcmp(currentLangPtr, "C")))
1677                 {
1678                     memset(fontPath, 0, MAXPATHLEN + 1);
1679                     strcpy(fontPath, "/C/");
1680                     strncat(fontPath, SM_SYSTEM_FONT_FILE, MAXPATHLEN);
1681
1682                     FixPath(fontPath);
1683                 
1684                     status = stat(fontPath, &buf);
1685                     if(status != -1)
1686                     {
1687                         resIndep = True;
1688                     }
1689                 }
1690             }
1691             else
1692             {
1693                 resIndep = True;
1694             }
1695         }
1696         else
1697         {
1698             resIndep = True;
1699         }
1700
1701         strncpy(smGD.fontPath, fontPath, MAXPATHLEN);
1702
1703         if(resIndep == True)
1704         {
1705
1706             /*
1707              * add the auxillary resources onto the root window
1708              */
1709             RestoreResources(True, "-merge", "-file", smGD.fontPath, NULL);
1710
1711             /*
1712              * Load the resources from the RESOURCE_MANAGER
1713              * property on the root window
1714              */
1715             if(XGetWindowProperty(smGD.display, RootWindow(smGD.display, 0),
1716                                XA_RESOURCE_MANAGER,0L,
1717                                100000000L,False,XA_STRING,&actualType,
1718                                &actualFormat,&nitems,&leftover,
1719                                (unsigned char**) &data) == Success)
1720             {
1721                 smBase = XrmGetStringDatabase((char *)data);
1722             }
1723             else
1724             {
1725                 smBase = NULL;
1726             }
1727             
1728             if(smBase == NULL)
1729             {
1730                 PrintError(DtError, GETMESSAGE(16, 6, "Invalid display/language independent resource file.  No display/language independent resources will be restored."));
1731                 SM_FREE((char *)data);
1732                 return;
1733             }
1734             else
1735             {
1736                 /*
1737                  * Get the new fontlist from the resources and
1738                  * Put it on the application shell.  Then add
1739                  * the auxillary resources into the display struct
1740                  */
1741                 resRet = XrmGetResource(smBase,  "*fontList", "*FontList",
1742                                         &resValRet, &fontResourceReturn);
1743
1744                 i = 0;
1745                 XtSetArg(uiArgs[i], XmNdefaultFontList,
1746                          (XmFontList) fontResourceReturn.addr);i++;
1747                 XtSetValues(smGD.topLevelWid, uiArgs, i);
1748                 
1749                 /*
1750                  * Overwrite the old font preferences, otherwise,
1751                  * they'll come back to haunt us if the user logs in again
1752                  * under the current language. We need to get the font
1753                  * resources which have just been loaded, then overlay
1754                  * them onto the _DT_SM_PREFERENCES root property to make
1755                  * sure we get them back when we login again.
1756                  */
1757                 for (i = 0; i < XtNumber(fonttype); i++)
1758                 {
1759                     resRet = XrmGetResource(smBase, fonttype[i], fontclass[i],
1760                                             &resValRet, &fontResourceReturn);
1761                     if (resRet)
1762                     {
1763                         resdata =
1764                             (char *)SM_MALLOC(fontResourceReturn.size + 30);
1765                         bzero(resdata, fontResourceReturn.size + 30);
1766                         strcat(resdata, fonttype[i]);
1767                         strcat(resdata, ": ");
1768                         strcat(resdata, fontResourceReturn.addr);
1769                         strcat(resdata, "\n");
1770                         _DtAddResString(smGD.display, resdata, _DT_ATR_PREFS);
1771                         SM_FREE(resdata);
1772                     }
1773                 }
1774
1775                 XrmMergeDatabases(smBase, &(smGD.display->db));
1776                 SM_FREE((char *)data);
1777             }
1778         }
1779
1780         SM_FREE((char*) fontPath);
1781     }
1782
1783     return;
1784 }
1785     
1786 \f
1787 /*************************************<->*************************************
1788  *
1789  *  RestoreClients ()
1790  *
1791  *
1792  *  Description:
1793  *  -----------
1794  *  Reads through the client file and restores its contents.  A client file
1795  *  consists of hints for the workspace manager, actual client commands, and
1796  *  remote execution commands.  All commands are processed accordingly.
1797  *  If this is the first DT 3.0 session for a DT 2.0 user then we will
1798  *  also launch the helpviewer. If this is the first DT 3.0 session for a
1799  *  DT 2.0 user then we will also run convertVS.sh to change all
1800  *  occurances of /usr/bin/X11/hpterm to .../dt/bin/hpterm,
1801  *  /usr/bin/X11/xterm to .../dt/bin/xterm and
1802  *  /usr/bin/X11/xload to .../dt/bin/xload.
1803  *
1804  *
1805  *  Inputs:
1806  *  ------
1807  * 
1808  *  Outputs:
1809  *  -------
1810  *
1811  *  Comments:
1812  *  --------
1813  *  Any information read from the client file will be mucked with during
1814  *  processing, and should not try to be mucked with again.
1815  *
1816  *  WARNING:  This routine closes cfileP - not the calling routine
1817  *  DOUBLE-WARNING: This routine starts the window manager
1818  *
1819  *************************************<->***********************************/
1820 static int 
1821 RestoreClients( void )
1822 {
1823     unsigned char *lineP, *string;
1824     char *pch, *dispPtr = NULL;
1825     char *dispEnv, *dispSav, *dispEnvHelpview, *dispSavHelpview;
1826     unsigned char *hostPtr=NULL, *cmdPtr=NULL, *hintPtr = NULL;
1827     unsigned char *remoteDisplay;
1828     char *displayName;
1829     char *envVal;
1830     unsigned char  tmpChar[35];
1831     int     screenNum = 0, i, j, chlen, numClientsExec;
1832     int     numRemoteDone = 0;
1833     Window      dtwmWin = 0;
1834     Boolean     clientsDone = False, wmHandshake = False, cmdInvInit = False;
1835     XClientMessageEvent smToWmMessage;
1836     
1837     /*
1838      * These variables are needed to buffer up the commands and then
1839      * execute them (also buffer up hints then put them on the root window
1840      */
1841     unsigned char *hintsBuf[MAX_SCREENS_SAVED];
1842     unsigned char *cmdBuf[MAX_SCREENS_SAVED];
1843     unsigned int  maxHintsSize[MAX_SCREENS_SAVED];
1844     unsigned int  actHintsSize[MAX_SCREENS_SAVED];
1845     unsigned int  numHints[MAX_SCREENS_SAVED];
1846     unsigned int  maxCmdSize[MAX_SCREENS_SAVED];
1847     unsigned int  actCmdSize[MAX_SCREENS_SAVED];
1848     unsigned int  numCmd[MAX_SCREENS_SAVED];
1849     unsigned int  maxRemoteSize[MAX_SCREENS_SAVED];
1850
1851     /*
1852      * Initialize the buffers and their sizes to null and 0.  Because of
1853      * all possible combinations - buffers aren't malloc'd until they're
1854      * needed
1855      */
1856     for(i = 0;i<smGD.numSavedScreens;i++)
1857     {
1858         hintsBuf[i] = NULL;
1859         cmdBuf[i] = NULL;
1860         remoteBuf[i] = NULL;
1861         maxHintsSize[i] = 0;
1862         actHintsSize[i] = 0;
1863         numHints[i] = 0;
1864         maxCmdSize[i] = 0;
1865         actCmdSize[i] = 0;
1866         numCmd[i] = 0;
1867         maxRemoteSize[i] = 0;
1868         actRemoteSize[i] = 0;
1869     }
1870     
1871     /*
1872      * Save the contents of the DISPLAY environment variable so that it
1873      * can be restored when we're through
1874      */
1875     dispEnv = getenv(DISPLAY_NAME);
1876     if(dispEnv != NULL)
1877     {
1878         dispSav = (char *) SM_MALLOC(((strlen(dispEnv) + 
1879                                        strlen(DISPLAY_NAME_EQUAL)) * sizeof(char) + 1));
1880         sprintf(dispSav, "%s%s", DISPLAY_NAME_EQUAL, dispEnv);
1881     }
1882     else
1883     {
1884         dispSav = NULL;
1885     }
1886     
1887     linec = 0;
1888     displayName = strdup(smGD.display->display_name);
1889     remoteDisplay = (unsigned char *)
1890       SM_MALLOC(sizeof(unsigned char) * (strlen(displayName) + 101));
1891
1892     /*
1893      * Create the display name for locally executing clients
1894      */
1895     pch = displayName;
1896     while (*pch)
1897     {
1898         if (*pch == ':')
1899         {
1900             dispPtr = pch;
1901             pch++;
1902             break;
1903         }
1904         pch++;
1905     }
1906
1907     while (*pch)
1908     {
1909         if (*pch == '.')
1910         {
1911             pch++;
1912             *pch = '\0';
1913             break;
1914         }
1915         pch++;
1916     }
1917
1918     /*
1919      * Create the display name for remotely executing clients.
1920      * These two may or may not be the same
1921      */
1922     DtGetShortHostname((char *)remoteDisplay, 100);
1923
1924     /*
1925      * Add the display qualifications to the host name
1926      * screen is added at execution time
1927      */
1928     strcat((char *)remoteDisplay, (char *)dispPtr);
1929
1930     /*
1931      * Intern the atom needed to put the hints on the root window
1932      * This has to be done here because InitProtocol has not been called yet
1933      */
1934     XaWmDtHints = XInternAtom(smGD.display, _XA_DT_SESSION_HINTS, False);
1935
1936     while(GetNextLine() != NULL)
1937     {
1938         lineP = line;
1939         string = GetSmartString(&lineP);
1940         if( string != NULL && !strcmp((char *)string, "dtsmcmd"))
1941         {
1942             while((string = GetSmartString(&lineP)) != NULL )
1943             {
1944                 if(!strcmp((char *)string, "-host"))
1945                 {
1946                     /*
1947                      * Extract a host pointer - host pointers
1948                      * only exist on remote executions
1949                      */
1950                     string = GetSmartString(&lineP);
1951                     hostPtr = string;
1952                 }
1953                 else
1954                 {
1955                     if(!strcmp((char *)string, "-cmd"))
1956                     {
1957                         /*
1958                          * Extract the command pointer from the
1959                          * hints string
1960                          */
1961                         string = GetSmartString(&lineP);
1962                         cmdPtr = string;
1963                     }
1964                     else
1965                     {
1966                         if(!strcmp((char *)string, "-screen"))
1967                         {
1968                             /*
1969                              * Extract the screen number from the command
1970                              */
1971                             string = GetSmartString(&lineP);
1972                             screenNum = atoi((char *)string);
1973
1974                         }
1975                         else
1976                         {
1977                             if(!strcmp((char *)string, "-hints"))
1978                             {
1979                                 /*
1980                                  * Extract the hints string
1981                                  */
1982                                 string = GetSmartString(&lineP);
1983                                 hintPtr = string;
1984                             }
1985                         }
1986                     }
1987                 }
1988             }
1989
1990             /*
1991              * Now put our information in buffers and reinitialize the pointers
1992              */
1993             if(hintPtr != NULL)
1994             {
1995                 if(FillHintBuf(hintPtr, hintsBuf, maxHintsSize,
1996                             actHintsSize, screenNum, numHints) != 0)
1997                 {
1998                     /*
1999                      * Free all malloc'd buffers and exit
2000                      */
2001                     for(i = 0;i < smGD.numSavedScreens;i++)
2002                     {
2003                         if(actHintsSize[i] > 0)
2004                         {
2005                             SM_FREE((char *) hintsBuf[i]);
2006                         }
2007                         if(actCmdSize[i] > 0)
2008                         {
2009                             SM_FREE((char *) cmdBuf[i]);
2010                         }
2011                         if(actRemoteSize[i] > 0)
2012                         {
2013                             SM_FREE((char *) remoteBuf[i]);
2014                         }
2015                     }
2016                     return(-1);
2017                 }
2018                 hintPtr = NULL;
2019             }
2020
2021             if((cmdPtr != NULL) && (hostPtr == NULL))
2022             {
2023                 if(FillCmdBuf(cmdPtr, cmdBuf, maxCmdSize,
2024                               actCmdSize,screenNum, &numCmd[screenNum]) != 0)
2025                 {
2026                     /*
2027                      * Free all malloc'd buffers and exit
2028                      */
2029                     for(i = 0;i < smGD.numSavedScreens;i++)
2030                     {
2031                         if(actHintsSize[i] > 0)
2032                         {
2033                             SM_FREE((char *) hintsBuf[i]);
2034                         }
2035                         if(actCmdSize[i] > 0)
2036                         {
2037                             SM_FREE((char *) cmdBuf[i]);
2038                         }
2039                         if(actRemoteSize[i] > 0)
2040                         {
2041                             SM_FREE((char *) remoteBuf[i]);
2042                         }
2043                     }
2044                     return(-1);
2045                 }
2046                 cmdPtr = NULL;
2047             }
2048             else
2049             {
2050                 if((cmdPtr != NULL) && (hostPtr != NULL))
2051                 {
2052                     if(FillRemoteBuf(cmdPtr, hostPtr, remoteDisplay,
2053                                   remoteBuf, maxRemoteSize,
2054                                   actRemoteSize, screenNum) != 0)
2055                     {
2056                         /*
2057                          * Free all malloc'd buffers and exit
2058                          */
2059                         for(i = 0;i < smGD.numSavedScreens;i++)
2060                         {
2061                             if(actHintsSize[i] > 0)
2062                             {
2063                                 SM_FREE((char *) hintsBuf[i]);
2064                             }
2065                             if(actCmdSize[i] > 0)
2066                             {
2067                                 SM_FREE((char *) cmdBuf[i]);
2068                             }
2069                             if(actRemoteSize[i] > 0)
2070                             {
2071                                 SM_FREE((char *) remoteBuf[i]);
2072                             }
2073                         }
2074                         free(displayName);
2075                         return(-1);
2076                     }
2077                     cmdPtr = NULL;
2078                     hostPtr = NULL;
2079                 }
2080             }
2081             screenNum = XDefaultScreen(smGD.display);
2082         }
2083     }
2084
2085     /*
2086      * All done with file so close it off and set descriptor to NULL -
2087      * This is done so that parsing routines can be used with a buffer later
2088      */
2089     fclose(cfileP);
2090     cfileP = NULL;
2091
2092     /*
2093      * Now execute all the buffers, put all hints on the root windows
2094      * Do all remote executions
2095      */
2096     for(i = 0;i < smGD.numSavedScreens;i++)
2097     {
2098         /*
2099          * Put the root window property on each root window
2100          */
2101         if(actHintsSize[i] > 0)
2102         {
2103             /*
2104              * Append number of hints to front of buffer
2105              */
2106             sprintf((char *)tmpChar, "%d", numHints[i]);
2107             strncpy((char *)hintsBuf[i], (char *)tmpChar,
2108                     strlen((char *)tmpChar));
2109             XChangeProperty(smGD.display, RootWindow(smGD.display, i),
2110                             XaWmDtHints, XA_STRING, 8, PropModeReplace,
2111                             hintsBuf[i], actHintsSize[i]);
2112             SM_FREE((char *) hintsBuf[i]);
2113             XSync(smGD.display, 0);
2114         }
2115     }
2116
2117     StartWM();
2118
2119
2120     /*
2121      * Now exec on the local clients - we're doing contention management
2122      * to make sure the system doesn't get swamped
2123      */
2124     i = 0;
2125
2126     while((actCmdSize[i] == 0) && (i < smGD.numSavedScreens))
2127     {
2128         i++;
2129     }
2130
2131     envVal = SM_MALLOC(BUFSIZ);
2132     if(i >= smGD.numSavedScreens)
2133     {
2134         clientsDone = True;
2135     }
2136     else
2137     {
2138         sprintf(envVal,"%s%s%d", DISPLAY_NAME_EQUAL, displayName, i);
2139         putenv(envVal);
2140
2141         linec = 0;
2142         parseP = cmdBuf[i];
2143     }
2144
2145     /*
2146      *  Keep forking one client after the other until the
2147      *  memory utilization gets beyond the threshold -
2148      *  (but only if the capability exists)  Then go to
2149      *  window manager handshaking
2150      */
2151 #ifdef DEBUG_CONT_MANAGEMENT
2152     if(smRes.contManagement & SM_CM_SYSTEM)
2153     {
2154         fprintf(stderr, "SM_CM_SYSTEM flag set in smRes.contManagement\n");
2155     }
2156     if(smRes.contManagement & SM_CM_HANDSHAKE)
2157     {
2158         fprintf(stderr, "SM_CM_HANDSHAKE flag set in smRes.contManagement\n");
2159     }
2160 #endif /* DEBUG_CONT */
2161     numClientsExec = 0;
2162     if((smRes.contManagement & SM_CM_SYSTEM) &&
2163        ((GetMemoryUtilization() != MEM_NOT_AVAILABLE) && 
2164         (clientsDone == False)))
2165     {
2166         while((GetMemoryUtilization() == MEM_NOT_FULL) &&
2167               (clientsDone == False))
2168         {       
2169             GetNextLine();
2170             lineP = line;
2171             CreateExecString((char *) lineP);
2172             if(smExecArray[0] != NULL)
2173             {
2174                 (void) StartClient(smExecArray[0], (char **)smExecArray, NULL, 
2175                                 NULL, NULL, False, False, -1);
2176             }   
2177             numClientsExec++;
2178
2179             /*
2180              * When all the clients have been exec'd for this screen
2181              * go on to the next
2182              */
2183             if(numClientsExec >= numCmd[i])
2184             {
2185                 ResetScreenInfo(cmdBuf, &i, actCmdSize, &clientsDone,
2186                                 envVal, displayName);
2187                 numClientsExec = 0;
2188             }
2189         }
2190     }
2191
2192     /*
2193      *  After we've checked memory utilization - finish up
2194      *  by handshaking with the worksapce manager - if it's there
2195      */
2196     if(clientsDone == False)
2197     {
2198         if((smGD.dtwmRunning) && (smRes.contManagement & SM_CM_HANDSHAKE))
2199         {
2200             /*
2201              * Get the window id of the workspace manager and tell it
2202              * to start messaging
2203              */
2204             _DtGetMwmWindow(smGD.display, RootWindow(smGD.display, 0),
2205                            &dtwmWin);
2206             smToWmMessage.type = ClientMessage;
2207             smToWmMessage.window = dtwmWin;
2208             smToWmMessage.message_type = XaSmWmProtocol;
2209             smToWmMessage.format = 32;
2210             smToWmMessage.data.l[0] = XaSmStartAckWindow;
2211             smToWmMessage.data.l[1] = CurrentTime;
2212             if (XSendEvent(smGD.display, dtwmWin,False,NoEventMask,
2213                            (XEvent *) &smToWmMessage) != 0)
2214             {
2215                 wmHandshake = True;
2216                 XSync(smGD.display, 0);
2217             }
2218                 
2219         }
2220                 
2221         /*
2222          *  Start a client - and wait for the workspace manager to
2223          *  map a window to start a new client
2224          */
2225         while(clientsDone == False)
2226         {
2227             GetNextLine();
2228             lineP = line;
2229             CreateExecString((char *) lineP);
2230             if(smExecArray[0] != NULL)
2231             {
2232                 (void) StartClient(smExecArray[0], smExecArray, 
2233                                         NULL, NULL, NULL, False, False, -1);
2234             }
2235
2236             /*
2237              * If we're handshaking with the workspace manager
2238              * wait for the client to be mapped before starting
2239              * the next one
2240              */
2241             if(wmHandshake == True)
2242             {
2243                 WaitForClientMap();
2244             }
2245
2246             numClientsExec++;
2247
2248             /*
2249              * When all the clients have been exec'd for this screen
2250              * go on to the next
2251              */
2252             if(numClientsExec >= numCmd[i])
2253             {
2254                 ResetScreenInfo(cmdBuf, &i, actCmdSize, &clientsDone,
2255                                 envVal, displayName);
2256                 numClientsExec = 0;
2257             }
2258         }
2259
2260         if(wmHandshake == True)
2261         {
2262             /*
2263              * If we are handshaking - tell the workspace manager to
2264              * stop
2265              */
2266             smToWmMessage.type = ClientMessage;
2267             smToWmMessage.window = dtwmWin;
2268             smToWmMessage.message_type = XaSmWmProtocol;
2269             smToWmMessage.format = 32;
2270             smToWmMessage.data.l[0] = XaSmStopAckWindow;
2271             smToWmMessage.data.l[0] = CurrentTime;
2272             XSendEvent(smGD.display, dtwmWin,False,NoEventMask,
2273                        (XEvent *) &smToWmMessage);
2274                 
2275         }
2276     }
2277     
2278     for(i = 0;i < smGD.numSavedScreens;i++)
2279     {
2280         if(numRemoteDone == MAX_REMOTE_CLIENTS)
2281         {
2282             break;
2283         }
2284
2285         /*
2286          * Send out all the remote execution commands for the screen to
2287          * the command invoker.  On failure - do a remsh instead
2288          */
2289         if(actRemoteSize[i] > 0)
2290         {
2291             /*
2292              * Initialize the command invoker - if not done
2293              */
2294             if(cmdInvInit == False)
2295             {
2296                 _DtInitializeCommandInvoker(smGD.display,
2297                                            DtSM_TOOL_CLASS,
2298                                            SM_RESOURCE_CLASS,
2299                                            NULL, smGD.appCon);
2300                 cmdInvInit = True;
2301             }
2302             
2303             /*
2304              *  Set up the display environment variable so that the
2305              *  application comes back to the right screen
2306              */
2307             sprintf(envVal,"%s%s%d", DISPLAY_NAME_EQUAL, displayName, i);
2308             putenv(envVal);
2309             
2310             linec = 0;
2311             parseP = remoteBuf[i];
2312             while(numRemoteExecs > 0 && GetNextLine() != NULL)
2313             {
2314                 /*
2315                  * Get the host and the command and send them off
2316                  * On failure of the command invoker do a remsh
2317                  */
2318                 lineP = line;
2319                 string = GetSmartString(&lineP);
2320                 hostPtr = string;
2321                 string = GetSmartString(&lineP);
2322                 cmdPtr = string;
2323
2324                 remoteBufPtr[numRemoteDone].cmdPtr = cmdPtr;
2325                 remoteBufPtr[numRemoteDone].hostPtr = hostPtr;
2326                 
2327                 _DtCommandInvokerExecute(DtSTART_SESSION, NULL, NULL, NULL,
2328                                         "-", (char *) hostPtr, (char *) cmdPtr,
2329                                         RemoteRequestSucceeded, NULL,
2330                                         RemoteRequestFailed,
2331                                         &remoteBufPtr[numRemoteDone]);
2332                 numRemoteDone++;
2333
2334                 /*
2335                  * If there is no more room in the remote client
2336                  * array - quit exec'ing remote clients
2337                  */
2338                 if(numRemoteDone == MAX_REMOTE_CLIENTS)
2339                 {
2340                     PrintError(DtError, GETMESSAGE(16, 5, "You have reached the maximum allowed number of remote clients.  No further remote clients will be restored."));
2341                     break;
2342                 }
2343                 
2344             }
2345         }
2346     }
2347
2348
2349     /*
2350      * Now return the display variable back to the display that was
2351      * originally opened (the default display)
2352      */
2353     if(dispSav != NULL)
2354     {
2355         putenv(dispSav);
2356     }
2357     else
2358     {
2359         FixEnvironmentData();
2360     }
2361     free(displayName);
2362
2363     return(0);
2364 } /* END OF FUNCTION RestoreClients */
2365
2366
2367 \f
2368 /*************************************<->*************************************
2369  *
2370  *  StartEtc ( exiting )
2371  *
2372  *
2373  *  Description:
2374  *  -----------
2375  *  Call the StartClient routine to fork and exec either the sessionetc file
2376  *  (if exiting==False) or the sessionexit file (if exiting==True).
2377  *
2378  *
2379  *  Inputs:
2380  *  ------
2381  * 
2382  *  Outputs:
2383  *  -------
2384  *
2385  *  Comments:
2386  *  --------
2387  *
2388  *************************************<->***********************************/
2389 void 
2390 StartEtc( Boolean exiting )
2391 {
2392     int status;
2393     struct stat buf;
2394     char *execArray[3];
2395
2396     if (exiting) {
2397         execArray[0] = smGD.exitPath;
2398         execArray[1] = smExitFile;
2399     } else {
2400         execArray[0] = smGD.etcPath;
2401         execArray[1] = smEtcFile;
2402     }
2403     execArray[2] = '\0';
2404
2405     if ((status=stat(execArray[0], &buf)) != -1)
2406     {
2407         StartClient(execArray[0], execArray, NULL, NULL, NULL, False, False, -1);
2408     }
2409 }
2410
2411 \f
2412 /*************************************<->*************************************
2413  *
2414  *  GetNextLine ()
2415  *
2416  *
2417  *  Description:
2418  *  -----------
2419  *  Returns the next line from an fopened configuration file or a newline-
2420  *  embedded configuration string.
2421  *
2422  *
2423  *  Inputs:
2424  *  ------
2425  *  cfileP =  (global) file pointer to fopened configuration file or NULL
2426  *  line   =  (global) line buffer
2427  *  linec  =  (global) line count
2428  *  parseP =  (global) parse string pointer if cfileP == NULL
2429  *
2430  * 
2431  *  Outputs:
2432  *  -------
2433  *  line =     (global) next line 
2434  *  linec =    (global) line count incremented
2435  *  parseP =   (global) parse string pointer incremented
2436  *  Return =  line or NULL if file or string is exhausted.
2437  *
2438  *
2439  *  Comments:
2440  *  --------
2441  *  If there are more than MAXLINE characters on a line in the file cfileP the
2442  *  excess are truncated.  
2443  *  Assumes the line buffer is long enough for any parse string line.
2444  *  Code stolen from dtmwm
2445  * 
2446  *************************************<->***********************************/
2447 static unsigned char * 
2448 GetNextLine( void )
2449 {
2450     unsigned char *string;
2451 #ifdef MULTIBYTE
2452     int   chlen;
2453 #endif
2454
2455     if (cfileP != NULL)
2456     /* read fopened file */
2457     {
2458         string = (unsigned char *) fgets((char *)line, fileSize, cfileP);
2459     }
2460     else if ((parseP != NULL) && (*parseP != 0))
2461     /* read parse string */
2462     {
2463         string = line;
2464 #ifdef MULTIBYTE
2465         while ((*parseP != 0) &&
2466                ((chlen = mblen ((char *) parseP, MB_CUR_MAX)) > 0) &&
2467                (*parseP != '\n'))
2468         /* copy all but NULL and newlines to line buffer */
2469         {
2470             while (chlen--)
2471             {
2472                 *(string++) = *(parseP++);
2473             }
2474         }
2475 #else
2476         while ((*parseP != NULL) && (*parseP != '\n'))
2477         /* copy all but NULL and newlines to line buffer */
2478         {
2479             *(string++) = *(parseP++);
2480         }
2481 #endif
2482         *string = 0;
2483         if (*parseP == '\n')
2484         {
2485             parseP++;
2486         }
2487     }
2488     else
2489     {
2490         string = NULL;
2491     }
2492
2493     linec++;
2494     return (string);
2495
2496 } /* END OF FUNCTION GetNextLine */
2497
2498
2499 \f
2500 /*************************************<->*************************************
2501  *
2502  *  PeekAhead (currentChar, currentLev)
2503  *
2504  *
2505  *  Description:
2506  *  -----------
2507  *  Returns a new level value if this is a new nesting level of quoted string
2508  *  Otherwise it returns a zero
2509  *
2510  *
2511  *  Inputs:
2512  *  ------
2513  *  currentChar = current position in the string
2514  *  currentLev = current level of nesting
2515  *
2516  * 
2517  *  Outputs:
2518  *  -------
2519  *  Returns either a new level of nesting or zero if the character is copied in
2520  *
2521  *
2522  *  Comments:
2523  *  --------
2524  * 
2525  *************************************<->***********************************/
2526 static unsigned int 
2527 PeekAhead(
2528         unsigned char *currentChar,
2529         unsigned int currentLev )
2530 {
2531     Boolean             done = False;
2532     unsigned int        tmpLev = 1;
2533 #ifdef MULTIBYTE
2534     unsigned int        chlen;
2535
2536     while (((chlen = mblen ((char *) currentChar, MB_CUR_MAX)) > 0) &&
2537            (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))
2538            && (done == False))
2539     {
2540         currentChar++;
2541
2542         if(((chlen = mblen ((char *) currentChar, MB_CUR_MAX)) > 0) && (chlen == 1) &&
2543            ((*currentChar == '"') || (*currentChar == '\\')))
2544         {
2545             tmpLev++;
2546             if(*currentChar == '"')
2547             {
2548                 done = True;
2549             }
2550             else
2551             {
2552                 currentChar++;
2553             }
2554         }
2555     }
2556 #else
2557     while((*currentChar != NULL) && (done == False) &&
2558           ((*currentChar == '"') || (*currentChar == '\\')))
2559     {
2560         currentChar++;
2561         if((*currentChar != NULL) &&
2562            ((*currentChar == '"') || (*currentChar == '\\')))
2563         {
2564             tmpLev++;
2565             if(*currentChar == '"')
2566             {
2567                 done = True;
2568             }
2569             else
2570             {
2571                 currentChar++;
2572             }
2573         }
2574     }
2575 #endif /*MULTIBYTE*/
2576
2577     /*
2578      * Figure out if this is truly a new level of nesting - else ignore it
2579      * This section probably could do some error checking and return -1
2580          * If so, change type of routine from unsigned int to int
2581      */
2582     if(done == True)
2583     {
2584         return(tmpLev);
2585     }
2586     else
2587     {
2588         return(0);
2589     }
2590 }
2591     
2592     
2593 \f
2594 /*************************************<->*************************************
2595  *
2596  *  GetSmartString (linePP)
2597  *
2598  *
2599  *  Description:
2600  *  -----------
2601  *  Returns the next quoted or whitespace-terminated nonquoted string in the
2602  *  line buffer.
2603  *  Additional functionality added to GetString in that anything in a
2604  *  quoted string is considered sacred and nothing will be stripped from
2605  *  the middle of a quoted string.
2606  *
2607  *
2608  *  Inputs:
2609  *  ------
2610  *  linePP =  pointer to current line buffer pointer.
2611  *
2612  * 
2613  *  Outputs:
2614  *  -------
2615  *  linePP =  pointer to revised line buffer pointer.
2616  *  Return =  string 
2617  *
2618  *
2619  *  Comments:
2620  *  --------
2621  *  May alter the line buffer contents.
2622  *  Handles quoted strings and characters, removing trailing whitespace from
2623  *  quoted strings.
2624  *  Returns NULL string if the line is empty or is a comment.
2625  *  Code stolen from dtmwm.
2626  * 
2627  *************************************<->***********************************/
2628
2629 static unsigned char * 
2630 GetSmartString(
2631         unsigned char **linePP )
2632 {
2633     unsigned char *lineP = *linePP;
2634     unsigned char *endP;
2635     unsigned char *curP;
2636     unsigned char *lnwsP;
2637     unsigned int  level = 0, checkLev, i, quoteLevel[MAX_QUOTE_DEPTH];
2638 #ifdef MULTIBYTE
2639     int            chlen;
2640
2641     /* get rid of leading white space */
2642     ScanWhitespace (&lineP);
2643
2644     /*
2645      * Return NULL if line is empty, whitespace, or begins with a comment.
2646      */
2647     if((chlen = mblen ((char *) lineP, MB_CUR_MAX)) < 1)
2648     {
2649         *linePP = lineP;
2650         return (NULL);
2651     }
2652
2653     if ((chlen == 1) && (*lineP == '"'))
2654     /* Quoted string */
2655     {
2656         quoteLevel[level] = 1;  
2657         /*
2658          * Start beyond double quote and find the end of the quoted string.
2659          * '\' quotes the next character - but is not stripped out.
2660          * Otherwise,  matching double quote or NULL terminates the string.
2661          *
2662          * We use lnwsP to point to the last non-whitespace character in the
2663          * quoted string.  When we have found the end of the quoted string,
2664          * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
2665          * This removes any trailing whitespace without overwriting the 
2666          * matching quote, needed later.  If the quoted string was all 
2667          * whitespace, then this will write a NULL at the beginning of the 
2668          * string that will be returned -- OK.
2669          */
2670         lnwsP = lineP++;                /* lnwsP points to first '"' */
2671         curP = endP = lineP;            /* other pointers point beyond */
2672
2673         while ((*endP = *curP) &&
2674                ((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0) &&
2675                ((chlen > 1) || (*curP != '"')))
2676         /* Haven't found matching quote yet.
2677          * First byte of next character has been copied to endP.
2678          */
2679         {
2680             curP++;
2681             if ((chlen == 1) && (*endP == '\\') && 
2682                 ((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0))
2683             {
2684                 /*
2685                  * Check to see if this is a quoted quote - if it is
2686                  * strip off a level - if not - it's sacred leave it alone
2687                  */
2688                 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
2689                 if(checkLev > 0)
2690                 {
2691                     if(quoteLevel[level] >= checkLev)
2692                     {
2693                         if (level > 0) level--;
2694                     }
2695                     else if (level < MAX_QUOTE_DEPTH)
2696                     {
2697                         level++;
2698                         quoteLevel[level] = checkLev;
2699                     }
2700                     
2701                     for(i = 0;i < (checkLev - 2);i++)
2702                     {
2703                         *endP++ = *curP++;curP++;
2704                     }
2705                     *endP = *curP++;
2706                 }
2707             }
2708
2709             if (chlen == 1)
2710             /* Singlebyte character:  character copy finished. */
2711             {
2712                 if (isspace (*endP))
2713                 /* whitespace character:  leave lnwsP unchanged. */
2714                 {
2715                     endP++;
2716                 }
2717                 else
2718                 /* non-whitespace character:  point lnwsP to it. */
2719                 {
2720                     lnwsP = endP++;
2721                 }
2722             }
2723             else if (chlen > 1)
2724             /* Multibyte (nonwhitespace) character:  point lnwsP to it.
2725              * Finish character byte copy.
2726              */
2727             {
2728                 lnwsP = endP++;
2729                 while (--chlen)
2730                 {
2731                     *endP++ = *curP++;
2732                     lnwsP++;
2733                 }
2734             }
2735         }
2736 #else
2737
2738     /* get rid of leading white space */
2739     ScanWhitespace (&lineP);
2740
2741     /* Return NULL if line is empty, or whitespace */
2742     if(*lineP == NULL)
2743     {
2744         *linePP = lineP;
2745         return (NULL);
2746     }
2747
2748     if (*lineP == '"')
2749     /* Quoted string */
2750     {
2751         quoteLevel[level] = 1;  
2752         /*
2753          * Start beyond double quote and find the end of the quoted string.
2754          * '\' quotes the next character.
2755          * Otherwise,  matching double quote or NULL terminates the string.
2756          *
2757          * We use lnwsP to point to the last non-whitespace character in the
2758          * quoted string.  When we have found the end of the quoted string,
2759          * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
2760          * This removes any trailing whitespace without overwriting the 
2761          * matching quote, needed later.  If the quoted string was all 
2762          * whitespace, then this will write a NULL at the beginning of the 
2763          * string that will be returned -- OK.
2764          */
2765         lnwsP = lineP++;                /* lnwsP points to first '"' */
2766         curP = endP = lineP;            /* other pointers point beyond */
2767
2768         while ((*endP = *curP) && (*endP != '"'))
2769         /* haven't found matching quote yet */
2770         {
2771             /* point curP to next character */
2772             curP++;
2773             if ((*endP == '\\') && (*curP != NULL))
2774             /* shift quoted nonNULL character down and curP ahead */
2775             {
2776                 /*
2777                  * Check to see if this is a quoted quote - if it is
2778                  * strip off a level - if not - it's sacred leave it alone
2779                  */
2780                 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
2781                 if(checkLev > 0)
2782                 {
2783                     if(quoteLevel[level] >= checkLev)
2784                     {
2785                         if (level > 0) level--;
2786                     }
2787                     else if (level < MAX_QUOTE_DEPTH)
2788                     {
2789                         level++;
2790                         quoteLevel[level] = checkLev;
2791                     }
2792                     
2793                     for(i = 0;i < (checkLev - 2);i++)
2794                     {
2795                         *endP++ = *curP++;curP++;
2796                     }
2797                     *endP = *curP++;
2798                 }
2799             }
2800
2801             if (isspace (*endP))
2802             /* whitespace character:  leave lnwsP unchanged. */
2803             {
2804                 endP++;
2805             }
2806             else
2807             /* non-whitespace character:  point lnwsP to it. */
2808             {
2809                 lnwsP = endP++;
2810             }
2811         }
2812 #endif
2813
2814         /*
2815          *  Found matching quote or NULL.  
2816          *  NULL out any trailing whitespace.
2817          */
2818
2819         lnwsP++;
2820         if (lnwsP < endP)
2821         {
2822             *lnwsP = 0;
2823         }
2824     }
2825
2826     else
2827     /* Unquoted string */
2828     {
2829         /* 
2830          * Find the end of the nonquoted string.
2831          * '\' quotes the next character.
2832          * Otherwise,  whitespace, NULL, terminates the string.
2833          */
2834         curP = endP = lineP;
2835
2836 #ifdef MULTIBYTE
2837         while ((*endP = *curP) &&
2838                ((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0) &&
2839                ((chlen > 1) || (!isspace (*curP))))
2840         /* Haven't found whitespace  yet.
2841          * First byte of next character has been copied to endP.
2842          */
2843         {
2844             curP++;
2845             if ((chlen == 1) && (*endP == '\\') && 
2846                 ((chlen = mblen ((char *) curP, MB_CUR_MAX)) > 0))
2847             /* character quote:
2848              * copy first byte of quoted nonNULL character down.
2849              * point curP to next byte
2850              */
2851             {
2852                 *endP = *curP++;
2853             }
2854             endP++;
2855             if (chlen > 1)
2856             /* Multibyte character:  finish character copy. */
2857             {
2858                 while (--chlen)
2859                 {
2860                     *endP++ = *curP++;
2861                 }
2862             }
2863         }
2864 #else
2865         while ((*endP = *curP) && !isspace (*endP))
2866         {
2867             /* point curP to next character */
2868             curP++;
2869             if ((*endP == '\\') && (*curP != NULL))
2870             /* shift quoted nonNULL character down and curP ahead */
2871             {
2872                 *endP = *curP++;
2873             }
2874             endP++;
2875         }
2876 #endif
2877     }
2878
2879     /*
2880      * Two cases for *endP:
2881      *   whitespace or
2882      *     matching quote -> write NULL over char and point beyond
2883      *   NULL -> point to NULL 
2884      */
2885
2886     if (*endP != 0)
2887     {
2888         *endP = 0;       /* write NULL over terminator */
2889         *linePP = ++curP;   /* point beyond terminator */
2890     }
2891     else
2892     {
2893         *linePP = endP;
2894     }
2895     return ((unsigned char *)lineP);
2896
2897 } /* END OF FUNCTION GetString */
2898
2899
2900
2901 \f
2902 /*************************************<->*************************************
2903  *
2904  *  ScanWhitespace(linePP)
2905  *
2906  *
2907  *  Description:
2908  *  -----------
2909  *  Scan the string, skipping over all white space characters.
2910  *
2911  *
2912  *  Inputs:
2913  *  ------
2914  *  linePP = nonNULL pointer to current line buffer pointer
2915  *
2916  * 
2917  *  Outputs:
2918  *  -------
2919  *  linePP = nonNULL pointer to revised line buffer pointer
2920  *
2921  *
2922  *  Comments:
2923  *  --------
2924  *  Assumes linePP is nonNULL
2925  *  Code Stolen from dtmwm
2926  * 
2927  *************************************<->***********************************/
2928 void 
2929 ScanWhitespace(
2930         unsigned char **linePP )
2931 {
2932 #ifdef MULTIBYTE
2933     while (*linePP && (mblen ((char *) *linePP, MB_CUR_MAX) == 1) && isspace (**linePP))
2934 #else
2935     while (*linePP && isspace (**linePP))
2936 #endif
2937     {
2938         (*linePP)++;
2939     }
2940
2941 } /* END OF FUNCTION ScanWhitespace */
2942
2943
2944 \f
2945 /*************************************<->*************************************
2946  *
2947  *  FillHintBuf(newHint, hintBuf, maxSize, actSize, screen, numHints)
2948  *
2949  *
2950  *  Description:
2951  *  -----------
2952  *  Put the new hint into the hint buffer.  Each hint is separated by a 
2953  *  newline.
2954  *
2955  *
2956  *  Inputs:
2957  *  ------
2958  *  newHint = hint to add to the buffer
2959  *  hintBuf = an array of buffers - one for each screen
2960  *  maxSize = array of buffers of the current malloced size of each hintBuf
2961  *  actSize = array of space currently used by each hintBuf
2962  *  screen  = screen number for this hint
2963  *  numHints = array of the number of hints for each screen
2964  *  smGD.numSavedScreens = (global) checked to make sure this hint should be
2965  *                              added.
2966  * 
2967  *  Outputs:
2968  *  -------
2969  *  hintBuf[screen] = updated hint buf for this screen (newHint added)
2970  *  maxSize[screen] = enlarged if not big enough or malloced if not done before
2971  *  actSize[screen] = updated size of the hints buffer
2972  *  numHints[screen] = updated by 1 if this hint is added
2973  *
2974  *
2975  *  Comments:
2976  *  --------
2977  * 
2978  *************************************<->***********************************/
2979 static int
2980 FillHintBuf(
2981         unsigned char *newHint,
2982         unsigned char **hintBuf,
2983         unsigned int  *maxSize,
2984         unsigned int  *actSize,
2985         unsigned int  screen,
2986         unsigned int  *numHints)
2987 {
2988     static int hintBufSize = 5000;
2989     
2990     /*
2991      * If the screen that this hint was meant for is not in the current
2992      * set of available screens, don't save it
2993      */
2994     if(screen >= smGD.numSavedScreens)
2995     {
2996         return(0);
2997     }
2998
2999     /*
3000      * Check to see if this buffer has been malloc'd before - if it hasn't
3001      * malloc it.  If it has - check to make sure it's big enough to hold the
3002      * new information.
3003      */
3004     if(maxSize[screen] == 0)
3005     {
3006         hintBuf[screen] = (unsigned char *) SM_MALLOC(hintBufSize * sizeof(char));
3007         if(hintBuf[screen] == NULL)
3008         {
3009             actSize[screen] = 0;
3010             PrintErrnoError(DtError, smNLS.cantMallocErrorString);
3011             return(-1);
3012         }
3013         maxSize[screen] = hintBufSize * sizeof(char);
3014
3015         /*
3016          * Now reserve 4 bytes for the length
3017          */
3018         strcpy((char *)hintBuf[screen], "     \n");
3019     }
3020     else
3021     {
3022         if((actSize[screen] + strlen((char *)newHint) + 2) >= maxSize[screen])
3023         {
3024             hintBuf[screen] = (unsigned char *)
3025                 SM_REALLOC((char *) hintBuf[screen],
3026                            maxSize[screen] +
3027                            (hintBufSize *
3028                             sizeof(char)));
3029             if(hintBuf[screen] == NULL)
3030             {
3031                 actSize[screen] = 0;
3032                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
3033                 return(-1);
3034             }
3035             maxSize[screen] = maxSize[screen] + (hintBufSize * sizeof(char));
3036         }
3037     }
3038
3039     /*
3040      * add the new hint AFTER the last newline
3041      */
3042     strcat((char *)hintBuf[screen], (char *)newHint);
3043     strcat((char *)hintBuf[screen], "\n");
3044     actSize[screen] = strlen((char *)hintBuf[screen]);
3045     numHints[screen] += 1;
3046     
3047     return(0);
3048 }
3049                                       
3050
3051 \f
3052 /*************************************<->*************************************
3053  *
3054  *  FillCmdBuf(newCmd, cmdBuf, maxSize, actSize, screen)
3055  *
3056  *
3057  *  Description:
3058  *  -----------
3059  *  Put a new command into the command buffer.  The command buffer is just
3060  *  one big long string of stuff to be executed.
3061  *
3062  *
3063  *  Inputs:
3064  *  ------
3065  *  newCmd = command to add to the buffer
3066  *  cmdBuf = an array of buffers - one for each screen
3067  *  maxSize = array of buffers of the current malloced size of each cmdBuf
3068  *  actSize = array of space currently used by each cmdBuf
3069  *  screen  = screen number for this command
3070  *  smGD.numSavedScreens = (global) checked to make sure this hint should be
3071  *                              added.
3072  * 
3073  *  Outputs:
3074  *  -------
3075  *  cmdBuf[screen] = updated command buf for this screen (newCmd added)
3076  *  maxSize[screen] = enlarged if not big enough or malloced if not done before
3077  *  actSize[screen] = updated size of the command buffer
3078  *
3079  *
3080  *  Comments:
3081  *  --------
3082  * 
3083  *************************************<->***********************************/
3084 static int 
3085 FillCmdBuf(
3086         unsigned char *newCmd,
3087         unsigned char **cmdBuf,
3088         unsigned int *maxSize,
3089         unsigned int *actSize,
3090         unsigned int screen,
3091         unsigned int *numCmd )
3092 {
3093     static int cmdBufSize = 5000;
3094     
3095     /*
3096      * If the screen that this command was meant for is not in the current
3097      * set of available screens, don't save it
3098      */
3099     if(screen >= smGD.numSavedScreens)
3100     {
3101         return(0);
3102     }
3103
3104     /*
3105      * Check to see if this buffer has been malloc'd before - if it hasn't
3106      * malloc it.  If it has - check to make sure it's big enough to hold the
3107      * new information.
3108      */
3109     if(maxSize[screen] == 0)
3110     {
3111         cmdBuf[screen] = (unsigned char *) SM_MALLOC(cmdBufSize * sizeof(char));
3112         if(cmdBuf[screen] == NULL)
3113         {
3114             actSize[screen] = 0;
3115             PrintErrnoError(DtError, smNLS.cantMallocErrorString);
3116             return(-1);
3117         }
3118         maxSize[screen] = cmdBufSize * sizeof(char);
3119     }
3120     else
3121     {
3122         if((actSize[screen] + strlen((char *)newCmd)) >= maxSize[screen])
3123         {
3124             cmdBuf[screen] = (unsigned char *) SM_REALLOC((char *)cmdBuf[screen],
3125                                                         maxSize[screen] +
3126                                                         (cmdBufSize *
3127                                                         sizeof(char)));
3128             if(cmdBuf[screen] == NULL)
3129             {
3130                 actSize[screen] = 0;
3131                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
3132                 return(-1);
3133             }
3134             maxSize[screen] = maxSize[screen] + (cmdBufSize * sizeof(char));
3135         }
3136     }
3137
3138     if(actSize[screen] == 0)
3139     {
3140         strcpy((char *)cmdBuf[screen], (char *)newCmd);
3141     }
3142     else
3143     {   
3144         strcat((char *)cmdBuf[screen], (char *)newCmd);
3145     }
3146
3147     *numCmd = *numCmd + 1;
3148     strcat((char *)cmdBuf[screen], "\n");
3149     actSize[screen] = strlen((char *)cmdBuf[screen]);
3150
3151     return(0);
3152 }
3153                                       
3154
3155 \f
3156 /*************************************<->*************************************
3157  *
3158  *  FillRemoteBuf(newCmd, hostName, displayName, remoteBuf,
3159  *                maxSize, actSize, screen)
3160  *
3161  *
3162  *  Description:
3163  *  -----------
3164  *  Put a new command into the remote execution buffer.  The command buffer is
3165  *  just one big long string of stuff to be executed.
3166  *
3167  *
3168  *  Inputs:
3169  *  ------
3170  *  newCmd = command to add to the buffer
3171  *  hostName = host where command is to be executed from
3172  *  displayName = display where host is to be executed to
3173  *  remoteBuf = an array of buffers - one for each screen
3174  *  maxSize = array of buffers of the current malloced size of each cmdBuf
3175  *  actSize = array of space currently used by each cmdBuf
3176  *  screen  = screen number for this command
3177  *  smGD.numSavedScreens = (global) checked to make sure this hint should be
3178  *                              added.
3179  * 
3180  *  Outputs:
3181  *  -------
3182  *  cmdBuf[screen] = updated command buf for this screen (newCmd added)
3183  *                   in remote format (host name and display name)
3184  *  maxSize[screen] = enlarged if not big enough or malloced if not done before
3185  *  actSize[screen] = updated size of the command buffer
3186  *
3187  *
3188  *  Comments:
3189  *  --------
3190  * 
3191  *************************************<->***********************************/
3192 static int 
3193 FillRemoteBuf(
3194         unsigned char *newCmd,
3195         unsigned char *hostName,
3196         unsigned char *displayName,
3197         unsigned char *remoteBuf[] ,
3198         unsigned int *maxSize ,
3199         unsigned int *actSize , 
3200         unsigned int screen )
3201 {
3202     unsigned char *string;
3203     static int remoteBufSize = 5000;
3204     
3205     /*
3206      * If the screen that this command was meant for is not in the current
3207      * set of available screens, don't save it
3208      */
3209     if(screen >= smGD.numSavedScreens)
3210     {
3211         return(0);
3212     }
3213
3214     /*
3215      * Check to see if this buffer has been malloc'd before - if it hasn't
3216      * malloc it.  If it has - check to make sure it's big enough to hold the
3217      * new information.
3218      */
3219     if(maxSize[screen] == 0)
3220     {
3221         remoteBuf[screen] = (unsigned char *)
3222             SM_MALLOC(remoteBufSize * sizeof(char));
3223         if(remoteBuf[screen] == NULL)
3224         {
3225             actSize[screen] = 0;
3226             PrintErrnoError(DtError, smNLS.cantMallocErrorString);
3227             return(-1);
3228         }
3229         maxSize[screen] = remoteBufSize * sizeof(char);
3230     }
3231     else
3232     {
3233         if((actSize[screen] + strlen((char *)newCmd) +
3234             strlen((char *)hostName) +
3235             strlen((char *)displayName) +
3236             strlen("-display ") + 5) >= maxSize[screen])
3237         {
3238             remoteBuf[screen] = (unsigned char *)
3239                 SM_REALLOC((char *)remoteBuf[screen],
3240                            maxSize[screen] +
3241                            (remoteBufSize * sizeof(char)));
3242             if(remoteBuf[screen] == NULL)
3243             {
3244                 actSize[screen] = 0;
3245                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
3246                 return(-1);
3247             }
3248             maxSize[screen] = maxSize[screen] + (remoteBufSize * sizeof(char));
3249         }
3250     }
3251
3252     if(actSize[screen] == 0)
3253     {
3254         /*
3255          * If the buffer is empty fill it with the initial contents
3256          */
3257         strcpy((char *)remoteBuf[screen], (char *)hostName);
3258         strcat((char *)remoteBuf[screen], " ");
3259     }
3260     else
3261     {
3262         /*
3263          * if this buffer is not emtpy
3264          * add the new command BEFORE the last null terminator
3265          * Commands for remote executions are separated by newlines
3266          */
3267         strcat((char *)remoteBuf[screen], "\n");
3268         strcat((char *)remoteBuf[screen], (char *)hostName);
3269     }
3270
3271     /*
3272      * Copy the command in - quote it
3273      */
3274     strcat((char *)remoteBuf[screen], " \"");
3275     string = GetSmartString(&newCmd);
3276     strcat((char *)remoteBuf[screen], (char *)string);
3277     strcat((char *)remoteBuf[screen], " ");
3278
3279     /*
3280      * Once display name has been put in place - concatenate the
3281      * rest of the command
3282      */
3283     while((string = GetSmartString(&newCmd)) != NULL )
3284     {
3285         strcat((char *)remoteBuf[screen], " ");
3286         strcat((char *)remoteBuf[screen], (char *)string);
3287     }
3288
3289     /*
3290      * Now close off the command with a quote
3291      */
3292     strcat((char *)remoteBuf[screen], "\"");
3293
3294     actSize[screen] = strlen((char *)remoteBuf[screen]);
3295
3296     /*
3297      * Bump the remote command counter
3298      */
3299     numRemoteExecs++;
3300     
3301     return(0);
3302 }
3303                                       
3304 \f
3305 /*************************************<->*************************************
3306  *
3307  *  CreateExecString(execString)
3308  *
3309  *
3310  *  Description:
3311  *  -----------
3312  *  Create a string that can be fed to a fork and exec by breaking it up
3313  *  into argc and argv
3314  *
3315  *
3316  *  Inputs:
3317  *  ------
3318  *  execString = whole command
3319  * 
3320  *  Outputs:
3321  *  -------
3322  *  smExecArray = global modified to contain pointers to argc and argv
3323  *
3324  *
3325  *  Comments:
3326  *  --------
3327  * 
3328  *************************************<->***********************************/
3329 void
3330 CreateExecString(
3331                  char *execString)
3332                  
3333 {
3334 #define ARG_AMT 100
3335
3336     static int  iSizeArgv = ARG_AMT;
3337
3338     char *string;
3339     int  argc = 0;
3340
3341     if (smExecArray == NULL)
3342     {
3343         smExecArray = (char **) XtMalloc (ARG_AMT * sizeof(char *));
3344     }
3345     string = (char *) GetSmartString((unsigned char **) &execString);
3346     while(string != NULL)
3347     {
3348         smExecArray[argc] = string; 
3349         argc++;
3350         if (argc >= iSizeArgv)
3351         {
3352             iSizeArgv += ARG_AMT;
3353             smExecArray = (char **)
3354                 XtRealloc ((char *)smExecArray, (iSizeArgv * sizeof(char *)));
3355         }
3356         string = (char *) GetSmartString((unsigned char **) &execString);
3357     }
3358
3359     /*
3360      *  If the last string is a background character
3361      *  get rid of it
3362      */
3363     if(argc > 0)
3364     {
3365         if(!strcmp((char *)smExecArray[argc - 1], "&"))
3366         {
3367             smExecArray[argc - 1] = '\0';
3368         }
3369     }
3370      
3371     smExecArray[argc] = '\0';
3372
3373 } /* END OF FUNCTION CreateExecString */
3374
3375
3376 /*
3377  * SetTemporaryDisplay - does a putenv of the current value of the
3378  *      DISPLAY environment variable but with the given screen number.
3379  *
3380  * GLOBALS MODIFIED:
3381  *   savedDisplay  
3382  */
3383 static void
3384 SetTemporaryDisplay (
3385         int                     screenNum)
3386 {
3387         static char             * tmpDisplay = NULL;
3388         static int              lastScreen = -1;
3389         char                    * pch;
3390
3391         if (screenNum == -1)
3392                 return;
3393
3394         if (!savedDisplay) {
3395                 char            * dispEnv;
3396
3397                 if ((dispEnv = getenv (DISPLAY_NAME)) == NULL)
3398                         return;
3399                 savedDisplay = XtMalloc (strlen (DISPLAY_NAME_EQUAL) +
3400                                          strlen (dispEnv) + 2);
3401                 if (!savedDisplay)
3402                         return;
3403                 sprintf (savedDisplay, "%s%s", DISPLAY_NAME_EQUAL, dispEnv);
3404         }
3405
3406         if (lastScreen == screenNum && tmpDisplay != NULL) {
3407                 putenv (tmpDisplay);
3408                 return;
3409         }
3410         lastScreen = screenNum;
3411
3412         if (!tmpDisplay) {
3413                 if (!savedDisplay)
3414                         return;
3415                 tmpDisplay = XtMalloc (strlen (savedDisplay) + 4);
3416                 if (!tmpDisplay)
3417                         return;
3418                 strcpy (tmpDisplay, savedDisplay);
3419         }
3420
3421         if (pch = strrchr (tmpDisplay, ':')) {
3422                 char            *pch2, *pch3;
3423
3424                 if (pch2 = strchr (pch, '.'))
3425                         *pch2 = '\000';
3426                 pch3 = XtMalloc (strlen (tmpDisplay) + 4);
3427                 if (!pch3)
3428                         return;
3429                 sprintf (pch3, "%s.%d", tmpDisplay, screenNum);
3430                 strcpy (tmpDisplay, pch3);
3431                 XtFree ((char *) pch3);
3432
3433                 putenv (tmpDisplay);
3434         }
3435 }
3436
3437
3438 /*
3439  * RestoreDisplay - does a putenv of the global variable savedDisplay
3440  */
3441 static void
3442 RestoreDisplay (
3443         int                     screenNum)
3444 {
3445         if (screenNum != -1 && savedDisplay)
3446                 putenv (savedDisplay);
3447 }
3448
3449
3450 /*************************************<->*************************************
3451  *
3452  *  StartClient - calls StartLocalClient or StartRemoteClient depending
3453  *     on the value of hostName.
3454  *
3455  *  Description:
3456  *  -----------
3457  *  Starts a local or remote application 
3458  *
3459  *  Inputs:
3460  *  ------
3461  *  program = execArray[0]
3462  *  execArray = command to fork and exec
3463  *  hostName = the name of the host where program should be executed
3464  *  cwd = directory to chdir to before doing the exec
3465  *  envp = the envrironment variables to add to the child processes env
3466  *  checkCwd = if True and cwd is NULL, a message will be logged; if
3467  *     False, cwd will not be checked and the cwd will be set to $HOME
3468  *  useIgnoreEnvironmentResource = if True, the variables listed in the
3469  *     IgnoreEnvironment resource will be removed from 'environ' before
3470  *     execArray is exec'd
3471  *  screen = if set to -1, it will be ignored; otherwise, the screen
3472  *     number will be used to define DISPLAY for the duration of this
3473  *     function - DISPLAY will be reset before the function returns.
3474  * 
3475  *  Outputs:
3476  *  -------
3477  *  Returns True if the command is successfully executed; False otherwise.
3478  *
3479  *  Comments:
3480  *  --------
3481  *  localHost - is modified
3482  *
3483  *************************************<->***********************************/
3484 Boolean 
3485 StartClient(
3486         char                    * program,
3487         char                    * execArray[],
3488         char                    * hostName,
3489         char                    * cwd,
3490         char                    ** envp,
3491         Boolean                 checkCwd,
3492         Boolean                 useIgnoreEnvironmentResource,
3493         int                     screen)
3494 {
3495         static char             * defaultCwd = NULL;
3496         Boolean                 cwdNull = False;
3497         Boolean                 startStatus;
3498
3499         SetTemporaryDisplay (screen);
3500
3501         if (!ignoreEnvPtr && useIgnoreEnvironmentResource) {
3502                 if (smRes.ignoreEnvironment)
3503                         ignoreEnvPtr = _DtVectorizeInPlace (
3504                                         smRes.ignoreEnvironment, ',');
3505         }
3506
3507         if (!defaultCwd) 
3508           {
3509             char *tstr = getenv("HOME");
3510             if (tstr)
3511               {
3512                 int slen = strlen(tstr) + 1;
3513                 defaultCwd = XtCalloc(1, slen);
3514                 strncpy(defaultCwd, tstr, slen - 1);
3515               }
3516             else
3517               defaultCwd = getcwd (NULL, MAXPATHLEN + 1);
3518             
3519             (void) gethostname (localHost, MAXHOSTNAMELEN);
3520           }
3521
3522         if (!cwd) {
3523                 cwdNull = True;
3524                 cwd = defaultCwd;
3525         }
3526
3527         if (!hostName || (_DtIsSameHost (localHost, hostName)))
3528                 startStatus = StartLocalClient (program, execArray, 
3529                                         cwd, envp, checkCwd, 
3530                                         useIgnoreEnvironmentResource);
3531         else
3532                 startStatus = StartRemoteClient (program, execArray, hostName, 
3533                                         cwd, envp, 
3534                                         useIgnoreEnvironmentResource);
3535
3536         RestoreDisplay (screen);
3537
3538         return (startStatus);
3539 }
3540                                       
3541 /*************************************<->*************************************
3542  *
3543  *  StartLocalClient 
3544  *
3545  *  Description:
3546  *  -----------
3547  *  Starts a local application.
3548  *
3549  *  -------
3550  *  Returns True if the command is successfully executed; False otherwise.
3551  *
3552  *************************************<->***********************************/
3553 static Boolean 
3554 StartLocalClient (
3555         char                    *program,
3556         char                    *execArray[],
3557         char                    *cwd,
3558         char                    **envp,
3559         Boolean                 doChdir,
3560         Boolean                 useIgnoreEnvironmentResource)
3561 {
3562     pid_t  clientFork;
3563     int    execStatus, i;
3564     char   clientMessage[MAXPATHLEN + 30];
3565     char   **tmpEnv, **ppchar;
3566            
3567     /*
3568      * Fork and exec the client process
3569      */
3570     clientFork = vfork();
3571     
3572     /*
3573      * If the fork fails - Send out an error and return
3574      */
3575     if(clientFork < 0)
3576     {
3577         PrintErrnoError(DtError, smNLS.cantForkClientString);
3578         return (False);
3579     }
3580     
3581     /*
3582      * Fork succeeded - now do the exec
3583      */
3584     if(clientFork == 0)
3585     {
3586         SetSIGPIPEToDefault ();
3587
3588         /*
3589          * Log a warning if the given cwd is not valid
3590          */
3591         if (doChdir && cwd) 
3592         {
3593             if ((chdir (cwd)) == -1) 
3594             {
3595                 char    *tmpCwd;
3596
3597                 tmpCwd = getcwd (NULL, MAXPATHLEN + 1);
3598
3599                 LogCWDMessage (cwd, program, tmpCwd);
3600             }
3601         }
3602
3603         /*
3604          * Add envp to the client's environ if the variable
3605          * is not in the ignoreEnvironment list
3606          */
3607         if (useIgnoreEnvironmentResource && envp) {
3608         
3609             if (ignoreEnvPtr)
3610                 tmpEnv = RemoveEnvironmentVars (envp);
3611             else
3612                 tmpEnv = envp;
3613
3614             for (ppchar = tmpEnv; ppchar && *ppchar; ppchar++) 
3615                 putenv (strdup (*ppchar));
3616         }
3617
3618 #ifndef __hpux
3619         /*
3620          * Set the gid of the process back from bin
3621          */
3622 #ifndef SVR4
3623         setregid(smGD.runningGID, smGD.runningGID);
3624 #else
3625         setgid(smGD.runningGID);
3626         setegid(smGD.runningGID);
3627 #endif
3628 #endif
3629
3630         _DtEnvControl(DT_ENV_RESTORE_PRE_DT);
3631
3632 #if defined(__osf__) || defined(CSRG_BASED)
3633         setsid();
3634 #else
3635         (void)setpgrp();
3636 #endif /* __osf__ */
3637         
3638         MarkFileDescriptors (3, F_SETFD, 1);
3639
3640         execStatus = execvp(program, execArray);
3641         if(execStatus != 0)
3642         {
3643             sprintf(clientMessage, ((char *)GETMESSAGE(16, 3, "Unable to exec %s.")), execArray[0]);
3644             PrintErrnoError(DtError, clientMessage);
3645             SM_EXIT(-1);
3646         }
3647     }
3648
3649     return (True);
3650 }
3651
3652 /*************************************<->*************************************
3653  *
3654  *  StartRemoteClient 
3655  *
3656  *  Description:
3657  *  -----------
3658  *  Starts a remote application.
3659  *
3660  *  -------
3661  *  Returns True if the command is successfully executed; False otherwise.
3662  *
3663  *************************************<->***********************************/
3664 static Boolean 
3665 StartRemoteClient (
3666         char                    * program,
3667         char                    * execArray[],
3668         char                    * hostName,
3669         char                    * cwd,
3670         char                    ** envp,
3671         Boolean                 useIgnoreEnvironmentResource)
3672 {
3673         int                     ioMode;
3674         SPC_Channel_Ptr         channel;
3675         char                    * netfile;
3676         char                    errorMessage[1024];
3677         char                    * message;
3678         static Boolean          cmdInvokerInitialized = False;
3679         char                    ** tmpEnv = envp;
3680
3681         ioMode = SPCIO_NOIO | SPCIO_FORCE_CONTEXT;
3682
3683         if (!cmdInvokerInitialized) {
3684                 _DtInitializeCommandInvoker(smGD.display,
3685                                            DtSM_TOOL_CLASS,
3686                                            SM_RESOURCE_CLASS,
3687                                            NULL, smGD.appCon);
3688                 cmdInvokerInitialized = True;
3689         }
3690
3691         (void) strcpy (errorMessage, "");
3692
3693         channel = (SPC_Channel_Ptr) _DtSPCOpen (hostName, ioMode, errorMessage);
3694         if (channel == SPC_ERROR) {
3695                 message = strdup ((char *) GETMESSAGE (40, 13,
3696                         "The following application cannot be started on host '%s'\nbecause this host cannot be reached from host '%s':\n\n   %s"));
3697
3698                 if (message) {
3699                         DtMsgLogMessage (smGD.programName, DtMsgLogError, 
3700                                          message, hostName, localHost, program);
3701                         free (message);
3702                 }
3703                 return (False);
3704         }
3705
3706         netfile = tt_host_file_netfile (hostName, cwd);
3707         if (tt_pointer_error (netfile) != TT_OK) {
3708
3709                 message = strdup ((char *) GETMESSAGE (40, 14,
3710                         "An attempt to start application '%s'\non host '%s' failed because the following directory\ncould not be translated into cannonical form:\n\n   %s\n\n[%s]"));
3711
3712                 if (message) {
3713                         DtMsgLogMessage (smGD.programName, DtMsgLogError, 
3714                                         message, program, hostName, cwd,
3715                                         tt_status_message (tt_pointer_error (
3716                                                 netfile)));
3717                         free (message);
3718                 }
3719                 return (False);
3720         }
3721
3722         /*
3723          * Add envp to the client's environ if the variable
3724          * is not in the ignoreEnvironment list
3725          */
3726         if (useIgnoreEnvironmentResource && ignoreEnvPtr && envp)
3727                 tmpEnv = RemoveEnvironmentVars (envp);
3728
3729         if ((_DtSPCSpawn (program, netfile, execArray, tmpEnv, channel, 
3730                         hostName, NULL, cwd, errorMessage)) == SPC_ERROR) {
3731                 DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMessage);
3732                 if (tmpEnv)
3733                         XtFree ((char *) tmpEnv);
3734                 return (False);
3735         }
3736
3737         tt_free (netfile);
3738         if (tmpEnv)
3739                 XtFree ((char *) tmpEnv);
3740         return (True);
3741 }
3742
3743                                       
3744 \f
3745 /*************************************<->*************************************
3746  *
3747  *  ForkWM()
3748  *
3749  *
3750  *  Description:
3751  *  -----------
3752  *  Fork and exec the default window manager
3753  *
3754  *
3755  *  Inputs:
3756  *  ------
3757  * 
3758  *  Outputs:
3759  *  -------
3760  *
3761  *
3762  *  Comments:
3763  *  --------
3764  * 
3765  *************************************<->***********************************/
3766 static void 
3767 ForkWM( void )
3768 {
3769     pid_t  clientFork;
3770     int    execStatus, i;
3771
3772 #ifdef __hpux
3773     /* 
3774      * These lines were added to support the builtin
3775      * panacomm dtwm.
3776      */
3777     char   *homeDir;
3778     char   *hostName;
3779     char   *displayName,*dpy;
3780
3781     hostName = SM_MALLOC(MAXPATHSM);
3782     displayName = SM_MALLOC(MAXPATHSM);
3783
3784     if( gethostname(hostName, (sizeof(hostName) - 1) ) == 0)
3785     {
3786         hostName[MAXPATHSM - 1] = '\0';
3787         dpy = getenv(DISPLAY_NAME);
3788         homeDir = getenv("HOME");
3789         if (dpy && homeDir)
3790         {
3791             strcpy(displayName, dpy);
3792             dpy = strchr(displayName, ':');
3793             if (dpy)
3794             {
3795                 *dpy = '\0';
3796             }
3797             sprintf(tmpExecWmFile, "%s/.dt/bin/%s/%s/dtwm", homeDir,
3798                     hostName,displayName);
3799             if (access(tmpExecWmFile,X_OK) != 0)
3800             {
3801                 strcpy(tmpExecWmFile,CDE_INSTALLATION_TOP "/bin/dtwm");
3802             }
3803             else
3804             {
3805                 localWmLaunched = True;
3806                 if (!smGD.userSetWaitWmTimeout)
3807                 {
3808                     smRes.waitWmTimeout = 60000;
3809                 }
3810             }
3811         }
3812         else
3813         {
3814           strcpy(tmpExecWmFile,CDE_INSTALLATION_TOP "/bin/dtwm");
3815         }
3816     }
3817     else
3818     {
3819         strcpy(tmpExecWmFile,CDE_INSTALLATION_TOP "/bin/dtwm");
3820     }
3821
3822     SM_FREE(hostName);
3823     SM_FREE(displayName);
3824     /* 
3825      *     ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  
3826      * End of  lines were added to support the builtin
3827      * panacomm dtwm.
3828      */
3829 #else
3830      strcpy(tmpExecWmFile,CDE_INSTALLATION_TOP "/bin/dtwm");
3831 #endif /* __hpux */
3832
3833
3834     /*
3835      * Fork and exec the client process
3836      */
3837     clientFork = vfork();
3838     
3839     /*
3840      * If the fork fails - Send out an error and return
3841      */
3842     if(clientFork < 0)
3843     {
3844         PrintErrnoError(DtError, smNLS.cantForkClientString);
3845         return;
3846     }
3847     
3848     /*
3849      * Fork succeeded - now do the exec
3850      */
3851     if(clientFork == 0)
3852     {
3853         SetSIGPIPEToDefault ();
3854
3855 #ifndef __hpux
3856         /*
3857          * Set the gid of the process back from bin
3858          */
3859 #ifndef SVR4
3860         setregid(smGD.runningGID, smGD.runningGID);
3861 #else
3862         setgid(smGD.runningGID);
3863         setegid(smGD.runningGID);
3864 #endif
3865 #endif
3866         _DtEnvControl(DT_ENV_RESTORE_PRE_DT);
3867
3868 #if defined(__osf__) || defined(CSRG_BASED)
3869         setsid();
3870 #else
3871         (void)setpgrp();
3872 #endif /* __osf__ */
3873
3874         MarkFileDescriptors (3, F_SETFD, 1);
3875
3876         /* 
3877          * These lines were added to support the builtin
3878          * panacomm dtwm.
3879          * This used to be
3880          * execStatus = execlp(".../dt/bin/dtwm", "dtwm", (char *) 0);
3881          */
3882
3883         execStatus = execlp(tmpExecWmFile, "dtwm", (char *) 0);
3884
3885         /* 
3886          *     ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  ^^^^^  
3887          * End of  lines were added to support the builtin
3888          * panacomm dtwm.
3889          */
3890
3891         if(execStatus != 0 && (!localWmLaunched))
3892         {
3893             PrintErrnoError(DtError, GETMESSAGE(16, 4, "Unable to exec process /usr/dt/bin/dtwm.  No window manager will be started."));
3894             SM_EXIT(-1);
3895         }
3896     }
3897 }
3898                                       
3899 \f
3900 /*************************************<->*************************************
3901  *
3902  *  KillParent()
3903  *
3904  *
3905  *  Description:
3906  *  -----------
3907  *  Fork a copy of ourselves and kill the parent off so that scripts starting
3908  *  up the session manager can continue.
3909  *
3910  *  Inputs:
3911  *  ------
3912  * 
3913  *  Outputs:
3914  *  -------
3915  *
3916  *
3917  *  Comments:
3918  *  --------
3919  * 
3920  *************************************<->***********************************/
3921 void 
3922 KillParent( void )
3923 {
3924     pid_t  clientFork;
3925
3926     
3927     /*
3928      * Fork and exec the client process
3929      */
3930     clientFork = fork();
3931     
3932     /*
3933      * If the fork fails - We have to exit so that the rest of the
3934      * script can continue
3935      */
3936     if(clientFork < 0)
3937     {
3938         PrintErrnoError(DtError, smNLS.cantForkClientString);
3939         SM_EXIT(-1);
3940     }
3941     
3942     /*
3943      * Fork succeeded - now kill the parent
3944      */
3945     if(clientFork != 0)
3946     {
3947         SM_EXIT(0);
3948     }
3949
3950     /*
3951      * Disassociate from parent
3952      */
3953 #if defined(__osf__) || defined(CSRG_BASED)
3954     setsid();
3955 #else
3956     setpgrp();
3957 #endif /* __osf__ */
3958 }
3959
3960
3961 \f
3962 /*************************************<->*************************************
3963  *
3964  *  WaitForWM ()
3965  *
3966  *
3967  *  Description:
3968  *  -----------
3969  *  This routine waits for the window manager to start.  It uses a
3970  *  resource (waitWmTimeout) with a dynamic default to determine how many
3971  *  seconds to wait for WM start and then starts clients.
3972  *
3973  *
3974  *  Inputs:
3975  *  ------
3976  *  appContext = application context for the window
3977  *  window = window id for the
3978  *
3979  * 
3980  *  Outputs:
3981  *  -------
3982  *
3983  *  Comments:
3984  *  --------
3985  * 
3986  *************************************<->***********************************/
3987 static void 
3988 WaitForWM( void )
3989 {
3990     XEvent              event;
3991     XtIntervalId        wmTimerId;
3992     
3993     XtAddEventHandler(smGD.topLevelWid,
3994                       0,
3995                       True,
3996                       (XtEventHandler)HandleWMClientMessage,
3997                       (XtPointer) NULL);
3998
3999     /*
4000      * Set a timer which stops the block on waiting for the
4001      * window manager to start
4002      */
4003     wmTimeout = False;
4004     wmTimerId = XtAppAddTimeOut(smGD.appCon, 
4005                                 smRes.waitWmTimeout,
4006                                 WaitWMTimeout, NULL);
4007     
4008     while((smGD.dtwmRunning == False) && (wmTimeout == False))
4009     {
4010         XtAppProcessEvent(smGD.appCon, XtIMAll);
4011     }
4012     
4013     XtRemoveTimeOut(wmTimerId);
4014     XtRemoveEventHandler(smGD.topLevelWid,
4015                       0,
4016                       True,
4017                       (XtEventHandler)HandleWMClientMessage,
4018                       (XtPointer) NULL);
4019
4020     return;
4021 } /* END OF FUNCTION WaitForWM */
4022
4023 \f
4024 /*************************************<->*************************************
4025  *
4026  *  WaitWMTimeout
4027  *
4028  *
4029  *  Description:
4030  *  -----------
4031  *  Timeout procedure the WaitForCommand routine.  It stops a loop waiting
4032  *  for the window manager to get started.
4033  *
4034  *
4035  *  Inputs:
4036  *  ------
4037  *
4038  * 
4039  *  Outputs:
4040  *  -------
4041  *  wmTimeout = (global) flag that stops the loop
4042  *
4043  *  Comments:
4044  *  --------
4045  * 
4046  *************************************<->***********************************/
4047 static void 
4048 WaitWMTimeout(
4049         XtPointer client_data,
4050         XtIntervalId *id )
4051 {
4052     wmTimeout = True;
4053     return;
4054 } /* END OF FUNCTION WaitWMTimeout */
4055
4056
4057 \f
4058 /*************************************<->*************************************
4059  *
4060  *  HandleWMClientMessage
4061  *
4062  *
4063  *  Description:
4064  *  -----------
4065  *  This is the event handler registered to recieve the client message
4066  *  from dtwm when dtwm is ready for business
4067  *
4068  *
4069  *************************************<->***********************************/
4070 static void
4071 HandleWMClientMessage( Widget smWidget,
4072                     XtPointer dummy,
4073                     XEvent *event)
4074 {
4075     if (event->type == ClientMessage)
4076     {
4077         ProcessClientMessage(event);
4078     }
4079     return;
4080 } /* END OF FUNCTION HandleWMClientMessage */
4081
4082
4083
4084 \f
4085 /*************************************<->*************************************
4086  *
4087  *  FixEnvironmentData
4088  *
4089  *
4090  *  Description:
4091  *  -----------
4092  *  If DISPLAY variable exists in the environment - remove it
4093  *
4094  *
4095  *  Inputs:
4096  *  ------
4097  *
4098  * 
4099  *  Outputs:
4100  *  -------
4101  *  wmTimeout = (global) flag that stops the loop
4102  *
4103  *  Comments:
4104  *  --------
4105  * 
4106  *************************************<->***********************************/
4107 static void 
4108 FixEnvironmentData( void )
4109 {
4110    char **ppchar;
4111    int i;
4112    extern char **environ;  /* MODIFIED - DISPLAY is remove if found. */
4113
4114    for (i=0, ppchar = environ; *ppchar; ppchar++, i++)
4115    {
4116       if ((strncmp (*ppchar, DISPLAY_NAME_EQUAL, strlen(DISPLAY_NAME_EQUAL))) == 0)
4117       {
4118          /*
4119           * Change the DISPLAY environment variable.
4120           */
4121          for (; *ppchar; ppchar++, i++)
4122          {
4123              environ[i]=environ[i+1];
4124          }
4125          break;
4126       }
4127    }
4128 }
4129
4130
4131 \f
4132 /*************************************<->*************************************
4133  *
4134  *  ResetScreenInfo()
4135  *
4136  *
4137  *  Description:
4138  *  -----------
4139  *  After one screen is finished - set up the info for the next
4140  *
4141  *
4142  *  Inputs:
4143  *  ------
4144  *  cmdBuf - Buffer that holds all the invocation information
4145  *  screen - Pointer to the screen number that we're currently working on
4146  *  env - used to set up the environment for changing the display var
4147  *  displayName - name of the current display
4148  * 
4149  *  Outputs:
4150  *  -------
4151  *  cmdBuf - old buffers are freed
4152  *  screen - updated to point to the new screen info
4153  *  done   - tells whether the clients are done being exec'd
4154  *  linec - *GLOBAL* sets line being read from
4155  *  parseP - *GLOBAL*
4156  *
4157  *  Comments:
4158  *  --------
4159  * 
4160  *************************************<->***********************************/
4161 static void 
4162 ResetScreenInfo(unsigned char **cmdBuf,
4163                 int             *screen,
4164                 unsigned int    *cmdSize,
4165                 Boolean         *done,
4166                 char            *env,
4167                 char            *displayName)
4168 {
4169     SM_FREE((char *) cmdBuf[*screen]);
4170     (*screen)++;
4171     while((cmdSize[*screen] == 0) && (*screen < smGD.numSavedScreens))
4172     {
4173         (*screen)++;
4174     }
4175     
4176     if(*screen >= smGD.numSavedScreens)
4177     {
4178         *done = True;
4179     }
4180     else
4181     {
4182         sprintf((char *)env,"%s%s%d", DISPLAY_NAME_EQUAL, displayName, *screen);
4183         putenv(env);
4184         
4185         linec = 0;
4186         parseP = cmdBuf[*screen];
4187     }
4188 }
4189
4190
4191 \f
4192 /*************************************<->*************************************
4193  *
4194  *  RemoteRequestFailed ()
4195  *
4196  *
4197  *  Description:
4198  *  -----------
4199  *  If a request to the command invoker fails, this callback will be called.
4200  *  It will then try to execute the command by performing a remsh on it.
4201  *
4202  *  Inputs:
4203  *  ------
4204  *
4205  * 
4206  *  Outputs:
4207  *  -------
4208  *
4209  *
4210  *  Comments:
4211  *  --------
4212  * 
4213  *************************************<->***********************************/
4214 static void 
4215 RemoteRequestFailed(char *message,
4216                     void *client_data)
4217 {
4218     static char *cmdBuf = NULL;
4219     static char *tmpCmdBuf = NULL;
4220     char *errorString = NULL;
4221     String tmpString;
4222
4223     static int  cmdBufSize = 0;
4224     int         i;
4225     int         tmpSize;
4226     RemoteReq   *tmpReq = (RemoteReq *) client_data;
4227
4228     /*
4229      * If the memory for the buffer has not been malloced - do so
4230      */
4231     if(cmdBuf == NULL)
4232     {
4233         cmdBuf = SM_MALLOC((200 * sizeof(char)) + 1 );
4234         if(cmdBuf == NULL)
4235         {
4236             PrintErrnoError(DtError, smNLS.cantMallocErrorString);
4237             return;
4238         }
4239         cmdBufSize = 200 + 1;
4240
4241         tmpCmdBuf = SM_MALLOC((200 * sizeof(char)) + 1 );
4242         if(tmpCmdBuf == NULL)
4243         {
4244             PrintErrnoError(DtError, smNLS.cantMallocErrorString);
4245         }
4246     }
4247
4248     /*
4249      *  Copy in the host and command field and execute the command
4250      */
4251
4252     tmpSize = (strlen(REMOTE_CMD_STRING) + 
4253                strlen((char *) tmpReq->hostPtr) +
4254                strlen((char *) tmpReq->cmdPtr)  + 1);
4255
4256     if(tmpSize >= cmdBufSize)
4257     {
4258         cmdBuf =  SM_REALLOC(cmdBuf, (tmpSize) * sizeof(char));
4259
4260         if(cmdBuf == NULL)
4261         {
4262             PrintErrnoError(DtError, smNLS.cantMallocErrorString);
4263             cmdBufSize = 0;
4264             return;
4265         }
4266         cmdBufSize = tmpSize;
4267
4268         if(tmpCmdBuf != NULL)
4269         {
4270             tmpCmdBuf =  SM_REALLOC(tmpCmdBuf, (tmpSize) * sizeof(char));
4271             if(tmpCmdBuf == NULL)
4272             {
4273                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
4274             }
4275         }
4276     }
4277
4278     sprintf(cmdBuf, REMOTE_CMD_STRING, tmpReq->hostPtr, tmpReq->cmdPtr);
4279
4280     /* 
4281      * save cmdBuf for error message, cmdBuf is changed
4282      * by CreateExecString
4283      */
4284     if (tmpCmdBuf != NULL)
4285     {
4286         strcpy(tmpCmdBuf,cmdBuf);
4287     }
4288
4289     CreateExecString(cmdBuf);
4290     if(smExecArray[0] != NULL)
4291     {
4292         (void) StartClient(smExecArray[0], smExecArray, NULL, NULL, 
4293                                 NULL, False, False, -1);
4294
4295         if (tmpCmdBuf != NULL)
4296         {
4297            tmpString = GETMESSAGE(16, 8, 
4298 "An attempt to restore the following\ncommand (using the DT remote execution process)\non host \"%s\" failed:\n\n      %s\n\nThe following execution string will be tried:\n\n   %s\n\n");
4299             
4300            errorString = 
4301                     (char *)SM_MALLOC((strlen(tmpString) + 
4302                                        strlen((char *)tmpReq->hostPtr) +
4303                                        strlen((char *)tmpReq->cmdPtr)  +
4304                                        strlen(tmpCmdBuf) + 1 ) * 
4305                                       sizeof(char));
4306                 
4307            if(errorString == NULL)
4308            {
4309                     PrintErrnoError(DtError, smNLS.cantMallocErrorString);
4310            }
4311            else
4312            {
4313                     sprintf(errorString, tmpString, tmpReq->hostPtr, 
4314                             tmpReq->cmdPtr, tmpCmdBuf );
4315                     PrintError(DtError, errorString);
4316                     SM_FREE(errorString);
4317            }
4318         }
4319     }
4320     /*
4321      * Now check to make sure that this isn't the last remote request.
4322      * If so, free the data
4323      */
4324     numRemoteExecs--;
4325
4326     if(numRemoteExecs == 0)
4327     {
4328         for(i = 0;i < smGD.numSavedScreens;i++)
4329         {
4330             if(actRemoteSize[i] > 0)
4331             {
4332                 SM_FREE((char *) remoteBuf[i]);
4333             }
4334         }
4335     }
4336     
4337     return;
4338 }
4339
4340
4341 \f
4342 /*************************************<->*************************************
4343  *
4344  *  RemoteRequestSucceeded ()
4345  *
4346  *
4347  *  Description:
4348  *  -----------
4349  *  If a request to the command invoker succeeds, this callback will be called.
4350  *  It decrements the remote execution counter, and frees the info if
4351  *  remote executions are finished
4352  *
4353  *  Inputs:
4354  *  ------
4355  *
4356  * 
4357  *  Outputs:
4358  *  -------
4359  *
4360  *
4361  *  Comments:
4362  *  --------
4363  * 
4364  *************************************<->***********************************/
4365 static void 
4366 RemoteRequestSucceeded(char *message,
4367                        void *client_data)
4368 {
4369     int i;
4370     
4371     numRemoteExecs--;
4372
4373     if(numRemoteExecs == 0)
4374     {
4375         for(i = 0;i < smGD.numSavedScreens;i++)
4376         {
4377             if(actRemoteSize[i] > 0)
4378             {
4379                 SM_FREE((char *) remoteBuf[i]);
4380             }
4381         }
4382     }
4383 }
4384
4385 /**************************************************************************
4386  *
4387  * XSMP code follows
4388  *
4389  **************************************************************************/
4390
4391 Boolean 
4392 StartXSMPSession (
4393         char                    * databaseName)
4394 {
4395         ClientDB                inputDB;
4396         XSMPClientDBRecPtr      pXSMPRec;
4397         ProxyClientDBRecPtr     pProxyRec;
4398         int                     i;
4399
4400         StartWM ();
4401
4402         if ((inputDB = OpenInputClientDB (databaseName, 
4403                                           &smXSMP.dbVersion, 
4404                                           &smXSMP.dbSessionId)) == NULL) {
4405                 LogXSMPOpenDatabaseFailure (databaseName, DtMsgLogError, 1);
4406                 return (False);
4407         }
4408
4409         if (!smXSMP.dbVersion) {
4410                 LogXSMPOpenDatabaseFailure (databaseName, DtMsgLogWarning, 2);
4411                 smXSMP.dbVersion = SM_VENDOR_NAME;
4412         }
4413
4414         if (!smXSMP.dbSessionId) {
4415                 LogXSMPOpenDatabaseFailure (databaseName, DtMsgLogWarning, 3);
4416                 smXSMP.dbSessionId = SM_RELEASE_NAME;
4417         }
4418
4419         /*
4420          * First start the XSMP clients
4421          */
4422         for (;;) {
4423       
4424                 if ((pXSMPRec = GetXSMPClientDBRec (inputDB)) == NULL)
4425                         break;
4426
4427                 if (!CheckRequiredProperties (pXSMPRec, databaseName)) {
4428                         FreeXSMPClientDBRec (pXSMPRec);
4429                         continue;
4430                 }
4431
4432                 if (StartXSMPClient (pXSMPRec, databaseName)) {
4433
4434                         XSMPClientDBRecPtr      tmpRecPtr;
4435                         
4436                         pXSMPRec->next = NULL;
4437
4438                         if (!smXSMP.xsmpDbList) {
4439                                 smXSMP.xsmpDbList = pXSMPRec;
4440                                 continue;
4441                         }
4442
4443                         /*
4444                          * Find the end of the list
4445                          */
4446                         for (tmpRecPtr = smXSMP.xsmpDbList; 
4447                                 tmpRecPtr && tmpRecPtr->next != NULL; 
4448                                 tmpRecPtr = tmpRecPtr->next);
4449
4450                         tmpRecPtr->next = pXSMPRec;
4451                 }
4452                 else
4453                         FreeXSMPClientDBRec (pXSMPRec);
4454         }
4455
4456         /*
4457          * Now start the Proxy clients
4458          */
4459         for (i = 0; ; i++) {
4460       
4461                 if ((pProxyRec = GetProxyClientDBRec (inputDB)) == NULL)
4462                         break;
4463
4464                 if (!CheckRequiredFields (pProxyRec, databaseName, i)) {
4465                         FreeProxyClientDBRec (pProxyRec);
4466                         continue;
4467                 }
4468
4469                 (void) StartProxyClient (pProxyRec);
4470
4471                 FreeProxyClientDBRec (pProxyRec);
4472         }
4473
4474         (void) CloseClientDB (inputDB, False);
4475
4476         return (True);
4477 }
4478
4479
4480 Boolean 
4481 StartXSMPClient (
4482         XSMPClientDBRecPtr      pDbRec,
4483         char                    * databaseName)
4484 {
4485         return (StartClient (pDbRec->restartCommand[0], 
4486                              pDbRec->restartCommand, 
4487                              pDbRec->clientHost,
4488                              pDbRec->cwd, 
4489                              pDbRec->environment, 
4490                              True, 
4491                              True,
4492                              pDbRec->screenNum));
4493 }
4494
4495
4496 Boolean 
4497 StartProxyClient (
4498         ProxyClientDBRecPtr     pDbRec)
4499 {
4500         return (StartClient (pDbRec->command[0], 
4501                              pDbRec->command,
4502                              pDbRec->clientHost, 
4503                              NULL, 
4504                              NULL, 
4505                              False, 
4506                              False,
4507                              pDbRec->screenNum));
4508 }
4509
4510
4511 Boolean 
4512 ExecuteCommandProperty (
4513         char                    * commandName,
4514         ClientRecPtr            pClientRec)
4515 {
4516         char                    ** argv;
4517         char                    ** envp = NULL;
4518         char                    * cwd;
4519         PropertyRecPtr          pPropRec;
4520         int                     i;
4521         Boolean                 retValue;
4522
4523         if ((pPropRec = GetPropertyRec (pClientRec, commandName)) == NULL)
4524                 return (False);
4525
4526         argv = (char **) XtMalloc ((pPropRec->prop.num_vals + 1) *
4527                                    sizeof (char *));
4528         if (!argv)
4529                 return (False);
4530
4531         for (i = 0; i < pPropRec->prop.num_vals; i++)
4532                 argv[i] = pPropRec->prop.vals[i].value;
4533         argv[pPropRec->prop.num_vals] = NULL;
4534         
4535         cwd = GetArrayPropertyValue (pClientRec, SmCurrentDirectory);
4536
4537
4538         if ((pPropRec = GetPropertyRec (pClientRec, SmEnvironment)) != NULL) {
4539                 envp = (char **) XtMalloc ((pPropRec->prop.num_vals + 1) *
4540                                            sizeof (char *));
4541                 if (!envp) 
4542                         return (False);
4543                 
4544                 for (i = 0; i < pPropRec->prop.num_vals; i++)
4545                         envp[i] = pPropRec->prop.vals[i].value;
4546                 envp[pPropRec->prop.num_vals] = NULL;
4547         }
4548
4549         retValue = StartClient (argv[0], argv,
4550                                 pClientRec->clientHost,
4551                                 cwd, envp,
4552                                 True, True,
4553                                 pClientRec->screenNum);
4554
4555         XtFree ((char *) argv);
4556         if (envp)
4557                 XtFree ((char *) envp);
4558
4559         return (retValue);
4560 }
4561
4562
4563 /*************************************<->*************************************
4564  *
4565  *  ExecuteDiscardCommands -
4566  *
4567  *  Description: Executes all of the DiscardCommand properties in the
4568  *      given client database
4569  *
4570  *  Inputs: None
4571  * 
4572  *************************************<->***********************************/
4573 void
4574 ExecuteDiscardCommands (
4575         char                    * db)
4576 {
4577         ClientDB                inputDB;
4578         XSMPClientDBRecPtr      pXSMPRec;
4579         char                    * version = NULL;
4580         char                    * id = NULL;
4581         char                    * str;
4582
4583         if ((inputDB = OpenInputClientDB (db, &version, &id )) == NULL) {
4584                 str = strdup ((char *) GETMESSAGE (40, 26,
4585                                 "The following client database cannot be opened:\n\n   %s\n\nThe 'DiscardCommand' properties cannot be run."));
4586                 if (!str) 
4587                         return;
4588                 DtMsgLogMessage (smGD.programName, DtMsgLogWarning, str, db);
4589                 free (str);
4590                 return;
4591         }
4592
4593         if (version)
4594                 XtFree ((char *) version);
4595         if (id)
4596                 XtFree ((char *) id);
4597
4598         for (;;) {
4599                 if ((pXSMPRec = GetXSMPClientDBRec (inputDB)) == NULL)
4600                         break;
4601                 
4602                 if (!pXSMPRec->discardCommand)
4603                         continue;
4604
4605                 if (!StartClient (pXSMPRec->discardCommand[0],
4606                                   pXSMPRec->discardCommand,
4607                                   pXSMPRec->clientHost,
4608                                   pXSMPRec->cwd,
4609                                   pXSMPRec->environment,
4610                                   True,
4611                                   True,
4612                                   pXSMPRec->screenNum)) {
4613                         str = strdup ((char *) GETMESSAGE (40, 27,
4614                                 "An attempt to execute the 'DiscardCommand' property for\napplication '%s' failed."));
4615                         if (!str) 
4616                                 return;
4617                         DtMsgLogMessage (smGD.programName, DtMsgLogWarning, str, 
4618                                          pXSMPRec->program);
4619                         free (str);
4620                 }
4621
4622                 FreeXSMPClientDBRec (pXSMPRec);
4623         }
4624
4625         (void) CloseClientDB (inputDB, False);
4626 }
4627
4628
4629 static Boolean 
4630 CheckRequiredProperties (
4631         XSMPClientDBRecPtr      pDbRec,
4632         char                    * databaseName)
4633 {
4634         Boolean                 propsOK = True;
4635
4636         if (!pDbRec->program) {
4637                 LogMissingPropertyMessage (pDbRec, SmProgram, 
4638                                                 databaseName, DtMsgLogError);
4639                 propsOK = False;
4640         }
4641
4642         if (!pDbRec->restartCommand) {
4643                 LogMissingPropertyMessage (pDbRec, SmRestartCommand, 
4644                                                 databaseName, DtMsgLogError);
4645                 propsOK = False;
4646         }
4647
4648         return (propsOK);
4649 }
4650
4651
4652 static Boolean 
4653 CheckRequiredFields (
4654         ProxyClientDBRecPtr     pDbRec,
4655         char                    * databaseName,
4656         int                     clientNum)
4657 {
4658         char                    * message;
4659
4660         if (!pDbRec->command) {
4661
4662                 message = strdup ((char *) GETMESSAGE (40, 11,
4663                         "The required resource '%s' is missing for client '%d'\nin the file '%s'."));
4664
4665                 if (!message) 
4666                         return (False);
4667
4668                 DtMsgLogMessage (smGD.programName, DtMsgLogError, message,
4669                                 SmProgram, clientNum, databaseName);
4670
4671                 free (message);
4672
4673                 return (False);
4674         }
4675
4676         return (True);
4677 }
4678
4679
4680 static void
4681 LogXSMPOpenDatabaseFailure (
4682         char                    * databaseName,
4683         DtMsgLogType            msgType,
4684         int                     errorNum)
4685 {
4686         char                    * message = NULL;
4687         char                    * data;
4688         int                     msgNum;
4689
4690         switch (errorNum) {
4691                 case 1: data = databaseName;
4692                         msgNum = 8;
4693                         message = strdup ((char *) GETMESSAGE (40, msgNum,
4694                                 "The following session database could not be opened:\n\n   '%s'"));
4695                         break;
4696
4697                 case 2: data = versionStr;
4698                         msgNum = 9;
4699                         message = strdup ((char *) GETMESSAGE (40, msgNum,
4700                                 "The following session database does not contain\nthe required resource '%s':\n\n   %s"));
4701                         break;
4702
4703                 case 3: data = dtsessionIDStr;
4704                         msgNum = 9;
4705                         message = strdup ((char *) GETMESSAGE (40, msgNum,
4706                                 "The following session database does not contain\nthe required resource '%s':\n\n   %s"));
4707                         break;
4708         }
4709
4710         if (!message) 
4711                 return;
4712
4713         if (errorNum == 1)
4714                 DtMsgLogMessage (smGD.programName, msgType, message, data);
4715         else
4716                 DtMsgLogMessage (smGD.programName, msgType, message, 
4717                                 data, databaseName);
4718
4719         free (message); 
4720 }
4721
4722
4723 static void
4724 LogMissingPropertyMessage (
4725         XSMPClientDBRecPtr      pDbRec,
4726         char                    * propName,
4727         char                    * databaseName,
4728         DtMsgLogType            msgType)
4729 {
4730         char                    * message;
4731
4732         message = strdup ((char *) GETMESSAGE (40, 10,
4733                         "The required property '%s' is missing for client\n\n   %s\n\nin the file '%s'."));
4734
4735         if (!message) 
4736                 return;
4737
4738         DtMsgLogMessage (smGD.programName, msgType, message,
4739                         propName, pDbRec->clientId, databaseName);
4740
4741         free (message);
4742 }
4743
4744
4745 static void
4746 LogCWDMessage (
4747         char                    * badDir,
4748         char                    * appName,
4749         char                    * goodDir)
4750 {
4751         char                    * message;
4752
4753         message = strdup ((char *) GETMESSAGE (40, 12,
4754                         "The directory '%s'\nis not available for application '%s'.\n\nThe following directory will be used:\n\n   %s"));
4755
4756         if (!message) 
4757                 return;
4758
4759         DtMsgLogMessage (smGD.programName, DtMsgLogWarning, message, 
4760                         badDir, appName, goodDir);
4761
4762         free (message);
4763 }
4764
4765
4766 static 
4767 char ** RemoveEnvironmentVars (
4768         char                    **envp)
4769 {
4770
4771         char                    ** retEnv = NULL;
4772         char                    **ppchar, **ppchar2;
4773         int                     count;
4774         Boolean         found;
4775
4776         if (!envp)
4777                 return (NULL);
4778
4779         for (count = 0, ppchar = envp; ppchar && *ppchar; count++, ppchar++) ;
4780
4781         retEnv = (char **) XtMalloc ((count + 1) * sizeof (char *));
4782         if (!retEnv)
4783                 return (NULL);
4784
4785         if (!ignoreEnvPtr) {
4786                 for (count = 0, ppchar = envp; ppchar && *ppchar; 
4787                         count++, ppchar++) {
4788                         retEnv[count] = *ppchar;
4789                 }
4790                 retEnv[count] = NULL;
4791
4792                 return (retEnv);
4793         }
4794
4795         for (count = 0, ppchar = envp; ppchar && *ppchar; ppchar++) {
4796
4797                 found = False;
4798
4799                 for (ppchar2 = ignoreEnvPtr; ppchar2 && *ppchar2; ppchar2++) {
4800
4801                         if ((!strncmp (*ppchar, *ppchar2, strlen (*ppchar2))) &&
4802                             (((*ppchar)[strlen(*ppchar2)]) == '=')) {
4803                                 found = True;
4804                                 break;
4805                         }
4806                 }
4807                 if (!found) {
4808                         retEnv[count] = *ppchar;
4809                         count++;
4810                 }
4811         }
4812         retEnv[count] = NULL;
4813
4814         return (retEnv);
4815 }
4816
4817 /*
4818  * MarkFileDescriptors - mark file descriptiors start_fd through open_max
4819  *    with the given "cmd" and "data".
4820  *
4821  * The code for calculating open_max was taken from DtSvc/DtUtil1/CmdMain.c
4822  */
4823 static void 
4824 MarkFileDescriptors (
4825         int                     start_fd,
4826         int                     cmd,
4827         int                     data)
4828 {
4829         int                     i;
4830         long                    open_max;
4831
4832         open_max = sysconf(_SC_OPEN_MAX);
4833
4834         if (open_max == -1) {
4835 #ifdef _SUN_OS
4836                 open_max = NOFILE;
4837 #else
4838 #if defined(USL) || defined(__uxp__) || defined(_AIX)
4839                 open_max = FOPEN_MAX;
4840 #else
4841                 open_max = FD_SETSIZE;
4842 #endif
4843 #endif /* _SUN_OS */
4844         }
4845
4846         for (i = start_fd; i < open_max; i++)
4847                 (void) fcntl (i, cmd, data);
4848 }