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