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