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 (&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 (file_short, 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 size_t count = strlen (string); 117 118 if (write_byte (file, (unsigned char)count) == 0) 119 return 0; 120 if (fwrite (string, sizeof (char), 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 (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 (file_short, 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 = malloc ((size_t) len + 1); 167 if (!data) 168 return 0; 169 if (fread (data, sizeof (char), (size_t) 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 if (!write_counted_string (proxyFile, theWindow->client_id)) 204 return 0; 205 if (!write_counted_string (proxyFile, theWindow->class.res_name)) 206 return 0; 207 if (!write_counted_string (proxyFile, theWindow->class.res_class)) 208 return 0; 209 if (!write_counted_string (proxyFile, theWindow->wm_name)) 210 return 0; 211 212 if (!theWindow->wm_command || theWindow->wm_command_count == 0) 213 { 214 if (!write_byte (proxyFile, 0)) 215 return 0; 216 } 217 else 218 { 219 if (!write_byte (proxyFile, (char) theWindow->wm_command_count)) 220 return 0; 221 for (int i = 0; i < theWindow->wm_command_count; i++) 222 if (!write_counted_string (proxyFile, theWindow->wm_command[i])) 223 return 0; 224 } 225 226 return 1; 227} 228 229 230int 231ReadProxyFileEntry(FILE *proxyFile, ProxyFileEntry **pentry) 232{ 233 ProxyFileEntry *entry; 234 unsigned char byte; 235 int i; 236 237 *pentry = entry = malloc (sizeof (ProxyFileEntry)); 238 if (!*pentry) 239 return 0; 240 241 entry->tag = 0; 242 entry->client_id = NULL; 243 entry->class.res_name = NULL; 244 entry->class.res_class = NULL; 245 entry->wm_name = NULL; 246 entry->wm_command = NULL; 247 entry->wm_command_count = 0; 248 249 if (!read_counted_string (proxyFile, &entry->client_id)) 250 goto give_up; 251 if (!read_counted_string (proxyFile, &entry->class.res_name)) 252 goto give_up; 253 if (!read_counted_string (proxyFile, &entry->class.res_class)) 254 goto give_up; 255 if (!read_counted_string (proxyFile, &entry->wm_name)) 256 goto give_up; 257 258 if (!read_byte (proxyFile, &byte)) 259 goto give_up; 260 entry->wm_command_count = byte; 261 262 if (entry->wm_command_count == 0) 263 entry->wm_command = NULL; 264 else 265 { 266 entry->wm_command = calloc (entry->wm_command_count, sizeof (char *)); 267 268 if (!entry->wm_command) 269 goto give_up; 270 271 for (i = 0; i < entry->wm_command_count; i++) 272 if (!read_counted_string (proxyFile, &entry->wm_command[i])) 273 goto give_up; 274 } 275 276 return 1; 277 278give_up: 279 280 if (entry->client_id) 281 free (entry->client_id); 282 if (entry->class.res_name) 283 free (entry->class.res_name); 284 if (entry->class.res_class) 285 free (entry->class.res_class); 286 if (entry->wm_name) 287 free (entry->wm_name); 288 if (entry->wm_command) 289 { 290 if (entry->wm_command_count) 291 { 292 for (i = 0; i < entry->wm_command_count; i++) 293 if (entry->wm_command[i]) 294 free (entry->wm_command[i]); 295 } 296 free (entry->wm_command); 297 } 298 299 free (entry); 300 *pentry = NULL; 301 302 return 0; 303} 304 305 306void 307ReadProxyFile(char *filename) 308{ 309 FILE *proxyFile; 310 ProxyFileEntry *entry; 311 int done = 0; 312 unsigned short version; 313 314 proxyFile = fopen (filename, "rb"); 315 if (!proxyFile) 316 return; 317 318 if (!read_short (proxyFile, &version) || 319 version > SAVEFILE_VERSION) 320 { 321 done = 1; 322 } 323 324 while (!done) 325 { 326 if (ReadProxyFileEntry (proxyFile, &entry)) 327 { 328 entry->next = proxyFileHead; 329 proxyFileHead = entry; 330 } 331 else 332 done = 1; 333 } 334 335 fclose (proxyFile); 336} 337 338 339 340static char * 341unique_filename(const char *path, const char *prefix, int *pFd) 342{ 343 char *tempFile = NULL; 344 int tempFd = 0; 345 346#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP) 347 if (asprintf (&tempFile, "%s/%sXXXXXX", path, prefix) == -1) 348 return NULL; 349#endif 350 351#ifdef HAVE_MKSTEMP 352 tempFd = mkstemp(tempFile); 353#else 354 355# ifdef HAVE_MKTEMP 356 if (mktemp(tempFile) == NULL) 357 tempFd = -1; 358# else /* fallback to tempnam */ 359 tempFile = tempnam (path, prefix); 360# endif /* HAVE_MKTEMP */ 361 362 if (tempFd != -1 && tempFile != NULL) 363 tempFd = open(tempFile, O_RDWR | O_CREAT | O_EXCL, 0600); 364#endif 365 366 if (tempFd == -1) { 367 free(tempFile); 368 return (NULL); 369 } 370 371 *pFd = tempFd; 372 return tempFile; 373 374} 375 376 377 378char * 379WriteProxyFile(void) 380{ 381 FILE *proxyFile = NULL; 382 char *filename = NULL; 383 int fd = -1; 384 const char *path; 385 WinInfo *winptr; 386 Bool success = False; 387 388 path = getenv ("SM_SAVE_DIR"); 389 if (!path) 390 { 391 path = getenv ("HOME"); 392 if (!path) 393 path = "."; 394 } 395 396 if ((filename = unique_filename (path, ".prx", &fd)) == NULL) 397 goto bad; 398 399 if (!(proxyFile = fdopen(fd, "wb"))) 400 goto bad; 401 402 if (!write_short (proxyFile, SAVEFILE_VERSION)) 403 goto bad; 404 405 success = True; 406 winptr = win_head; 407 408 while (winptr && success) 409 { 410 if (winptr->client_id) 411 if (!WriteProxyFileEntry (proxyFile, winptr)) 412 { 413 success = False; 414 break; 415 } 416 417 winptr = winptr->next; 418 } 419 420 bad: 421 422 if (proxyFile) 423 fclose (proxyFile); 424 else if (fd != -1) 425 close (fd); 426 427 if (success) 428 return (filename); 429 else 430 { 431 if (filename) 432 free (filename); 433 return (NULL); 434 } 435} 436 437 438 439char * 440LookupClientID(WinInfo *theWindow) 441{ 442 ProxyFileEntry *ptr; 443 int found = 0; 444 445 ptr = proxyFileHead; 446 while (ptr && !found) 447 { 448 if (!ptr->tag && 449 strcmp (theWindow->class.res_name, ptr->class.res_name) == 0 && 450 strcmp (theWindow->class.res_class, ptr->class.res_class) == 0 && 451 strcmp (theWindow->wm_name, ptr->wm_name) == 0) 452 { 453 if (theWindow->wm_command_count == ptr->wm_command_count) 454 { 455 int i; 456 457 for (i = 0; i < theWindow->wm_command_count; i++) 458 if (strcmp (theWindow->wm_command[i], 459 ptr->wm_command[i]) != 0) 460 break; 461 462 if (i == theWindow->wm_command_count) 463 found = 1; 464 } 465 } 466 467 if (!found) 468 ptr = ptr->next; 469 } 470 471 if (found) 472 { 473 ptr->tag = 1; 474 return (ptr->client_id); 475 } 476 else 477 return NULL; 478} 479