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