/*
   Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> 
   All rights reserved.

This file is part of x11vnc.

x11vnc is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

x11vnc is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with x11vnc; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
or see <http://www.gnu.org/licenses/>.

In addition, as a special exception, Karl J. Runge
gives permission to link the code of its release of x11vnc with the
OpenSSL project's "OpenSSL" library (or with modified versions of it
that use the same license as the "OpenSSL" library), and distribute
the linked executables.  You must obey the GNU General Public License
in all respects for all of the code used other than "OpenSSL".  If you
modify this file, you may extend this exception to your version of the
file, but you are not obligated to do so.  If you do not wish to do
so, delete this exception statement from your version.
*/

/* -- gui.c -- */

#include "x11vnc.h"
#include "xevents.h"
#include "win_utils.h"
#include "remote.h"
#include "cleanup.h"
#include "xwrappers.h"
#include "connections.h"

#include "tkx11vnc.h"

#define SYSTEM_TRAY_REQUEST_DOCK    0
#define SYSTEM_TRAY_BEGIN_MESSAGE   1
#define SYSTEM_TRAY_CANCEL_MESSAGE  2
#define XEMBED_VERSION 0
#define XEMBED_MAPPED  (1 << 0)

int icon_mode = 0;		/* hack for -gui tray/icon */
char *icon_mode_file = NULL;
FILE *icon_mode_fh = NULL;
int icon_mode_socks[ICON_MODE_SOCKS];
int tray_manager_ok = 0;
Window tray_request = None;
Window tray_window = None;
int tray_unembed = 0;
pid_t run_gui_pid = 0;
pid_t gui_pid = 0;


char *get_gui_code(void);
int tray_embed(Window iconwin, int remove);
void do_gui(char *opts, int sleep);


static Window tweak_tk_window_id(Window win);
static int tray_manager_running(Display *d, Window *manager);
static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc,
    int simple_gui, pid_t parent, char *gui_opts);


char *get_gui_code(void) {
	return gui_code;
}

static Window tweak_tk_window_id(Window win) {
#if NO_X11
	if (!win) {}
	return None;
#else
	char *name = NULL;
	Window parent, new_win;

	if (getenv("NO_TWEAK_TK_WINDOW_ID")) {
		return win;
	}

	/* hack for tk, does not report outermost window */
	new_win = win;
	parent = parent_window(win, &name);
	if (parent && name != NULL) {
		lowercase(name);
		if (strstr(name, "wish") || strstr(name, "x11vnc")) {
			new_win = parent;
			rfbLog("tray_embed: using parent: %s\n", name);
		}
	}
	if (name != NULL) {
		XFree_wr(name);
	}
	return new_win;
#endif	/* NO_X11 */
}

int tray_embed(Window iconwin, int remove) {
#if NO_X11
	RAWFB_RET(0)
	if (!iconwin || !remove) {}
	return 0;
#else
	XEvent ev;
	XErrorHandler old_handler;
	Window manager;
	Atom xembed_info;
	Atom tatom;
	XWindowAttributes attr;
	long info[2] = {XEMBED_VERSION, XEMBED_MAPPED};
	long data = 0;

	RAWFB_RET(0)

	if (remove) {
		if (!valid_window(iconwin, &attr, 1)) {
			return 0;
		}
		iconwin = tweak_tk_window_id(iconwin);
		trapped_xerror = 0;
		old_handler = XSetErrorHandler(trap_xerror);

		/*
		 * unfortunately no desktops seem to obey this
		 * part of the XEMBED spec yet...
		 */
		XReparentWindow(dpy, iconwin, rootwin, 0, 0);

		XSetErrorHandler(old_handler);
		if (trapped_xerror) {
			trapped_xerror = 0;
			return 0;
		}
		trapped_xerror = 0;
		return 1;
	}

	xembed_info = XInternAtom(dpy, "_XEMBED_INFO", False);
	if (xembed_info == None) {
		return 0;
	}

	if (!tray_manager_running(dpy, &manager)) {
		return 0;
	}

	memset(&ev, 0, sizeof(ev));
	ev.xclient.type = ClientMessage;
	ev.xclient.window = manager;
	ev.xclient.message_type = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE",
	    False);
	ev.xclient.format = 32;
	ev.xclient.data.l[0] = CurrentTime;
	ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
	ev.xclient.data.l[2] = iconwin;
	ev.xclient.data.l[3] = 0;
	ev.xclient.data.l[4] = 0;

	if (!valid_window(iconwin, &attr, 1)) {
		return 0;
	}

	iconwin = tweak_tk_window_id(iconwin);
	ev.xclient.data.l[2] = iconwin;

	XUnmapWindow(dpy, iconwin);

	trapped_xerror = 0;
	old_handler = XSetErrorHandler(trap_xerror);

	XSendEvent(dpy, manager, False, NoEventMask, &ev);
	XSync(dpy, False);

	if (trapped_xerror) {
		XSetErrorHandler(old_handler);
		trapped_xerror = 0;
		return 0;
	}

	XChangeProperty(dpy, iconwin, xembed_info, xembed_info, 32,
	    PropModeReplace, (unsigned char *)&info, 2);

#if 0
{
XSizeHints *xszh = XAllocSizeHints();
xszh->flags = PMinSize;
xszh->min_width = 24;
xszh->min_height = 24;
XSetWMNormalHints(dpy, iconwin, xszh);
}
#endif

	/* kludge for KDE evidently needed... */
	tatom = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
	XChangeProperty(dpy, iconwin, tatom, tatom, 32, PropModeReplace,
	    (unsigned char *)&data, 1);
	tatom = XInternAtom(dpy, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
	XChangeProperty(dpy, iconwin, tatom, XA_WINDOW, 32, PropModeReplace,
	    (unsigned char *)&data, 1);

	XSetErrorHandler(old_handler);
	trapped_xerror = 0;
	return 1;
#endif	/* NO_X11 */
}

static int tray_manager_running(Display *d, Window *manager) {
#if NO_X11
	RAWFB_RET(0)
	if (!d || !manager) {}
	return 0;
#else
	char tray_string[100];
	Atom tray_manager;
	Window tray_win;

	RAWFB_RET(0)

	if (manager) {
		*manager = None;
	}
	sprintf(tray_string, "_NET_SYSTEM_TRAY_S%d", scr);

	tray_manager = XInternAtom(d, tray_string, True);
	if (tray_manager == None) {
		return 0;
	}

	tray_win = XGetSelectionOwner(d, tray_manager);
	if (manager) {
		*manager = tray_win;
	}

	if (tray_win == None) {
		return 0;
	} else {
		return 1;
	}
#endif	/* NO_X11 */
}

static char *gui_geometry = NULL;
static int icon_in_tray = 0;
static char *icon_mode_embed_id = NULL;
static char *icon_mode_font = NULL;
static char *icon_mode_params = NULL;

static int got_sigusr1 = 0;

static void sigusr1 (int sig) {
	got_sigusr1 = 1;
	if (0) sig = 0;
}

/* Most of the following mess is for wish on Solaris: */

static char *extra_path = ":/usr/local/bin:/usr/bin/X11:/usr/sfw/bin"
	    ":/usr/X11R6/bin:/usr/openwin/bin:/usr/dt/bin:/opt/sfw/bin";
static char *wishes[] = {"wish8.4", "wish", "wish8.3", "wish8.5", "wish8.6", "wish8.7", "wishx", "wish8.0", NULL};

static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc,
    int simple_gui, pid_t parent, char *gui_opts) {
	char *x11vnc_xdisplay = NULL;
	char cmd[100];
	char *wish = NULL, *orig_path, *full_path, *tpath, *p;
	char *old_xauth = NULL;
	int try_max = 4, sleep = 300, totms, rc = 0;
	pid_t mypid = getpid();
	FILE *pipe, *tmpf;

if (0) fprintf(stderr, "run_gui: %s -- %d %d\n", gui_xdisplay, connect_to_x11vnc, (int) parent);
	if (*gui_code == '\0') {
		rfbLog("gui: gui not compiled into this program.\n");
		exit(0);
	}
	if (getenv("DISPLAY") != NULL) {
		/* worst case */
		x11vnc_xdisplay = strdup(getenv("DISPLAY"));
	}
	if (use_dpy) {
		/* better */
		x11vnc_xdisplay = strdup(use_dpy);
	}
	if (connect_to_x11vnc) {
		int i;
		rfbLogEnable(1);
		if (! client_connect_file) {
			if (getenv("XAUTHORITY") != NULL) {
				old_xauth = strdup(getenv("XAUTHORITY"));
			} else {
				old_xauth = strdup("");
			}
			dpy = XOpenDisplay_wr(x11vnc_xdisplay); 
			if (! dpy && auth_file) {
				set_env("XAUTHORITY", auth_file);
				dpy = XOpenDisplay_wr(x11vnc_xdisplay);
			}
			if (! dpy && ! x11vnc_xdisplay) {
				/* worstest case */
				x11vnc_xdisplay = strdup(":0");
				dpy = XOpenDisplay_wr(x11vnc_xdisplay); 
			}
			if (! dpy) {
				rfbLog("gui: could not open x11vnc "
				    "display: %s\n", NONUL(x11vnc_xdisplay));
#ifdef MACOSX
				goto macjump;
#endif
				exit(1);
			}
			scr = DefaultScreen(dpy);
			rootwin = RootWindow(dpy, scr);
			initialize_vnc_connect_prop();
			initialize_x11vnc_remote_prop();
		}

#ifdef MACOSX
		macjump:
#endif
		
		signal(SIGUSR1, sigusr1);
		got_sigusr1 = 0;
		totms = 0;
		while (totms < 3500) {
			usleep(50*1000);
			totms += 50;
			if (got_sigusr1) {
				fprintf(stderr, "\n");
				if (! quiet) rfbLog("gui: got SIGUSR1\n");
				break;
			}
			if (! start_x11vnc && totms >= 150) {
				break;
			}
		}
		signal(SIGUSR1, SIG_DFL);
		if (! got_sigusr1) fprintf(stderr, "\n");

		if (!quiet && ! got_sigusr1) {
			rfbLog("gui: trying to contact a x11vnc server at X"
			    " display %s ...\n", NONUL(x11vnc_xdisplay));
		}

		for (i=0; i<try_max; i++) {
			if (! got_sigusr1) {
				if (!quiet) {
					rfbLog("gui: pinging %s try=%d ...\n",
					    NONUL(x11vnc_xdisplay), i+1);
				}
				rc = send_remote_cmd("qry=ping", 1, 1);
				if (rc == 0) {
					break;
				}
			} else {
				rc = 0;
				break;
			}
			if (parent && mypid != parent && kill(parent, 0) != 0) {
				rfbLog("gui: parent process %d has gone"
				    " away: bailing out.\n", parent);
				rc = 1;
				break;
			}
			usleep(sleep*1000);
		}
		set_env("X11VNC_XDISPLAY", x11vnc_xdisplay);
		if (getenv("XAUTHORITY") != NULL) {
			set_env("X11VNC_AUTH_FILE", getenv("XAUTHORITY"));
		}
		if (rc == 0) {
			rfbLog("gui: ping succeeded.\n");
			set_env("X11VNC_CONNECT", "1");
		} else {
			rfbLog("gui: could not connect to: '%s', try"
			    " again manually.\n", x11vnc_xdisplay);
		}
		if (client_connect_file) {
			set_env("X11VNC_CONNECT_FILE", client_connect_file);
		}
		if (dpy)  {
			XCloseDisplay_wr(dpy);
			dpy = NULL;
		}
		if (old_xauth) {
			if (*old_xauth == '\0') {
				/* wasn't set, hack it out if it is now */
				char *xauth = getenv("XAUTHORITY");
				if (xauth) {
					*(xauth-2) = '_';	/* yow */
				}
			} else {
				set_env("XAUTHORITY", old_xauth);
			}
			free(old_xauth);
		}
		rfbLogEnable(0);
	}

	orig_path = getenv("PATH");
	if (! orig_path) {
		orig_path = strdup("/bin:/usr/bin:/usr/bin/X11");
	}
	full_path = (char *) malloc(strlen(orig_path)+strlen(extra_path)+1);
	strcpy(full_path, orig_path);
	strcat(full_path, extra_path);

	tpath = strdup(full_path);
	p = strtok(tpath, ":");

	while (p) {
		char *try;
		struct stat sbuf;
		int i;

		try = (char *) malloc(strlen(p) + 1 + strlen("wish8.4") + 1);
		i = 0;
		while (wishes[i] != NULL) {
			sprintf(try, "%s/%s", p, wishes[i]);
			if (stat(try, &sbuf) == 0) {
				/* assume executable, should check mode */
				wish = wishes[i];
				break;
			}
			i++;
		}
		free(try);
		if (wish) {
			break;
		}
		p = strtok(NULL, ":");
	}
	free(tpath);
	if (!wish) {
		wish = strdup("wish");
	}
	if (getenv("WISH")) {
		char *w = getenv("WISH");
		if (strcmp(w, "")) {
			wish = strdup(w);
		}
	}
	if (getenv("DEBUG_WISH")) {
		fprintf(stderr, "wish: %s\n", wish);
	}
	set_env("PATH", full_path);
	set_env("DISPLAY", gui_xdisplay);
	set_env("X11VNC_PROG", program_name);
	set_env("X11VNC_CMDLINE", program_cmdline);
	set_env("X11VNC_WISHCMD", wish);
	if (simple_gui) {
		set_env("X11VNC_SIMPLE_GUI", "1");
	}
	if (gui_opts) {
		set_env("X11VNC_GUI_PARAMS", gui_opts);
	}
	if (gui_geometry) {
		set_env("X11VNC_GUI_GEOM", gui_geometry);
	}
	if (start_x11vnc) {
		set_env("X11VNC_STARTED", "1");
	}
	if (icon_mode) {
		set_env("X11VNC_ICON_MODE", "1");
		if (icon_mode_file) {
			set_env("X11VNC_CLIENT_FILE", icon_mode_file);
		}
		if (icon_in_tray) {
			if (tray_manager_ok) {
				set_env("X11VNC_ICON_MODE", "TRAY:RUNNING");
			} else {
				set_env("X11VNC_ICON_MODE", "TRAY");
			}
		} else {
			set_env("X11VNC_ICON_MODE", "ICON");
		}
		if (icon_mode_params) {
			char *p, *str = strdup(icon_mode_params);
			p = strtok(str, ":-/,.+");
			while (p) {
				if(strstr(p, "setp") == p) {
					set_env("X11VNC_ICON_SETPASS", "1");
					if (rc != 0) {
						set_env("X11VNC_SETPASS_FAIL", "1");
					}
				} else if(strstr(p, "noadvanced") == p) {
					set_env("X11VNC_ICON_NOADVANCED", "1");
				} else if(strstr(p, "minimal") == p) {
					set_env("X11VNC_ICON_MINIMAL", "1");
				} else if (strstr(p, "0x") == p) {
					set_env("X11VNC_ICON_EMBED_ID", p);
					icon_mode_embed_id = strdup(p);
				}
				p = strtok(NULL, ":-/,.+");
			}
			free(str);
		}
	}
	if (icon_mode_font) {
		set_env("X11VNC_ICON_FONT", icon_mode_font);
	}

	/* gui */
	if (no_external_cmds || !cmd_ok("gui")) {
		fprintf(stderr, "cannot run external commands in -nocmds "
		    "mode:\n");
		fprintf(stderr, "   \"%s\"\n", "gui + wish");
		fprintf(stderr, "   exiting.\n");
		fflush(stderr);
		exit(1);
	}

	tmpf = tmpfile();
	if (tmpf == NULL) {
		/* if no tmpfile, use a pipe */
		if (icon_mode_embed_id) {
			if (strlen(icon_mode_embed_id) < 20) {
				strcat(cmd, " -use ");
				strcat(cmd, icon_mode_embed_id);
			}
		}
		close_exec_fds();
		pipe = popen(cmd, "w");
		if (! pipe) {
			fprintf(stderr, "could not run: %s\n", cmd);
			perror("popen");
		}
		fprintf(pipe, "%s", gui_code);
		pclose(pipe);
	} else {
		/*
		 * we prefer a tmpfile since then this x11vnc process
		 * will then be gone, otherwise the x11vnc program text
		 * will still be in use.
		 */
		int n = fileno(tmpf);
		fprintf(tmpf, "%s", gui_code);
		fflush(tmpf);
		rewind(tmpf);
		dup2(n, 0);
		close(n);
		if (icon_mode_embed_id) {
			execlp(wish, wish, "-", "-use", icon_mode_embed_id,
			    (char *) NULL); 
		} else {
			execlp(wish, wish, "-", (char *) NULL); 
		}
		fprintf(stderr, "could not exec wish: %s -\n", wish);
		perror("execlp");
	}
	exit(0);
}

void do_gui(char *opts, int sleep) {
	char *s, *p;
	char *old_xauth = NULL;
	char *gui_xdisplay = NULL;
	int got_gui_xdisplay = 0;
	int start_x11vnc = 1;
	int connect_to_x11vnc = 0;
	int simple_gui = 0, none_gui = 0;
	int portprompt = 0;
	Display *test_dpy;

	if (opts) {
		s = strdup(opts);
	} else {
		s = strdup("");
	}

	if (use_dpy) {
		/* worst case */
		gui_xdisplay = strdup(use_dpy);
		
	}
	if (getenv("DISPLAY") != NULL) {
		/* better */
		gui_xdisplay = strdup(getenv("DISPLAY"));
	}

	p = strtok(s, ",");

	while(p) {
		if (*p == '\0') {
			;
		} else if (strchr(p, ':') != NULL) {
			/* best */
			if (gui_xdisplay) {
				free(gui_xdisplay);
			}
			gui_xdisplay = strdup(p);
			got_gui_xdisplay = 1;
		} else if (!strcmp(p, "wait")) {
			start_x11vnc = 0;
			connect_to_x11vnc = 0;
		} else if (!strcmp(p, "none")) {
			none_gui = 1;
		} else if (!strcmp(p, "portprompt")) {
			start_x11vnc = 0;
			connect_to_x11vnc = 0;
			portprompt = 1;
		} else if (!strcmp(p, "conn") || !strcmp(p, "connect")) {
			start_x11vnc = 0;
			connect_to_x11vnc = 1;
		} else if (!strcmp(p, "ez") || !strcmp(p, "simple")) {
			simple_gui = 1;
		} else if (strstr(p, "iconfont") == p) {
			char *q;
			if ((q = strchr(p, '=')) != NULL) {
				icon_mode_font = strdup(q+1);
			}
		} else if (strstr(p, "full") == p) {
			if (strstr(p, "setp") && 0) {
				set_env("X11VNC_ICON_MODE", "2");
				set_env("X11VNC_ICON_SETPASS", "2");
			}
		} else if (strstr(p, "tray") == p || strstr(p, "icon") == p) {
			char *q;
			icon_mode = 1;
			if ((q = strchr(p, '=')) != NULL) {
				icon_mode_params = strdup(q+1);
				if (strstr(icon_mode_params, "setp")) {
					deny_all = 1;
				}
			}
			if (strstr(p, "tray") == p) {
				icon_in_tray = 1;
			}
		} else if (strstr(p, "geom") == p) {
			char *q;
			if ((q = strchr(p, '=')) != NULL) {
				gui_geometry = strdup(q+1);
			}
		} else {
			fprintf(stderr, "unrecognized gui opt: %s\n", p);
		}
		
		p = strtok(NULL, ",");
	}
	free(s);

	if (none_gui) {
		if (!start_x11vnc) {
			exit(0);
		}
		return;
	}
	if (start_x11vnc) {
		connect_to_x11vnc = 1;
	}


#ifdef MACOSX
	goto startit;
#endif

	if (icon_mode && !got_gui_xdisplay) {
		/* for tray mode, prefer the polled DISPLAY */
		if (use_dpy) {
			if (gui_xdisplay) {
				free(gui_xdisplay);
			}
			gui_xdisplay = strdup(use_dpy);
		}
	}

	if (! gui_xdisplay) {
		fprintf(stderr, "error: cannot determine X DISPLAY for gui"
		    " to display on.\n");
		exit(1);
	}
	if (!quiet && !portprompt) {
		fprintf(stderr, "starting gui, trying display: %s\n",
		    gui_xdisplay);
	}
	test_dpy = XOpenDisplay_wr(gui_xdisplay);
	if (! test_dpy && auth_file) {
		if (getenv("XAUTHORITY") != NULL) {
			old_xauth = strdup(getenv("XAUTHORITY"));
		}
		set_env("XAUTHORITY", auth_file);
		test_dpy = XOpenDisplay_wr(gui_xdisplay);
	}
	if (! test_dpy) {
		if (! old_xauth && getenv("XAUTHORITY") != NULL) {
			old_xauth = strdup(getenv("XAUTHORITY"));
		}
		set_env("XAUTHORITY", "");
		test_dpy = XOpenDisplay_wr(gui_xdisplay);
	}
	if (! test_dpy) {
		fprintf(stderr, "error: cannot connect to gui X DISPLAY: %s\n",
		    gui_xdisplay);
		exit(1);
	}
	if (icon_mode && icon_in_tray) {
		if (tray_manager_running(test_dpy, NULL)) {
			tray_manager_ok = 1;
		} else {
			tray_manager_ok = 0;
		}
	}
	XCloseDisplay_wr(test_dpy);

#ifdef MACOSX
	startit:
#endif
	if (portprompt) {
		char *cmd, *p, *p2, *p1, *p0 = getenv("PATH");
		char tf1[] = "/tmp/x11vnc_port_prompt.2XXXXXX";
		char tf2[] = "/tmp/x11vnc_port_prompt.1XXXXXX";
		int fd;
		char *dstr = "", *wish = NULL;
		char line[128];
		FILE *fp;

		if (no_external_cmds || !cmd_ok("gui")) {
			return;
		}

		if (gui_xdisplay) {
			dstr = gui_xdisplay;
			if (strchr(gui_xdisplay, '\'')) {
				return;
			}
		}
		if (!p0) {
			p0 = "";
		}
		if (strchr(p0, '\'')) {
			return;
		}

		fd = mkstemp(tf2);
		if (fd < 0) {
			return;
		}
		close(fd);

		fd = mkstemp(tf1);
		if (fd < 0) {
			unlink(tf2);
			return;
		}

		write(fd, gui_code, strlen(gui_code));
		close(fd);

		p1 = (char *) malloc(10 + strlen(p0) + strlen(extra_path));
		sprintf(p1, "%s:%s", p0, extra_path);
		p2 = strdup(p1);
		p = strtok(p2, ":");

		while (p) {
			char *try;
			struct stat sbuf;
			int i;

			try = (char *) malloc(strlen(p) + 1 + strlen("wish8.4") + 1);
			i = 0;
			while (wishes[i] != NULL) {
				sprintf(try, "%s/%s", p, wishes[i]);
				if (stat(try, &sbuf) == 0) {
					/* assume executable, should check mode */
					wish = wishes[i];
					break;
				}
				i++;
			}
			free(try);
			if (wish) {
				break;
			}
			p = strtok(NULL, ":");
		}
		free(p2);

		if (!wish) {
			wish = "wish";
		}

		cmd = (char *) malloc(200 + strlen(dstr) + strlen(p1));

		if (!strcmp(dstr, "")) {
			sprintf(cmd, "env PATH='%s' %s %s -name x11vnc_port_prompt -portprompt > %s", p1, wish, tf1, tf2);
		} else {
			sprintf(cmd, "env PATH='%s' DISPLAY='%s' %s %s -name x11vnc_port_prompt -portprompt > %s", p1, dstr, wish, tf1, tf2);
		}
		if (getenv("X11VNC_DEBUG_PORTPROMPT")) {
			fprintf(stderr, "cmd=%s\n", cmd);
		}
		if (use_openssl) {
			set_env("X11VNC_SSL_ENABLED", "1");
		}
		if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
			set_env("X11VNC_LOCALHOST_ENABLED", "1");
		}
		if (got_ultrafilexfer) {
			set_env("X11VNC_FILETRANSFER_ENABLED", "ultra");
		} else if (tightfilexfer) {
			set_env("X11VNC_FILETRANSFER_ENABLED", "tight");
		}
		system(cmd);
		free(cmd);
		free(p1);

		fp = fopen(tf2, "r");
		memset(line, 0, sizeof(line));
		if (fp) {
			fgets(line, 128, fp);
			fclose(fp);
			if (line[0] != '\0') {
				int readport = atoi(line);
				if (readport > 0) {
					got_rfbport_val = readport;
				}
			}
		}

		if (strstr(line, "ssl0")) {
			if (use_openssl) use_openssl = 0;
		} else if (strstr(line, "ssl1")) {
			if (!use_openssl) {
				use_openssl = 1;
				openssl_pem = strdup("SAVE_NOPROMPT");
				set_env("X11VNC_GOT_SSL", "1");
			}
		}

		if (strstr(line, "localhost0")) {
			if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
				allow_list = NULL;
			}
		} else if (strstr(line, "localhost1")) {
			allow_list = strdup("127.0.0.1");
		}

		if (strstr(line, "ft_ultra")) {
			got_ultrafilexfer = 1;
			tightfilexfer = 0;
		} else if (strstr(line, "ft_tight")) {
			got_ultrafilexfer = 0;
			tightfilexfer = 1;
		} else if (strstr(line, "ft_none")) {
			got_ultrafilexfer = 0;
			tightfilexfer = 0;
		}

		unlink(tf1);
		unlink(tf2);

		if (old_xauth) {
			set_env("XAUTHORITY", old_xauth);
		}

		return;
	}

	if (start_x11vnc) {

#if HAVE_FORK
		/* fork into the background now */
		int p;
		pid_t parent = getpid();

		if (icon_mode) {
			char tf[] = "/tmp/x11vnc.tray.XXXXXX"; 
			int fd;

			fd = mkstemp(tf);
			if (fd < 0) {
				icon_mode = 0;
			} else {
				close(fd);
				icon_mode_fh = fopen(tf, "w");
				if (! icon_mode_fh) {
					icon_mode = 0;
				} else {
					chmod(tf, 0400);
					icon_mode_file = strdup(tf);
					rfbLog("icon_mode_file=%s\n", icon_mode_file);
					fprintf(icon_mode_fh, "none\n");
					fprintf(icon_mode_fh, "none\n");
					fflush(icon_mode_fh);
					if (! got_connect_once) {
						if (!client_connect && !connect_or_exit) {
							/* want -forever for tray? */
							connect_once = 0;
						}
					}
				}
			}
		}

		if ((p = fork()) > 0)  {
			;	/* parent */
		} else if (p == -1) {
			fprintf(stderr, "could not fork\n");
			perror("fork");
			clean_up_exit(1);
		} else {
			if (sleep > 0) {
				usleep(sleep * 1000 * 1000);
			}
			run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc,
			    simple_gui, parent, opts);
			exit(1);
		}
		if (connect_to_x11vnc) {
			run_gui_pid = p;
			gui_pid = p;
		}
#else
		fprintf(stderr, "system does not support fork: start "
		    "x11vnc in the gui.\n");
		start_x11vnc = 0;
#endif
	}
	if (!start_x11vnc) {
		run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc,
		    simple_gui, 0, opts);
		exit(1);
	}
	if (old_xauth) {
		set_env("XAUTHORITY", old_xauth);
	}
}


