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