save.c revision 1a054510
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)
253    {
254        if (entry->wm_command_count)
255        {
256	    for (i = 0; i < entry->wm_command_count; i++)
257	        if (entry->wm_command[i])
258		    free (entry->wm_command[i]);
259        }
260	free ((char *) entry->wm_command);
261    }
262
263    free ((char *) entry);
264    *pentry = NULL;
265
266    return 0;
267}
268
269
270void
271ReadProxyFile(char *filename)
272{
273    FILE *proxyFile;
274    ProxyFileEntry *entry;
275    int done = 0;
276    unsigned short version;
277
278    proxyFile = fopen (filename, "rb");
279    if (!proxyFile)
280	return;
281
282    if (!read_short (proxyFile, &version) ||
283	version > SAVEFILE_VERSION)
284    {
285	done = 1;
286    }
287
288    while (!done)
289    {
290	if (ReadProxyFileEntry (proxyFile, &entry))
291	{
292	    entry->next = proxyFileHead;
293	    proxyFileHead = entry;
294	}
295	else
296	    done = 1;
297    }
298
299    fclose (proxyFile);
300}
301
302
303
304#ifndef HAVE_MKSTEMP
305static char *
306unique_filename(char *path, char *prefix)
307#else
308static char *
309unique_filename(char *path, char *prefix, int *pFd)
310#endif
311{
312#ifndef HAVE_MKSTEMP
313#ifndef X_NOT_POSIX
314    return ((char *) tempnam (path, prefix));
315#else
316    char tempFile[PATH_MAX];
317    char *tmp;
318
319    sprintf (tempFile, "%s/%sXXXXXX", path, prefix);
320    tmp = (char *) mktemp (tempFile);
321    if (tmp)
322    {
323	char *ptr = (char *) malloc (strlen (tmp) + 1);
324	strcpy (ptr, tmp);
325	return (ptr);
326    }
327    else
328	return (NULL);
329#endif
330#else
331    char tempFile[PATH_MAX];
332    char *ptr;
333
334    sprintf (tempFile, "%s/%sXXXXXX", path, prefix);
335    ptr = (char *)malloc(strlen(tempFile) + 1);
336    if (ptr != NULL)
337    {
338	strcpy(ptr, tempFile);
339	*pFd =  mkstemp(ptr);
340    }
341    return ptr;
342#endif
343}
344
345
346
347char *
348WriteProxyFile(void)
349{
350    FILE *proxyFile = NULL;
351    char *filename = NULL;
352#ifdef HAVE_MKSTEMP
353    int fd;
354#endif
355    char *path;
356    WinInfo *winptr;
357    Bool success = False;
358
359    path = getenv ("SM_SAVE_DIR");
360    if (!path)
361    {
362	path = getenv ("HOME");
363	if (!path)
364	    path = ".";
365    }
366
367#ifndef HAVE_MKSTEMP
368    if ((filename = unique_filename (path, ".prx")) == NULL)
369	goto bad;
370
371    if (!(proxyFile = fopen (filename, "wb")))
372	goto bad;
373#else
374    if ((filename = unique_filename (path, ".prx", &fd)) == NULL)
375	goto bad;
376
377    if (!(proxyFile = fdopen(fd, "wb")))
378	goto bad;
379#endif
380    if (!write_short (proxyFile, SAVEFILE_VERSION))
381	goto bad;
382
383    success = True;
384    winptr = win_head;
385
386    while (winptr && success)
387    {
388	if (winptr->client_id)
389	    if (!WriteProxyFileEntry (proxyFile, winptr))
390	    {
391		success = False;
392		break;
393	    }
394
395	winptr = winptr->next;
396    }
397
398 bad:
399
400    if (proxyFile)
401	fclose (proxyFile);
402
403    if (success)
404	return (filename);
405    else
406    {
407	if (filename)
408	    free (filename);
409	return (NULL);
410    }
411}
412
413
414
415char *
416LookupClientID(WinInfo *theWindow)
417{
418    ProxyFileEntry *ptr;
419    int found = 0;
420
421    ptr = proxyFileHead;
422    while (ptr && !found)
423    {
424	if (!ptr->tag &&
425            strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 &&
426	    strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 &&
427	    strcmp (theWindow->wm_name, ptr->wm_name) == 0)
428	{
429	    int i;
430
431	    if (theWindow->wm_command_count == ptr->wm_command_count)
432	    {
433		for (i = 0; i < theWindow->wm_command_count; i++)
434		    if (strcmp (theWindow->wm_command[i],
435			ptr->wm_command[i]) != 0)
436			break;
437
438		if (i == theWindow->wm_command_count)
439		    found = 1;
440	    }
441	}
442
443	if (!found)
444	    ptr = ptr->next;
445    }
446
447    if (found)
448    {
449	ptr->tag = 1;
450	return (ptr->client_id);
451    }
452    else
453	return NULL;
454}
455