save.c revision 24047306
1/******************************************************************************
2
3Copyright 1994, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Author:  Ralph Mor, X Consortium
26******************************************************************************/
27
28#include "smproxy.h"
29#ifdef HAVE_MKSTEMP
30#include <unistd.h>
31#endif
32
33
34static ProxyFileEntry *proxyFileHead = NULL;
35
36static int write_byte ( FILE *file, unsigned char b );
37static int write_short ( FILE *file, unsigned short s );
38static int write_counted_string ( FILE *file, char *string );
39static int read_byte ( FILE *file, unsigned char *bp );
40static int read_short ( FILE *file, unsigned short *shortp );
41static int read_counted_string ( FILE *file, char **stringp );
42
43#ifndef HAVE_ASPRINTF
44# include <stdarg.h>
45
46/* sprintf variant found in newer libc's which allocates string to print to */
47_X_HIDDEN int _X_ATTRIBUTE_PRINTF(2,3)
48asprintf(char ** ret, const char *format, ...)
49{
50    char buf[256];
51    int len;
52    va_list ap;
53
54    va_start(ap, format);
55    len = vsnprintf(buf, sizeof(buf), format, ap);
56    va_end(ap);
57
58    if (len < 0)
59	return -1;
60
61    if (len < sizeof(buf))
62    {
63	*ret = strdup(buf);
64    }
65    else
66    {
67	*ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */
68	if (*ret != NULL)
69	{
70	    va_start(ap, format);
71	    len = vsnprintf(*ret, len + 1, format, ap);
72	    va_end(ap);
73	    if (len < 0) {
74		free(*ret);
75		*ret = NULL;
76	    }
77	}
78    }
79
80    if (*ret == NULL)
81	return -1;
82
83    return len;
84}
85#endif
86
87
88
89static int
90write_byte (FILE *file, unsigned char b)
91{
92    if (fwrite ((char *) &b, 1, 1, file) != 1)
93	return 0;
94    return 1;
95}
96
97
98static int
99write_short (FILE *file, unsigned short s)
100{
101    unsigned char   file_short[2];
102
103    file_short[0] = (s & (unsigned)0xff00) >> 8;
104    file_short[1] = s & 0xff;
105    if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
106	return 0;
107    return 1;
108}
109
110
111static int
112write_counted_string(FILE *file, char *string)
113{
114    if (string)
115    {
116	unsigned char count = strlen (string);
117
118	if (write_byte (file, count) == 0)
119	    return 0;
120	if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
121	    return 0;
122    }
123    else
124    {
125	if (write_byte (file, 0) == 0)
126	    return 0;
127    }
128
129    return 1;
130}
131
132
133
134static int
135read_byte(FILE *file, unsigned char *bp)
136{
137    if (fread ((char *) bp, 1, 1, file) != 1)
138	return 0;
139    return 1;
140}
141
142
143static int
144read_short(FILE *file, unsigned short *shortp)
145{
146    unsigned char   file_short[2];
147
148    if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
149	return 0;
150    *shortp = file_short[0] * 256 + file_short[1];
151    return 1;
152}
153
154
155static int
156read_counted_string(FILE *file, char **stringp)
157{
158    unsigned char  len;
159    char	   *data;
160
161    if (read_byte (file, &len) == 0)
162	return 0;
163    if (len == 0) {
164	data = NULL;
165    } else {
166    	data = (char *) malloc ((unsigned) len + 1);
167    	if (!data)
168	    return 0;
169    	if (fread (data, (int) sizeof (char), (int) len, file) != len) {
170	    free (data);
171	    return 0;
172    	}
173	data[len] = '\0';
174    }
175    *stringp = data;
176    return 1;
177}
178
179
180
181/*
182 * An entry in the .smproxy file looks like this:
183 *
184 * FIELD				BYTES
185 * -----                                ----
186 * client ID len			1
187 * client ID				LIST of bytes
188 * WM_CLASS "res name" length		1
189 * WM_CLASS "res name"			LIST of bytes
190 * WM_CLASS "res class" length          1
191 * WM_CLASS "res class"                 LIST of bytes
192 * WM_NAME length			1
193 * WM_NAME				LIST of bytes
194 * WM_COMMAND arg count			1
195 * For each arg in WM_COMMAND
196 *    arg length			1
197 *    arg				LIST of bytes
198 */
199
200int
201WriteProxyFileEntry(FILE *proxyFile, WinInfo *theWindow)
202{
203    int i;
204
205    if (!write_counted_string (proxyFile, theWindow->client_id))
206	return 0;
207    if (!write_counted_string (proxyFile, theWindow->class.res_name))
208	return 0;
209    if (!write_counted_string (proxyFile, theWindow->class.res_class))
210	return 0;
211    if (!write_counted_string (proxyFile, theWindow->wm_name))
212	return 0;
213
214    if (!theWindow->wm_command || theWindow->wm_command_count == 0)
215    {
216	if (!write_byte (proxyFile, 0))
217	    return 0;
218    }
219    else
220    {
221	if (!write_byte (proxyFile, (char) theWindow->wm_command_count))
222	    return 0;
223	for (i = 0; i < theWindow->wm_command_count; i++)
224	    if (!write_counted_string (proxyFile, theWindow->wm_command[i]))
225		return 0;
226    }
227
228    return 1;
229}
230
231
232int
233ReadProxyFileEntry(FILE *proxyFile, ProxyFileEntry **pentry)
234{
235    ProxyFileEntry *entry;
236    unsigned char byte;
237    int i;
238
239    *pentry = entry = (ProxyFileEntry *) malloc (
240	sizeof (ProxyFileEntry));
241    if (!*pentry)
242	return 0;
243
244    entry->tag = 0;
245    entry->client_id = NULL;
246    entry->class.res_name = NULL;
247    entry->class.res_class = NULL;
248    entry->wm_name = NULL;
249    entry->wm_command = NULL;
250    entry->wm_command_count = 0;
251
252    if (!read_counted_string (proxyFile, &entry->client_id))
253	goto give_up;
254    if (!read_counted_string (proxyFile, &entry->class.res_name))
255	goto give_up;
256    if (!read_counted_string (proxyFile, &entry->class.res_class))
257	goto give_up;
258    if (!read_counted_string (proxyFile, &entry->wm_name))
259	goto give_up;
260
261    if (!read_byte (proxyFile, &byte))
262	goto give_up;
263    entry->wm_command_count = byte;
264
265    if (entry->wm_command_count == 0)
266	entry->wm_command = NULL;
267    else
268    {
269	entry->wm_command = (char **) malloc (entry->wm_command_count *
270	    sizeof (char *));
271
272	if (!entry->wm_command)
273	    goto give_up;
274
275	for (i = 0; i < entry->wm_command_count; i++)
276	    if (!read_counted_string (proxyFile, &entry->wm_command[i]))
277		goto give_up;
278    }
279
280    return 1;
281
282give_up:
283
284    if (entry->client_id)
285	free (entry->client_id);
286    if (entry->class.res_name)
287	free (entry->class.res_name);
288    if (entry->class.res_class)
289	free (entry->class.res_class);
290    if (entry->wm_name)
291	free (entry->wm_name);
292    if (entry->wm_command)
293    {
294        if (entry->wm_command_count)
295        {
296	    for (i = 0; i < entry->wm_command_count; i++)
297	        if (entry->wm_command[i])
298		    free (entry->wm_command[i]);
299        }
300	free ((char *) entry->wm_command);
301    }
302
303    free ((char *) entry);
304    *pentry = NULL;
305
306    return 0;
307}
308
309
310void
311ReadProxyFile(char *filename)
312{
313    FILE *proxyFile;
314    ProxyFileEntry *entry;
315    int done = 0;
316    unsigned short version;
317
318    proxyFile = fopen (filename, "rb");
319    if (!proxyFile)
320	return;
321
322    if (!read_short (proxyFile, &version) ||
323	version > SAVEFILE_VERSION)
324    {
325	done = 1;
326    }
327
328    while (!done)
329    {
330	if (ReadProxyFileEntry (proxyFile, &entry))
331	{
332	    entry->next = proxyFileHead;
333	    proxyFileHead = entry;
334	}
335	else
336	    done = 1;
337    }
338
339    fclose (proxyFile);
340}
341
342
343
344static char *
345unique_filename(const char *path, const char *prefix, int *pFd)
346{
347    char *tempFile = NULL;
348    int tempFd = 0;
349
350#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP)
351    if (asprintf (&tempFile, "%s/%sXXXXXX", path, prefix) == -1)
352	return NULL;
353#endif
354
355#ifdef HAVE_MKSTEMP
356    tempFd = mkstemp(tempFile);
357#else
358
359# ifdef HAVE_MKTEMP
360    if (mktemp(tempFile) == NULL)
361	tempFd = -1;
362# else /* fallback to tempnam */
363    tempFile = tempnam (path, prefix);
364# endif /* HAVE_MKTEMP */
365
366    if (tempFd != -1 && tempFile != NULL)
367	tempFd = open(tempFile, O_RDWR | O_CREAT | O_EXCL, 0600);
368#endif
369
370    if (tempFd == -1) {
371	free(tempFile);
372	return (NULL);
373    }
374
375    *pFd = tempFd;
376    return tempFile;
377
378}
379
380
381
382char *
383WriteProxyFile(void)
384{
385    FILE *proxyFile = NULL;
386    char *filename = NULL;
387    int fd = -1;
388    const char *path;
389    WinInfo *winptr;
390    Bool success = False;
391
392    path = getenv ("SM_SAVE_DIR");
393    if (!path)
394    {
395	path = getenv ("HOME");
396	if (!path)
397	    path = ".";
398    }
399
400    if ((filename = unique_filename (path, ".prx", &fd)) == NULL)
401	goto bad;
402
403    if (!(proxyFile = fdopen(fd, "wb")))
404	goto bad;
405
406    if (!write_short (proxyFile, SAVEFILE_VERSION))
407	goto bad;
408
409    success = True;
410    winptr = win_head;
411
412    while (winptr && success)
413    {
414	if (winptr->client_id)
415	    if (!WriteProxyFileEntry (proxyFile, winptr))
416	    {
417		success = False;
418		break;
419	    }
420
421	winptr = winptr->next;
422    }
423
424 bad:
425
426    if (proxyFile)
427	fclose (proxyFile);
428    else if (fd != -1)
429	close (fd);
430
431    if (success)
432	return (filename);
433    else
434    {
435	if (filename)
436	    free (filename);
437	return (NULL);
438    }
439}
440
441
442
443char *
444LookupClientID(WinInfo *theWindow)
445{
446    ProxyFileEntry *ptr;
447    int found = 0;
448
449    ptr = proxyFileHead;
450    while (ptr && !found)
451    {
452	if (!ptr->tag &&
453            strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 &&
454	    strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 &&
455	    strcmp (theWindow->wm_name, ptr->wm_name) == 0)
456	{
457	    int i;
458
459	    if (theWindow->wm_command_count == ptr->wm_command_count)
460	    {
461		for (i = 0; i < theWindow->wm_command_count; i++)
462		    if (strcmp (theWindow->wm_command[i],
463			ptr->wm_command[i]) != 0)
464			break;
465
466		if (i == theWindow->wm_command_count)
467		    found = 1;
468	    }
469	}
470
471	if (!found)
472	    ptr = ptr->next;
473    }
474
475    if (found)
476    {
477	ptr->tag = 1;
478	return (ptr->client_id);
479    }
480    else
481	return NULL;
482}
483