save.c revision 576bae58
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#ifndef HAVE_MKSTEMP
43static char * unique_filename ( char *path, char *prefix );
44#else
45static char * unique_filename ( char *path, char *prefix, int *pFd );
46#endif
47
48
49static int
50write_byte (FILE *file, unsigned char b)
51{
52    if (fwrite ((char *) &b, 1, 1, file) != 1)
53	return 0;
54    return 1;
55}
56
57
58static int
59write_short (FILE *file, unsigned short s)
60{
61    unsigned char   file_short[2];
62
63    file_short[0] = (s & (unsigned)0xff00) >> 8;
64    file_short[1] = s & 0xff;
65    if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
66	return 0;
67    return 1;
68}
69
70
71static int
72write_counted_string(FILE *file, char *string)
73{
74    if (string)
75    {
76	unsigned char count = strlen (string);
77
78	if (write_byte (file, count) == 0)
79	    return 0;
80	if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
81	    return 0;
82    }
83    else
84    {
85	if (write_byte (file, 0) == 0)
86	    return 0;
87    }
88
89    return 1;
90}
91
92
93
94static int
95read_byte(FILE *file, unsigned char *bp)
96{
97    if (fread ((char *) bp, 1, 1, file) != 1)
98	return 0;
99    return 1;
100}
101
102
103static int
104read_short(FILE *file, unsigned short *shortp)
105{
106    unsigned char   file_short[2];
107
108    if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
109	return 0;
110    *shortp = file_short[0] * 256 + file_short[1];
111    return 1;
112}
113
114
115static int
116read_counted_string(FILE *file, char **stringp)
117{
118    unsigned char  len;
119    char	   *data;
120
121    if (read_byte (file, &len) == 0)
122	return 0;
123    if (len == 0) {
124	data = NULL;
125    } else {
126    	data = (char *) malloc ((unsigned) len + 1);
127    	if (!data)
128	    return 0;
129    	if (fread (data, (int) sizeof (char), (int) len, file) != len) {
130	    free (data);
131	    return 0;
132    	}
133	data[len] = '\0';
134    }
135    *stringp = data;
136    return 1;
137}
138
139
140
141/*
142 * An entry in the .smproxy file looks like this:
143 *
144 * FIELD				BYTES
145 * -----                                ----
146 * client ID len			1
147 * client ID				LIST of bytes
148 * WM_CLASS "res name" length		1
149 * WM_CLASS "res name"			LIST of bytes
150 * WM_CLASS "res class" length          1
151 * WM_CLASS "res class"                 LIST of bytes
152 * WM_NAME length			1
153 * WM_NAME				LIST of bytes
154 * WM_COMMAND arg count			1
155 * For each arg in WM_COMMAND
156 *    arg length			1
157 *    arg				LIST of bytes
158 */
159
160int
161WriteProxyFileEntry(FILE *proxyFile, WinInfo *theWindow)
162{
163    int i;
164
165    if (!write_counted_string (proxyFile, theWindow->client_id))
166	return 0;
167    if (!write_counted_string (proxyFile, theWindow->class.res_name))
168	return 0;
169    if (!write_counted_string (proxyFile, theWindow->class.res_class))
170	return 0;
171    if (!write_counted_string (proxyFile, theWindow->wm_name))
172	return 0;
173
174    if (!theWindow->wm_command || theWindow->wm_command_count == 0)
175    {
176	if (!write_byte (proxyFile, 0))
177	    return 0;
178    }
179    else
180    {
181	if (!write_byte (proxyFile, (char) theWindow->wm_command_count))
182	    return 0;
183	for (i = 0; i < theWindow->wm_command_count; i++)
184	    if (!write_counted_string (proxyFile, theWindow->wm_command[i]))
185		return 0;
186    }
187
188    return 1;
189}
190
191
192int
193ReadProxyFileEntry(FILE *proxyFile, ProxyFileEntry **pentry)
194{
195    ProxyFileEntry *entry;
196    unsigned char byte;
197    int i;
198
199    *pentry = entry = (ProxyFileEntry *) malloc (
200	sizeof (ProxyFileEntry));
201    if (!*pentry)
202	return 0;
203
204    entry->tag = 0;
205    entry->client_id = NULL;
206    entry->class.res_name = NULL;
207    entry->class.res_class = NULL;
208    entry->wm_name = NULL;
209    entry->wm_command = NULL;
210    entry->wm_command_count = 0;
211
212    if (!read_counted_string (proxyFile, &entry->client_id))
213	goto give_up;
214    if (!read_counted_string (proxyFile, &entry->class.res_name))
215	goto give_up;
216    if (!read_counted_string (proxyFile, &entry->class.res_class))
217	goto give_up;
218    if (!read_counted_string (proxyFile, &entry->wm_name))
219	goto give_up;
220
221    if (!read_byte (proxyFile, &byte))
222	goto give_up;
223    entry->wm_command_count = byte;
224
225    if (entry->wm_command_count == 0)
226	entry->wm_command = NULL;
227    else
228    {
229	entry->wm_command = (char **) malloc (entry->wm_command_count *
230	    sizeof (char *));
231
232	if (!entry->wm_command)
233	    goto give_up;
234
235	for (i = 0; i < entry->wm_command_count; i++)
236	    if (!read_counted_string (proxyFile, &entry->wm_command[i]))
237		goto give_up;
238    }
239
240    return 1;
241
242give_up:
243
244    if (entry->client_id)
245	free (entry->client_id);
246    if (entry->class.res_name)
247	free (entry->class.res_name);
248    if (entry->class.res_class)
249	free (entry->class.res_class);
250    if (entry->wm_name)
251	free (entry->wm_name);
252    if (entry->wm_command_count)
253    {
254	for (i = 0; i < entry->wm_command_count; i++)
255	    if (entry->wm_command[i])
256		free (entry->wm_command[i]);
257    }
258    if (entry->wm_command)
259	free ((char *) entry->wm_command);
260
261    free ((char *) entry);
262    *pentry = NULL;
263
264    return 0;
265}
266
267
268void
269ReadProxyFile(char *filename)
270{
271    FILE *proxyFile;
272    ProxyFileEntry *entry;
273    int done = 0;
274    unsigned short version;
275
276    proxyFile = fopen (filename, "rb");
277    if (!proxyFile)
278	return;
279
280    if (!read_short (proxyFile, &version) ||
281	version > SAVEFILE_VERSION)
282    {
283	done = 1;
284    }
285
286    while (!done)
287    {
288	if (ReadProxyFileEntry (proxyFile, &entry))
289	{
290	    entry->next = proxyFileHead;
291	    proxyFileHead = entry;
292	}
293	else
294	    done = 1;
295    }
296
297    fclose (proxyFile);
298}
299
300
301
302#ifndef HAVE_MKSTEMP
303static char *
304unique_filename(char *path, char *prefix)
305#else
306static char *
307unique_filename(char *path, char *prefix, int *pFd)
308#endif
309{
310#ifndef HAVE_MKSTEMP
311#ifndef X_NOT_POSIX
312    return ((char *) tempnam (path, prefix));
313#else
314    char tempFile[PATH_MAX];
315    char *tmp;
316
317    sprintf (tempFile, "%s/%sXXXXXX", path, prefix);
318    tmp = (char *) mktemp (tempFile);
319    if (tmp)
320    {
321	char *ptr = (char *) malloc (strlen (tmp) + 1);
322	strcpy (ptr, tmp);
323	return (ptr);
324    }
325    else
326	return (NULL);
327#endif
328#else
329    char tempFile[PATH_MAX];
330    char *ptr;
331
332    sprintf (tempFile, "%s/%sXXXXXX", path, prefix);
333    ptr = (char *)malloc(strlen(tempFile) + 1);
334    if (ptr != NULL)
335    {
336	strcpy(ptr, tempFile);
337	*pFd =  mkstemp(ptr);
338    }
339    return ptr;
340#endif
341}
342
343
344
345char *
346WriteProxyFile(void)
347{
348    FILE *proxyFile = NULL;
349    char *filename = NULL;
350#ifdef HAVE_MKSTEMP
351    int fd;
352#endif
353    char *path;
354    WinInfo *winptr;
355    Bool success = False;
356
357    path = getenv ("SM_SAVE_DIR");
358    if (!path)
359    {
360	path = getenv ("HOME");
361	if (!path)
362	    path = ".";
363    }
364
365#ifndef HAVE_MKSTEMP
366    if ((filename = unique_filename (path, ".prx")) == NULL)
367	goto bad;
368
369    if (!(proxyFile = fopen (filename, "wb")))
370	goto bad;
371#else
372    if ((filename = unique_filename (path, ".prx", &fd)) == NULL)
373	goto bad;
374
375    if (!(proxyFile = fdopen(fd, "wb")))
376	goto bad;
377#endif
378    if (!write_short (proxyFile, SAVEFILE_VERSION))
379	goto bad;
380
381    success = True;
382    winptr = win_head;
383
384    while (winptr && success)
385    {
386	if (winptr->client_id)
387	    if (!WriteProxyFileEntry (proxyFile, winptr))
388	    {
389		success = False;
390		break;
391	    }
392
393	winptr = winptr->next;
394    }
395
396 bad:
397
398    if (proxyFile)
399	fclose (proxyFile);
400
401    if (success)
402	return (filename);
403    else
404    {
405	if (filename)
406	    free (filename);
407	return (NULL);
408    }
409}
410
411
412
413char *
414LookupClientID(WinInfo *theWindow)
415{
416    ProxyFileEntry *ptr;
417    int found = 0;
418
419    ptr = proxyFileHead;
420    while (ptr && !found)
421    {
422	if (!ptr->tag &&
423            strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 &&
424	    strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 &&
425	    strcmp (theWindow->wm_name, ptr->wm_name) == 0)
426	{
427	    int i;
428
429	    if (theWindow->wm_command_count == ptr->wm_command_count)
430	    {
431		for (i = 0; i < theWindow->wm_command_count; i++)
432		    if (strcmp (theWindow->wm_command[i],
433			ptr->wm_command[i]) != 0)
434			break;
435
436		if (i == theWindow->wm_command_count)
437		    found = 1;
438	    }
439	}
440
441	if (!found)
442	    ptr = ptr->next;
443    }
444
445    if (found)
446    {
447	ptr->tag = 1;
448	return (ptr->client_id);
449    }
450    else
451	return NULL;
452}
453