Link with C++ linker
[oweals/cde.git] / cde / programs / dtsession / 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 librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: 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         rename(outputDB->tmpDBFileName, fileName);
502         XtFree(outputDB->xrmDBFileName);
503         XtFree(outputDB->tmpDBFileName);
504         XtFree((char *)outputDB);
505         return (ClientDB)NULL;
506     }
507
508     /* Store version and session ID. */
509     fprintf(outputDB->xrmDBFile, "! dtsession.db\n!\n%s: %s\n",
510             versionStr, version);
511     fprintf(outputDB->xrmDBFile, "%s: %s\n", dtsessionIDStr, dtsessionID);
512
513     return (ClientDB)outputDB;
514 }
515
516 XSMPClientDBRecPtr
517 GetXSMPClientDBRec(ClientDB inputDBPtr)
518 {
519     ClientDBRec *inputDB = (ClientDBRec *)inputDBPtr;
520     XSMPClientDBRecPtr clientPtr;
521     char *clientID;
522
523     if ((inputDB == (ClientDBRec *)NULL) ||
524         (!inputDB->openForInput) ||
525         (inputDB->nextXSMPClientIndex >= inputDB->nXSMPClients) ||
526         ((clientPtr = (XSMPClientDBRecPtr)XtMalloc(sizeof(XSMPClientDBRec)))
527          == (XSMPClientDBRecPtr)NULL))
528     {
529         return (XSMPClientDBRecPtr)NULL;
530     }
531
532     clientID = inputDB->XSMPClients[inputDB->nextXSMPClientIndex];
533
534     /* Initialize pointers so Free is easy. */
535     clientPtr->clientId = (char *)NULL;
536     clientPtr->clientHost = clientPtr->program =
537         clientPtr->cwd = (char *)NULL;
538     clientPtr->restartCommand = clientPtr->cloneCommand =
539         clientPtr->discardCommand = clientPtr->environment = (char **)NULL;
540
541     /* Retrieve resources from the database. */
542     if (!_getStringResource(inputDB->xrmDB, sessionIDStr, clientID,
543                             &clientPtr->clientId, (char *)NULL) ||
544         !_getStringResource(inputDB->xrmDB, clientHostStr, clientID,
545                              &clientPtr->clientHost, (char *)NULL) ||
546         !_getStringResource(inputDB->xrmDB, programStr, clientID,
547                             &clientPtr->program, (char *)NULL) ||
548         !_getStringResource(inputDB->xrmDB, cwdStr, clientID,
549                             &clientPtr->cwd, (char *)NULL) ||
550         !_getIntResource(inputDB->xrmDB, screenNumStr, clientID,
551                          &clientPtr->screenNum, 0) ||
552         !_getStringArrayResource(inputDB->xrmDB, restartCmdStr, clientID,
553                                  &clientPtr->restartCommand, (char **)NULL) ||
554         !_getStringArrayResource(inputDB->xrmDB, cloneCmdStr, clientID,
555                                  &clientPtr->cloneCommand, (char **)NULL) ||
556         !_getStringArrayResource(inputDB->xrmDB, discardCmdStr, clientID,
557                                  &clientPtr->discardCommand, (char **)NULL) ||
558         !_getStringArrayResource(inputDB->xrmDB, environmentStr, clientID,
559                                  &clientPtr->environment, (char **)NULL) ||
560         !_getIntResource(inputDB->xrmDB, restartHintStr, clientID,
561                          (int *)&clientPtr->restartHint, 0))
562     {
563         FreeXSMPClientDBRec(clientPtr);
564         return (XSMPClientDBRecPtr)NULL;
565     }
566
567     clientPtr->next = (XSMPClientDBRec *)NULL;
568
569     inputDB->nextXSMPClientIndex++;
570
571     return clientPtr;
572 }
573
574 ProxyClientDBRecPtr
575 GetProxyClientDBRec(ClientDB inputDBPtr)
576 {
577     ClientDBRec *inputDB = (ClientDBRec *)inputDBPtr;
578     ProxyClientDBRecPtr clientPtr;
579     char *clientID;
580
581     if ((inputDB == (ClientDBRec *)NULL) ||
582         (!inputDB->openForInput) ||
583         (inputDB->nextProxyClientIndex >= inputDB->nProxyClients) ||
584         ((clientPtr = (ProxyClientDBRecPtr)XtMalloc(sizeof(ProxyClientDBRec)))
585          == (ProxyClientDBRecPtr)NULL))
586     {
587         return (ProxyClientDBRecPtr)NULL;
588     }
589
590     clientID = inputDB->proxyClients[inputDB->nextProxyClientIndex];
591
592     /* Initialize pointers so Free is easy. */
593     clientPtr->clientHost = (char *)NULL;
594     clientPtr->command = (char **)NULL;
595
596     /* Retrieve resources from the database. */
597     if (!_getStringResource(inputDB->xrmDB, clientHostStr, clientID,
598                              &clientPtr->clientHost, (char *)NULL) ||
599         !_getStringArrayResource(inputDB->xrmDB, commandStr, clientID,
600                                  &clientPtr->command, (char **)NULL) ||
601         !_getIntResource(inputDB->xrmDB, screenNumStr, clientID,
602                          &clientPtr->screenNum, 0))
603     {
604         FreeProxyClientDBRec(clientPtr);
605         return (ProxyClientDBRecPtr)NULL;
606     }
607
608     inputDB->nextProxyClientIndex++;
609
610     return clientPtr;
611 }
612
613 Boolean
614 PutXSMPClientDBRec(ClientDB outputDBPtr,
615                    XSMPClientDBRecPtr clientPtr)
616 {
617     ClientDBRec *outputDB = (ClientDBRec *)outputDBPtr;
618     char clientID[CLIENT_ID_SZ];
619
620     if ((outputDB == (ClientDBRec *)NULL) ||
621         (outputDB->openForInput) ||
622         (clientPtr == (XSMPClientDBRecPtr)NULL) ||
623         (clientPtr->clientId == (char *)NULL))
624         return False;
625
626     sprintf(clientID, "C%d", outputDB->nextXSMPClientIndex++);
627
628     if (!_putStringResource(outputDB, clientStr, clientID, clientID) ||
629         !_putStringResource(outputDB, sessionIDStr, clientID,
630                             clientPtr->clientId) ||
631         !_putStringResource(outputDB, clientHostStr, clientID,
632                             clientPtr->clientHost) ||
633         !_putStringResource(outputDB, programStr, clientID,
634                             clientPtr->program) ||
635         !_putStringResource(outputDB, cwdStr, clientID,
636                             clientPtr->cwd) ||
637         !_putIntResource(outputDB, screenNumStr, clientID,
638                          clientPtr->screenNum) ||
639         !_putStringArrayResource(outputDB, restartCmdStr, clientID,
640                                  clientPtr->restartCommand) ||
641         !_putStringArrayResource(outputDB, cloneCmdStr, clientID,
642                                  clientPtr->cloneCommand) ||
643         !_putStringArrayResource(outputDB, discardCmdStr, clientID,
644                                  clientPtr->discardCommand) ||
645         !_putStringArrayResource(outputDB, environmentStr, clientID,
646                                  clientPtr->environment) ||
647         !_putIntResource(outputDB, restartHintStr, clientID,
648                          (int)clientPtr->restartHint))
649         return False;
650
651     return True;
652 }
653
654 Boolean
655 PutProxyClientDBRec(ClientDB outputDBPtr,
656                     ProxyClientDBRecPtr clientPtr)
657 {
658     ClientDBRec *outputDB = (ClientDBRec *)outputDBPtr;
659     char clientID[CLIENT_ID_SZ];
660
661     if ((outputDB == (ClientDBRec *)NULL) ||
662         (outputDB->openForInput) ||
663         (clientPtr == (ProxyClientDBRecPtr)NULL))
664         return False;
665
666     sprintf(clientID, "PC%d", outputDB->nextProxyClientIndex++);
667
668     if (!_putStringResource(outputDB, proxyStr, clientID, clientID) ||
669         !_putStringResource(outputDB, clientHostStr, clientID,
670                             clientPtr->clientHost) ||
671         !_putStringArrayResource(outputDB, commandStr, clientID,
672                                  clientPtr->command) ||
673         !_putIntResource(outputDB, screenNumStr, clientID,
674                          clientPtr->screenNum))
675         return False;
676
677     return True;
678 }
679
680 Boolean
681 CloseClientDB(ClientDB clientDBPtr, Boolean writeDB)
682 {
683     ClientDBRec *clientDB = (ClientDBRec *)clientDBPtr;
684
685     if (clientDB == (ClientDBRec *)NULL)
686         return False;
687
688     /* Input? */
689     if (clientDB->openForInput)
690     {
691         XtFree((char *)clientDB->XSMPClients);
692         XtFree((char *)clientDB->proxyClients);
693         XrmDestroyDatabase(clientDB->xrmDB);
694         XtFree((char *)clientDB);
695
696         return True;
697     }
698
699     /* Otherwise, output. */
700     if (writeDB)
701     {
702         /* Close file and remove temp DB. */
703         fclose(clientDB->xrmDBFile);
704         unlink(clientDB->tmpDBFileName);
705     }
706     else
707     {
708         /* Close file and remove it; restore original DB. */
709         fclose(clientDB->xrmDBFile);
710         rename(clientDB->tmpDBFileName, clientDB->xrmDBFileName);
711     }
712
713     XtFree(clientDB->xrmDBFileName);
714     XtFree(clientDB->tmpDBFileName);
715     XtFree((char *)clientDB);
716
717     return True;
718 }
719
720 void
721 FreeXSMPClientDBRec(XSMPClientDBRecPtr clientPtr)
722 {
723     if (clientPtr != (XSMPClientDBRecPtr)NULL)
724     {
725         XtFree(clientPtr->clientId);
726         XtFree(clientPtr->clientHost);
727         XtFree(clientPtr->program);
728         XtFree(clientPtr->cwd);
729
730         _freeStringArray(clientPtr->restartCommand);
731         _freeStringArray(clientPtr->cloneCommand);
732         _freeStringArray(clientPtr->discardCommand);
733         _freeStringArray(clientPtr->environment);
734
735         XtFree((char *)clientPtr);
736     }
737 }
738
739 void
740 FreeProxyClientDBRec(ProxyClientDBRecPtr clientPtr)
741 {
742     if (clientPtr != (ProxyClientDBRecPtr)NULL)
743     {
744         XtFree(clientPtr->clientHost);
745
746         _freeStringArray(clientPtr->command);
747
748         XtFree((char *)clientPtr);
749     }
750 }