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