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