| /* |
| Copyright (C) 2002-2010 Karl J. Runge <[email protected]> |
| 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 LIBVNCSERVER_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); |
| } |
| } |
| |
| |