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