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