save.c revision 24047306
114c0a534Smrg/******************************************************************************
214c0a534Smrg
314c0a534SmrgCopyright 1994, 1998  The Open Group
414c0a534Smrg
514c0a534SmrgPermission to use, copy, modify, distribute, and sell this software and its
614c0a534Smrgdocumentation for any purpose is hereby granted without fee, provided that
714c0a534Smrgthe above copyright notice appear in all copies and that both that
814c0a534Smrgcopyright notice and this permission notice appear in supporting
914c0a534Smrgdocumentation.
1014c0a534Smrg
1114c0a534SmrgThe above copyright notice and this permission notice shall be included in
1214c0a534Smrgall copies or substantial portions of the Software.
1314c0a534Smrg
1414c0a534SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1514c0a534SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1614c0a534SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1714c0a534SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1814c0a534SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1914c0a534SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2014c0a534Smrg
2114c0a534SmrgExcept as contained in this notice, the name of The Open Group shall not be
2214c0a534Smrgused in advertising or otherwise to promote the sale, use or other dealings
2314c0a534Smrgin this Software without prior written authorization from The Open Group.
2414c0a534Smrg
2514c0a534SmrgAuthor:  Ralph Mor, X Consortium
2614c0a534Smrg******************************************************************************/
2714c0a534Smrg
2814c0a534Smrg#include "smproxy.h"
29576bae58Smrg#ifdef HAVE_MKSTEMP
3014c0a534Smrg#include <unistd.h>
3114c0a534Smrg#endif
3214c0a534Smrg
3314c0a534Smrg
34bf2eeab3Smrgstatic ProxyFileEntry *proxyFileHead = NULL;
3514c0a534Smrg
3614c0a534Smrgstatic int write_byte ( FILE *file, unsigned char b );
3714c0a534Smrgstatic int write_short ( FILE *file, unsigned short s );
3814c0a534Smrgstatic int write_counted_string ( FILE *file, char *string );
3914c0a534Smrgstatic int read_byte ( FILE *file, unsigned char *bp );
4014c0a534Smrgstatic int read_short ( FILE *file, unsigned short *shortp );
4114c0a534Smrgstatic int read_counted_string ( FILE *file, char **stringp );
4224047306Smrg
4324047306Smrg#ifndef HAVE_ASPRINTF
4424047306Smrg# include <stdarg.h>
4524047306Smrg
4624047306Smrg/* sprintf variant found in newer libc's which allocates string to print to */
4724047306Smrg_X_HIDDEN int _X_ATTRIBUTE_PRINTF(2,3)
4824047306Smrgasprintf(char ** ret, const char *format, ...)
4924047306Smrg{
5024047306Smrg    char buf[256];
5124047306Smrg    int len;
5224047306Smrg    va_list ap;
5324047306Smrg
5424047306Smrg    va_start(ap, format);
5524047306Smrg    len = vsnprintf(buf, sizeof(buf), format, ap);
5624047306Smrg    va_end(ap);
5724047306Smrg
5824047306Smrg    if (len < 0)
5924047306Smrg	return -1;
6024047306Smrg
6124047306Smrg    if (len < sizeof(buf))
6224047306Smrg    {
6324047306Smrg	*ret = strdup(buf);
6424047306Smrg    }
6524047306Smrg    else
6624047306Smrg    {
6724047306Smrg	*ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */
6824047306Smrg	if (*ret != NULL)
6924047306Smrg	{
7024047306Smrg	    va_start(ap, format);
7124047306Smrg	    len = vsnprintf(*ret, len + 1, format, ap);
7224047306Smrg	    va_end(ap);
7324047306Smrg	    if (len < 0) {
7424047306Smrg		free(*ret);
7524047306Smrg		*ret = NULL;
7624047306Smrg	    }
7724047306Smrg	}
7824047306Smrg    }
7924047306Smrg
8024047306Smrg    if (*ret == NULL)
8124047306Smrg	return -1;
8224047306Smrg
8324047306Smrg    return len;
8424047306Smrg}
8514c0a534Smrg#endif
8614c0a534Smrg
8724047306Smrg
8814c0a534Smrg
8914c0a534Smrgstatic int
9014c0a534Smrgwrite_byte (FILE *file, unsigned char b)
9114c0a534Smrg{
9214c0a534Smrg    if (fwrite ((char *) &b, 1, 1, file) != 1)
9314c0a534Smrg	return 0;
9414c0a534Smrg    return 1;
9514c0a534Smrg}
9614c0a534Smrg
9714c0a534Smrg
9814c0a534Smrgstatic int
9914c0a534Smrgwrite_short (FILE *file, unsigned short s)
10014c0a534Smrg{
10114c0a534Smrg    unsigned char   file_short[2];
10214c0a534Smrg
10314c0a534Smrg    file_short[0] = (s & (unsigned)0xff00) >> 8;
10414c0a534Smrg    file_short[1] = s & 0xff;
10514c0a534Smrg    if (fwrite ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
10614c0a534Smrg	return 0;
10714c0a534Smrg    return 1;
10814c0a534Smrg}
10914c0a534Smrg
11014c0a534Smrg
11114c0a534Smrgstatic int
112bf2eeab3Smrgwrite_counted_string(FILE *file, char *string)
11314c0a534Smrg{
11414c0a534Smrg    if (string)
11514c0a534Smrg    {
11614c0a534Smrg	unsigned char count = strlen (string);
11714c0a534Smrg
11814c0a534Smrg	if (write_byte (file, count) == 0)
11914c0a534Smrg	    return 0;
12014c0a534Smrg	if (fwrite (string, (int) sizeof (char), (int) count, file) != count)
12114c0a534Smrg	    return 0;
12214c0a534Smrg    }
12314c0a534Smrg    else
12414c0a534Smrg    {
12514c0a534Smrg	if (write_byte (file, 0) == 0)
12614c0a534Smrg	    return 0;
12714c0a534Smrg    }
12814c0a534Smrg
12914c0a534Smrg    return 1;
13014c0a534Smrg}
13114c0a534Smrg
13214c0a534Smrg
13314c0a534Smrg
13414c0a534Smrgstatic int
135bf2eeab3Smrgread_byte(FILE *file, unsigned char *bp)
13614c0a534Smrg{
13714c0a534Smrg    if (fread ((char *) bp, 1, 1, file) != 1)
13814c0a534Smrg	return 0;
13914c0a534Smrg    return 1;
14014c0a534Smrg}
14114c0a534Smrg
14214c0a534Smrg
14314c0a534Smrgstatic int
144bf2eeab3Smrgread_short(FILE *file, unsigned short *shortp)
14514c0a534Smrg{
14614c0a534Smrg    unsigned char   file_short[2];
14714c0a534Smrg
14814c0a534Smrg    if (fread ((char *) file_short, (int) sizeof (file_short), 1, file) != 1)
14914c0a534Smrg	return 0;
15014c0a534Smrg    *shortp = file_short[0] * 256 + file_short[1];
15114c0a534Smrg    return 1;
15214c0a534Smrg}
15314c0a534Smrg
15414c0a534Smrg
15514c0a534Smrgstatic int
156bf2eeab3Smrgread_counted_string(FILE *file, char **stringp)
15714c0a534Smrg{
15814c0a534Smrg    unsigned char  len;
15914c0a534Smrg    char	   *data;
16014c0a534Smrg
16114c0a534Smrg    if (read_byte (file, &len) == 0)
16214c0a534Smrg	return 0;
16314c0a534Smrg    if (len == 0) {
164bf2eeab3Smrg	data = NULL;
16514c0a534Smrg    } else {
16614c0a534Smrg    	data = (char *) malloc ((unsigned) len + 1);
16714c0a534Smrg    	if (!data)
16814c0a534Smrg	    return 0;
16914c0a534Smrg    	if (fread (data, (int) sizeof (char), (int) len, file) != len) {
17014c0a534Smrg	    free (data);
17114c0a534Smrg	    return 0;
17214c0a534Smrg    	}
17314c0a534Smrg	data[len] = '\0';
17414c0a534Smrg    }
17514c0a534Smrg    *stringp = data;
17614c0a534Smrg    return 1;
17714c0a534Smrg}
17814c0a534Smrg
17914c0a534Smrg
18014c0a534Smrg
18114c0a534Smrg/*
18214c0a534Smrg * An entry in the .smproxy file looks like this:
18314c0a534Smrg *
18414c0a534Smrg * FIELD				BYTES
18514c0a534Smrg * -----                                ----
18614c0a534Smrg * client ID len			1
18714c0a534Smrg * client ID				LIST of bytes
18814c0a534Smrg * WM_CLASS "res name" length		1
18914c0a534Smrg * WM_CLASS "res name"			LIST of bytes
19014c0a534Smrg * WM_CLASS "res class" length          1
19114c0a534Smrg * WM_CLASS "res class"                 LIST of bytes
19214c0a534Smrg * WM_NAME length			1
19314c0a534Smrg * WM_NAME				LIST of bytes
19414c0a534Smrg * WM_COMMAND arg count			1
19514c0a534Smrg * For each arg in WM_COMMAND
19614c0a534Smrg *    arg length			1
19714c0a534Smrg *    arg				LIST of bytes
19814c0a534Smrg */
19914c0a534Smrg
20014c0a534Smrgint
201bf2eeab3SmrgWriteProxyFileEntry(FILE *proxyFile, WinInfo *theWindow)
20214c0a534Smrg{
20314c0a534Smrg    int i;
20414c0a534Smrg
20514c0a534Smrg    if (!write_counted_string (proxyFile, theWindow->client_id))
20614c0a534Smrg	return 0;
20714c0a534Smrg    if (!write_counted_string (proxyFile, theWindow->class.res_name))
20814c0a534Smrg	return 0;
20914c0a534Smrg    if (!write_counted_string (proxyFile, theWindow->class.res_class))
21014c0a534Smrg	return 0;
21114c0a534Smrg    if (!write_counted_string (proxyFile, theWindow->wm_name))
21214c0a534Smrg	return 0;
21314c0a534Smrg
21414c0a534Smrg    if (!theWindow->wm_command || theWindow->wm_command_count == 0)
21514c0a534Smrg    {
21614c0a534Smrg	if (!write_byte (proxyFile, 0))
21714c0a534Smrg	    return 0;
21814c0a534Smrg    }
21914c0a534Smrg    else
22014c0a534Smrg    {
22114c0a534Smrg	if (!write_byte (proxyFile, (char) theWindow->wm_command_count))
22214c0a534Smrg	    return 0;
22314c0a534Smrg	for (i = 0; i < theWindow->wm_command_count; i++)
22414c0a534Smrg	    if (!write_counted_string (proxyFile, theWindow->wm_command[i]))
22514c0a534Smrg		return 0;
22614c0a534Smrg    }
22714c0a534Smrg
22814c0a534Smrg    return 1;
22914c0a534Smrg}
23014c0a534Smrg
23114c0a534Smrg
23214c0a534Smrgint
233bf2eeab3SmrgReadProxyFileEntry(FILE *proxyFile, ProxyFileEntry **pentry)
23414c0a534Smrg{
23514c0a534Smrg    ProxyFileEntry *entry;
23614c0a534Smrg    unsigned char byte;
23714c0a534Smrg    int i;
23814c0a534Smrg
23914c0a534Smrg    *pentry = entry = (ProxyFileEntry *) malloc (
24014c0a534Smrg	sizeof (ProxyFileEntry));
24114c0a534Smrg    if (!*pentry)
24214c0a534Smrg	return 0;
24314c0a534Smrg
24414c0a534Smrg    entry->tag = 0;
24514c0a534Smrg    entry->client_id = NULL;
24614c0a534Smrg    entry->class.res_name = NULL;
24714c0a534Smrg    entry->class.res_class = NULL;
24814c0a534Smrg    entry->wm_name = NULL;
24914c0a534Smrg    entry->wm_command = NULL;
25014c0a534Smrg    entry->wm_command_count = 0;
25114c0a534Smrg
25214c0a534Smrg    if (!read_counted_string (proxyFile, &entry->client_id))
25314c0a534Smrg	goto give_up;
25414c0a534Smrg    if (!read_counted_string (proxyFile, &entry->class.res_name))
25514c0a534Smrg	goto give_up;
25614c0a534Smrg    if (!read_counted_string (proxyFile, &entry->class.res_class))
25714c0a534Smrg	goto give_up;
25814c0a534Smrg    if (!read_counted_string (proxyFile, &entry->wm_name))
25914c0a534Smrg	goto give_up;
26014c0a534Smrg
26114c0a534Smrg    if (!read_byte (proxyFile, &byte))
26214c0a534Smrg	goto give_up;
26314c0a534Smrg    entry->wm_command_count = byte;
26414c0a534Smrg
26514c0a534Smrg    if (entry->wm_command_count == 0)
26614c0a534Smrg	entry->wm_command = NULL;
26714c0a534Smrg    else
26814c0a534Smrg    {
26914c0a534Smrg	entry->wm_command = (char **) malloc (entry->wm_command_count *
27014c0a534Smrg	    sizeof (char *));
27114c0a534Smrg
27214c0a534Smrg	if (!entry->wm_command)
27314c0a534Smrg	    goto give_up;
27414c0a534Smrg
27514c0a534Smrg	for (i = 0; i < entry->wm_command_count; i++)
27614c0a534Smrg	    if (!read_counted_string (proxyFile, &entry->wm_command[i]))
27714c0a534Smrg		goto give_up;
27814c0a534Smrg    }
27914c0a534Smrg
28014c0a534Smrg    return 1;
28114c0a534Smrg
28214c0a534Smrggive_up:
28314c0a534Smrg
28414c0a534Smrg    if (entry->client_id)
28514c0a534Smrg	free (entry->client_id);
28614c0a534Smrg    if (entry->class.res_name)
28714c0a534Smrg	free (entry->class.res_name);
28814c0a534Smrg    if (entry->class.res_class)
28914c0a534Smrg	free (entry->class.res_class);
29014c0a534Smrg    if (entry->wm_name)
29114c0a534Smrg	free (entry->wm_name);
29214c0a534Smrg    if (entry->wm_command)
2931a054510Smrg    {
2941a054510Smrg        if (entry->wm_command_count)
2951a054510Smrg        {
2961a054510Smrg	    for (i = 0; i < entry->wm_command_count; i++)
2971a054510Smrg	        if (entry->wm_command[i])
2981a054510Smrg		    free (entry->wm_command[i]);
2991a054510Smrg        }
30014c0a534Smrg	free ((char *) entry->wm_command);
3011a054510Smrg    }
3021a054510Smrg
30314c0a534Smrg    free ((char *) entry);
30414c0a534Smrg    *pentry = NULL;
30514c0a534Smrg
30614c0a534Smrg    return 0;
30714c0a534Smrg}
30814c0a534Smrg
30914c0a534Smrg
31014c0a534Smrgvoid
311bf2eeab3SmrgReadProxyFile(char *filename)
31214c0a534Smrg{
31314c0a534Smrg    FILE *proxyFile;
31414c0a534Smrg    ProxyFileEntry *entry;
31514c0a534Smrg    int done = 0;
31614c0a534Smrg    unsigned short version;
31714c0a534Smrg
31814c0a534Smrg    proxyFile = fopen (filename, "rb");
31914c0a534Smrg    if (!proxyFile)
32014c0a534Smrg	return;
32114c0a534Smrg
32214c0a534Smrg    if (!read_short (proxyFile, &version) ||
32314c0a534Smrg	version > SAVEFILE_VERSION)
32414c0a534Smrg    {
32514c0a534Smrg	done = 1;
32614c0a534Smrg    }
32714c0a534Smrg
32814c0a534Smrg    while (!done)
32914c0a534Smrg    {
33014c0a534Smrg	if (ReadProxyFileEntry (proxyFile, &entry))
33114c0a534Smrg	{
33214c0a534Smrg	    entry->next = proxyFileHead;
33314c0a534Smrg	    proxyFileHead = entry;
33414c0a534Smrg	}
33514c0a534Smrg	else
33614c0a534Smrg	    done = 1;
33714c0a534Smrg    }
33814c0a534Smrg
33914c0a534Smrg    fclose (proxyFile);
34014c0a534Smrg}
34114c0a534Smrg
34214c0a534Smrg
34314c0a534Smrg
34414c0a534Smrgstatic char *
34524047306Smrgunique_filename(const char *path, const char *prefix, int *pFd)
34614c0a534Smrg{
34724047306Smrg    char *tempFile = NULL;
34824047306Smrg    int tempFd = 0;
34924047306Smrg
35024047306Smrg#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP)
35124047306Smrg    if (asprintf (&tempFile, "%s/%sXXXXXX", path, prefix) == -1)
35224047306Smrg	return NULL;
35324047306Smrg#endif
35424047306Smrg
35524047306Smrg#ifdef HAVE_MKSTEMP
35624047306Smrg    tempFd = mkstemp(tempFile);
35714c0a534Smrg#else
35814c0a534Smrg
35924047306Smrg# ifdef HAVE_MKTEMP
36024047306Smrg    if (mktemp(tempFile) == NULL)
36124047306Smrg	tempFd = -1;
36224047306Smrg# else /* fallback to tempnam */
36324047306Smrg    tempFile = tempnam (path, prefix);
36424047306Smrg# endif /* HAVE_MKTEMP */
36524047306Smrg
36624047306Smrg    if (tempFd != -1 && tempFile != NULL)
36724047306Smrg	tempFd = open(tempFile, O_RDWR | O_CREAT | O_EXCL, 0600);
36814c0a534Smrg#endif
36914c0a534Smrg
37024047306Smrg    if (tempFd == -1) {
37124047306Smrg	free(tempFile);
37224047306Smrg	return (NULL);
37314c0a534Smrg    }
37424047306Smrg
37524047306Smrg    *pFd = tempFd;
37624047306Smrg    return tempFile;
37724047306Smrg
37814c0a534Smrg}
37914c0a534Smrg
38014c0a534Smrg
38114c0a534Smrg
38214c0a534Smrgchar *
383bf2eeab3SmrgWriteProxyFile(void)
38414c0a534Smrg{
38514c0a534Smrg    FILE *proxyFile = NULL;
38614c0a534Smrg    char *filename = NULL;
38724047306Smrg    int fd = -1;
38824047306Smrg    const char *path;
38914c0a534Smrg    WinInfo *winptr;
39014c0a534Smrg    Bool success = False;
39114c0a534Smrg
39214c0a534Smrg    path = getenv ("SM_SAVE_DIR");
39314c0a534Smrg    if (!path)
39414c0a534Smrg    {
39514c0a534Smrg	path = getenv ("HOME");
39614c0a534Smrg	if (!path)
39714c0a534Smrg	    path = ".";
39814c0a534Smrg    }
39914c0a534Smrg
40014c0a534Smrg    if ((filename = unique_filename (path, ".prx", &fd)) == NULL)
40114c0a534Smrg	goto bad;
40214c0a534Smrg
40314c0a534Smrg    if (!(proxyFile = fdopen(fd, "wb")))
40414c0a534Smrg	goto bad;
40524047306Smrg
40614c0a534Smrg    if (!write_short (proxyFile, SAVEFILE_VERSION))
40714c0a534Smrg	goto bad;
40814c0a534Smrg
40914c0a534Smrg    success = True;
41014c0a534Smrg    winptr = win_head;
41114c0a534Smrg
41214c0a534Smrg    while (winptr && success)
41314c0a534Smrg    {
41414c0a534Smrg	if (winptr->client_id)
41514c0a534Smrg	    if (!WriteProxyFileEntry (proxyFile, winptr))
41614c0a534Smrg	    {
41714c0a534Smrg		success = False;
41814c0a534Smrg		break;
41914c0a534Smrg	    }
42014c0a534Smrg
42114c0a534Smrg	winptr = winptr->next;
42214c0a534Smrg    }
42314c0a534Smrg
42414c0a534Smrg bad:
42514c0a534Smrg
42614c0a534Smrg    if (proxyFile)
42714c0a534Smrg	fclose (proxyFile);
42824047306Smrg    else if (fd != -1)
42924047306Smrg	close (fd);
43014c0a534Smrg
43114c0a534Smrg    if (success)
43214c0a534Smrg	return (filename);
43314c0a534Smrg    else
43414c0a534Smrg    {
43514c0a534Smrg	if (filename)
43614c0a534Smrg	    free (filename);
43714c0a534Smrg	return (NULL);
43814c0a534Smrg    }
43914c0a534Smrg}
44014c0a534Smrg
44114c0a534Smrg
44214c0a534Smrg
44314c0a534Smrgchar *
444bf2eeab3SmrgLookupClientID(WinInfo *theWindow)
44514c0a534Smrg{
44614c0a534Smrg    ProxyFileEntry *ptr;
44714c0a534Smrg    int found = 0;
44814c0a534Smrg
44914c0a534Smrg    ptr = proxyFileHead;
45014c0a534Smrg    while (ptr && !found)
45114c0a534Smrg    {
45214c0a534Smrg	if (!ptr->tag &&
45314c0a534Smrg            strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 &&
45414c0a534Smrg	    strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 &&
45514c0a534Smrg	    strcmp (theWindow->wm_name, ptr->wm_name) == 0)
45614c0a534Smrg	{
45714c0a534Smrg	    int i;
45814c0a534Smrg
45914c0a534Smrg	    if (theWindow->wm_command_count == ptr->wm_command_count)
46014c0a534Smrg	    {
46114c0a534Smrg		for (i = 0; i < theWindow->wm_command_count; i++)
46214c0a534Smrg		    if (strcmp (theWindow->wm_command[i],
46314c0a534Smrg			ptr->wm_command[i]) != 0)
46414c0a534Smrg			break;
46514c0a534Smrg
46614c0a534Smrg		if (i == theWindow->wm_command_count)
46714c0a534Smrg		    found = 1;
46814c0a534Smrg	    }
46914c0a534Smrg	}
47014c0a534Smrg
47114c0a534Smrg	if (!found)
47214c0a534Smrg	    ptr = ptr->next;
47314c0a534Smrg    }
47414c0a534Smrg
47514c0a534Smrg    if (found)
47614c0a534Smrg    {
47714c0a534Smrg	ptr->tag = 1;
47814c0a534Smrg	return (ptr->client_id);
47914c0a534Smrg    }
48014c0a534Smrg    else
48114c0a534Smrg	return NULL;
48214c0a534Smrg}
483