Fix dttypes for BSD systems
[oweals/cde.git] / cde / programs / dtsession / SmSave.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: SmSave.c /main/27 1998/07/23 18:07:58 mgreess $ */
24 /*************************************<+>*************************************
25  *****************************************************************************
26  **
27  **  File:        SmSave.c
28  **
29  **  Project:     HP DT Session Manager (dtsession)
30  **
31  **  Description:
32  **  -----------
33  **  This file contains all routines that save off the session at any point
34  **  in time.  The session includes settings, resources, and clients.  How
35  **  the session manager behaves during a save depends on how the user has
36  **  configured it to behave.
37  **
38  **
39  *****************************************************************************
40  *************************************<+>*************************************/
41 /*
42  * (c) Copyright 1997 The Open Group
43  * (c) Copyright 1996 Digital Equipment Corporation.
44  * (c) Copyright 1990, 1993, 1994, 1996 Hewlett-Packard Company.
45  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
46  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
47  * (c) Copyright 1993, 1994, 1996 Novell, Inc. 
48  * (c) Copyright 1996 FUJITSU LIMITED.
49  * (c) Copyright 1996 Hitachi.
50  */
51
52
53 #include <stdio.h>
54 #include <string.h>
55 #include <dirent.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/param.h>
59
60 #include <sys/socket.h>
61 #include <netinet/in.h>
62 #include <netdb.h>
63 #ifdef _SUN_OS
64 #include <arpa/inet.h>
65 #include <string.h>
66 #endif /* _SUN_OS */
67
68 #include <X11/Intrinsic.h>
69 #include <X11/Xutil.h>
70 #include <X11/Xatom.h>
71 #include <X11/StringDefs.h>
72 #include <X11/keysymdef.h>
73 #include <Dt/DtP.h>
74 #include <Dt/Connect.h>
75 #include <Dt/UserMsg.h>
76 #include <Dt/SessionM.h>
77 #include <Dt/MsgLog.h>
78 #include "Sm.h"
79 #include "SmSave.h"
80 #include "SmResource.h"
81 #include "SmError.h"
82 #include "SmGlobals.h"
83 #include "SmUI.h"
84 #include "SmWindow.h"
85 #include "SmProtocol.h"
86 #include "SmRestore.h"
87 #include "SmXSMP.h"
88 #include "SmDB.h"
89 #include "SmProperty.h"
90 #include "SmProp.h"
91 #include "Srv.h"
92 #include "SrvFile_io.h"
93
94 #ifdef   MULTIBYTE
95 #include <stdlib.h>
96 #include <limits.h>
97 #endif
98
99 #ifndef __osf__
100 #include <X11/Xlibint.h>
101 #endif /* __osf__ */
102
103 typedef struct _ProxyClientCache {
104         Window          window;
105         int             screen;
106 } ProxyClientCache, *ProxyClientCachePtr;
107
108 static ProxyClientCachePtr proxyList;
109 static int numProxyClients = 0;
110 static int numProxyAllocated = 0;
111 static int proxyCacheAllocIncrement = 10;
112
113 /*
114  * Local Function Declarations
115  */
116 static void CacheProxyClient (
117         Boolean                 firstClient, 
118         int                     screenNum, 
119         Window                  window);
120
121 static void PruneSessionDirectory ();
122
123 static Boolean WriteClientDatabase ();
124
125 static void OutputXSMPClients (
126         ClientDB                outputDB);
127
128 static void OutputProxyClients (
129         ClientDB                outputDB);
130
131 static Boolean CheckRequiredProperties (
132         ClientRecPtr            pClientRec);
133
134 static void PrintStartupInfo( 
135                         ClientDB outputDB,
136                         int screen,
137                         Window window);
138 static int QueryServerSettings( void ) ;
139 static int SaveCustomizeSettings( void ) ;
140 static int OutputResource( void ) ;
141 static void PrintPointerControl( 
142                         XrmDatabase *smBase) ;
143 static void PrintSessionInfo( 
144                         XrmDatabase *smBase) ;
145 static void PrintScreenSaver( 
146                         XrmDatabase *smBase) ;
147 static int PrintFontPaths( 
148                         XrmDatabase *smBase,
149                         char **fontPath,
150                         int numPaths) ;
151 static int PrintKeyboardControl( 
152                         XrmDatabase *smBase);
153 static int PrintPointerMapping( 
154                         XrmDatabase *smBase,
155                         char *buttonRet,
156                         int numButton) ;
157 static void PrintWorkHintString( 
158                         FILE *hintFile,
159                         char *hintString) ;
160 static void PrintCmdHintString( 
161                         FILE *hintFile,
162                         char *hintString) ;
163 static void PrintCmdString( 
164                         FILE *cmdFile,
165                         char *cmdString) ;
166 static void PrintRemoteCmdString( 
167                         FILE *cmdFile,
168                         char *cmdString) ;
169
170
171 /*
172  * Global variables that are exposed
173  */
174 SmScreenInfo            screenSaverVals;
175 SmAudioInfo             audioVals;
176 SmKeyboardInfo          keyboardVals;
177
178 /*
179  * Variables global to this module only
180  */
181
182 /*
183  * used as a buffer to write resources into
184  * before they are written out
185  */
186 static int      resSize = 10000;
187 static char     *resSpec;
188
189 /*
190  * Vars used to maintain state that is sent to the SaveState
191  * function.
192  */
193 static Boolean  saveHome;
194 int             saveMode;
195
196 \f
197
198
199 /*************************************<->*************************************
200  *
201  *  SetupSaveState
202  *
203  *  Description:
204  *  -----------
205  *  Do all of the preliminary work that must be done before the state
206  *  of a checkpoint can be saved.
207  *
208  *  Inputs:
209  *  ------
210  *  saveToHome:  This session is to be saved to the home session or current
211  *  mode = whether the session is to be reset or restarted
212  *
213  *************************************<->***********************************/
214 void
215 SetupSaveState(
216         Boolean         saveToHome,
217         int             mode)
218 {
219   unsigned char         *propData;
220
221   /*
222    * Cache saveToHome and mode - they will be needed after all of
223    * the XSMP clients are saved and the Proxy clients are saved.
224    */
225   saveHome = saveToHome;
226   saveMode = mode;
227
228   /*
229    * First set up the save paths so we know if we have to do anything here
230    */
231   if ((SetSavePath(saveToHome, mode)) == -1)
232       return;
233
234   /*
235    * Take care of the save mode property on the root window so that the
236    * clients will know how to save this file (if they save files)
237    */
238   if(saveToHome == False)
239   {
240       propData = (unsigned char *) SM_CURRENT_DIRECTORY;
241   }
242   else
243   {
244       propData = (unsigned char *) SM_HOME_DIRECTORY;
245   }
246
247   /*
248    * Change the save mode to give the subdirectory saved to
249    *
250    */
251   XChangeProperty(smGD.display, RootWindow(smGD.display, 0),
252                   XaSmSaveMode, XA_STRING, 8, PropModeReplace,
253                    propData, strlen((char *)propData));
254   XFlush(smGD.display);
255 }
256
257 /*************************************<->*************************************
258  *
259  *  SaveState
260  *
261  *  Description:
262  *  -----------
263  *  Tells the SM to notify the XSMP clients to save their state.
264  *  The function CompleteSave fill be invoked after the XSMP clients
265  *  have completed their save.
266  *
267  *  Inputs:
268  *  ------
269  *  saveToHome:  This session is to be saved to the home session or current
270  *  mode = whether the session is to be reset or restarted
271  *
272  *  Comments:
273  *  --------
274  *  As a result of this routine files will be saved in the users .dt directory
275  *  that will allow the session manager to restore the session at a later
276  *  time.
277  *
278  *  NOTE - this function is called as the result of the following
279  *      events:
280  *
281  *      1. User initiates a Save Home Session via the Style Manager
282  *      2. The Session Manager receives a SM_XSESSION_EXIT message
283  *      3. The Session Manager receives a SM_SAVE_SESSION message
284  * 
285  *************************************<->***********************************/
286 void
287 SaveState(
288         Boolean                 saveToHome,
289         int                     mode,
290         int                     saveType,
291         Bool                    shutdown,
292         int                     interactStyle,
293         Bool                    fast,
294         Bool                    global)
295 {
296   /*
297    * Notify XSMP clients of the save
298    */
299   SaveYourselfReqProc (NULL, NULL, saveType, shutdown, interactStyle, 
300                         fast, global);
301 }
302
303
304 /*************************************<->*************************************
305  *
306  *  CompleteSave 
307  *
308  *  Description:
309  *  -----------
310  *  Called after the XSMP clients have saved their state.  In charge of 
311  *  calling all routines that save session information for XSMP client
312  *  and Proxy clients as well as settings, resources, etc.
313  *
314  *  Outputs:
315  *  -------
316  *
317  *************************************<->***********************************/
318 int 
319 CompleteSave ( )
320 {
321
322   FILE                  *convertFP;
323   unsigned char         *propData;
324   char                  *tmpPath, tmpVersion[20];
325
326   Boolean               saveToHome = saveHome;
327   int                   mode = saveMode;
328
329   /*
330    * If this is a Home session and the user is logging out, return
331    * now - the XSMP clients have all responded to the save and the
332    * ICCC clients don't save their state when a Home session is
333    * exited.
334    */
335   if (smGD.sessionType == HOME_SESSION && 
336       smXSMP.saveState.shutdown == True && 
337       smSettings.startState == DtSM_HOME_STATE)
338       return (0);
339
340   /*
341    * Start a wait state - don't want anything to happen while
342    * ICCC clients are being saved
343    */
344   ShowWaitState(True);
345   
346   resSpec = (char *) SM_MALLOC(resSize * sizeof(char));
347   if (resSpec==NULL)
348   {
349       PrintErrnoError(DtError, smNLS.cantMallocErrorString);
350       return(-1);
351   }
352
353   if (!WriteClientDatabase ()) {
354       ShowWaitState(False);
355       SM_FREE(resSpec);
356       return (-1);
357   }
358
359   /*
360    * WARNING - THIS VARIABLE MUST BE SET BEFORE THE SETTING INFORMATION IS
361    * CALLED - SETTINGS MUST BE SAVED BEFORE RESOURCES BECAUSE SETTINGS
362    * GETS INFORMATION SAVED IN RESOURCES (smToSet.dClickBuf)
363    */
364   smToSet.dClickBuf[0] = 0;
365
366   /*
367    * Do the actual output of the X settings information.  Output will
368    * go to the resource database at this point and be written to the
369    * resource file with the rest of the resources (below).
370    */
371   if(smRes.querySettings == True)
372   {
373       QueryServerSettings();
374   }
375   else
376   {
377       SaveCustomizeSettings();
378   }
379
380   /*
381    * Do the output of resource information.
382    */
383   if(OutputResource())
384   {
385       ShowWaitState(False);
386       SM_FREE(resSpec);
387       return(-1);
388   }
389
390   XDeleteProperty(smGD.display, DefaultRootWindow(smGD.display), XaSmSaveMode);
391  
392   /* 
393    * Go save the default palette at this time
394    */
395   if(saveToHome == True)
396      SaveDefaultPalette(smGD.display, smGD.savePath, DtSM_HOME_STATE);
397   else
398      SaveDefaultPalette(smGD.display, smGD.savePath, mode);
399  
400   PruneSessionDirectory ();
401
402   ShowWaitState(False);
403
404   return(0);
405 }
406
407
408 /*************************************<->*************************************
409  *
410  *  PruneSessionDirectory -
411  *
412  *  Description: Removes the oldest session direcotry if the number
413  *      of directories exceeds the smRes.numSessionsBackedup.
414  *
415  *  Inputs: void
416  * 
417  *************************************<->***********************************/
418 static void
419 PruneSessionDirectory ()
420 {
421         DIR                     * dirp;
422         struct dirent           * dp;
423         int                     numDirs = 0;
424         struct                  stat buf;
425         time_t                  oldestTime;
426         char                    *clientDB;
427         char                    *dirPrefix;
428         char                    *oldDir;        /* the .old dir */
429         char                    *oldestDir;
430         char                    *saveDir;
431         char                    *tmpDir;
432
433         if ((dirp = opendir (smGD.savePath)) == NULL)
434                 return;
435
436         clientDB = (char*) XtMalloc((2*MAXPATHLEN) + 1);
437         oldestDir = (char*) XtMalloc(MAXPATHLEN + 1);
438         saveDir = (char*) XtMalloc(MAXPATHLEN + 1);
439         tmpDir = (char*) XtMalloc(MAXPATHLEN + 1);
440         
441         dirPrefix = XtMalloc (strlen (smGD.restoreSession) + 2);
442         sprintf (dirPrefix, "%s.", smGD.restoreSession);
443         if (strlen (dirPrefix) > 5) {
444                 dirPrefix[4] = '.';
445                 dirPrefix[5] = '\000';
446         }
447
448         oldDir = XtMalloc (strlen (smGD.restoreSession) + 
449                            strlen (SM_OLD_EXTENSION) + 2);
450         sprintf (oldDir, "%s.%s", smGD.restoreSession, SM_OLD_EXTENSION);
451
452         (void) time (&oldestTime);
453
454         while ((dp = readdir (dirp)) != NULL) {
455                 /*
456                  * Do some sanity checks to limit the number of * stat() 
457                  * calls.  Note that for backward compatibility with CDE 
458                  * 1.0 if a ".old" directory exists, keep it.
459                  */
460                 if ((!strcmp (dp->d_name, ".")) || 
461                     (!strcmp (dp->d_name, "..")) ||
462                     (!strcmp (dp->d_name, oldDir)) ||
463                     (strncmp  (dp->d_name, dirPrefix, strlen (dirPrefix))))
464                         continue;
465
466                 sprintf (tmpDir, "%s/%s", smGD.savePath, dp->d_name);
467
468                 if (((stat (tmpDir, &buf)) == 0) && S_ISDIR (buf.st_mode)) {
469                         if (buf.st_mtime < oldestTime) {
470                                 /*
471                                  * Keep track of the oldest dir in case
472                                  * it needs to be removed
473                                  */
474                                 oldestTime = buf.st_mtime;
475                                 strcpy (oldestDir, tmpDir);
476                         }
477                         numDirs++;
478                 }
479         }
480         closedir(dirp);
481
482         if (numDirs > smRes.numSessionsBackedup) {
483                 /*
484                  * Need to remove the oldest directory.  The general
485                  * process (using "home" as an example) is:
486                  *
487                  *   mv home home.tmp
488                  *   mv oldestDir home
489                  *   Execute the DiscardCommand props in the home directory
490                  *   rm -rf home
491                  *   mv home.tmp home
492                  *
493                  * The reason this is done is because when the 
494                  * DiscardCommand were saved, the directory at the time of
495                  * the save contained "home".  For example, a DiscardCommand
496                  * may look like:
497                  *
498                  *    rm -f /u/somebody/.dt/sessions/home/app.state
499                  *
500                  * yet because of the session archiving, the app.state
501                  * file may actually be in a directory like:
502                  *
503                  *    /u/somebody/.dt/sessions/home.<tempnam>
504                  */ 
505
506                 char            * tmpName;
507                 char            * tmp;
508
509                 tmpName = (char *) XtMalloc (strlen (smGD.restoreSession) + 2);
510                 sprintf (tmpName, "%s.", smGD.restoreSession);
511                 if (strlen (tmpName) > 5) {
512                         tmpName[4] = '.';
513                         tmpName[5] = '\000';
514                 }
515                 tmp = (char *) tempnam (smGD.savePath, tmpName);
516
517                 sprintf (saveDir, "%s/%s", smGD.savePath, smGD.restoreSession);
518
519                 MoveDirectory (saveDir, tmp, False);
520                 MoveDirectory (oldestDir, saveDir, False);
521
522                 sprintf (clientDB, "%s/%s/%s", smGD.savePath, 
523                                 smGD.restoreSession, SM_CLIENT_FILE2);
524
525                 ExecuteDiscardCommands (clientDB);
526
527                 MoveDirectory (tmp, saveDir, True);
528
529                 free (tmp);
530                 XtFree (tmpName);
531         }
532
533         /*
534          * If exiting and the current session is a Current session
535          * but smSettings.startState has been set to to a 
536          * Home session (this would be true if a user started a 
537          * Current session but used the Style Manager to set the session
538          * upon next login to be a Home session), then if a home
539          * directory exists, mv current to current.old
540          */
541
542         if (smXSMP.saveState.shutdown && smGD.sessionType == CURRENT_SESSION &&
543             smSettings.startState == DtSM_HOME_STATE) {
544
545                 sprintf (tmpDir, "%s/%s", smGD.savePath, SM_HOME_DIRECTORY);
546
547                 if (((stat (tmpDir, &buf)) == 0) && S_ISDIR (buf.st_mode)) {
548
549                         sprintf (saveDir, "%s/%s", smGD.savePath, oldDir);
550
551                         if (((stat (saveDir, &buf)) == 0) && 
552                                         S_ISDIR (buf.st_mode)) {
553
554                                 sprintf (clientDB, "rm -rf %s", saveDir);
555                                 SystemCmd (clientDB);
556
557                                 sprintf (oldestDir, "%s/%s", smGD.savePath, 
558                                         SM_CURRENT_DIRECTORY);
559
560                                 MoveDirectory (oldestDir, saveDir, False);
561                         }
562                 }
563         }
564
565         XtFree(clientDB);
566         XtFree(dirPrefix);
567         XtFree(oldDir);
568         XtFree(oldestDir);
569         XtFree(saveDir);
570         XtFree(tmpDir);
571 }
572
573
574 /*************************************<->*************************************
575  *
576  *  WriteClientDatabase -
577  *
578  *  Description: Writes the client database (for XSMP and Proxy clients)
579  *
580  *  Inputs: None
581  * 
582  *  Returns True if the database is wrtten OK; False otherwise
583  *
584  *************************************<->***********************************/
585 static Boolean
586 WriteClientDatabase ()
587 {
588         char                    *db;
589         ClientDB                outputDB;
590
591         db = (char*) XtMalloc(MAXPATHLEN + 1);
592         (void) sprintf (db, "%s/%s/%s", smGD.savePath, smGD.restoreSession,
593                         SM_CLIENT_FILE2);
594
595         if ((outputDB = OpenOutputClientDB (db, smXSMP.dbVersion,
596                                             smXSMP.dbSessionId)) == NULL) {
597                 char            * str;
598
599                 str = strdup ((char *) GETMESSAGE (40, 18,
600                         "The following database file cannot be opened for writing:\n\n   %s\n\nThe session will not be saved."));
601
602                 if (str) {
603                         DtMsgLogMessage (smGD.programName, DtMsgLogError,
604                                          str, db);
605                         free (str);
606                 }
607                         
608                 XtFree(db);
609                 return (False);
610         }
611         XtFree(db);
612
613         OutputProxyClients (outputDB);
614         
615         OutputXSMPClients (outputDB);
616
617         CloseClientDB (outputDB, True);
618
619         return (True);
620 }
621
622
623 /*************************************<->*************************************
624  *
625  *  OutputProxyClients -
626  *
627  *  Description: Outputs the Proxy clients
628  *
629  *  Inputs: database pointer
630  * 
631  *  Returns: void
632  *
633  *************************************<->***********************************/
634 static void
635 OutputProxyClients (
636         ClientDB                outputDB)
637 {
638         int             i;
639         for (i = 0; i < numProxyClients; i++)
640                 PrintStartupInfo (outputDB, 
641                                   proxyList[i].screen, 
642                                   proxyList[i].window);
643 }
644
645
646 /*************************************<->*************************************
647  *
648  *  OutputXSMPClients -
649  *
650  *  Description: Outputs the XSMP clients
651  *
652  *  Inputs: database pointer
653  * 
654  *  Returns: void
655  *
656  *************************************<->***********************************/
657 static void
658 OutputXSMPClients (
659         ClientDB                outputDB)
660 {
661         XSMPClientDBRec         dbRec;
662         ClientRecPtr            pClientRec;
663
664         for (pClientRec = connectedList; pClientRec != NULL;
665                 pClientRec = pClientRec->next) {
666
667                 dbRec.restartHint = pClientRec->restartHint;
668                 (void) GetCardPropertyValue (pClientRec, SmRestartStyleHint, 
669                                              &dbRec.restartHint);
670
671                 if (dbRec.restartHint == SmRestartNever)
672                         continue;
673
674                 if (!pClientRec->active)
675                         continue;
676
677                 if (!CheckRequiredProperties (pClientRec))
678                         continue;
679
680                 dbRec.screenNum = 0;
681
682                 dbRec.clientId = pClientRec->clientId;
683                 dbRec.clientHost = pClientRec->clientHost;
684
685                 dbRec.program = GetArrayPropertyValue (pClientRec, 
686                                         SmProgram);
687                 dbRec.cwd = GetArrayPropertyValue (pClientRec, 
688                                         SmCurrentDirectory);
689
690                 dbRec.restartCommand = GetListOfArrayPropertyValue (pClientRec,
691                                         SmRestartCommand);
692                 dbRec.cloneCommand = GetListOfArrayPropertyValue (pClientRec,
693                                         SmCloneCommand);
694                 dbRec.discardCommand = GetListOfArrayPropertyValue (pClientRec,
695                                         SmDiscardCommand);
696                 dbRec.environment = GetListOfArrayPropertyValue (pClientRec,
697                                         SmEnvironment);
698
699                 if (!PutXSMPClientDBRec (outputDB, &dbRec)) {
700                         
701                         char            *str;
702
703                         str = strdup ((char *) GETMESSAGE (40, 19,
704                                 "Application '%s' cannot be saved."));
705
706                         if (str) {
707                                 DtMsgLogMessage (smGD.programName, 
708                                                  DtMsgLogError, str, 
709                                                  dbRec.program);
710                                 free (str);
711                         }
712                 }
713
714                 if (dbRec.restartCommand)
715                         XtFree ((char *) dbRec.restartCommand);
716                 if (dbRec.cloneCommand)
717                         XtFree ((char *) dbRec.cloneCommand);
718                 if (dbRec.discardCommand)
719                         XtFree ((char *) dbRec.discardCommand);
720                 if (dbRec.environment)
721                         XtFree ((char *) dbRec.environment);
722         }
723 }
724
725
726 /*************************************<->*************************************
727  *
728  *  CheckRequiredProperties -
729  *
730  *  Description: Check a client's required properties
731  *
732  *  Inputs: ClientRecPtr
733  * 
734  *  Returns: True if the client has all of the required properties;
735  *      otherwise returns False
736  *
737  *************************************<->***********************************/
738 static Boolean
739 CheckRequiredProperties (
740         ClientRecPtr            pClientRec)
741 {
742         PropertyRecPtr          pPropRec;
743         char                    * str;
744         char                    * program = NULL;
745
746         if ((program = GetArrayPropertyValue (pClientRec, SmProgram)) == NULL){
747
748                 str = strdup ((char *) GETMESSAGE (40, 23,
749                         "The following application did not set the required\nproperty '%s':\n\n   %s\n\nThis application will not be saved."));
750
751                 if (str) {
752                         DtMsgLogMessage (smGD.programName, DtMsgLogError, str, 
753                                          SmProgram, pClientRec->clientId);
754                         free (str);
755                 }
756                 return (False);
757         }
758
759         if ((pPropRec = GetPropertyRec (pClientRec, SmRestartCommand)) == NULL){
760
761                 str = strdup ((char *) GETMESSAGE (40, 24,
762                         "24 Application '%s' will not be saved because it did not set\nthe required property '%s'."));
763
764                 if (str) {
765                         DtMsgLogMessage (smGD.programName, DtMsgLogError,
766                                          str, program, SmRestartCommand);
767                         free (str);
768                 }
769                 return (False);
770         }
771
772         if ((pPropRec = GetPropertyRec (pClientRec, SmCloneCommand)) == NULL) {
773                 /*
774                  * This is a warning - still want to save the client
775                  */
776                 str = strdup ((char *) GETMESSAGE (40, 25,
777                         "Application '%s' did not set the required property '%s'."));
778
779                 if (str) {
780                         DtMsgLogMessage (smGD.programName, DtMsgLogWarning, str,
781                                          program, SmCloneCommand);
782                         free (str);
783                 }
784         }
785
786         return (True);
787 }
788
789
790 /*************************************<->*************************************
791  *
792  *  NotifyProxyClients -
793  *
794  *
795  *  Description:
796  *  -----------
797  *  Notify Proxy clients - calls routines to find top level windows, and 
798  *  notifies the Proxy clients about an impending save.
799  *
800  *  Inputs:
801  *  ------
802  *
803  *  Outputs:
804  *  -------
805  *
806  *************************************<->***********************************/
807 void 
808 NotifyProxyClients ( )
809 {
810   unsigned int          topListLength, containedListLength;
811   WindowInfo            * topList;      /* list of top-level windows */
812   WindowInfo            topLevelWindowInfo;
813   Atom                  actualType;
814   int                   actualFormat;
815   unsigned long         nitems;
816   unsigned long         leftover;
817   unsigned char         * data = NULL;
818   Boolean               containedClient;
819   int                   i, j;
820   int                   numClients = 0;
821
822   /*
823    * Save off the clients currently running.  This will be done
824    * one screen at a time
825    */
826   for(j = 0;j < smGD.numSavedScreens;j++)
827   {
828       /*
829        * Get a list of children of the root window. If there are none
830        * return with an error condition.
831        */
832       if(GetTopLevelWindows(j,&topList,&topListLength, &containedListLength))
833           return;
834   
835       /*
836        * Figure out how to restart the client associate with each window.
837        */
838       for (i=0 ; i<(topListLength + containedListLength); ++i)
839       {
840           topLevelWindowInfo=topList[i];
841
842           if(i >= topListLength)
843           {
844               containedClient = True;
845           }
846           else
847           {
848               containedClient = False;
849           }
850       
851           /*
852            * If this window is my window - skip it I don't want to
853            * save myself because I will be started automatically
854            */
855           if (XGetWindowProperty(smGD.display, topLevelWindowInfo.wid,
856                                  XA_WM_CLASS,0L,
857                                  (long)BUFSIZ,False,XA_STRING,&actualType,
858                                  &actualFormat,&nitems,&leftover,
859                                  &data)==Success)
860           {
861               if (actualType==XA_STRING &&
862                   !strcmp((char *) data, SM_RESOURCE_NAME))
863               {
864                   SM_FREE((char *)data);
865                   continue;
866               }
867               else
868               {
869                   SM_FREE((char *)data);
870               }
871           }
872       
873          /*
874           * If the client participates in the WM_SAVE_YOURSELF protocol, 
875           * send the appropriate messages and wait for the proper 
876           * responses.
877           */
878          (void) SaveYourself(topLevelWindowInfo);
879
880          CacheProxyClient ((numClients == 0), j, topLevelWindowInfo.wid);
881
882          numClients++;
883       }
884
885       /*
886        * Free space malloc'd by GetTopLevelWindowInfo
887        */
888       if(topListLength > 0)
889       {
890           SM_FREE((char *) topList);
891       }
892   }
893 }
894
895
896 /*************************************<->*************************************
897  *
898  *  CacheProxyClient -
899  *
900  *  Description:
901  *  -----------
902  *  Add a Proxy client to the proxy client cache.
903  *
904  *  Inputs:
905  *  ------
906  *  firstClient - if True, this is the first client in the cache
907  *  screenNum - the client's screen number
908  *  window - the client's window number
909  *
910  *  Outputs:
911  *  -------
912  *
913  *************************************<->***********************************/
914 static void CacheProxyClient (
915         Boolean                 firstClient, 
916         int                     screenNum, 
917         Window                  window)
918 {
919         if (firstClient)
920                 numProxyClients = 0;
921
922         if (numProxyClients >= numProxyAllocated) {
923                 numProxyAllocated += proxyCacheAllocIncrement;
924                 proxyList = (ProxyClientCachePtr) XtRealloc ((char *) proxyList,
925                         numProxyAllocated * sizeof (ProxyClientCache));
926         }
927
928         proxyList[numProxyClients].screen = screenNum;
929         proxyList[numProxyClients].window = window;
930
931         numProxyClients++;
932 }
933
934
935 \f
936 /*************************************<->*************************************
937  *
938  *  PrintStartupInfo -
939  *
940  *  Description:
941  *  -----------
942  *  Output startup information for one proxy client 
943  *
944  *  Inputs:
945  *  ------
946  *  outputDB = a pointer to the client database
947  *  screen = which screen the client is running on
948  *  window = the top level window of the lient
949  * 
950  *  Outputs:
951  *  -------
952  *
953  *  Comments:
954  *  --------
955  * 
956  *************************************<->***********************************/
957 static void
958 PrintStartupInfo(
959         ClientDB outputDB,
960         int screen,
961         Window window)
962 {
963   Boolean               writeStatus;
964   int                   wargc;
965   char                  ** wargv;
966   char                  *clientMachine;
967   XWindowAttributes     windowAttr;
968   Boolean               remoteHost;
969   Boolean               xsmpClient;
970   ProxyClientDBRec      dbRec;
971   char                  ** argv;
972   int                   i;
973   Status                status;
974
975 #ifdef _SUN_OS /* pull out quotes from OpenWindow tools commands */
976   char                  * ptr;
977 #endif
978
979   /*
980    * Get the attributes and properties on the window
981    */
982   if ((XGetWindowAttributes(smGD.display, window, &windowAttr)) == 0)
983     return;
984
985   if (GetStandardProperties(window, screen, &wargc, &wargv, 
986                             &clientMachine, &xsmpClient)==0)
987     return;
988   
989   /*
990    * If the client doesn't have a WM_COMMAND property, we can't restart it
991    */
992   if (!wargv||!wargv[0]) 
993     return;
994
995   /*
996    * If the client is an XSMP client, don't save it as a Proxy client.
997    */
998   if (xsmpClient)
999      return;
1000
1001 #ifdef _SUN_OS /* pull out quotes from OpenWindow tools commands */
1002   if (wargc == 1) {
1003      ptr = wargv[0];
1004      /* check for foreground */
1005      if ((ptr = strstr (ptr, "fg \"")) != NULL) {
1006         if (strlen (ptr) > 3)
1007            ptr[3] = ' ';
1008         if ((ptr = strchr (ptr, '"')) != NULL)
1009            ptr[0] = ' ';
1010      }
1011
1012      /* check for background */
1013      if ((ptr = strstr (wargv[0], "bg \"")) != NULL) {
1014         if (strlen (ptr) > 3)
1015            ptr[3] = ' ';
1016         if ((ptr = strchr (ptr, '"')) != NULL)
1017            ptr[0] = ' ';
1018      }
1019   }
1020 #endif
1021   
1022   /*
1023    * Find out if the client is running locally
1024    */
1025   dbRec.clientHost = NULL;
1026   if(clientMachine != NULL)
1027   {
1028       if(DtIsLocalHostP(clientMachine) == FALSE)
1029       {
1030           dbRec.clientHost = clientMachine;
1031       }
1032   }
1033
1034   /*
1035    * Must NULL-terminate the WM_COMMAND before writing it
1036    */
1037   argv = (char **) XtMalloc ((wargc + 1) * sizeof (char *));
1038   if (!argv)
1039       return;
1040
1041   for (i = 0; i < wargc; i++)
1042       argv[i] = wargv[i];
1043   argv[wargc] = NULL;
1044
1045   dbRec.command = argv;
1046   dbRec.screenNum = screen;
1047
1048   writeStatus = PutProxyClientDBRec (outputDB, &dbRec);
1049
1050   XtFree ((char *) argv);
1051
1052   if (writeStatus == False)
1053   {
1054     /*
1055      * There should be an error written here - however
1056      * since this means that there already is a write error to
1057      * the disk - no error can be written
1058      */
1059     (void) CloseClientDB (outputDB, True);
1060
1061     /*
1062      * On a write error - move the old session back to
1063      * be used and exit with an error condition
1064      */
1065     XFreeStringList(wargv);
1066
1067     strcat(smGD.savePath, "/");
1068     if(smGD.sessionType == HOME_SESSION)
1069     {
1070         strcat(smGD.savePath, SM_HOME_DIRECTORY);
1071     }
1072     else
1073     {
1074         strcat(smGD.savePath, SM_CURRENT_DIRECTORY);
1075     }
1076
1077     MoveDirectory(smGD.etcPath, smGD.savePath, False);
1078     SM_EXIT(-1);
1079   }
1080
1081   /*
1082    * Free up the argv property
1083    */
1084   XFreeStringList(wargv);
1085 }
1086
1087 \f
1088 /*************************************<->*************************************
1089  *
1090  *  QueryServerSettings ()
1091  *
1092  *
1093  *  Description:
1094  *  -----------
1095  *  Query the server for all it's current settings information, and then
1096  *  write that information to the session managers settings resource file.
1097  *
1098  *  Inputs:
1099  *  ------
1100  *  smGD.settingPath = (global) pointer to file where
1101  *                      setting info should be saved.
1102  * 
1103  *  Outputs:
1104  *  -------
1105  *
1106  *  Comments:
1107  *  --------
1108  *  This routine slows down the session manager's shutdown process
1109  *  considerably, and is therefore only called when the user specifies
1110  *  that all settings should be queried.  Otherwise, only settings set in
1111  *  the customizer should be saved.
1112  * 
1113  *************************************<->***********************************/
1114 static int 
1115 QueryServerSettings( void )
1116 {
1117     int                 i, numLoops;
1118     char                **fontPath;
1119     KeySym              *tmpSyms, tmpMod;
1120     XModifierKeymap     *modMap;
1121     char                *buttonRet;
1122     int                 numButton, numPaths;
1123     int                 buttonSize = 128;
1124     XrmDatabase         smBase = NULL;
1125     char                tmpChar[35];
1126
1127
1128     buttonRet = (char *) SM_MALLOC(buttonSize * sizeof(char));
1129     if (buttonRet==NULL)
1130     {
1131         PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1132         return(-1);
1133     }
1134
1135     /*
1136      * First set up all pointer control parameters
1137      * These are simple integer values that get saved
1138      * here, then read into a structure and set at restore
1139      * time
1140      */
1141     XGetPointerControl(smGD.display, &smSettings.accelNum,
1142                        &smSettings.accelDenom,
1143                        &smSettings.threshold);
1144     PrintPointerControl(&smBase);
1145
1146     /*
1147      * Get all the screen saver values.  These are all simple integer
1148      * values that are read back into a structure and set at restore
1149      * time.
1150      */
1151     XGetScreenSaver(smGD.display, &screenSaverVals.smTimeout,
1152                     &screenSaverVals.smInterval,
1153                     &screenSaverVals.smPreferBlank,
1154                     &screenSaverVals.smAllowExp);
1155     PrintScreenSaver(&smBase);
1156
1157     /*
1158      *  Write out all font path information. 
1159      *  Write out all the paths one by one concatenated by commas.
1160      */
1161     fontPath = XGetFontPath(smGD.display, &numPaths);
1162     if(fontPath != NULL)
1163     {
1164         if(PrintFontPaths(&smBase, fontPath, numPaths) != 0)
1165         {
1166             XFreeFontPath(fontPath);
1167             SM_FREE(buttonRet);
1168             return(-1);
1169         }
1170     }
1171
1172     /*
1173      * Write out all the keyboard control information.
1174      */
1175     XGetKeyboardControl(smGD.display, &smSettings.kbdState);
1176     if(PrintKeyboardControl(&smBase) != 0)
1177     {
1178         if (fontPath)
1179             XFreeFontPath(fontPath);
1180         return(-1);
1181     }
1182     
1183     /*
1184      * Put all the button modifier information into the resource database.
1185      * Find out the number of buttons and then write out the character
1186      * string for each button.
1187      */
1188     numButton = XGetPointerMapping(smGD.display, (unsigned char *)buttonRet, 128);
1189     if(numButton > 128)
1190     {
1191         buttonRet = (char *) SM_REALLOC(buttonRet, numButton * sizeof(char));
1192         if (buttonRet==NULL)
1193         {
1194             if (fontPath)
1195                 XFreeFontPath(fontPath);
1196             PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1197             return(-1);
1198         }
1199         numButton = XGetPointerMapping(smGD.display, (unsigned char *)buttonRet, numButton);
1200     }
1201     if(PrintPointerMapping(&smBase, buttonRet,
1202                            numButton)  != 0)
1203     {
1204         if (fontPath)
1205             XFreeFontPath(fontPath);
1206         SM_FREE(buttonRet);
1207         return(-1);
1208     }
1209
1210     /*
1211      * Put all keyboard mapping information in the resource database
1212      * Don't bother putting this in a separate print function because
1213      * the customizer doesn't do keymap savings this way.
1214      */
1215     smSettings.numKeyCode = smGD.display->max_keycode -
1216         smGD.display->min_keycode;
1217     tmpSyms = XGetKeyboardMapping(smGD.display,
1218                                   (KeyCode) smGD.display->min_keycode,
1219                                   smSettings.numKeyCode,
1220                                   &smSettings.keySymPerCode);
1221     if(tmpSyms == NULL)
1222     {
1223         if (fontPath)
1224             XFreeFontPath(fontPath);
1225         SM_FREE(buttonRet);
1226         PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1227         return(-1);
1228     }
1229     
1230     strcpy(resSpec, SM_RESOURCE_CLASS);
1231     strcat(resSpec, "*");
1232     strcat(resSpec, SmCnumKeyCode);
1233     strcat(resSpec, ":");
1234     sprintf(tmpChar,"%d", smSettings.numKeyCode);
1235     strcat(resSpec, tmpChar);
1236     XrmPutLineResource( &smBase, resSpec);
1237     
1238     strcpy(resSpec, SM_RESOURCE_CLASS);
1239     strcat(resSpec, "*");
1240     strcat(resSpec, SmCkeySymsPerKey);
1241     strcat(resSpec, ":");
1242     sprintf(tmpChar,"%d", smSettings.keySymPerCode);
1243     strcat(resSpec, tmpChar);
1244     XrmPutLineResource( &smBase, resSpec);
1245
1246     strcpy(resSpec, SM_RESOURCE_CLASS);
1247     strcat(resSpec, "*");
1248     strcat(resSpec, SmCkeySyms);
1249     strcat(resSpec, ":");
1250     numLoops = smSettings.numKeyCode * smSettings.keySymPerCode;
1251     sprintf(tmpChar,"%ld", tmpSyms[0]);
1252     strcat(resSpec, tmpChar);
1253     for(i = 1;i < numLoops;i++)
1254     {
1255         if((strlen(resSpec) + 5) >= resSize)
1256         {
1257             resSize += 5000;
1258             resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
1259             if (resSpec==NULL)
1260             {
1261                 SM_FREE((char *)tmpSyms);
1262                 if (fontPath)
1263                     SM_FREE((char *)fontPath);
1264                 SM_FREE(buttonRet);
1265                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1266                 return(-1);
1267             }
1268         }
1269         strcat(resSpec, ",");
1270         sprintf(tmpChar,"%ld", tmpSyms[i]);
1271         strcat(resSpec, tmpChar);
1272     }
1273     XrmPutLineResource( &smBase, resSpec);
1274         
1275
1276     /*
1277      * Write out all keyboard modifier info.  This will be a pretty slow
1278      * process considering that every keycode will have to be turned into
1279      * a keysym before writing.  Don't bother putting print stuff in a
1280      * separate function because it will not be handled in the customize
1281      * version.
1282      */
1283     modMap = XGetModifierMapping(smGD.display);
1284     if(modMap == NULL)
1285     {
1286         SM_FREE((char *)tmpSyms);
1287         if (fontPath)
1288             XFreeFontPath(fontPath);
1289         SM_FREE(buttonRet);
1290         PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1291         return(-1);
1292     }
1293
1294     strcpy(resSpec, SM_RESOURCE_CLASS);
1295     strcat(resSpec, "*");
1296     strcat(resSpec, SmCmaxKeyPerMod);
1297     strcat(resSpec, ":");
1298     sprintf(tmpChar,"%d", modMap->max_keypermod);
1299     strcat(resSpec, tmpChar);
1300     XrmPutLineResource( &smBase, resSpec);
1301
1302     strcpy(resSpec, SM_RESOURCE_CLASS);
1303     strcat(resSpec, "*");
1304     strcat(resSpec, SmCmodMap);
1305     strcat(resSpec, ":");
1306     numLoops = (8 * modMap->max_keypermod) - 1;
1307     for(i = 0;i <= numLoops;i++)
1308     {
1309         if((strlen(resSpec) + 9) >= resSize)
1310         {
1311             resSize += 5000;
1312             resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
1313             if (resSpec==NULL)
1314             {
1315                 SM_FREE((char *)tmpSyms);
1316                 XFreeModifiermap(modMap);
1317                 if (fontPath)
1318                     XFreeFontPath(fontPath);
1319                 SM_FREE(buttonRet);
1320                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1321                 return(-1);
1322             }
1323         }
1324         tmpMod = XKeycodeToKeysym(smGD.display, modMap->modifiermap[i], 0);
1325         sprintf(tmpChar,"%ld", tmpMod);
1326         strcat(resSpec, tmpChar);
1327         if(i != numLoops)
1328         {
1329             strcat(resSpec, ",");
1330         }
1331     }
1332     XrmPutLineResource( &smBase, resSpec);
1333     
1334
1335     /*
1336      * Print session manager settings
1337      */
1338     PrintSessionInfo(&smBase);
1339     
1340     /*
1341      * Write settings resources out to disk
1342      */
1343     XrmPutFileDatabase(smBase, smGD.settingPath);
1344
1345     /*
1346      * Free all allocated resources
1347      */
1348     if (fontPath)
1349         XFreeFontPath(fontPath);
1350     SM_FREE((char *)tmpSyms);
1351     XFreeModifiermap(modMap);
1352     SM_FREE(buttonRet);
1353     XrmDestroyDatabase(smBase);
1354     return(0);
1355 }
1356
1357 \f
1358 /*************************************<->*************************************
1359  *
1360  *  SaveCustomizeSettings ()
1361  *
1362  *
1363  *  Description:
1364  *  ------------
1365  *  Saves those settings that have been set in the customizer during the
1366  *  session to whatever values they were set to during the session.
1367  *
1368  *
1369  *  Inputs:
1370  *  ------
1371  *  smGD.resourcePath = (global) a pointer
1372  *                      to where the settings should be stored.
1373  *
1374  * 
1375  *  Outputs:
1376  *  -------
1377  *
1378  *
1379  *  Comments:
1380  *  --------
1381  *  This routine is the default saved for saving settings.  If the user
1382  *  wants all settings saved, they have to set a resource saying that that
1383  *  will be the case.
1384  * 
1385  *************************************<->***********************************/
1386 static int 
1387 SaveCustomizeSettings( void )
1388 {
1389     int                 i,numPaths;
1390     char                **fontPath;
1391     XrmDatabase         smBase = NULL;
1392     char                *tmpChar[20], *ptrRet = NULL, *tmpKey;
1393     Status              newStat;
1394         char            tmpMap[128];
1395
1396
1397     if(smCust.pointerChange)
1398     {
1399         newStat = _DtGetSmPointer(smGD.display, smGD.topLevelWindow,
1400                                  XaDtSmPointerInfo, &ptrRet);
1401         if(newStat != Success)
1402         {
1403             smToSet.pointerChange = False;
1404             smToSet.pointerMapChange = False;
1405         }
1406         else
1407         {
1408             sscanf(ptrRet, "%d %s %d %d %s",
1409                    &smToSet.numButton,
1410                    &tmpMap,
1411                    &smSettings.accelNum,
1412                    &smSettings.threshold,
1413                    &smToSet.dClickBuf);
1414             smSettings.accelDenom = 1;
1415
1416             tmpKey = strtok(tmpMap, "_");
1417             i = 0;
1418             while(tmpKey != NULL)
1419             {
1420                 smToSet.pointerMap[i] = (char) atoi(tmpKey);
1421                 i++;
1422                 tmpKey = strtok(NULL, "_");
1423             }
1424
1425
1426             /*
1427              * append a \n to dClickBuf because it was scanned out
1428              */
1429             strcat(smToSet.dClickBuf, "\n");
1430         }
1431         if (ptrRet) XFree(ptrRet);
1432     }
1433                                      
1434     if(smToSet.pointerChange == True)
1435     {
1436         PrintPointerControl(&smBase);
1437     }
1438
1439     if(smToSet.pointerMapChange == True)
1440     {
1441         if(PrintPointerMapping(&smBase, smToSet.pointerMap,
1442                             smToSet.numButton) != 0)
1443         {
1444             return(-1);
1445         }
1446     }
1447
1448     if(smToSet.screenSavChange == True)
1449     {
1450         PrintScreenSaver(&smBase);
1451     }
1452
1453     if(smCust.audioChange == True)
1454     {
1455       newStat = _DtGetSmAudio(smGD.display, smGD.topLevelWindow,
1456                                    XaDtSmAudioInfo, &audioVals);
1457      
1458       if(newStat == Success)
1459       {
1460         smSettings.kbdState.bell_percent = audioVals.smBellPercent;
1461         smSettings.kbdState.bell_pitch = audioVals.smBellPitch;
1462         smSettings.kbdState.bell_duration = audioVals.smBellDuration;
1463       }  
1464       else
1465       {
1466         smToSet.audioChange = False;
1467       }
1468     }
1469     
1470     if (smToSet.audioChange)
1471     {
1472       strcpy(resSpec, SM_RESOURCE_CLASS);
1473       strcat(resSpec, "*");
1474       strcat(resSpec, SmCbellPercent);
1475       strcat(resSpec, ":");
1476       sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_percent);
1477       strcat(resSpec, (char *)tmpChar);
1478       XrmPutLineResource(&smBase, resSpec);
1479
1480       strcpy(resSpec, SM_RESOURCE_CLASS);
1481       strcat(resSpec, "*");
1482       strcat(resSpec, SmCbellPitch);
1483       strcat(resSpec, ":");
1484       sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_pitch);
1485       strcat(resSpec, (char *)tmpChar);
1486       XrmPutLineResource(&smBase, resSpec);
1487
1488       strcpy(resSpec, SM_RESOURCE_CLASS);
1489       strcat(resSpec, "*");
1490       strcat(resSpec, SmCbellDuration);
1491       strcat(resSpec, ":");
1492       sprintf((char *)tmpChar,"%d",smSettings.kbdState.bell_duration);
1493       strcat(resSpec, (char *)tmpChar);
1494       XrmPutLineResource(&smBase, resSpec);
1495     }
1496
1497     if(smCust.keyboardChange == True)
1498     {
1499       newStat = _DtGetSmKeyboard(smGD.display, smGD.topLevelWindow,
1500                                       XaDtSmKeyboardInfo, &keyboardVals);
1501       if(newStat == Success)
1502       {
1503         smSettings.kbdState.key_click_percent = keyboardVals.smKeyClickPercent;
1504         smSettings.kbdState.global_auto_repeat = keyboardVals.smGlobalAutoRepeat;
1505       }
1506       else
1507       {
1508         smToSet.keyboardChange = False;
1509       }
1510     }
1511
1512     if(smToSet.keyboardChange == True)
1513     {
1514       strcpy(resSpec, SM_RESOURCE_CLASS);
1515       strcat(resSpec, "*");
1516       strcat(resSpec, SmCkeyClick);
1517       strcat(resSpec, ":");
1518       sprintf((char *)tmpChar,"%d", smSettings.kbdState.key_click_percent);
1519       strcat(resSpec, (char *)tmpChar);
1520       XrmPutLineResource(&smBase, resSpec);
1521
1522       strcpy(resSpec, SM_RESOURCE_CLASS);
1523       strcat(resSpec, "*");
1524       strcat(resSpec, SmCglobalRepeats);
1525       strcat(resSpec, ":");
1526       sprintf((char *)tmpChar,"%d", smSettings.kbdState.global_auto_repeat);
1527       strcat(resSpec, (char *)tmpChar);
1528       XrmPutLineResource(&smBase, resSpec);
1529     }
1530
1531
1532     /*
1533      *  Write out all font path information. 
1534      *  Write out all the paths one by one concatenated by commas.
1535      */
1536
1537     fontPath = XGetFontPath(smGD.display, &numPaths);
1538     if(fontPath != NULL) {
1539         if(PrintFontPaths(&smBase,  fontPath, numPaths) != 0) {
1540             XFreeFontPath(fontPath);
1541             return(-1);
1542         }
1543     }
1544
1545     /*
1546      * Save session manager settings
1547      */
1548     PrintSessionInfo(&smBase);
1549     
1550     if (fontPath)
1551         XFreeFontPath(fontPath);
1552
1553     /*
1554      * Write settings resources out to disk
1555      */
1556     XrmPutFileDatabase(smBase, smGD.settingPath);
1557     XrmDestroyDatabase(smBase);
1558
1559     return(0);
1560 }
1561
1562
1563 \f
1564 /*************************************<->*************************************
1565  *
1566  *  OutputResource ()
1567  *
1568  *
1569  *  Description:
1570  *  -----------
1571  *  Save session resources by getting the current RESOURCE_MANAGER property
1572  *  on the root window.
1573  *
1574  *  Inputs:
1575  *  ------
1576  *  smGD.resourcePath = (global) file name
1577  *                      where property contents should be saved.
1578  * 
1579  *  Outputs:
1580  *  -------
1581  *
1582  *
1583  *  Comments:
1584  *  --------
1585  *  This method is not a 100% accurate representation of currently active
1586  *  resources in the system.  It is however, the best representation (the
1587  *  values with the highest priority) without becoming overly invasive
1588  *  and slow.
1589  * 
1590  *************************************<->***********************************/
1591 static int 
1592 OutputResource( void )
1593 {
1594     Atom                actualType;
1595     int                 actualFormat;
1596     unsigned long       nitems, leftover; 
1597     char                *data = NULL;
1598     XrmDatabase         db;
1599     Status              newStat;
1600     char                *fontBuf = NULL, *langPtr, tmpChar[20], *sessionRes;
1601     float               fltYRes;
1602     int                 intYRes;
1603     char                *preeditBuf = NULL;
1604
1605     /*
1606      * Add anything to the Resource Manager property that needs to be added
1607      */
1608
1609     /*
1610      * Write out the LANG variable and the screen's Y resolution
1611      */
1612     *resSpec = 0;
1613     langPtr = getenv("LANG");
1614     if((langPtr != NULL) && (*langPtr != 0))
1615     {
1616         sprintf(resSpec, "%s*%s: %s\n", SM_RESOURCE_NAME, SmNsessionLang,
1617                 langPtr);
1618     }
1619     else
1620     {
1621         sprintf(resSpec, "%s*%s:   \n", SM_RESOURCE_NAME, SmNsessionLang);
1622     }
1623
1624     fltYRes = ((float) DisplayHeight(smGD.display, 0) /
1625         (float) DisplayHeightMM(smGD.display, 0)) * 1000;
1626     intYRes = fltYRes;
1627
1628     if(*resSpec == 0)
1629     {
1630         strcpy(resSpec, SM_RESOURCE_NAME);
1631     }
1632     else
1633     {
1634         strcat(resSpec, SM_RESOURCE_NAME);
1635     }
1636     strcat(resSpec, "*");
1637     strcat(resSpec, SmNdisplayResolution);
1638     strcat(resSpec, ":");
1639     sprintf(tmpChar, "%d",intYRes);
1640     strcat(resSpec, tmpChar);
1641     strcat(resSpec, "\n");
1642     _DtAddToResource(smGD.display, resSpec);
1643     
1644     if(smCust.fontChange == True)
1645     {
1646         newStat = _DtGetSmFont(smGD.display, smGD.topLevelWindow,
1647                               XaDtSmFontInfo, &fontBuf);
1648         if(newStat == Success)
1649         {
1650             /*
1651              * Create the auxillary resource file
1652              */
1653             if(SetFontSavePath(langPtr) != -1)
1654             {
1655                 db = XrmGetStringDatabase(fontBuf);
1656             
1657                 if(intYRes < MED_RES_Y_RES)
1658                 {
1659                     sessionRes = SM_LOW_RES_EXT;
1660                 }
1661                 else
1662                 {
1663                     if(intYRes >= HIGH_RES_Y_RES)
1664                     {
1665                         sessionRes = SM_HIGH_RES_EXT;
1666                     }
1667                     else
1668                     {
1669                         sessionRes = SM_MED_RES_EXT;
1670                     }
1671                 }
1672
1673                 strcat(smGD.fontPath, "/");
1674                 strcat(smGD.fontPath, SM_FONT_FILE);
1675                 
1676                 strcat(smGD.fontPath, ".");
1677                 strcat(smGD.fontPath, sessionRes);
1678                     
1679                 XrmPutFileDatabase(db, smGD.fontPath);    
1680                 XrmDestroyDatabase(db);
1681             }
1682             
1683             /*
1684              * Now add this to the resource manager property to be saved
1685              */
1686             _DtAddToResource(smGD.display, fontBuf);
1687         }
1688         if (fontBuf) XFree(fontBuf);
1689     }
1690
1691     if(smCust.preeditChange == True)
1692     {
1693         newStat = _DtGetSmPreedit(smGD.display, smGD.topLevelWindow,
1694                                   XaDtSmPreeditInfo, &preeditBuf);
1695         if(newStat == Success)
1696         {
1697             _DtAddToResource(smGD.display, preeditBuf);
1698         }
1699         if (preeditBuf) XFree(preeditBuf);
1700     }
1701
1702     if((smCust.dClickChange == True) && (smToSet.dClickBuf[0] != 0))
1703     {
1704         _DtAddToResource(smGD.display, (char *)smToSet.dClickBuf);
1705     }
1706
1707     /*
1708      * Get the contents of the _DT_SM_PREFERENCES property
1709      */
1710     data = _DtGetResString(smGD.display, _DT_ATR_PREFS);
1711
1712    /* 
1713     * Get _DT_SM_PREFERENCES database 'db'.
1714     */
1715     db  = XrmGetStringDatabase((char *)data);
1716
1717     XrmPutFileDatabase(db, smGD.resourcePath);
1718
1719     /*
1720      * Don't forget to free your data
1721      */
1722     SM_FREE((char *)data);
1723     XrmDestroyDatabase(db);
1724     
1725     return(0);
1726 }
1727
1728
1729 \f
1730 /*************************************<->*************************************
1731  *
1732  *  PrintPointerControl (smBase)
1733  *
1734  *
1735  *  Description:
1736  *  -----------
1737  *  A convenience function that is separated out instead of being included
1738  *  in both QueryServerSettings, and SaveCustomizeSettings.
1739  *  Saves pointer control information to the named resource file.
1740  *
1741  *  Inputs:
1742  *  ------
1743  *  smBase = pointer to newly opened resource db used to store setting info
1744  *  resSpec = a buffer to hold string resource information until it is
1745  *            printed.
1746  *  smSettings = place where settings are stored.
1747  * 
1748  *  Outputs:
1749  *  -------
1750  *
1751  *  Comments:
1752  *  --------
1753  * 
1754  *************************************<->***********************************/
1755 static void 
1756 PrintPointerControl(
1757         XrmDatabase *smBase)
1758 {
1759     char tmpChar[20];
1760     
1761     strcpy(resSpec, SM_RESOURCE_CLASS);
1762     strcat(resSpec, "*");
1763     strcat(resSpec, SmCaccelNum);
1764     strcat(resSpec, ":");
1765     sprintf(tmpChar, "%d", smSettings.accelNum);
1766     strcat(resSpec, tmpChar);
1767     XrmPutLineResource(smBase, resSpec);
1768     
1769     strcpy(resSpec, SM_RESOURCE_CLASS);
1770     strcat(resSpec, "*");
1771     strcat(resSpec, SmCaccelDenom);
1772     strcat(resSpec, ":");
1773     sprintf(tmpChar, "%d",smSettings.accelDenom);
1774     strcat(resSpec, tmpChar);
1775     XrmPutLineResource(smBase, resSpec);
1776     
1777     strcpy(resSpec, SM_RESOURCE_CLASS);
1778     strcat(resSpec, "*");
1779     strcat(resSpec, SmCthreshold);
1780     strcat(resSpec, ":");
1781     sprintf(tmpChar, "%d",smSettings.threshold);
1782     strcat(resSpec, tmpChar);
1783     XrmPutLineResource(smBase, resSpec);
1784
1785     return;
1786 }
1787
1788 \f
1789 /*************************************<->*************************************
1790  *
1791  *  PrintSessionInfo (smBase)
1792  *
1793  *
1794  *  Description:
1795  *  -----------
1796  *  A convenience function that is separated out instead of being included
1797  *  in both QueryServerSettings, and SaveCustomizeSettings.
1798  *  Saves session manager settings to the named resource file.
1799  *
1800  *  Inputs:
1801  *  ------
1802  *  smBase = pointer to newly opened resource db used to store setting info
1803  *  resSpec = a buffer to hold string resource information until it is
1804  *            printed.
1805  *  smSettings = place where settings are stored.
1806  * 
1807  *  Outputs:
1808  *  -------
1809  *
1810  *  Comments:
1811  *  --------
1812  * 
1813  *************************************<->***********************************/
1814 static void 
1815 PrintSessionInfo(
1816         XrmDatabase *smBase)
1817 {
1818     char tmpChar[20];
1819
1820     /*
1821      * Write out the settings for logout confirmation and
1822      * the correct session to return to
1823      */
1824     strcpy(resSpec, SM_RESOURCE_CLASS);
1825     strcat(resSpec, "*");
1826     strcat(resSpec, SmCshutDownState);
1827     strcat(resSpec, ":");
1828     sprintf(tmpChar, "%d",smSettings.confirmMode);
1829     strcat(resSpec, tmpChar);
1830     XrmPutLineResource(smBase, resSpec);
1831     
1832     strcpy(resSpec, SM_RESOURCE_CLASS);
1833     strcat(resSpec, "*");
1834     strcat(resSpec, SmCshutDownMode);
1835     strcat(resSpec, ":");
1836     sprintf(tmpChar, "%d",smSettings.startState);
1837     strcat(resSpec, tmpChar);
1838     XrmPutLineResource(smBase, resSpec);
1839
1840     return;
1841 }
1842
1843 \f
1844 /*************************************<->*************************************
1845  *
1846  *  PrintScreenSaver (smBase)
1847  *
1848  *
1849  *  Description:
1850  *  -----------
1851  *  A convenience function that is separated out instead of being included
1852  *  in both QueryServerSettings, and SaveCustomizeSettings.
1853  *  Saves screen saver information to the named resource file.
1854  *
1855  *  Inputs:
1856  *  ------
1857  *  smBase = pointer to newly opened resource db used to store setting info
1858  *  resSpec = a buffer to hold string resource information until it is
1859  *            printed.
1860  * 
1861  *  Outputs:
1862  *  -------
1863  *
1864  *  Comments:
1865  *  --------
1866  * 
1867  *************************************<->***********************************/
1868 static void 
1869 PrintScreenSaver(
1870         XrmDatabase *smBase)
1871 {
1872     Status              newScreenStat;
1873     char                tmpChar[20];
1874
1875     if(smCust.screenSavChange == True)
1876     {
1877         newScreenStat = _DtGetSmScreen(smGD.display, smGD.topLevelWindow,
1878                                       XaDtSmScreenInfo, &screenSaverVals);
1879         /*
1880          *  If the property has been deleted, it means that we return to
1881          *  the default
1882          */
1883         if(newScreenStat != Success)
1884         {
1885             return;
1886         }
1887     }
1888
1889     strcpy(resSpec, SM_RESOURCE_CLASS);
1890     strcat(resSpec, "*");
1891     strcat(resSpec, SmCtimeout);
1892     strcat(resSpec, ":");
1893     sprintf(tmpChar, "%d", screenSaverVals.smTimeout);
1894     strcat(resSpec, tmpChar);
1895     XrmPutLineResource(smBase, resSpec);
1896     
1897     strcpy(resSpec, SM_RESOURCE_CLASS);
1898     strcat(resSpec, "*");
1899     strcat(resSpec, SmCinterval);
1900     strcat(resSpec, ":");
1901     sprintf(tmpChar, "%d", screenSaverVals.smInterval);
1902     strcat(resSpec, tmpChar);
1903     XrmPutLineResource(smBase, resSpec);
1904     
1905     strcpy(resSpec, SM_RESOURCE_CLASS);
1906     strcat(resSpec, "*");
1907     strcat(resSpec, SmCpreferBlank);
1908     strcat(resSpec, ":");
1909     sprintf(tmpChar, "%d", screenSaverVals.smPreferBlank);
1910     strcat(resSpec, tmpChar);
1911     XrmPutLineResource(smBase, resSpec);
1912     
1913     strcpy(resSpec, SM_RESOURCE_CLASS);
1914     strcat(resSpec, "*");
1915     strcat(resSpec, SmCallowExp);
1916     strcat(resSpec, ":");
1917     sprintf(tmpChar, "%d", screenSaverVals.smAllowExp);
1918     strcat(resSpec, tmpChar);
1919     XrmPutLineResource(smBase, resSpec);
1920
1921     return;
1922 }
1923
1924 \f
1925 /*************************************<->*************************************
1926  *
1927  *  PrintFontPaths (smBase, fontPaths, numPaths)
1928  *
1929  *
1930  *  Description:
1931  *  -----------
1932  *  A convenience function that is separated out instead of being included
1933  *  in both QueryServerSettings, and SaveCustomizeSettings.
1934  *  Saves pointer control information to the named resource file.
1935  *
1936  *  Inputs:
1937  *  ------
1938  *  smBase = pointer to newly opened resource db used to store setting info
1939  *  resSpec = a buffer to hold string resource information until it is
1940  *            printed
1941  *  fontPaths = font paths to be saved
1942  *  numPaths = number of font paths to be saved
1943  * 
1944  *  Outputs:
1945  *  -------
1946  *  resSize = made bigger if current buffer is too small to hold all font info
1947  *
1948  *  Comments:
1949  *  --------
1950  * 
1951  *************************************<->***********************************/
1952 static int 
1953 PrintFontPaths(
1954         XrmDatabase *smBase,
1955         char **fontPath,
1956         int numPaths)
1957 {
1958     int i;
1959     
1960     /* If no fp save req'd, just pretend we did it */
1961     if (smRes.saveFontPath == False) return 0;
1962
1963     strcpy(resSpec, SM_RESOURCE_CLASS);
1964     strcat(resSpec, "*");
1965     strcat(resSpec, SmCfontPath);
1966     strcat(resSpec, ":");
1967     strcat(resSpec, *fontPath);
1968     for(i = 1;i < numPaths;i++)
1969     {
1970         if((strlen(resSpec) + strlen(fontPath[i]) + 1) >= resSize)
1971         {
1972             resSize += 5000;
1973             resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
1974             if (resSpec==NULL)
1975             {
1976                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
1977                 return(-1);
1978             }
1979         }
1980         strcat(resSpec, ",");
1981         strcat(resSpec, fontPath[i]);
1982     }
1983     XrmPutLineResource(smBase, resSpec);
1984
1985     return(0);
1986 }
1987
1988
1989 \f
1990 /*************************************<->*************************************
1991  *
1992  *  PrintKeyboardControl (smBase)
1993  *
1994  *
1995  *  Description:
1996  *  -----------
1997  *  A convenience function that is separated out instead of being included
1998  *  in both QueryServerSettings, and SaveCustomizeSettings.
1999  *  Saves pointer control information to the named resource file.
2000  *
2001  *  Inputs:
2002  *  ------
2003  *  smBase = pointer to newly opened resource db used to store setting info
2004  *  resSpec = a buffer to hold string resource information until it is
2005  *            printed
2006  *  resSize = size of current resource buffer
2007  * 
2008  *  Outputs:
2009  *  -------
2010  *  resSize = buffer is enlarged if more room is need to hold this info
2011  *
2012  *  Comments:
2013  *  --------
2014  * 
2015  *************************************<->***********************************/
2016 static int 
2017 PrintKeyboardControl(
2018         XrmDatabase *smBase)
2019 {
2020     int         i,j;
2021     char        bitTest;
2022     Bool        firstRepeat = True;
2023     char        tmpChar[20];
2024     
2025     strcpy(resSpec, SM_RESOURCE_CLASS);
2026     strcat(resSpec, "*");
2027     strcat(resSpec, SmCkeyClick);
2028     strcat(resSpec, ":");
2029     sprintf(tmpChar, "%d",smSettings.kbdState.key_click_percent);
2030     strcat(resSpec, tmpChar);
2031     XrmPutLineResource(smBase, resSpec);
2032
2033     strcpy(resSpec, SM_RESOURCE_CLASS);
2034     strcat(resSpec, "*");
2035     strcat(resSpec, SmCbellPercent);
2036     strcat(resSpec, ":");
2037     sprintf(tmpChar, "%d",smSettings.kbdState.bell_percent);
2038     strcat(resSpec, tmpChar);
2039     XrmPutLineResource(smBase, resSpec);
2040
2041     strcpy(resSpec, SM_RESOURCE_CLASS);
2042     strcat(resSpec, "*");
2043     strcat(resSpec, SmCbellPitch);
2044     strcat(resSpec, ":");
2045     sprintf(tmpChar, "%d",smSettings.kbdState.bell_pitch);
2046     strcat(resSpec, tmpChar);
2047     XrmPutLineResource(smBase, resSpec);
2048
2049     strcpy(resSpec, SM_RESOURCE_CLASS);
2050     strcat(resSpec, "*");
2051     strcat(resSpec, SmCbellDuration);
2052     strcat(resSpec, ":");
2053     sprintf(tmpChar, "%d",smSettings.kbdState.bell_duration);
2054     strcat(resSpec, tmpChar);
2055     XrmPutLineResource(smBase, resSpec);
2056     
2057     strcpy(resSpec, SM_RESOURCE_CLASS);
2058     strcat(resSpec, "*");
2059     strcat(resSpec, SmCledMask);
2060     strcat(resSpec, ":");
2061     sprintf(tmpChar, "%ld",smSettings.kbdState.led_mask);
2062     strcat(resSpec, tmpChar);
2063     XrmPutLineResource(smBase, resSpec);
2064
2065     strcpy(resSpec, SM_RESOURCE_CLASS);
2066     strcat(resSpec, "*");
2067     strcat(resSpec, SmCglobalRepeats);
2068     strcat(resSpec, ":");
2069     sprintf(tmpChar, "%d",smSettings.kbdState.global_auto_repeat);
2070     strcat(resSpec, tmpChar);
2071     XrmPutLineResource(smBase, resSpec);
2072
2073     strcpy(resSpec, SM_RESOURCE_CLASS);
2074     strcat(resSpec, "*");
2075     strcat(resSpec, SmCautoRepeats);
2076     strcat(resSpec, ":");
2077
2078     /*
2079      * Now write out which keys need to be auto repeated one at a time
2080      */
2081     if(smSettings.kbdState.global_auto_repeat != AutoRepeatModeOn)
2082     {
2083         for(i = 0;i < 32;i++)
2084         {
2085             bitTest = 0x01;
2086             for(j = 0;j < 8;j++)
2087             {
2088                 if((bitTest & smSettings.kbdState.auto_repeats[i]) != 0)
2089                 {
2090                     if(firstRepeat == True)
2091                     {
2092                         firstRepeat = False;
2093                     }
2094                     else
2095                     {
2096                         strcat(resSpec, ",");
2097                     }
2098                     
2099                     if((strlen(resSpec) + 5) >= resSize)
2100                     {
2101                         resSize += 5000;
2102                         resSpec = (char *) SM_REALLOC(resSpec,
2103                                                    resSize * sizeof(char));
2104                         if (resSpec==NULL)
2105                         {
2106                             PrintErrnoError(DtError,
2107                                             smNLS.cantMallocErrorString);
2108                             return(-1);
2109                         }
2110                     }
2111                         
2112                     sprintf(tmpChar, "%d", ((8 * i) + j));
2113                     strcat(resSpec, tmpChar);
2114                 }
2115                 bitTest <<= 1;
2116             }
2117         }
2118     }
2119     else
2120     {
2121         strcat(resSpec, "");
2122     }
2123     XrmPutLineResource(smBase, resSpec);
2124
2125     return(0);
2126 }
2127
2128
2129 \f
2130 /*************************************<->*************************************
2131  *
2132  *  PrintPointerMapping (smBase, buttonRet,  numButton)
2133  *
2134  *
2135  *  Description:
2136  *  -----------
2137  *  A convenience function that is separated out instead of being included
2138  *  in both QueryServerSettings, and SaveCustomizeSettings.
2139  *  Saves pointer mapping information to the named resource file.
2140  *
2141  *  Inputs:
2142  *  ------
2143  *  smBase = pointer to newly opened resource db used to store setting info
2144  *  resSpec = a buffer to hold string resource information until it is
2145  *            printed
2146  *  resSize = size of resource buffer
2147  *  buttonRet = button mapping to be saved
2148  *  numButton = number of buttons in button mapping
2149  * 
2150  *  Outputs:
2151  *  -------
2152  *  resSize = size of buffer is change if it needs to be enlarged during
2153  *            routine
2154  *
2155  *  Comments:
2156  *  --------
2157  * 
2158  *************************************<->***********************************/
2159 static int 
2160 PrintPointerMapping(
2161         XrmDatabase *smBase,
2162         char *buttonRet,
2163         int numButton )
2164 {
2165     int         i, numLoops;
2166     char        tmpChar[20];
2167     
2168     strcpy(resSpec, SM_RESOURCE_CLASS);
2169     strcat(resSpec, "*");
2170     strcat(resSpec, SmCbuttonMap);
2171     strcat(resSpec, ":");
2172
2173     numLoops = numButton - 1;
2174     for(i = 0;i <= numLoops;i++)
2175     {
2176         if((strlen(resSpec) + 5) >= resSize)
2177         {
2178             resSize += 5000;
2179             resSpec = (char *) SM_REALLOC(resSpec, resSize * sizeof(char));
2180             if (resSpec==NULL)
2181             {
2182                 PrintErrnoError(DtError, smNLS.cantMallocErrorString);
2183                 return(-1);
2184             }
2185         }
2186             
2187         sprintf(tmpChar, "%d",buttonRet[i]);
2188         strcat(resSpec, tmpChar);
2189         if(i != numLoops)
2190         {
2191             strcat(resSpec, ",");
2192         }
2193         XrmPutLineResource(smBase, resSpec);
2194     }
2195
2196     return(0);
2197 }