save.c 9.9 KB

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