1 /*
2    Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3    All rights reserved.
4 
5 This file is part of x11vnc.
6 
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11 
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21 
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables.  You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL".  If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so.  If you do not wish to do
30 so, delete this exception statement from your version.
31 */
32 
33 /* -- gui.c -- */
34 
35 #include "x11vnc.h"
36 #include "xevents.h"
37 #include "win_utils.h"
38 #include "remote.h"
39 #include "cleanup.h"
40 #include "xwrappers.h"
41 #include "connections.h"
42 
43 #include "tkx11vnc.h"
44 
45 #define SYSTEM_TRAY_REQUEST_DOCK    0
46 #define SYSTEM_TRAY_BEGIN_MESSAGE   1
47 #define SYSTEM_TRAY_CANCEL_MESSAGE  2
48 #define XEMBED_VERSION 0
49 #define XEMBED_MAPPED  (1 << 0)
50 
51 int icon_mode = 0;		/* hack for -gui tray/icon */
52 char *icon_mode_file = NULL;
53 FILE *icon_mode_fh = NULL;
54 int icon_mode_socks[ICON_MODE_SOCKS];
55 int tray_manager_ok = 0;
56 Window tray_request = None;
57 Window tray_window = None;
58 int tray_unembed = 0;
59 pid_t run_gui_pid = 0;
60 pid_t gui_pid = 0;
61 
62 
63 char *get_gui_code(void);
64 int tray_embed(Window iconwin, int remove);
65 void do_gui(char *opts, int sleep);
66 
67 
68 static Window tweak_tk_window_id(Window win);
69 static int tray_manager_running(Display *d, Window *manager);
70 static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc,
71     int simple_gui, pid_t parent, char *gui_opts);
72 
73 
get_gui_code(void)74 char *get_gui_code(void) {
75 	return gui_code;
76 }
77 
tweak_tk_window_id(Window win)78 static Window tweak_tk_window_id(Window win) {
79 #if NO_X11
80 	if (!win) {}
81 	return None;
82 #else
83 	char *name = NULL;
84 	Window parent, new_win;
85 
86 	if (getenv("NO_TWEAK_TK_WINDOW_ID")) {
87 		return win;
88 	}
89 
90 	/* hack for tk, does not report outermost window */
91 	new_win = win;
92 	parent = parent_window(win, &name);
93 	if (parent && name != NULL) {
94 		lowercase(name);
95 		if (strstr(name, "wish") || strstr(name, "x11vnc")) {
96 			new_win = parent;
97 			rfbLog("tray_embed: using parent: %s\n", name);
98 		}
99 	}
100 	if (name != NULL) {
101 		XFree_wr(name);
102 	}
103 	return new_win;
104 #endif	/* NO_X11 */
105 }
106 
tray_embed(Window iconwin,int remove)107 int tray_embed(Window iconwin, int remove) {
108 #if NO_X11
109 	RAWFB_RET(0)
110 	if (!iconwin || !remove) {}
111 	return 0;
112 #else
113 	XEvent ev;
114 	XErrorHandler old_handler;
115 	Window manager;
116 	Atom xembed_info;
117 	Atom tatom;
118 	XWindowAttributes attr;
119 	long info[2] = {XEMBED_VERSION, XEMBED_MAPPED};
120 	long data = 0;
121 
122 	RAWFB_RET(0)
123 
124 	if (remove) {
125 		if (!valid_window(iconwin, &attr, 1)) {
126 			return 0;
127 		}
128 		iconwin = tweak_tk_window_id(iconwin);
129 		trapped_xerror = 0;
130 		old_handler = XSetErrorHandler(trap_xerror);
131 
132 		/*
133 		 * unfortunately no desktops seem to obey this
134 		 * part of the XEMBED spec yet...
135 		 */
136 		XReparentWindow(dpy, iconwin, rootwin, 0, 0);
137 
138 		XSetErrorHandler(old_handler);
139 		if (trapped_xerror) {
140 			trapped_xerror = 0;
141 			return 0;
142 		}
143 		trapped_xerror = 0;
144 		return 1;
145 	}
146 
147 	xembed_info = XInternAtom(dpy, "_XEMBED_INFO", False);
148 	if (xembed_info == None) {
149 		return 0;
150 	}
151 
152 	if (!tray_manager_running(dpy, &manager)) {
153 		return 0;
154 	}
155 
156 	memset(&ev, 0, sizeof(ev));
157 	ev.xclient.type = ClientMessage;
158 	ev.xclient.window = manager;
159 	ev.xclient.message_type = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE",
160 	    False);
161 	ev.xclient.format = 32;
162 	ev.xclient.data.l[0] = CurrentTime;
163 	ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
164 	ev.xclient.data.l[2] = iconwin;
165 	ev.xclient.data.l[3] = 0;
166 	ev.xclient.data.l[4] = 0;
167 
168 	if (!valid_window(iconwin, &attr, 1)) {
169 		return 0;
170 	}
171 
172 	iconwin = tweak_tk_window_id(iconwin);
173 	ev.xclient.data.l[2] = iconwin;
174 
175 	XUnmapWindow(dpy, iconwin);
176 
177 	trapped_xerror = 0;
178 	old_handler = XSetErrorHandler(trap_xerror);
179 
180 	XSendEvent(dpy, manager, False, NoEventMask, &ev);
181 	XSync(dpy, False);
182 
183 	if (trapped_xerror) {
184 		XSetErrorHandler(old_handler);
185 		trapped_xerror = 0;
186 		return 0;
187 	}
188 
189 	XChangeProperty(dpy, iconwin, xembed_info, xembed_info, 32,
190 	    PropModeReplace, (unsigned char *)&info, 2);
191 
192 #if 0
193 {
194 XSizeHints *xszh = XAllocSizeHints();
195 xszh->flags = PMinSize;
196 xszh->min_width = 24;
197 xszh->min_height = 24;
198 XSetWMNormalHints(dpy, iconwin, xszh);
199 }
200 #endif
201 
202 	/* kludge for KDE evidently needed... */
203 	tatom = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
204 	XChangeProperty(dpy, iconwin, tatom, tatom, 32, PropModeReplace,
205 	    (unsigned char *)&data, 1);
206 	tatom = XInternAtom(dpy, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
207 	XChangeProperty(dpy, iconwin, tatom, XA_WINDOW, 32, PropModeReplace,
208 	    (unsigned char *)&data, 1);
209 
210 	XSetErrorHandler(old_handler);
211 	trapped_xerror = 0;
212 	return 1;
213 #endif	/* NO_X11 */
214 }
215 
tray_manager_running(Display * d,Window * manager)216 static int tray_manager_running(Display *d, Window *manager) {
217 #if NO_X11
218 	RAWFB_RET(0)
219 	if (!d || !manager) {}
220 	return 0;
221 #else
222 	char tray_string[100];
223 	Atom tray_manager;
224 	Window tray_win;
225 
226 	RAWFB_RET(0)
227 
228 	if (manager) {
229 		*manager = None;
230 	}
231 	sprintf(tray_string, "_NET_SYSTEM_TRAY_S%d", scr);
232 
233 	tray_manager = XInternAtom(d, tray_string, True);
234 	if (tray_manager == None) {
235 		return 0;
236 	}
237 
238 	tray_win = XGetSelectionOwner(d, tray_manager);
239 	if (manager) {
240 		*manager = tray_win;
241 	}
242 
243 	if (tray_win == None) {
244 		return 0;
245 	} else {
246 		return 1;
247 	}
248 #endif	/* NO_X11 */
249 }
250 
251 static char *gui_geometry = NULL;
252 static int icon_in_tray = 0;
253 static char *icon_mode_embed_id = NULL;
254 static char *icon_mode_font = NULL;
255 static char *icon_mode_params = NULL;
256 
257 static int got_sigusr1 = 0;
258 
sigusr1(int sig)259 static void sigusr1 (int sig) {
260 	got_sigusr1 = 1;
261 	if (0) sig = 0;
262 }
263 
264 /* Most of the following mess is for wish on Solaris: */
265 
266 static char *extra_path = ":/usr/local/bin:/usr/bin/X11:/usr/sfw/bin"
267 	    ":/usr/X11R6/bin:/usr/openwin/bin:/usr/dt/bin:/opt/sfw/bin";
268 static char *wishes[] = {"wish8.4", "wish", "wish8.3", "wish8.5", "wish8.6", "wish8.7", "wishx", "wish8.0", NULL};
269 
run_gui(char * gui_xdisplay,int connect_to_x11vnc,int start_x11vnc,int simple_gui,pid_t parent,char * gui_opts)270 static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc,
271     int simple_gui, pid_t parent, char *gui_opts) {
272 	char *x11vnc_xdisplay = NULL;
273 	char cmd[100];
274 	char *wish = NULL, *orig_path, *full_path, *tpath, *p;
275 	char *old_xauth = NULL;
276 	int try_max = 4, sleep = 300, totms, rc = 0;
277 	pid_t mypid = getpid();
278 	FILE *pipe, *tmpf;
279 
280 if (0) fprintf(stderr, "run_gui: %s -- %d %d\n", gui_xdisplay, connect_to_x11vnc, (int) parent);
281 	if (*gui_code == '\0') {
282 		rfbLog("gui: gui not compiled into this program.\n");
283 		exit(0);
284 	}
285 	if (getenv("DISPLAY") != NULL) {
286 		/* worst case */
287 		x11vnc_xdisplay = strdup(getenv("DISPLAY"));
288 	}
289 	if (use_dpy) {
290 		/* better */
291 		x11vnc_xdisplay = strdup(use_dpy);
292 	}
293 	if (connect_to_x11vnc) {
294 		int i;
295 		rfbLogEnable(1);
296 		if (! client_connect_file) {
297 			if (getenv("XAUTHORITY") != NULL) {
298 				old_xauth = strdup(getenv("XAUTHORITY"));
299 			} else {
300 				old_xauth = strdup("");
301 			}
302 			dpy = XOpenDisplay_wr(x11vnc_xdisplay);
303 			if (! dpy && auth_file) {
304 				set_env("XAUTHORITY", auth_file);
305 				dpy = XOpenDisplay_wr(x11vnc_xdisplay);
306 			}
307 			if (! dpy && ! x11vnc_xdisplay) {
308 				/* worstest case */
309 				x11vnc_xdisplay = strdup(":0");
310 				dpy = XOpenDisplay_wr(x11vnc_xdisplay);
311 			}
312 			if (! dpy) {
313 				rfbLog("gui: could not open x11vnc "
314 				    "display: %s\n", NONUL(x11vnc_xdisplay));
315 #ifdef MACOSX
316 				goto macjump;
317 #endif
318 				exit(1);
319 			}
320 			scr = DefaultScreen(dpy);
321 			rootwin = RootWindow(dpy, scr);
322 			initialize_vnc_connect_prop();
323 			initialize_x11vnc_remote_prop();
324 		}
325 
326 #ifdef MACOSX
327 		macjump:
328 #endif
329 
330 		signal(SIGUSR1, sigusr1);
331 		got_sigusr1 = 0;
332 		totms = 0;
333 		while (totms < 3500) {
334 			usleep(50*1000);
335 			totms += 50;
336 			if (got_sigusr1) {
337 				fprintf(stderr, "\n");
338 				if (! quiet) rfbLog("gui: got SIGUSR1\n");
339 				break;
340 			}
341 			if (! start_x11vnc && totms >= 150) {
342 				break;
343 			}
344 		}
345 		signal(SIGUSR1, SIG_DFL);
346 		if (! got_sigusr1) fprintf(stderr, "\n");
347 
348 		if (!quiet && ! got_sigusr1) {
349 			rfbLog("gui: trying to contact a x11vnc server at X"
350 			    " display %s ...\n", NONUL(x11vnc_xdisplay));
351 		}
352 
353 		for (i=0; i<try_max; i++) {
354 			if (! got_sigusr1) {
355 				if (!quiet) {
356 					rfbLog("gui: pinging %s try=%d ...\n",
357 					    NONUL(x11vnc_xdisplay), i+1);
358 				}
359 				rc = send_remote_cmd("qry=ping", 1, 1);
360 				if (rc == 0) {
361 					break;
362 				}
363 			} else {
364 				rc = 0;
365 				break;
366 			}
367 			if (parent && mypid != parent && kill(parent, 0) != 0) {
368 				rfbLog("gui: parent process %d has gone"
369 				    " away: bailing out.\n", parent);
370 				rc = 1;
371 				break;
372 			}
373 			usleep(sleep*1000);
374 		}
375 		set_env("X11VNC_XDISPLAY", x11vnc_xdisplay);
376 		if (getenv("XAUTHORITY") != NULL) {
377 			set_env("X11VNC_AUTH_FILE", getenv("XAUTHORITY"));
378 		}
379 		if (rc == 0) {
380 			rfbLog("gui: ping succeeded.\n");
381 			set_env("X11VNC_CONNECT", "1");
382 		} else {
383 			rfbLog("gui: could not connect to: '%s', try"
384 			    " again manually.\n", x11vnc_xdisplay);
385 		}
386 		if (client_connect_file) {
387 			set_env("X11VNC_CONNECT_FILE", client_connect_file);
388 		}
389 		if (dpy)  {
390 			XCloseDisplay_wr(dpy);
391 			dpy = NULL;
392 		}
393 		if (old_xauth) {
394 			if (*old_xauth == '\0') {
395 				/* wasn't set, hack it out if it is now */
396 				char *xauth = getenv("XAUTHORITY");
397 				if (xauth) {
398 					*(xauth-2) = '_';	/* yow */
399 				}
400 			} else {
401 				set_env("XAUTHORITY", old_xauth);
402 			}
403 			free(old_xauth);
404 		}
405 		rfbLogEnable(0);
406 	}
407 
408 	orig_path = getenv("PATH");
409 	if (! orig_path) {
410 		orig_path = strdup("/bin:/usr/bin:/usr/bin/X11");
411 	}
412 	full_path = (char *) malloc(strlen(orig_path)+strlen(extra_path)+1);
413 	strcpy(full_path, orig_path);
414 	strcat(full_path, extra_path);
415 
416 	tpath = strdup(full_path);
417 	p = strtok(tpath, ":");
418 
419 	while (p) {
420 		char *try;
421 		struct stat sbuf;
422 		int i;
423 
424 		try = (char *) malloc(strlen(p) + 1 + strlen("wish8.4") + 1);
425 		i = 0;
426 		while (wishes[i] != NULL) {
427 			sprintf(try, "%s/%s", p, wishes[i]);
428 			if (stat(try, &sbuf) == 0) {
429 				/* assume executable, should check mode */
430 				wish = wishes[i];
431 				break;
432 			}
433 			i++;
434 		}
435 		free(try);
436 		if (wish) {
437 			break;
438 		}
439 		p = strtok(NULL, ":");
440 	}
441 	free(tpath);
442 	if (!wish) {
443 		wish = strdup("wish");
444 	}
445 	if (getenv("WISH")) {
446 		char *w = getenv("WISH");
447 		if (strcmp(w, "")) {
448 			wish = strdup(w);
449 		}
450 	}
451 	if (getenv("DEBUG_WISH")) {
452 		fprintf(stderr, "wish: %s\n", wish);
453 	}
454 	set_env("PATH", full_path);
455 	set_env("DISPLAY", gui_xdisplay);
456 	set_env("X11VNC_PROG", program_name);
457 	set_env("X11VNC_CMDLINE", program_cmdline);
458 	set_env("X11VNC_WISHCMD", wish);
459 	if (simple_gui) {
460 		set_env("X11VNC_SIMPLE_GUI", "1");
461 	}
462 	if (gui_opts) {
463 		set_env("X11VNC_GUI_PARAMS", gui_opts);
464 	}
465 	if (gui_geometry) {
466 		set_env("X11VNC_GUI_GEOM", gui_geometry);
467 	}
468 	if (start_x11vnc) {
469 		set_env("X11VNC_STARTED", "1");
470 	}
471 	if (icon_mode) {
472 		set_env("X11VNC_ICON_MODE", "1");
473 		if (icon_mode_file) {
474 			set_env("X11VNC_CLIENT_FILE", icon_mode_file);
475 		}
476 		if (icon_in_tray) {
477 			if (tray_manager_ok) {
478 				set_env("X11VNC_ICON_MODE", "TRAY:RUNNING");
479 			} else {
480 				set_env("X11VNC_ICON_MODE", "TRAY");
481 			}
482 		} else {
483 			set_env("X11VNC_ICON_MODE", "ICON");
484 		}
485 		if (icon_mode_params) {
486 			char *p, *str = strdup(icon_mode_params);
487 			p = strtok(str, ":-/,.+");
488 			while (p) {
489 				if(strstr(p, "setp") == p) {
490 					set_env("X11VNC_ICON_SETPASS", "1");
491 					if (rc != 0) {
492 						set_env("X11VNC_SETPASS_FAIL", "1");
493 					}
494 				} else if(strstr(p, "noadvanced") == p) {
495 					set_env("X11VNC_ICON_NOADVANCED", "1");
496 				} else if(strstr(p, "minimal") == p) {
497 					set_env("X11VNC_ICON_MINIMAL", "1");
498 				} else if (strstr(p, "0x") == p) {
499 					set_env("X11VNC_ICON_EMBED_ID", p);
500 					icon_mode_embed_id = strdup(p);
501 				}
502 				p = strtok(NULL, ":-/,.+");
503 			}
504 			free(str);
505 		}
506 	}
507 	if (icon_mode_font) {
508 		set_env("X11VNC_ICON_FONT", icon_mode_font);
509 	}
510 
511 	/* gui */
512 	if (no_external_cmds || !cmd_ok("gui")) {
513 		fprintf(stderr, "cannot run external commands in -nocmds "
514 		    "mode:\n");
515 		fprintf(stderr, "   \"%s\"\n", "gui + wish");
516 		fprintf(stderr, "   exiting.\n");
517 		fflush(stderr);
518 		exit(1);
519 	}
520 
521 	tmpf = tmpfile();
522 	if (tmpf == NULL) {
523 		/* if no tmpfile, use a pipe */
524 		if (icon_mode_embed_id) {
525 			if (strlen(icon_mode_embed_id) < 20) {
526 				strcat(cmd, " -use ");
527 				strcat(cmd, icon_mode_embed_id);
528 			}
529 		}
530 		close_exec_fds();
531 		pipe = popen(cmd, "w");
532 		if (! pipe) {
533 			fprintf(stderr, "could not run: %s\n", cmd);
534 			perror("popen");
535 		}
536 		fprintf(pipe, "%s", gui_code);
537 		pclose(pipe);
538 	} else {
539 		/*
540 		 * we prefer a tmpfile since then this x11vnc process
541 		 * will then be gone, otherwise the x11vnc program text
542 		 * will still be in use.
543 		 */
544 		int n = fileno(tmpf);
545 		fprintf(tmpf, "%s", gui_code);
546 		fflush(tmpf);
547 		rewind(tmpf);
548 		dup2(n, 0);
549 		close(n);
550 		if (icon_mode_embed_id) {
551 			execlp(wish, wish, "-", "-use", icon_mode_embed_id,
552 			    (char *) NULL);
553 		} else {
554 			execlp(wish, wish, "-", (char *) NULL);
555 		}
556 		fprintf(stderr, "could not exec wish: %s -\n", wish);
557 		perror("execlp");
558 	}
559 	exit(0);
560 }
561 
do_gui(char * opts,int sleep)562 void do_gui(char *opts, int sleep) {
563 	char *s, *p;
564 	char *old_xauth = NULL;
565 	char *gui_xdisplay = NULL;
566 	int got_gui_xdisplay = 0;
567 	int start_x11vnc = 1;
568 	int connect_to_x11vnc = 0;
569 	int simple_gui = 0, none_gui = 0;
570 	int portprompt = 0;
571 	Display *test_dpy;
572 
573 	if (opts) {
574 		s = strdup(opts);
575 	} else {
576 		s = strdup("");
577 	}
578 
579 	if (use_dpy) {
580 		/* worst case */
581 		gui_xdisplay = strdup(use_dpy);
582 
583 	}
584 	if (getenv("DISPLAY") != NULL) {
585 		/* better */
586 		gui_xdisplay = strdup(getenv("DISPLAY"));
587 	}
588 
589 	p = strtok(s, ",");
590 
591 	while(p) {
592 		if (*p == '\0') {
593 			;
594 		} else if (strchr(p, ':') != NULL) {
595 			/* best */
596 			if (gui_xdisplay) {
597 				free(gui_xdisplay);
598 			}
599 			gui_xdisplay = strdup(p);
600 			got_gui_xdisplay = 1;
601 		} else if (!strcmp(p, "wait")) {
602 			start_x11vnc = 0;
603 			connect_to_x11vnc = 0;
604 		} else if (!strcmp(p, "none")) {
605 			none_gui = 1;
606 		} else if (!strcmp(p, "portprompt")) {
607 			start_x11vnc = 0;
608 			connect_to_x11vnc = 0;
609 			portprompt = 1;
610 		} else if (!strcmp(p, "conn") || !strcmp(p, "connect")) {
611 			start_x11vnc = 0;
612 			connect_to_x11vnc = 1;
613 		} else if (!strcmp(p, "ez") || !strcmp(p, "simple")) {
614 			simple_gui = 1;
615 		} else if (strstr(p, "iconfont") == p) {
616 			char *q;
617 			if ((q = strchr(p, '=')) != NULL) {
618 				icon_mode_font = strdup(q+1);
619 			}
620 		} else if (strstr(p, "full") == p) {
621 			if (strstr(p, "setp") && 0) {
622 				set_env("X11VNC_ICON_MODE", "2");
623 				set_env("X11VNC_ICON_SETPASS", "2");
624 			}
625 		} else if (strstr(p, "tray") == p || strstr(p, "icon") == p) {
626 			char *q;
627 			icon_mode = 1;
628 			if ((q = strchr(p, '=')) != NULL) {
629 				icon_mode_params = strdup(q+1);
630 				if (strstr(icon_mode_params, "setp")) {
631 					deny_all = 1;
632 				}
633 			}
634 			if (strstr(p, "tray") == p) {
635 				icon_in_tray = 1;
636 			}
637 		} else if (strstr(p, "geom") == p) {
638 			char *q;
639 			if ((q = strchr(p, '=')) != NULL) {
640 				gui_geometry = strdup(q+1);
641 			}
642 		} else {
643 			fprintf(stderr, "unrecognized gui opt: %s\n", p);
644 		}
645 
646 		p = strtok(NULL, ",");
647 	}
648 	free(s);
649 
650 	if (none_gui) {
651 		if (!start_x11vnc) {
652 			exit(0);
653 		}
654 		return;
655 	}
656 	if (start_x11vnc) {
657 		connect_to_x11vnc = 1;
658 	}
659 
660 
661 #ifdef MACOSX
662 	goto startit;
663 #endif
664 
665 	if (icon_mode && !got_gui_xdisplay) {
666 		/* for tray mode, prefer the polled DISPLAY */
667 		if (use_dpy) {
668 			if (gui_xdisplay) {
669 				free(gui_xdisplay);
670 			}
671 			gui_xdisplay = strdup(use_dpy);
672 		}
673 	}
674 
675 	if (! gui_xdisplay) {
676 		fprintf(stderr, "error: cannot determine X DISPLAY for gui"
677 		    " to display on.\n");
678 		exit(1);
679 	}
680 	if (!quiet && !portprompt) {
681 		fprintf(stderr, "starting gui, trying display: %s\n",
682 		    gui_xdisplay);
683 	}
684 	test_dpy = XOpenDisplay_wr(gui_xdisplay);
685 	if (! test_dpy && auth_file) {
686 		if (getenv("XAUTHORITY") != NULL) {
687 			old_xauth = strdup(getenv("XAUTHORITY"));
688 		}
689 		set_env("XAUTHORITY", auth_file);
690 		test_dpy = XOpenDisplay_wr(gui_xdisplay);
691 	}
692 	if (! test_dpy) {
693 		if (! old_xauth && getenv("XAUTHORITY") != NULL) {
694 			old_xauth = strdup(getenv("XAUTHORITY"));
695 		}
696 		set_env("XAUTHORITY", "");
697 		test_dpy = XOpenDisplay_wr(gui_xdisplay);
698 	}
699 	if (! test_dpy) {
700 		fprintf(stderr, "error: cannot connect to gui X DISPLAY: %s\n",
701 		    gui_xdisplay);
702 		exit(1);
703 	}
704 	if (icon_mode && icon_in_tray) {
705 		if (tray_manager_running(test_dpy, NULL)) {
706 			tray_manager_ok = 1;
707 		} else {
708 			tray_manager_ok = 0;
709 		}
710 	}
711 	XCloseDisplay_wr(test_dpy);
712 
713 #ifdef MACOSX
714 	startit:
715 #endif
716 	if (portprompt) {
717 		char *cmd, *p, *p2, *p1, *p0 = getenv("PATH");
718 		char tf1[] = "/tmp/x11vnc_port_prompt.2XXXXXX";
719 		char tf2[] = "/tmp/x11vnc_port_prompt.1XXXXXX";
720 		int fd;
721 		char *dstr = "", *wish = NULL;
722 		char line[128];
723 		FILE *fp;
724 
725 		if (no_external_cmds || !cmd_ok("gui")) {
726 			return;
727 		}
728 
729 		if (gui_xdisplay) {
730 			dstr = gui_xdisplay;
731 			if (strchr(gui_xdisplay, '\'')) {
732 				return;
733 			}
734 		}
735 		if (!p0) {
736 			p0 = "";
737 		}
738 		if (strchr(p0, '\'')) {
739 			return;
740 		}
741 
742 		fd = mkstemp(tf2);
743 		if (fd < 0) {
744 			return;
745 		}
746 		close(fd);
747 
748 		fd = mkstemp(tf1);
749 		if (fd < 0) {
750 			unlink(tf2);
751 			return;
752 		}
753 
754 		write(fd, gui_code, strlen(gui_code));
755 		close(fd);
756 
757 		p1 = (char *) malloc(10 + strlen(p0) + strlen(extra_path));
758 		sprintf(p1, "%s:%s", p0, extra_path);
759 		p2 = strdup(p1);
760 		p = strtok(p2, ":");
761 
762 		while (p) {
763 			char *try;
764 			struct stat sbuf;
765 			int i;
766 
767 			try = (char *) malloc(strlen(p) + 1 + strlen("wish8.4") + 1);
768 			i = 0;
769 			while (wishes[i] != NULL) {
770 				sprintf(try, "%s/%s", p, wishes[i]);
771 				if (stat(try, &sbuf) == 0) {
772 					/* assume executable, should check mode */
773 					wish = wishes[i];
774 					break;
775 				}
776 				i++;
777 			}
778 			free(try);
779 			if (wish) {
780 				break;
781 			}
782 			p = strtok(NULL, ":");
783 		}
784 		free(p2);
785 
786 		if (!wish) {
787 			wish = "wish";
788 		}
789 
790 		cmd = (char *) malloc(200 + strlen(dstr) + strlen(p1));
791 
792 		if (!strcmp(dstr, "")) {
793 			sprintf(cmd, "env PATH='%s' %s %s -name x11vnc_port_prompt -portprompt > %s", p1, wish, tf1, tf2);
794 		} else {
795 			sprintf(cmd, "env PATH='%s' DISPLAY='%s' %s %s -name x11vnc_port_prompt -portprompt > %s", p1, dstr, wish, tf1, tf2);
796 		}
797 		if (getenv("X11VNC_DEBUG_PORTPROMPT")) {
798 			fprintf(stderr, "cmd=%s\n", cmd);
799 		}
800 		if (use_openssl) {
801 			set_env("X11VNC_SSL_ENABLED", "1");
802 		}
803 		if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
804 			set_env("X11VNC_LOCALHOST_ENABLED", "1");
805 		}
806 		if (got_ultrafilexfer) {
807 			set_env("X11VNC_FILETRANSFER_ENABLED", "ultra");
808 		} else if (tightfilexfer) {
809 			set_env("X11VNC_FILETRANSFER_ENABLED", "tight");
810 		}
811 		system(cmd);
812 		free(cmd);
813 		free(p1);
814 
815 		fp = fopen(tf2, "r");
816 		memset(line, 0, sizeof(line));
817 		if (fp) {
818 			fgets(line, 128, fp);
819 			fclose(fp);
820 			if (line[0] != '\0') {
821 				int readport = atoi(line);
822 				if (readport > 0) {
823 					got_rfbport_val = readport;
824 				}
825 			}
826 		}
827 
828 		if (strstr(line, "ssl0")) {
829 			if (use_openssl) use_openssl = 0;
830 		} else if (strstr(line, "ssl1")) {
831 			if (!use_openssl) {
832 				use_openssl = 1;
833 				openssl_pem = strdup("SAVE_NOPROMPT");
834 				set_env("X11VNC_GOT_SSL", "1");
835 			}
836 		}
837 
838 		if (strstr(line, "localhost0")) {
839 			if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
840 				allow_list = NULL;
841 			}
842 		} else if (strstr(line, "localhost1")) {
843 			allow_list = strdup("127.0.0.1");
844 		}
845 
846 		if (strstr(line, "ft_ultra")) {
847 			got_ultrafilexfer = 1;
848 			tightfilexfer = 0;
849 		} else if (strstr(line, "ft_tight")) {
850 			got_ultrafilexfer = 0;
851 			tightfilexfer = 1;
852 		} else if (strstr(line, "ft_none")) {
853 			got_ultrafilexfer = 0;
854 			tightfilexfer = 0;
855 		}
856 
857 		unlink(tf1);
858 		unlink(tf2);
859 
860 		if (old_xauth) {
861 			set_env("XAUTHORITY", old_xauth);
862 		}
863 
864 		return;
865 	}
866 
867 	if (start_x11vnc) {
868 
869 #if LIBVNCSERVER_HAVE_FORK
870 		/* fork into the background now */
871 		int p;
872 		pid_t parent = getpid();
873 
874 		if (icon_mode) {
875 			char tf[] = "/tmp/x11vnc.tray.XXXXXX";
876 			int fd;
877 
878 			fd = mkstemp(tf);
879 			if (fd < 0) {
880 				icon_mode = 0;
881 			} else {
882 				close(fd);
883 				icon_mode_fh = fopen(tf, "w");
884 				if (! icon_mode_fh) {
885 					icon_mode = 0;
886 				} else {
887 					chmod(tf, 0400);
888 					icon_mode_file = strdup(tf);
889 					rfbLog("icon_mode_file=%s\n", icon_mode_file);
890 					fprintf(icon_mode_fh, "none\n");
891 					fprintf(icon_mode_fh, "none\n");
892 					fflush(icon_mode_fh);
893 					if (! got_connect_once) {
894 						if (!client_connect && !connect_or_exit) {
895 							/* want -forever for tray? */
896 							connect_once = 0;
897 						}
898 					}
899 				}
900 			}
901 		}
902 
903 		if ((p = fork()) > 0)  {
904 			;	/* parent */
905 		} else if (p == -1) {
906 			fprintf(stderr, "could not fork\n");
907 			perror("fork");
908 			clean_up_exit(1);
909 		} else {
910 			if (sleep > 0) {
911 				usleep(sleep * 1000 * 1000);
912 			}
913 			run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc,
914 			    simple_gui, parent, opts);
915 			exit(1);
916 		}
917 		if (connect_to_x11vnc) {
918 			run_gui_pid = p;
919 			gui_pid = p;
920 		}
921 #else
922 		fprintf(stderr, "system does not support fork: start "
923 		    "x11vnc in the gui.\n");
924 		start_x11vnc = 0;
925 #endif
926 	}
927 	if (!start_x11vnc) {
928 		run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc,
929 		    simple_gui, 0, opts);
930 		exit(1);
931 	}
932 	if (old_xauth) {
933 		set_env("XAUTHORITY", old_xauth);
934 	}
935 }
936 
937 
938