4fb1c7c45072a01b3e5ac055a30ea6d27f1de37c
[oweals/cde.git] / SmDB.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: SmDB.c /main/5 1998/07/23 18:11:31 mgreess $ */
24 /*
25  * (c) Copyright 1996 Digital Equipment Corporation.
26  * (c) Copyright 1996 Hewlett-Packard Company.
27  * (c) Copyright 1996 International Business Machines Corp.
28  * (c) Copyright 1996 Sun Microsystems, Inc.
29  * (c) Copyright 1996 Novell, Inc. 
30  * (c) Copyright 1996 FUJITSU LIMITED.
31  * (c) Copyright 1996 Hitachi.
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include "SmDB.h"
39
40 #define RESOURCE_BUF_SZ 1024
41 #define CLIENT_ID_SZ 20
42
43 typedef struct _ClientDBRec
44 {
45     XrmDatabase xrmDB;          /* Xrm resource database. */
46     Boolean openForInput;       /* True if input, False if output. */
47
48     char *xrmDBFileName;        /* Filename, for openForInput == False. */
49     char *tmpDBFileName;
50     FILE *xrmDBFile;
51
52     /* Below used if openForInput. */
53     char **XSMPClients;         /* malloc'd array of XSMP client IDs. */
54     int nXSMPClients;           /* number of XSMP clients. */
55     int nextXSMPClientIndex;    /* index of next XSMP client to Get;
56                                  * also used as sequence # for Put. */
57
58     char **proxyClients;        /* malloc'd array of Proxy client IDs. */
59     int nProxyClients;          /* number of Proxy clients. */
60     int nextProxyClientIndex;   /* index of next Proxy client to Get;
61                                  * also used as sequence # for Put. */
62 } ClientDBRec;
63
64 static Boolean xrmInitialized = False;
65 static XrmName XSMPName[2];
66 static XrmClass XSMPClass[2];
67 static XrmName proxyName[2];
68 static XrmClass proxyClass[2];
69 static XrmQuark anyQuark;
70 static char *resourceBuf = NULL;
71 static char *clientIDBuf = NULL;
72
73 /* Public strings */
74 char *versionStr = ".version";
75 char *dtsessionIDStr = ".dtsessionID";
76
77 /* Strings for XSMP clients. */
78 static char *clientStr = "!\nClient.%s";
79 static char *programStr = "%s.Program";
80 static char *cwdStr = "%s.Cwd";
81 static char *restartCmdStr = "%s.RestartCommand";
82 static char *cloneCmdStr = "%s.CloneCommand";
83 static char *discardCmdStr = "%s.DiscardCommand";
84 static char *environmentStr = "%s.Environment";
85 static char *restartHintStr = "%s.RestartHint";
86 static char *sessionIDStr = "%s.SessionID";
87
88 /* Strings for Proxy clients. */
89 static char *proxyStr = "!\nProxyClient.%s";
90 static char *commandStr = "%s.Command";
91
92 /* Common resources (XSMP and Proxy). */
93 static char *clientHostStr = "%s.ClientHost";
94 static char *screenNumStr = "%s.ScreenNum";
95
96 static void _initXrm(void);
97 static Bool _countProc(XrmDatabase *, XrmBindingList, XrmQuarkList,
98                        XrmRepresentation *, XrmValue *, XPointer);
99 static Bool _fillClientIDProc(XrmDatabase *, XrmBindingList, XrmQuarkList,
100                               XrmRepresentation *, XrmValue *, XPointer);
101 static Bool _fillStringArrayProc(XrmDatabase *, XrmBindingList, XrmQuarkList,
102                                  XrmRepresentation *, XrmValue *, XPointer);
103 static Boolean _getStringResource(XrmDatabase, char *,
104                                   char *, char **, char *);
105 static Boolean _getIntResource(XrmDatabase, char *, char *, int *, int);
106 static Boolean _getStringArrayResource(XrmDatabase, char *, char *,
107                                        char ***, char **);
108 static void _freeStringArray(char **);
109 static Boolean _putStringResource(ClientDBRec *, char *, char *, char *);
110 static Boolean _putIntResource(ClientDBRec *, char *, char *, int);
111 static Boolean _putStringArrayResource(ClientDBRec *, char *, char *, char **);
112 static char *_tmpFileName(char *);
113
114 static void
115 _initXrm(void)
116 {
117     if (!xrmInitialized)
118     {
119         XrmInitialize(); /* Just in case. */
120
121         anyQuark = XrmStringToQuark("?");
122         XSMPName[0] = proxyName[0] = anyQuark;
123         XSMPClass[0] = XrmStringToClass("Client");
124         proxyClass[0] = XrmStringToClass("ProxyClient");
125         XSMPName[1] = XSMPClass[1] =
126             proxyName[1] = proxyClass[1] = NULLQUARK;
127         xrmInitialized = True;
128     }
129 }
130
131 static Bool
132 _countProc(XrmDatabase *clientDB, XrmBindingList bindingList,
133            XrmQuarkList quarkList, XrmRepresentation *reps,
134            XrmValue *value, XPointer uData)
135 {
136     int *countP = (int *)uData;
137
138     (*countP)++;
139
140     return FALSE;
141 }
142
143 static Bool
144 _fillClientIDProc(XrmDatabase *clientDB, XrmBindingList bindingList,
145                   XrmQuarkList quarkList, XrmRepresentation *reps,
146                   XrmValue *value, XPointer uData)
147 {
148     char ***idListPtr = (char ***)uData;
149     char **clientIDPtr = *idListPtr;
150
151     *clientIDPtr = (char *)value->addr;
152     (*idListPtr)++;
153
154     return FALSE;
155 }
156
157 static Bool
158 _fillStringArrayProc(XrmDatabase *clientDB, XrmBindingList bindingList,
159                      XrmQuarkList quarkList, XrmRepresentation *reps,
160                      XrmValue *value, XPointer uData)
161 {
162     char **stringsPtr = (char **)uData;
163     char *indexStr;
164
165     /* Our index into this string array is at quarkList[2]. */
166     if ((indexStr = XrmQuarkToString(quarkList[2])) == (char *)NULL)
167         return True;
168
169     if ((stringsPtr[atoi(indexStr)] = XtNewString((char *)value->addr))
170         == (char *)NULL)
171         return True;
172
173     return FALSE;
174 }
175
176 static Boolean
177 _getStringResource(XrmDatabase xrmDB, char *fmtStr,
178                    char *clientID, char **resourcePtr, char *defaultVal)
179 {
180     char *resourceType;
181     XrmValue resourceValue;
182
183     if (NULL == resourceBuf) resourceBuf = XtMalloc(RESOURCE_BUF_SZ);
184     sprintf(resourceBuf, fmtStr, clientID);
185     if (XrmGetResource(xrmDB, resourceBuf, resourceBuf,
186                        &resourceType, &resourceValue))
187     {
188         if ((*resourcePtr = XtNewString(resourceValue.addr)) == (char *)NULL)
189             return False;
190
191         return True;
192     }
193
194     *resourcePtr = defaultVal;
195     return True;
196 }
197
198 static Boolean
199 _getIntResource(XrmDatabase xrmDB, char *fmtStr,
200                 char *clientID, int *resourcePtr, int defaultVal)
201 {
202     char *resourceType;
203     XrmValue resourceValue;
204
205     if (NULL == resourceBuf) resourceBuf = XtMalloc(RESOURCE_BUF_SZ);
206     sprintf(resourceBuf, fmtStr, clientID);
207     *resourcePtr = (XrmGetResource(xrmDB, resourceBuf, resourceBuf,
208                                    &resourceType, &resourceValue)) ?
209                         atoi(resourceValue.addr) : defaultVal;
210
211     return True;
212 }
213
214 static Boolean
215 _getStringArrayResource(XrmDatabase xrmDB, char *fmtStr,
216                         char *clientID, char ***resourcePtr,
217                         char **defaultVal)
218 {
219     XrmQuark resourceName[3];
220     XrmQuark resourceClass[3];
221     char *resourceType;
222     XrmValue resourceValue;
223     int nStrings;
224
225     resourceName[0] = resourceName[1] = anyQuark;
226     resourceName[2] = NULLQUARK;
227
228     if (NULL == resourceBuf) resourceBuf = XtMalloc(RESOURCE_BUF_SZ);
229     sprintf(resourceBuf, fmtStr, clientID);
230     XrmStringToQuarkList(resourceBuf, resourceClass);
231
232     nStrings = 0;
233     XrmEnumerateDatabase(xrmDB, resourceName, resourceClass,
234                          XrmEnumOneLevel, _countProc,
235                          (XPointer)&nStrings);
236
237     if (nStrings > 0)
238     {
239         char **stringsPtr;
240         int i;
241
242         if ((stringsPtr = (char **)XtMalloc((nStrings + 1) * sizeof(char *)))
243             == (char **)NULL)
244             return False;
245
246         /* Initialize array entries to NULL so free can work. */
247         /* NOTE: Final entry (nStrings) will remain NULL. */
248         for (i = 0; i <= nStrings; i++)
249             stringsPtr[i] = (char *)NULL;
250
251         if (XrmEnumerateDatabase(xrmDB,
252                                  resourceName, resourceClass,
253                                  XrmEnumOneLevel, _fillStringArrayProc,
254                                  (XPointer)stringsPtr))
255         {
256             for (i = 0; i < nStrings; i++)
257                 XtFree(stringsPtr[i]);
258             XtFree((char *)stringsPtr);
259             return False;
260         }
261
262         *resourcePtr = stringsPtr;
263         return True;
264     }
265
266     *resourcePtr = defaultVal;
267     return True;
268 }
269
270 static void
271 _freeStringArray(char **stringsPtr)
272 {
273     if (stringsPtr)
274     {
275         int i;
276
277         for (i = 0; stringsPtr[i] != (char *)NULL; i++)
278             XtFree(stringsPtr[i]);
279
280         XtFree((char *)stringsPtr);
281     }
282 }
283
284 static Boolean
285 _putStringResource(ClientDBRec *clientDB, char *fmtStr, char *clientID,
286                    char *resourceVal)
287 {
288     if (resourceVal != (char *)NULL)
289     {
290         if (NULL == clientIDBuf) clientIDBuf = XtMalloc(RESOURCE_BUF_SZ);
291         sprintf(clientIDBuf, fmtStr, clientID);
292         if (fprintf(clientDB->xrmDBFile, "%s: %s\n", clientIDBuf, resourceVal)
293             < 0)
294             return False;
295     }
296
297     return True;
298 }
299
300 static Boolean
301 _putIntResource(ClientDBRec *clientDB, char *fmtStr, char *clientID,
302                 int resourceVal)
303 {
304     if (NULL == clientIDBuf) clientIDBuf = XtMalloc(RESOURCE_BUF_SZ);
305     sprintf(clientIDBuf, fmtStr, clientID);
306     if (fprintf(clientDB->xrmDBFile, "%s: %d\n", clientIDBuf, resourceVal)
307         < 0)
308         return False;
309
310     return True;
311 }
312
313 static Boolean
314 _putStringArrayResource(ClientDBRec *clientDB, char *fmtStr, char *clientID,
315                         char **resourceVal)
316 {
317     int i;
318
319     if (resourceVal != (char **)NULL)
320     {
321         for (i = 0; resourceVal[i] != (char *)NULL; i++)
322         {
323             if (NULL == clientIDBuf) clientIDBuf = XtMalloc(RESOURCE_BUF_SZ);
324             sprintf(clientIDBuf, fmtStr, clientID);
325             if (fprintf(clientDB->xrmDBFile, "%s.%d: %s\n",
326                         clientIDBuf, i, resourceVal[i]) < 0)
327                 return False;
328         }
329     }
330
331     return True;
332 }
333
334 static char *
335 _tmpFileName(char *fileName)
336 {
337     int fileNameLen = strlen(fileName);
338     char *newFileName =
339         (char *)XtMalloc((fileNameLen + 20) * sizeof(char));
340
341     if (newFileName != (char *)NULL)
342     {
343         int i;
344         char *ptr = &(newFileName[fileNameLen]);
345
346         strcpy(newFileName, fileName);
347
348         /* Hm.  I suppose if a couple billion versions of this file exist */
349         /* we could loop forever, but that's not likely. */
350         for (i = 0; ; i++)
351         {
352             sprintf(ptr, "%d", i);
353             if (access(newFileName, F_OK) != 0)
354                 break;
355         }
356     }
357
358     return newFileName;
359 }
360
361 ClientDB
362 OpenInputClientDB(char *fileName,
363                   char **version,
364                   char **dtsessionID)
365 {
366     ClientDBRec *inputDB;
367     char **tmpPtr;
368     char *resourceType;
369     XrmValue resourceValue;
370
371     *version = (char *)NULL;
372     *dtsessionID = (char *)NULL;
373
374     _initXrm();
375
376     if ((fileName == (char *)NULL) ||
377         ((inputDB = (ClientDBRec *)XtMalloc(sizeof(ClientDBRec)))
378          == (ClientDBRec *)NULL))
379         return (ClientDB)NULL;
380
381     if ((inputDB->xrmDB = XrmGetFileDatabase(fileName))
382         == (XrmDatabase)NULL)
383     {
384         XtFree((char *)inputDB);
385         return (ClientDB)NULL;
386     }
387
388     inputDB->openForInput = True;
389     inputDB->XSMPClients = inputDB->proxyClients = (char **)NULL;
390     inputDB->nXSMPClients = inputDB->nProxyClients = 0;
391     inputDB->nextXSMPClientIndex = inputDB->nextProxyClientIndex = 0;
392
393     /* Count the number of XSMP and Proxy clients. */
394     XrmEnumerateDatabase(inputDB->xrmDB, XSMPName, XSMPClass,
395                          XrmEnumOneLevel, _countProc,
396                          (XPointer)&inputDB->nXSMPClients);
397     XrmEnumerateDatabase(inputDB->xrmDB, proxyName, proxyClass,
398                          XrmEnumOneLevel, _countProc,
399                          (XPointer)&inputDB->nProxyClients);
400
401     /* Allocate space for the client IDs and fill from database. */
402     if (inputDB->nXSMPClients > 0)
403     {
404         if ((inputDB->XSMPClients =
405              (char **)XtMalloc(inputDB->nXSMPClients * sizeof(char *)))
406             == (char **)NULL)
407         {
408             XrmDestroyDatabase(inputDB->xrmDB);
409             XtFree((char *)inputDB);
410             return (ClientDB)NULL;
411         }
412
413         tmpPtr = inputDB->XSMPClients;
414         XrmEnumerateDatabase(inputDB->xrmDB, XSMPName, XSMPClass,
415                              XrmEnumOneLevel, _fillClientIDProc,
416                              (XPointer)&tmpPtr);
417     }
418     if (inputDB->nProxyClients > 0)
419     {
420         if ((inputDB->proxyClients =
421              (char **)XtMalloc(inputDB->nProxyClients * sizeof(char *)))
422             == (char **)NULL)
423         {
424             XrmDestroyDatabase(inputDB->xrmDB);
425             XtFree((char *)inputDB->XSMPClients);
426             XtFree((char *)inputDB);
427             return (ClientDB)NULL;
428         }
429
430         tmpPtr = inputDB->proxyClients;
431         XrmEnumerateDatabase(inputDB->xrmDB, proxyName, proxyClass,
432                              XrmEnumOneLevel, _fillClientIDProc,
433                              (XPointer)&tmpPtr);
434     }
435
436     if ((!XrmGetResource(inputDB->xrmDB, versionStr, versionStr,
437                          &resourceType, &resourceValue)) ||
438         ((*version = XtNewString(resourceValue.addr)) == (char *)NULL) ||
439         (!XrmGetResource(inputDB->xrmDB, dtsessionIDStr, dtsessionIDStr,
440                          &resourceType, &resourceValue)) ||
441         ((*dtsessionID = XtNewString(resourceValue.addr)) == (char *)NULL))
442     {
443         if (*version)
444         {
445             XtFree(*version);
446             *version = (char *)NULL;
447         }
448         XrmDestroyDatabase(inputDB->xrmDB);
449         XtFree((char *)inputDB->XSMPClients);
450         XtFree((char *)inputDB->proxyClients);
451         XtFree((char *)inputDB);
452         return (ClientDB)NULL;
453     }
454
455     return (ClientDB)inputDB;
456 }
457
458 ClientDB
459 OpenOutputClientDB(char *fileName,
460                    char *version,
461                    char *dtsessionID)
462 {
463     ClientDBRec *outputDB;
464
465     _initXrm();
466
467     if ((fileName == (char *)NULL) ||
468         (version == (char *)NULL) ||
469         (dtsessionID == (char *)NULL) ||
470         ((outputDB = (ClientDBRec *)XtMalloc(sizeof(ClientDBRec)))
471          == (ClientDBRec *)NULL))
472         return (ClientDB)NULL;
473
474     outputDB->xrmDB = (XrmDatabase)NULL;
475     outputDB->openForInput = False;
476     outputDB->nextXSMPClientIndex = 0;
477     outputDB->nextProxyClientIndex = 0;
478
479     /* Save current DB to tmp file in case we need to restore later. */
480     if (((outputDB->xrmDBFileName = XtNewString(fileName)) == (char *)NULL) ||
481         ((outputDB->tmpDBFileName = _tmpFileName(fileName)) == (char *)NULL))
482     {
483         if (outputDB->xrmDBFileName != (char *)NULL)
484             XtFree(outputDB->xrmDBFileName);
485         XtFree((char *)outputDB);
486         return (ClientDB)NULL;
487     }
488
489     if ((rename(fileName, outputDB->tmpDBFileName) != 0) &&
490         (errno != ENOENT))
491     {
492         XtFree(outputDB->xrmDBFileName);
493         XtFree(outputDB->tmpDBFileName);
494         XtFree((char *)outputDB);
495         return (ClientDB)NULL;
496     }
497
498     /* Open fileName for writing. */
499     if ((outputDB->xrmDBFile = fopen(fileName, "w")) == (FILE *)NULL)
500     {
501         int rv;
502         rv = rename(outputDB->tmpDBFileName, fileName);
503         XtFree(outputDB->xrmDBFileName);
504         XtFree(outputDB->tmpDBFileName);
505         XtFree((char *)outputDB);
506         return (ClientDB)NULL;
507     }
508
509     /* Store version and session ID. */
510     fprintf(outputDB->xrmDBFile, "! dtsession.db\n!\n%s: %s\n",
511             versionStr, version);
512     fprintf(outputDB->xrmDBFile, "%s: %s\n", dtsessionIDStr, dtsessionID);
513
514     return (ClientDB)outputDB;
515 }
516
517 XSMPClientDBRecPtr
518 GetXSMPClientDBRec(ClientDB inputDBPtr)
519 {
520     ClientDBRec *inputDB = (ClientDBRec *)inputDBPtr;
521     XSMPClientDBRecPtr clientPtr;
522     char *clientID;
523
524     if ((inputDB == (ClientDBRec *)NULL) ||
525         (!inputDB->openForInput) ||
526         (inputDB->nextXSMPClientIndex >= inputDB->nXSMPClients) ||
527         ((clientPtr = (XSMPClientDBRecPtr)XtMalloc(sizeof(XSMPClientDBRec)))
528          == (XSMPClientDBRecPtr)NULL))
529     {
530         return (XSMPClientDBRecPtr)NULL;
531     }
532
533     clientID = inputDB->XSMPClients[inputDB->nextXSMPClientIndex];
534
535     /* Initialize pointers so Free is easy. */
536     clientPtr->clientId = (char *)NULL;
537     clientPtr->clientHost = clientPtr->program =
538         clientPtr->cwd = (char *)NULL;
539     clientPtr->restartCommand = clientPtr->cloneCommand =
540         clientPtr->discardCommand = clientPtr->environment = (char **)NULL;
541
542     /* Retrieve resources from the database. */
543     if (!_getStringResource(inputDB->xrmDB, sessionIDStr, clientID,
544                             &clientPtr->clientId, (char *)NULL) ||
545         !_getStringResource(inputDB->xrmDB, clientHostStr, clientID,
546                              &clientPtr->clientHost, (char *)NULL) ||
547         !_getStringResource(inputDB->xrmDB, programStr, clientID,
548                             &clientPtr->program, (char *)NULL) ||
549         !_getStringResource(inputDB->xrmDB, cwdStr, clientID,
550                             &clientPtr->cwd, (char *)NULL) ||
551         !_getIntResource(inputDB->xrmDB, screenNumStr, clientID,
552                          &clientPtr->screenNum, 0) ||
553         !_getStringArrayResource(inputDB->xrmDB, restartCmdStr, clientID,
554                                  &clientPtr->restartCommand, (char **)NULL) ||
555         !_getStringArrayResource(inputDB->xrmDB, cloneCmdStr, clientID,
556                                  &clientPtr->cloneCommand, (char **)NULL) ||
557         !_getStringArrayResource(inputDB->xrmDB, discardCmdStr, clientID,
558                                  &clientPtr->discardCommand, (char **)NULL) ||
559         !_getStringArrayResource(inputDB->xrmDB, environmentStr, clientID,
560                                  &clientPtr->environment, (char **)NULL) ||
561         !_getIntResource(inputDB->xrmDB, restartHintStr, clientID,
562                          (int *)&clientPtr->restartHint, 0))
563     {
564         FreeXSMPClientDBRec(clientPtr);
565         return (XSMPClientDBRecPtr)NULL;
566     }
567
568     clientPtr->next = (XSMPClientDBRec *)NULL;
569
570     inputDB->nextXSMPClientIndex++;
571
572     return clientPtr;
573 }
574
575 ProxyClientDBRecPtr
576 GetProxyClientDBRec(ClientDB inputDBPtr)
577 {
578     ClientDBRec *inputDB = (ClientDBRec *)inputDBPtr;
579     ProxyClientDBRecPtr clientPtr;
580     char *clientID;
581
582     if ((inputDB == (ClientDBRec *)NULL) ||
583         (!inputDB->openForInput) ||
584         (inputDB->nextProxyClientIndex >= inputDB->nProxyClients) ||
585         ((clientPtr = (ProxyClientDBRecPtr)XtMalloc(sizeof(ProxyClientDBRec)))
586          == (ProxyClientDBRecPtr)NULL))
587     {
588         return (ProxyClientDBRecPtr)NULL;
589     }
590
591     clientID = inputDB->proxyClients[inputDB->nextProxyClientIndex];
592
593     /* Initialize pointers so Free is easy. */
594     clientPtr->clientHost = (char *)NULL;
595     clientPtr->command = (char **)NULL;
596
597     /* Retrieve resources from the database. */
598     if (!_getStringResource(inputDB->xrmDB, clientHostStr, clientID,
599                              &clientPtr->clientHost, (char *)NULL) ||
600         !_getStringArrayResource(inputDB->xrmDB, commandStr, clientID,
601                                  &clientPtr->command, (char **)NULL) ||
602         !_getIntResource(inputDB->xrmDB, screenNumStr, clientID,
603                          &clientPtr->screenNum, 0))
604     {
605         FreeProxyClientDBRec(clientPtr);
606         return (ProxyClientDBRecPtr)NULL;
607     }
608
609     inputDB->nextProxyClientIndex++;
610
611     return clientPtr;
612 }
613
614 Boolean
615 PutXSMPClientDBRec(ClientDB outputDBPtr,
616                    XSMPClientDBRecPtr clientPtr)
617 {
618     ClientDBRec *outputDB = (ClientDBRec *)outputDBPtr;
619     char clientID[CLIENT_ID_SZ];
620
621     if ((outputDB == (ClientDBRec *)NULL) ||
622         (outputDB->openForInput) ||
623         (clientPtr == (XSMPClientDBRecPtr)NULL) ||
624         (clientPtr->clientId == (char *)NULL))
625         return False;
626
627     sprintf(clientID, "C%d", outputDB->nextXSMPClientIndex++);
628
629     if (!_putStringResource(outputDB, clientStr, clientID, clientID) ||
630         !_putStringResource(outputDB, sessionIDStr, clientID,
631                             clientPtr->clientId) ||
632         !_putStringResource(outputDB, clientHostStr, clientID,
633                             clientPtr->clientHost) ||
634         !_putStringResource(outputDB, programStr, clientID,
635                             clientPtr->program) ||
636         !_putStringResource(outputDB, cwdStr, clientID,
637                             clientPtr->cwd) ||
638         !_putIntResource(outputDB, screenNumStr, clientID,
639                          clientPtr->screenNum) ||
640         !_putStringArrayResource(outputDB, restartCmdStr, clientID,
641                                  clientPtr->restartCommand) ||
642         !_putStringArrayResource(outputDB, cloneCmdStr, clientID,
643                                  clientPtr->cloneCommand) ||
644         !_putStringArrayResource(outputDB, discardCmdStr, clientID,
645                                  clientPtr->discardCommand) ||
646         !_putStringArrayResource(outputDB, environmentStr, clientID,
647                                  clientPtr->environment) ||
648         !_putIntResource(outputDB, restartHintStr, clientID,
649                          (int)clientPtr->restartHint))
650         return False;
651
652     return True;
653 }
654
655 Boolean
656 PutProxyClientDBRec(ClientDB outputDBPtr,
657                     ProxyClientDBRecPtr clientPtr)
658 {
659     ClientDBRec *outputDB = (ClientDBRec *)outputDBPtr;
660     char clientID[CLIENT_ID_SZ];
661
662     if ((outputDB == (ClientDBRec *)NULL) ||
663         (outputDB->openForInput) ||
664         (clientPtr == (ProxyClientDBRecPtr)NULL))
665         return False;
666
667     sprintf(clientID, "PC%d", outputDB->nextProxyClientIndex++);
668
669     if (!_putStringResource(outputDB, proxyStr, clientID, clientID) ||
670         !_putStringResource(outputDB, clientHostStr, clientID,
671                             clientPtr->clientHost) ||
672         !_putStringArrayResource(outputDB, commandStr, clientID,
673                                  clientPtr->command) ||
674         !_putIntResource(outputDB, screenNumStr, clientID,
675                          clientPtr->screenNum))
676         return False;
677
678     return True;
679 }
680
681 Boolean
682 CloseClientDB(ClientDB clientDBPtr, Boolean writeDB)
683 {
684     ClientDBRec *clientDB = (ClientDBRec *)clientDBPtr;
685
686     if (clientDB == (ClientDBRec *)NULL)
687         return False;
688
689     /* Input? */
690     if (clientDB->openForInput)
691     {
692         XtFree((char *)clientDB->XSMPClients);
693         XtFree((char *)clientDB->proxyClients);
694         XrmDestroyDatabase(clientDB->xrmDB);
695         XtFree((char *)clientDB);
696
697         return True;
698     }
699
700     /* Otherwise, output. */
701     if (writeDB)
702     {
703         /* Close file and remove temp DB. */
704         fclose(clientDB->xrmDBFile);
705         unlink(clientDB->tmpDBFileName);
706     }
707     else
708     {
709       int rv;
710         /* Close file and remove it; restore original DB. */
711         fclose(clientDB->xrmDBFile);
712         rv = rename(clientDB->tmpDBFileName, clientDB->xrmDBFileName);
713     }
714
715     XtFree(clientDB->xrmDBFileName);
716     XtFree(clientDB->tmpDBFileName);
717     XtFree((char *)clientDB);
718
719     return True;
720 }
721
722 void
723 FreeXSMPClientDBRec(XSMPClientDBRecPtr clientPtr)
724 {
725     if (clientPtr != (XSMPClientDBRecPtr)NULL)
726     {
727         XtFree(clientPtr->clientId);
728         XtFree(clientPtr->clientHost);
729         XtFree(clientPtr->program);
730         XtFree(clientPtr->cwd);
731
732         _freeStringArray(clientPtr->restartCommand);
733         _freeStringArray(clientPtr->cloneCommand);
734         _freeStringArray(clientPtr->discardCommand);
735         _freeStringArray(clientPtr->environment);
736
737         XtFree((char *)clientPtr);
738     }
739 }
740
741 void
742 FreeProxyClientDBRec(ProxyClientDBRecPtr clientPtr)
743 {
744     if (clientPtr != (ProxyClientDBRecPtr)NULL)
745     {
746         XtFree(clientPtr->clientHost);
747
748         _freeStringArray(clientPtr->command);
749
750         XtFree((char *)clientPtr);
751     }
752 }