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