1/* 2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> 3 All rights reserved. 4 5This file is part of x11vnc. 6 7x11vnc is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2 of the License, or (at 10your option) any later version. 11 12x11vnc is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with x11vnc; if not, write to the Free Software 19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA 20or see <http://www.gnu.org/licenses/>. 21 22In addition, as a special exception, Karl J. Runge 23gives permission to link the code of its release of x11vnc with the 24OpenSSL project's "OpenSSL" library (or with modified versions of it 25that use the same license as the "OpenSSL" library), and distribute 26the linked executables. You must obey the GNU General Public License 27in all respects for all of the code used other than "OpenSSL". If you 28modify this file, you may extend this exception to your version of the 29file, but you are not obligated to do so. If you do not wish to do 30so, delete this exception statement from your version. 31*/ 32 33/* -- xevents.c -- */ 34 35#include "x11vnc.h" 36#include "xwrappers.h" 37#include "xkb_bell.h" 38#include "xrandr.h" 39#include "xdamage.h" 40#include "xrecord.h" 41#include "selection.h" 42#include "keyboard.h" 43#include "cursor.h" 44#include "gui.h" 45#include "connections.h" 46#include "unixpw.h" 47#include "cleanup.h" 48#include "macosx.h" 49#include "screen.h" 50#include "pm.h" 51#include "pointer.h" 52#include "remote.h" 53#include "inet.h" 54 55/* XXX CHECK BEFORE RELEASE */ 56int grab_buster = 0; 57int grab_kbd = 0; 58int grab_ptr = 0; 59int grab_always = 0; 60int ungrab_both = 0; 61int grab_local = 0; 62int sync_tod_delay = 20; 63 64void initialize_vnc_connect_prop(void); 65void initialize_x11vnc_remote_prop(void); 66void initialize_clipboard_atom(void); 67void spawn_grab_buster(void); 68void sync_tod_with_servertime(void); 69void check_keycode_state(void); 70void check_autorepeat(void); 71void set_prop_atom(Atom atom); 72void check_xevents(int reset); 73void xcut_receive(char *text, int len, rfbClientPtr cl); 74 75void kbd_release_all_keys(rfbClientPtr cl); 76void set_single_window(rfbClientPtr cl, int x, int y); 77void set_server_input(rfbClientPtr cl, int s); 78void set_text_chat(rfbClientPtr cl, int l, char *t); 79int get_keyboard_led_state_hook(rfbScreenInfoPtr s); 80int get_file_transfer_permitted(rfbClientPtr cl); 81void get_prop(char *str, int len, Atom prop, Window w); 82int guess_dm_gone(int t1, int t2); 83 84static void initialize_xevents(int reset); 85static void print_xevent_bases(void); 86static void bust_grab(int reset); 87static int process_watch(char *str, int parent, int db); 88static void grab_buster_watch(int parent, char *dstr); 89 90 91void initialize_vnc_connect_prop(void) { 92 char *prop_str; 93 vnc_connect_str[0] = '\0'; 94 RAWFB_RET_VOID 95#if !NO_X11 96 prop_str = getenv("VNC_CONNECT"); 97 if (prop_str == NULL) { 98 prop_str = "VNC_CONNECT"; 99 } 100 vnc_connect_prop = XInternAtom(dpy, "VNC_CONNECT", False); 101#endif 102} 103 104void initialize_x11vnc_remote_prop(void) { 105 char *prop_str; 106 x11vnc_remote_str[0] = '\0'; 107 RAWFB_RET_VOID 108#if !NO_X11 109 prop_str = getenv("X11VNC_REMOTE"); 110 if (prop_str == NULL) { 111 prop_str = "X11VNC_REMOTE"; 112 } 113 x11vnc_remote_prop = XInternAtom(dpy, prop_str, False); 114#endif 115} 116 117void initialize_clipboard_atom(void) { 118 RAWFB_RET_VOID 119#if NO_X11 120 return; 121#else 122 clipboard_atom = XInternAtom(dpy, "CLIPBOARD", False); 123 if (clipboard_atom == None) { 124 if (! quiet) rfbLog("could not find atom CLIPBOARD\n"); 125 if (watch_clipboard) { 126 watch_clipboard = 0; 127 } 128 if (set_clipboard) { 129 set_clipboard = 0; 130 } 131 } 132#endif /* NO_X11 */ 133} 134 135/* 136 we observed these strings: 137 138 6 gdm_string: Gnome-power-manager 139 6 gdm_string: Gnome-session 140 6 gdm_string: Gnome-settings-daemon 141 6 gdm_string: Login Window 142 6 gdm_string: Notify-osd 143 6 gdm_string: Panel 144 12 gdm_string: Metacity 145 12 gdm_string: gnome-power-manager 146 12 gdm_string: gnome-session 147 12 gdm_string: gnome-settings-daemon 148 12 gdm_string: notify-osd 149 18 gdm_string: Gdm-simple-greeter 150 24 gdm_string: metacity 151 36 gdm_string: gdm-simple-greeter 152 153 kdmgreet 154 Kdmgreet 155 */ 156 157static int dm_string(char *str) { 158 char *s = getenv("DEBUG_WM_RUNNING"); 159 if (str == NULL) { 160 return 0; 161 } 162 if (str[0] == '\0') { 163 return 0; 164 } 165 if (0) fprintf(stderr, "dm_string: %s\n", str); 166 if (strstr(str, "gdm-") == str || strstr(str, "Gdm-") == str) { 167 if (strstr(str, "-greeter") != NULL) { 168 if (s) rfbLog("dm_string: %s\n", str); 169 return 1; 170 } 171 } 172 if (!strcmp(str, "kdmgreet") || !strcmp(str, "Kdmgreet")) { 173 if (s) rfbLog("dm_string: %s\n", str); 174 return 1; 175 } 176 return 0; 177} 178 179static int dm_still_running(void) { 180#if NO_X11 181 return 0; 182#else 183 Window r, parent; 184 Window *winlist; 185 unsigned int nc; 186 int rc, i; 187 static XClassHint *classhint = NULL; 188 XErrorHandler old_handler; 189 int saw_gdm_name = 0; 190 191 /* some times a window can go away before we get to it */ 192 trapped_xerror = 0; 193 old_handler = XSetErrorHandler(trap_xerror); 194 195 if (! classhint) { 196 classhint = XAllocClassHint(); 197 } 198 199 /* we are xlocked. */ 200 rc = XQueryTree_wr(dpy, DefaultRootWindow(dpy), &r, &parent, &winlist, &nc); 201 if (!rc || winlist == NULL || nc == 0) { 202 nc = 0; 203 } 204 for (i=0; i < (int) nc; i++) { 205 char *name = NULL; 206 Window w = winlist[i]; 207 if (XFetchName(dpy, w, &name) && name != NULL) { 208 saw_gdm_name += dm_string(name); 209 XFree_wr(name); 210 } 211 classhint->res_name = NULL; 212 classhint->res_class = NULL; 213 if (XGetClassHint(dpy, w, classhint)) { 214 name = classhint->res_name; 215 if (name != NULL) { 216 saw_gdm_name += dm_string(name); 217 XFree_wr(name); 218 } 219 name = classhint->res_class; 220 if (name != NULL) { 221 saw_gdm_name += dm_string(name); 222 XFree_wr(name); 223 } 224 } 225 if (saw_gdm_name > 0) { 226 break; 227 } 228 } 229 if (winlist != NULL) { 230 XFree_wr(winlist); 231 } 232 233 XSync(dpy, False); 234 XSetErrorHandler(old_handler); 235 trapped_xerror = 0; 236 237 return saw_gdm_name; 238#endif 239} 240 241static int wm_running(void) { 242 char *s = getenv("DEBUG_WM_RUNNING"); 243 int ret = 0; 244 RAWFB_RET(0) 245#if NO_X11 246 return 0; 247#else 248 /* 249 * Unfortunately with recent GDM (v2.28), they run gnome-session, 250 * dbus-launch, and metacity for the Login greeter! So the simple 251 * XInternAtom checks below no longer work. 252 * We also see a similar thing with KDE. 253 */ 254 if (dm_still_running()) { 255 return 0; 256 } 257 258 /* we are xlocked. */ 259 if (XInternAtom(dpy, "_NET_SUPPORTED", True) != None) { 260 if (s) rfbLog("wm is running (_NET_SUPPORTED).\n"); 261 ret++; 262 } 263 if (XInternAtom(dpy, "_WIN_PROTOCOLS", True) != None) { 264 if (s) rfbLog("wm is running (_WIN_PROTOCOLS).\n"); 265 ret++; 266 } 267 if (XInternAtom(dpy, "_XROOTPMAP_ID", True) != None) { 268 if (s) rfbLog("wm is running (_XROOTPMAP_ID).\n"); 269 ret++; 270 } 271 if (XInternAtom(dpy, "_MIT_PRIORITY_COLORS", True) != None) { 272 if (s) rfbLog("wm is running (_MIT_PRIORITY_COLORS).\n"); 273 ret++; 274 } 275 if (!ret) { 276 if (s) rfbLog("wm is not running.\n"); 277 return 0; 278 } else { 279 if (s) rfbLog("wm is running ret=%d.\n", ret); 280 return 1; 281 } 282#endif /* NO_X11 */ 283 284} 285 286int guess_dm_gone(int t1, int t2) { 287 int wait = t2; 288 char *avoid = getenv("X11VNC_AVOID_WINDOWS"); 289 time_t tcheck = last_client; 290 291 if (last_open_xdisplay > last_client) { 292 /* better time for -display WAIT:... */ 293 tcheck = last_open_xdisplay; 294 } 295 296 if (avoid && !strcmp(avoid, "never")) { 297 return 1; 298 } 299 if (!screen || !screen->clientHead) { 300 return 0; 301 } 302 if (avoid) { 303 int n = atoi(avoid); 304 if (n > 1) { 305 wait = n; 306 } else { 307 wait = 90; 308 } 309 } else { 310 static time_t saw_wm = 0; 311 312 wait = t2; 313 314 X_LOCK; 315 if (wm_running()) { 316 if (saw_wm == 0) { 317 saw_wm = time(NULL); 318 } else if (time(NULL) <= saw_wm + 2) { 319 /* try to wait a few seconds after transition */ 320 ; 321 } else { 322 wait = t1; 323 } 324 } 325 X_UNLOCK; 326 } 327 if (getenv("DEBUG_WM_RUNNING")) { 328 rfbLog("guess_dm_gone: wait=%d\n", wait); 329 } 330 /* we assume they've logged in OK after wait seconds... */ 331 if (time(NULL) <= tcheck + wait) { 332 return 0; 333 } 334 return 1; 335} 336 337static void initialize_xevents(int reset) { 338#if NO_X11 339 RAWFB_RET_VOID 340 if (!reset) {} 341 return; 342#else 343 static int did_xselect_input = 0; 344 static int did_xcreate_simple_window = 0; 345 static int did_vnc_connect_prop = 0; 346 static int did_x11vnc_remote_prop = 0; 347 static int did_clipboard_atom = 0; 348 static int did_xfixes = 0; 349 static int did_xdamage = 0; 350 static int did_xrandr = 0; 351 352 RAWFB_RET_VOID 353 354 if (reset) { 355 did_xselect_input = 0; 356 did_xcreate_simple_window = 0; 357 did_vnc_connect_prop = 0; 358 did_x11vnc_remote_prop = 0; 359 did_clipboard_atom = 0; 360 did_xfixes = 0; 361 did_xdamage = 0; 362 did_xrandr = 0; 363 } 364 365 if ((watch_selection || vnc_connect) && !did_xselect_input) { 366 /* 367 * register desired event(s) for notification. 368 * PropertyChangeMask is for CUT_BUFFER0 changes. 369 * XXX: does this cause a flood of other stuff? 370 */ 371 X_LOCK; 372 xselectinput_rootwin |= PropertyChangeMask; 373 XSelectInput_wr(dpy, rootwin, xselectinput_rootwin); 374 375 if (subwin && freeze_when_obscured) { 376 XSelectInput_wr(dpy, subwin, VisibilityChangeMask); 377 } 378 X_UNLOCK; 379 did_xselect_input = 1; 380 } 381 if (watch_selection && !did_xcreate_simple_window) { 382 /* create fake window for our selection ownership, etc */ 383 384 /* 385 * We try to delay creating selwin until we are past 386 * any GDM, (or other KillInitClients=true) manager. 387 */ 388 if (guess_dm_gone(8, 45)) { 389 X_LOCK; 390 selwin = XCreateSimpleWindow(dpy, rootwin, 3, 2, 1, 1, 0, 0, 0); 391 X_UNLOCK; 392 did_xcreate_simple_window = 1; 393 if (! quiet) rfbLog("created selwin: 0x%lx\n", selwin); 394 } 395 } 396 397 if ((xrandr || xrandr_maybe) && !did_xrandr) { 398 initialize_xrandr(); 399 did_xrandr = 1; 400 } 401 if (vnc_connect && !did_vnc_connect_prop) { 402 initialize_vnc_connect_prop(); 403 did_vnc_connect_prop = 1; 404 } 405 if (vnc_connect && !did_x11vnc_remote_prop) { 406 initialize_x11vnc_remote_prop(); 407 did_x11vnc_remote_prop = 1; 408 } 409 if (run_gui_pid > 0) { 410 kill(run_gui_pid, SIGUSR1); 411 run_gui_pid = 0; 412 } 413 if (!did_clipboard_atom) { 414 initialize_clipboard_atom(); 415 did_clipboard_atom = 1; 416 } 417 if (xfixes_present && use_xfixes && !did_xfixes) { 418 /* 419 * We try to delay creating initializing xfixes until 420 * we are past the display manager, due to Xorg bug: 421 * http://bugs.freedesktop.org/show_bug.cgi?id=18451 422 */ 423 if (guess_dm_gone(8, 45)) { 424 initialize_xfixes(); 425 did_xfixes = 1; 426 if (! quiet) rfbLog("called initialize_xfixes()\n"); 427 } 428 } 429 if (xdamage_present && !did_xdamage) { 430 initialize_xdamage(); 431 did_xdamage = 1; 432 } 433#endif /* NO_X11 */ 434} 435 436static void print_xevent_bases(void) { 437 fprintf(stderr, "X event bases: xkb=%d, xtest=%d, xrandr=%d, " 438 "xfixes=%d, xdamage=%d, xtrap=%d\n", xkb_base_event_type, 439 xtest_base_event_type, xrandr_base_event_type, 440 xfixes_base_event_type, xdamage_base_event_type, 441 xtrap_base_event_type); 442 fprintf(stderr, " MapNotify=%d, ClientMsg=%d PropNotify=%d " 443 "SelNotify=%d, SelRequest=%d\n", MappingNotify, ClientMessage, 444 PropertyNotify, SelectionNotify, SelectionRequest); 445 fprintf(stderr, " SelClear=%d, Expose=%d\n", SelectionClear, Expose); 446} 447 448void get_prop(char *str, int len, Atom prop, Window w) { 449 int i; 450#if !NO_X11 451 Atom type; 452 int format, slen, dlen; 453 unsigned long nitems = 0, bytes_after = 0; 454 unsigned char* data = NULL; 455#endif 456 457 for (i=0; i<len; i++) { 458 str[i] = '\0'; 459 } 460 if (prop == None) { 461 return; 462 } 463 464 RAWFB_RET_VOID 465 466#if NO_X11 467 return; 468#else 469 470 slen = 0; 471 if (w == None) { 472 w = DefaultRootWindow(dpy); 473 } 474 475 do { 476 if (XGetWindowProperty(dpy, w, 477 prop, nitems/4, len/16, False, 478 AnyPropertyType, &type, &format, &nitems, &bytes_after, 479 &data) == Success) { 480 481 dlen = nitems * (format/8); 482 if (slen + dlen > len) { 483 /* too big */ 484 XFree_wr(data); 485 break; 486 } 487 memcpy(str+slen, data, dlen); 488 slen += dlen; 489 str[slen] = '\0'; 490 XFree_wr(data); 491 } 492 } while (bytes_after > 0); 493#endif /* NO_X11 */ 494} 495 496static void bust_grab(int reset) { 497#if NO_X11 498 if (!reset) {} 499 return; 500#else 501 static int bust_count = 0; 502 static time_t last_bust = 0; 503 time_t now = time(NULL); 504 KeyCode key; 505 int button, x, y, nb; 506 507 if (now > last_bust + 180) { 508 bust_count = 0; 509 } 510 if (reset) { 511 bust_count = 0; 512 return; 513 } 514 515 x = 0; 516 y = 0; 517 button = 0; 518 key = NoSymbol; 519 520 nb = 8; 521 if (bust_count >= 3 * nb) { 522 fprintf(stderr, "too many bust_grab's %d for me\n", bust_count); 523 exit(0); 524 } 525 if (bust_count % nb == 0) { 526 button = 1; 527 } else if (bust_count % nb == 1) { 528 button = 1; 529 } else if (bust_count % nb == 2) { 530 key = XKeysymToKeycode(dpy, XK_Escape); 531 } else if (bust_count % nb == 3) { 532 button = 3; 533 } else if (bust_count % nb == 4) { 534 key = XKeysymToKeycode(dpy, XK_space); 535 } else if (bust_count % nb == 5) { 536 x = bust_count * 23; 537 y = bust_count * 17; 538 } else if (bust_count % nb == 5) { 539 button = 2; 540 } else if (bust_count % nb == 6) { 541 key = XKeysymToKeycode(dpy, XK_a); 542 } 543 544 if (key == NoSymbol) { 545 key = XKeysymToKeycode(dpy, XK_a); 546 if (key == NoSymbol) { 547 button = 1; 548 } 549 } 550 551 bust_count++; 552 553 if (button) { 554 /* try button press+release */ 555 fprintf(stderr, "**bust_grab: button%d %.4f\n", 556 button, dnowx()); 557 XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime); 558 XFlush_wr(dpy); 559 usleep(50 * 1000); 560 XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime); 561 } else if (x > 0) { 562 /* try button motion*/ 563 int scr = DefaultScreen(dpy); 564 565 fprintf(stderr, "**bust_grab: x=%d y=%d %.4f\n", x, y, 566 dnowx()); 567 XTestFakeMotionEvent_wr(dpy, scr, x, y, CurrentTime); 568 XFlush_wr(dpy); 569 usleep(50 * 1000); 570 571 /* followed by button press */ 572 button = 1; 573 fprintf(stderr, "**bust_grab: button%d\n", button); 574 XTestFakeButtonEvent_wr(dpy, button, True, CurrentTime); 575 XFlush_wr(dpy); 576 usleep(50 * 1000); 577 XTestFakeButtonEvent_wr(dpy, button, False, CurrentTime); 578 } else { 579 /* try Escape or Space press+release */ 580 fprintf(stderr, "**bust_grab: keycode: %d %.4f\n", 581 (int) key, dnowx()); 582 XTestFakeKeyEvent_wr(dpy, key, True, CurrentTime); 583 XFlush_wr(dpy); 584 usleep(50 * 1000); 585 XTestFakeKeyEvent_wr(dpy, key, False, CurrentTime); 586 } 587 XFlush_wr(dpy); 588 last_bust = time(NULL); 589#endif /* NO_X11 */ 590} 591 592typedef struct _grabwatch { 593 int pid; 594 int tick; 595 unsigned long time; 596 time_t change; 597} grabwatch_t; 598#define GRABWATCH 16 599 600static int grab_buster_delay = 20; 601static pid_t grab_buster_pid = 0; 602 603static int grab_npids = 1; 604 605static int process_watch(char *str, int parent, int db) { 606 int i, pid, ticker, npids; 607 char diff[128]; 608 unsigned long xtime; 609 static grabwatch_t watches[GRABWATCH]; 610 static int first = 1; 611 time_t now = time(NULL); 612 static time_t last_bust = 0; 613 int too_long, problems = 0; 614 615 if (first) { 616 for (i=0; i < GRABWATCH; i++) { 617 watches[i].pid = 0; 618 watches[i].tick = 0; 619 watches[i].time = 0; 620 watches[i].change = 0; 621 } 622 first = 0; 623 } 624 625 /* record latest value of prop */ 626 if (str && *str != '\0') { 627 if (sscanf(str, "%d/%d/%lu/%s", &pid, &ticker, &xtime, diff) 628 == 4) { 629 int got = -1, free = -1; 630 631 if (db) fprintf(stderr, "grab_buster %d - %d - %lu - %s" 632 "\n", pid, ticker, xtime, diff); 633 634 if (pid == parent && !strcmp(diff, "QUIT")) { 635 /* that's it. */ 636 return 0; 637 } 638 if (pid == 0 || ticker == 0 || xtime == 0) { 639 /* bad prop read. */ 640 goto badtickerstr; 641 } 642 for (i=0; i < GRABWATCH; i++) { 643 if (watches[i].pid == pid) { 644 got = i; 645 break; 646 } 647 if (free == -1 && watches[i].pid == 0) { 648 free = i; 649 } 650 } 651 if (got == -1) { 652 if (free == -1) { 653 /* bad news */; 654 free = GRABWATCH - 1; 655 } 656 watches[free].pid = pid; 657 watches[free].tick = ticker; 658 watches[free].time = xtime; 659 watches[free].change = now; 660 if (db) fprintf(stderr, "grab_buster free slot: %d\n", free); 661 } else { 662 if (db) fprintf(stderr, "grab_buster got slot: %d\n", got); 663 if (watches[got].tick != ticker) { 664 watches[got].change = now; 665 } 666 if (watches[got].time != xtime) { 667 watches[got].change = now; 668 } 669 watches[got].tick = ticker; 670 watches[got].time = xtime; 671 } 672 } else { 673 if (db) fprintf(stderr, "grab_buster bad prop str: %s\n", str); 674 } 675 } 676 677 badtickerstr: 678 679 too_long = grab_buster_delay; 680 if (too_long < 3 * sync_tod_delay) { 681 too_long = 3 * sync_tod_delay; 682 } 683 684 npids = 0; 685 for (i=0; i < GRABWATCH; i++) { 686 if (watches[i].pid) { 687 npids++; 688 } 689 } 690 grab_npids = npids; 691 if (npids > 4) { 692 npids = 4; 693 } 694 695 /* now check everyone we are tracking */ 696 for (i=0; i < GRABWATCH; i++) { 697 int fac = 1; 698 if (!watches[i].pid) { 699 continue; 700 } 701 if (watches[i].change == 0) { 702 watches[i].change = now; /* just to be sure */ 703 continue; 704 } 705 706 pid = watches[i].pid; 707 708 if (pid != parent) { 709 fac = 2; 710 } 711 if (npids > 0) { 712 fac *= npids; 713 } 714 715 if (now > watches[i].change + fac*too_long) { 716 int process_alive = 1; 717 718 fprintf(stderr, "grab_buster: problem with pid: " 719 "%d - %d/%d/%d\n", pid, (int) now, 720 (int) watches[i].change, too_long); 721 722 if (kill((pid_t) pid, 0) != 0) { 723 if (1 || errno == ESRCH) { 724 process_alive = 0; 725 } 726 } 727 728 if (!process_alive) { 729 watches[i].pid = 0; 730 watches[i].tick = 0; 731 watches[i].time = 0; 732 watches[i].change = 0; 733 fprintf(stderr, "grab_buster: pid gone: %d\n", 734 pid); 735 if (pid == parent) { 736 /* that's it */ 737 return 0; 738 } 739 } else { 740 int sleep = sync_tod_delay * 1000 * 1000; 741 742 bust_grab(0); 743 problems++; 744 last_bust = now; 745 usleep(1 * sleep); 746 break; 747 } 748 } 749 } 750 751 if (!problems) { 752 bust_grab(1); 753 } 754 return 1; 755} 756 757static void grab_buster_watch(int parent, char *dstr) { 758#if NO_X11 759 RAWFB_RET_VOID 760 if (!parent || !dstr) {} 761 return; 762#else 763 Atom ticker_atom = None; 764 int sleep = sync_tod_delay * 921 * 1000; 765 char propval[200]; 766 int ev, er, maj, min; 767 int db = 0; 768 char *ticker_str = "X11VNC_TICKER"; 769 770 RAWFB_RET_VOID 771 772 if (grab_buster > 1) { 773 db = 1; 774 } 775 776 /* overwrite original dpy, we let orig connection sit unused. */ 777 dpy = XOpenDisplay_wr(dstr); 778 if (!dpy) { 779 fprintf(stderr, "grab_buster_watch: could not reopen: %s\n", 780 dstr); 781 return; 782 } 783 rfbLogEnable(0); 784 785 /* check for XTEST, etc, and then disable grabs for us */ 786 if (! XTestQueryExtension_wr(dpy, &ev, &er, &maj, &min)) { 787 xtest_present = 0; 788 } else { 789 xtest_present = 1; 790 } 791 if (! XETrapQueryExtension_wr(dpy, &ev, &er, &maj)) { 792 xtrap_present = 0; 793 } else { 794 xtrap_present = 1; 795 } 796 797 if (! xtest_present && ! xtrap_present) { 798 fprintf(stderr, "grab_buster_watch: no grabserver " 799 "protection on display: %s\n", dstr); 800 return; 801 } 802 disable_grabserver(dpy, 0); 803 804 usleep(3 * sleep); 805 806 if (getenv("X11VNC_TICKER")) { 807 ticker_str = getenv("X11VNC_TICKER"); 808 } 809 ticker_atom = XInternAtom(dpy, ticker_str, False); 810 if (! ticker_atom) { 811 fprintf(stderr, "grab_buster_watch: no ticker atom\n"); 812 return; 813 } 814 815 while(1) { 816 int slp = sleep; 817 if (grab_npids > 1) { 818 slp = slp / 8; 819 } 820 usleep(slp); 821 usleep((int) (0.60 * rfac() * slp)); 822 823 if (kill((pid_t) parent, 0) != 0) { 824 break; 825 } 826 827 get_prop(propval, 128, ticker_atom, None); 828 if (db) fprintf(stderr, "got_prop: %s\n", propval); 829 830 if (!process_watch(propval, parent, db)) { 831 break; 832 } 833 } 834#endif /* NO_X11 */ 835} 836 837void spawn_grab_buster(void) { 838#if LIBVNCSERVER_HAVE_FORK 839 pid_t pid; 840 int parent = (int) getpid(); 841 char *dstr = strdup(DisplayString(dpy)); 842 843 RAWFB_RET_VOID 844 845 XCloseDisplay_wr(dpy); 846 dpy = NULL; 847 848 if ((pid = fork()) > 0) { 849 grab_buster_pid = pid; 850 if (! quiet) { 851 rfbLog("grab_buster pid is: %d\n", (int) pid); 852 } 853 } else if (pid == -1) { 854 fprintf(stderr, "spawn_grab_buster: could not fork\n"); 855 rfbLogPerror("fork"); 856 } else { 857 signal(SIGHUP, SIG_DFL); 858 signal(SIGINT, SIG_DFL); 859 signal(SIGQUIT, SIG_DFL); 860 signal(SIGTERM, SIG_DFL); 861 862 grab_buster_watch(parent, dstr); 863 exit(0); 864 } 865 866 dpy = XOpenDisplay_wr(dstr); 867 if (!dpy) { 868 rfbLog("failed to reopen display %s in spawn_grab_buster\n", 869 dstr); 870 exit(1); 871 } 872#endif 873} 874 875void sync_tod_with_servertime(void) { 876#if NO_X11 877 RAWFB_RET_VOID 878 return; 879#else 880 static Atom ticker_atom = None; 881 XEvent xev; 882 char diff[128]; 883 static int seq = 0; 884 static unsigned long xserver_ticks = 1; 885 int i, db = 0; 886 887 RAWFB_RET_VOID 888 889 if (atom_NET_ACTIVE_WINDOW == None) { 890 atom_NET_ACTIVE_WINDOW = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", True); 891 } 892 if (atom_NET_CURRENT_DESKTOP == None) { 893 atom_NET_CURRENT_DESKTOP = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", True); 894 } 895 if (atom_NET_CLIENT_LIST_STACKING == None) { 896 atom_NET_CLIENT_LIST_STACKING = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", True); 897 } 898 if (atom_XROOTPMAP_ID == None) { 899 atom_XROOTPMAP_ID = XInternAtom(dpy, "_XROOTPMAP_ID", True); 900 } 901 902 if (! ticker_atom) { 903 char *ticker_str = "X11VNC_TICKER"; 904 if (getenv("X11VNC_TICKER")) { 905 ticker_str = getenv("X11VNC_TICKER"); 906 } 907 ticker_atom = XInternAtom(dpy, ticker_str, False); 908 } 909 if (! ticker_atom) { 910 return; 911 } 912 913 XSync(dpy, False); 914 while (XCheckTypedEvent(dpy, PropertyNotify, &xev)) { 915 set_prop_atom(xev.xproperty.atom); 916 } 917 918 snprintf(diff, 128, "%d/%08d/%lu/%.6f", (int) getpid(), seq++, 919 xserver_ticks, servertime_diff); 920 XChangeProperty(dpy, rootwin, ticker_atom, XA_STRING, 8, 921 PropModeReplace, (unsigned char *) diff, strlen(diff)); 922 XSync(dpy, False); 923 924 for (i=0; i < 10; i++) { 925 int k, got = 0; 926 927 for (k=0; k < 5; k++) { 928 while (XCheckTypedEvent(dpy, PropertyNotify, &xev)) { 929 if (xev.xproperty.atom == ticker_atom) { 930 double stime; 931 932 xserver_ticks = xev.xproperty.time; 933 stime = (double) xev.xproperty.time; 934 stime = stime/1000.0; 935 servertime_diff = dnow() - stime; 936 if (db) rfbLog("set servertime_diff: " 937 "%.6f\n", servertime_diff); 938 got = 1; 939 } 940 } 941 } 942 if (got) { 943 break; 944 } 945 usleep(1000); 946 } 947#endif /* NO_X11 */ 948} 949 950void check_keycode_state(void) { 951 static time_t last_check = 0; 952 int delay = 10, noinput = 3; 953 time_t now = time(NULL); 954 955 if (! client_count) { 956 return; 957 } 958 if (unixpw_in_progress) return; 959 960 RAWFB_RET_VOID 961 962 /* 963 * periodically update our model of the keycode_state[] 964 * by correlating with the Xserver. wait for a pause in 965 * keyboard input to be on the safe side. the idea here 966 * is to remove stale keycode state, not to be perfectly 967 * in sync with the Xserver at every instant of time. 968 */ 969 if (now > last_check + delay && now > last_keyboard_input + noinput) { 970 X_LOCK; 971 init_track_keycode_state(); 972 X_UNLOCK; 973 last_check = now; 974 } 975} 976 977/* 978 * To use the experimental -grablocal option configure like this: 979 * env CPPFLAGS=-DENABLE_GRABLOCAL LDFLAGS=-lXss ./configure 980 */ 981#ifdef ENABLE_GRABLOCAL 982#include <X11/extensions/scrnsaver.h> 983 984void check_local_grab(void) { 985 static double last_check = 0.0; 986 double now; 987 988 if (grab_local <= 0) { 989 return; 990 } 991 if (! client_count) { 992 return; 993 } 994 if (unixpw_in_progress) return; 995 996 if (last_rfb_key_injected <= 0.0 && last_rfb_ptr_injected <= 0.0) { 997 return; 998 } 999 1000 RAWFB_RET_VOID 1001 1002 now = dnow(); 1003 1004 if (now > last_check + 0.1) { 1005#if !NO_X11 1006 int ret; 1007 double idle; 1008 XScreenSaverInfo info; 1009 static int save_viewonly = -1, local_is_idle = -1, db = -1; 1010 1011 if (debug_keyboard) db = debug_keyboard; 1012 if (debug_pointer ) db = debug_pointer; 1013 1014 if (db < 0) { 1015 if (getenv("LOCAL_GRAB_DEBUG")) { 1016 db = atoi(getenv("LOCAL_GRAB_DEBUG")); 1017 } else { 1018 db = 0; 1019 } 1020 } 1021 1022 ret = XScreenSaverQueryInfo(dpy, RootWindowOfScreen( 1023 ScreenOfDisplay(dpy, 0)), &info); 1024 1025 if (ret) { 1026 double tlatest_rfb = 0.0; 1027 1028 idle = ((double) info.idle)/1000.0; 1029 now = dnow(); 1030 1031 if (last_rfb_key_injected > 0.0) { 1032 tlatest_rfb = last_rfb_key_injected; 1033 } 1034 if (last_rfb_ptr_injected > tlatest_rfb) { 1035 tlatest_rfb = last_rfb_ptr_injected; 1036 } 1037 if (db > 1) fprintf(stderr, "idle: %.4f latest: %.4f dt: %.4f\n", idle, now - tlatest_rfb, idle - (now - tlatest_rfb)); 1038 1039 if (now - tlatest_rfb <= idle + 0.005) { 1040 /* 0.005 is 5ms tolerance */ 1041 } else if (idle < grab_local) { 1042 if (local_is_idle < 0 || local_is_idle) { 1043 save_viewonly = view_only; 1044 view_only = 1; 1045 if (db) { 1046 rfbLog("check_local_grab: set viewonly\n"); 1047 } 1048 } 1049 1050 local_is_idle = 0; 1051 } else { 1052 if (!local_is_idle && save_viewonly >= 0) { 1053 view_only = save_viewonly; 1054 if (db) { 1055 rfbLog("check_local_grab: restored viewonly; %d\n", view_only); 1056 } 1057 } 1058 local_is_idle = 1; 1059 } 1060 } 1061#endif 1062 last_check = dnow(); 1063 } 1064} 1065#endif 1066 1067void check_autorepeat(void) { 1068 static time_t last_check = 0; 1069 static int idle_timeout = -300, idle_reset = 0; 1070 time_t now = time(NULL); 1071 int autorepeat_is_on, autorepeat_initially_on; 1072 1073 if (! no_autorepeat || ! client_count) { 1074 return; 1075 } 1076 if (now <= last_check + 1) { 1077 return; 1078 } 1079 1080 if (unixpw_in_progress) return; 1081 1082 if (idle_timeout < 0) { 1083 if (getenv("X11VNC_IDLE_TIMEOUT")) { 1084 idle_timeout = atoi(getenv("X11VNC_IDLE_TIMEOUT")); 1085 } 1086 if (idle_timeout < 0) { 1087 idle_timeout = -idle_timeout; 1088 } 1089 } 1090 1091 last_check = now; 1092 1093 autorepeat_is_on = get_autorepeat_state(); 1094 autorepeat_initially_on = get_initial_autorepeat_state(); 1095 1096 if (view_only) { 1097 if (! autorepeat_is_on) { 1098 autorepeat(1, 1); 1099 } 1100 return; 1101 } 1102 1103 if (now > last_keyboard_input + idle_timeout) { 1104 /* autorepeat should be on when idle */ 1105 if (! autorepeat_is_on && autorepeat_initially_on) { 1106 static time_t last_msg = 0; 1107 static int cnt = 0; 1108 if (now > last_msg + idle_timeout && cnt++ < 10) { 1109 rfbLog("idle keyboard: turning X autorepeat" 1110 " back on.\n"); 1111 last_msg = now; 1112 } 1113 autorepeat(1, 1); 1114 idle_reset = 1; 1115 } 1116 } else { 1117 if (idle_reset) { 1118 int i, state[256], didmsg = 0, pressed = 0; 1119 int mwt = 600, mmax = 20; 1120 static int msgcnt = 0; 1121 static double lastmsg = 0.0; 1122 1123 for (i=0; i<256; i++) { 1124 state[i] = 0; 1125 } 1126 if (use_threads) {X_LOCK;} 1127 get_keystate(state); 1128 if (use_threads) {X_UNLOCK;} 1129 1130 for (i=0; i<256; i++) { 1131 if (state[i] != 0) { 1132 /* better wait until all keys are up */ 1133 pressed++; 1134 if (msgcnt < mmax || dnow() > lastmsg + mwt) { 1135 char *str = "unset"; 1136#if !NO_X11 1137 if (use_threads) {X_LOCK;} 1138 str = XKeysymToString(XKeycodeToKeysym(dpy, i, 0)); 1139 if (use_threads) {X_UNLOCK;} 1140#endif 1141 str = str ? str : "nosymbol"; 1142 didmsg++; 1143 rfbLog("active keyboard: waiting until " 1144 "all keys are up. key_down=%d %s. " 1145 "If the key is inaccessible via keyboard, " 1146 "consider 'x11vnc -R clear_all'\n", i, str); 1147 } 1148 } 1149 } 1150 if (didmsg > 0) { 1151 msgcnt++; 1152 if (msgcnt == mmax) { 1153 rfbLog("active keyboard: last such " 1154 "message for %d secs.\n", mwt); 1155 } 1156 lastmsg = dnow(); 1157 } 1158 if (pressed > 0) { 1159 return; 1160 } 1161 } 1162 if (idle_reset) { 1163 static time_t last_msg = 0; 1164 static int cnt = 0; 1165 if (now > last_msg + idle_timeout && cnt++ < 10) { 1166 rfbLog("active keyboard: turning X autorepeat" 1167 " off.\n"); 1168 last_msg = now; 1169 } 1170 autorepeat(0, 1); 1171 idle_reset = 0; 1172 1173 } else if (no_repeat_countdown && autorepeat_is_on) { 1174 int n = no_repeat_countdown - 1; 1175 if (n >= 0) { 1176 rfbLog("Battling with something for " 1177 "-norepeat!! (%d resets left)\n", n); 1178 } else { 1179 rfbLog("Battling with something for " 1180 "-norepeat!!\n"); 1181 } 1182 if (no_repeat_countdown > 0) { 1183 no_repeat_countdown--; 1184 } 1185 autorepeat(1, 0); 1186 autorepeat(0, 0); 1187 } 1188 } 1189} 1190 1191void set_prop_atom(Atom atom) { 1192 if (atom == None) return; 1193 if (atom == atom_NET_ACTIVE_WINDOW) got_NET_ACTIVE_WINDOW = dnow(); 1194 if (atom == atom_NET_CURRENT_DESKTOP) got_NET_CURRENT_DESKTOP = dnow(); 1195 if (atom == atom_NET_CLIENT_LIST_STACKING) got_NET_CLIENT_LIST_STACKING = dnow(); 1196 if (atom == atom_XROOTPMAP_ID) got_XROOTPMAP_ID = dnow(); 1197} 1198 1199/* 1200 * This routine is periodically called to check for selection related 1201 * and other X11 events and respond to them as needed. 1202 */ 1203void check_xevents(int reset) { 1204#if NO_X11 1205 RAWFB_RET_VOID 1206 if (!reset) {} 1207 return; 1208#else 1209 XEvent xev; 1210 int tmp, have_clients = 0; 1211 static int sent_some_sel = 0; 1212 static time_t last_call = 0; 1213 static time_t last_bell = 0; 1214 static time_t last_init_check = 0; 1215 static time_t last_sync = 0; 1216 static time_t last_time_sync = 0; 1217 time_t now = time(NULL); 1218 static double last_request = 0.0; 1219 static double last_xrefresh = 0.0; 1220 XErrorHandler old_handler; 1221 1222 if (unixpw_in_progress) return; 1223 1224 RAWFB_RET_VOID 1225 1226 if (now > last_init_check+1 || reset) { 1227 last_init_check = now; 1228 initialize_xevents(reset); 1229 if (reset) { 1230 return; 1231 } 1232 } 1233 1234 if (screen && screen->clientHead) { 1235 have_clients = 1; 1236 } 1237 1238 X_LOCK; 1239 /* 1240 * There is a bug where we have to wait before sending text to 1241 * the client... so instead of sending right away we wait a 1242 * the few seconds. 1243 */ 1244 1245 if (have_clients && watch_selection && !sent_some_sel 1246 && now > last_client + sel_waittime) { 1247 if (XGetSelectionOwner(dpy, XA_PRIMARY) == None) { 1248 cutbuffer_send(); 1249 } 1250 sent_some_sel = 1; 1251 } 1252 if (! have_clients) { 1253 /* 1254 * If we don't have clients we can miss the X server 1255 * going away until a client connects. 1256 */ 1257 static time_t last_X_ping = 0; 1258 if (now > last_X_ping + 5) { 1259 last_X_ping = now; 1260 XGetSelectionOwner(dpy, XA_PRIMARY); 1261 } 1262 } 1263 1264 if (have_clients && xrefresh > 0.0 && dnow() > last_xrefresh + xrefresh) { 1265 XSetWindowAttributes swa; 1266 Visual visual; 1267 Window xrf; 1268 unsigned long mask; 1269 1270 swa.override_redirect = True; 1271 swa.backing_store = NotUseful; 1272 swa.save_under = False; 1273 swa.background_pixmap = None; 1274 visual.visualid = CopyFromParent; 1275 mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap); 1276 1277 xrf = XCreateWindow(dpy, window, coff_x, coff_y, dpy_x, dpy_y, 0, CopyFromParent, 1278 InputOutput, &visual, mask, &swa); 1279 if (xrf != None) { 1280 if (0) fprintf(stderr, "XCreateWindow(%d, %d, %d, %d) 0x%lx\n", coff_x, coff_y, dpy_x, dpy_y, xrf); 1281 XMapWindow(dpy, xrf); 1282 XFlush_wr(dpy); 1283 XDestroyWindow(dpy, xrf); 1284 XFlush_wr(dpy); 1285 } 1286 last_xrefresh = dnow(); 1287 } 1288 1289 if (now > last_call+1) { 1290 /* we only check these once a second or so. */ 1291 int n = 0; 1292 1293 trapped_xerror = 0; 1294 old_handler = XSetErrorHandler(trap_xerror); 1295 1296 while (XCheckTypedEvent(dpy, MappingNotify, &xev)) { 1297 XRefreshKeyboardMapping((XMappingEvent *) &xev); 1298 n++; 1299 } 1300 if (n && use_modifier_tweak) { 1301 X_UNLOCK; 1302 initialize_modtweak(); 1303 X_LOCK; 1304 } 1305 if (xtrap_base_event_type) { 1306 int base = xtrap_base_event_type; 1307 while (XCheckTypedEvent(dpy, base, &xev)) { 1308 ; 1309 } 1310 } 1311 if (xtest_base_event_type) { 1312 int base = xtest_base_event_type; 1313 while (XCheckTypedEvent(dpy, base, &xev)) { 1314 ; 1315 } 1316 } 1317 /* 1318 * we can get ClientMessage from our XSendEvent() call in 1319 * selection_request(). 1320 */ 1321 while (XCheckTypedEvent(dpy, ClientMessage, &xev)) { 1322 ; 1323 } 1324 1325 XSetErrorHandler(old_handler); 1326 trapped_xerror = 0; 1327 last_call = now; 1328 } 1329 1330 if (freeze_when_obscured) { 1331 if (XCheckTypedEvent(dpy, VisibilityNotify, &xev)) { 1332 if (xev.type == VisibilityNotify && xev.xany.window == subwin) { 1333 int prev = subwin_obscured; 1334 if (xev.xvisibility.state == VisibilityUnobscured) { 1335 subwin_obscured = 0; 1336 } else if (xev.xvisibility.state == VisibilityPartiallyObscured) { 1337 subwin_obscured = 1; 1338 } else { 1339 subwin_obscured = 2; 1340 } 1341 rfbLog("subwin_obscured: %d -> %d\n", prev, subwin_obscured); 1342 } 1343 } 1344 } 1345 1346 /* check for CUT_BUFFER0, VNC_CONNECT, X11VNC_REMOTE changes: */ 1347 if (XCheckTypedEvent(dpy, PropertyNotify, &xev)) { 1348 int got_cutbuffer = 0; 1349 int got_vnc_connect = 0; 1350 int got_x11vnc_remote = 0; 1351 static int prop_dbg = -1; 1352 1353 /* to avoid piling up between calls, read all PropertyNotify now */ 1354 do { 1355 if (xev.type == PropertyNotify) { 1356 if (xev.xproperty.atom == XA_CUT_BUFFER0) { 1357 got_cutbuffer++; 1358 } else if (vnc_connect && vnc_connect_prop != None 1359 && xev.xproperty.atom == vnc_connect_prop) { 1360 got_vnc_connect++; 1361 } else if (vnc_connect && x11vnc_remote_prop != None 1362 && xev.xproperty.atom == x11vnc_remote_prop) { 1363 got_x11vnc_remote++; 1364 } 1365 set_prop_atom(xev.xproperty.atom); 1366 } 1367 } while (XCheckTypedEvent(dpy, PropertyNotify, &xev)); 1368 1369 if (prop_dbg < 0) { 1370 prop_dbg = 0; 1371 if (getenv("PROP_DBG")) { 1372 prop_dbg = 1; 1373 } 1374 } 1375 1376 if (prop_dbg && (got_cutbuffer > 1 || got_vnc_connect > 1 || got_x11vnc_remote > 1)) { 1377 static double lastmsg = 0.0; 1378 static int count = 0; 1379 double now = dnow(); 1380 1381 if (1 && now > lastmsg + 300.0) { 1382 if (got_cutbuffer > 1) { 1383 rfbLog("check_xevents: warning: %d cutbuffer events since last check.\n", got_cutbuffer); 1384 } 1385 if (got_vnc_connect > 1) { 1386 rfbLog("check_xevents: warning: %d vnc_connect events since last check.\n", got_vnc_connect); 1387 } 1388 if (got_x11vnc_remote > 1) { 1389 rfbLog("check_xevents: warning: %d x11vnc_remote events since last check.\n", got_x11vnc_remote); 1390 } 1391 count++; 1392 if (count >= 3) { 1393 lastmsg = now; 1394 count = 0; 1395 } 1396 } 1397 } 1398 1399 if (got_cutbuffer) { 1400 /* 1401 * Go retrieve CUT_BUFFER0 and send it. 1402 * 1403 * set_cutbuffer is a flag to try to avoid 1404 * processing our own cutbuffer changes. 1405 */ 1406 if (have_clients && watch_selection && !set_cutbuffer) { 1407 cutbuffer_send(); 1408 sent_some_sel = 1; 1409 } 1410 set_cutbuffer = 0; 1411 } 1412 if (got_vnc_connect) { 1413 /* 1414 * Go retrieve VNC_CONNECT string. 1415 */ 1416 read_vnc_connect_prop(0); 1417 } 1418 if (got_x11vnc_remote) { 1419 /* 1420 * Go retrieve X11VNC_REMOTE string. 1421 */ 1422 read_x11vnc_remote_prop(0); 1423 } 1424 } 1425 1426 /* do this now that we have just cleared PropertyNotify */ 1427 tmp = 0; 1428 if (rfac() < 0.6) { 1429 tmp = 1; 1430 } 1431 if (now > last_time_sync + sync_tod_delay + tmp) { 1432 sync_tod_with_servertime(); 1433 last_time_sync = now; 1434 } 1435 1436#if LIBVNCSERVER_HAVE_LIBXRANDR 1437 if (xrandr || xrandr_maybe) { 1438 check_xrandr_event("check_xevents"); 1439 } 1440#endif 1441#if LIBVNCSERVER_HAVE_LIBXFIXES 1442 if (xfixes_present && use_xfixes && xfixes_first_initialized && xfixes_base_event_type) { 1443 if (XCheckTypedEvent(dpy, xfixes_base_event_type + 1444 XFixesCursorNotify, &xev)) { 1445 got_xfixes_cursor_notify++; 1446 } 1447 } 1448#endif 1449 1450 /* check for our PRIMARY request notification: */ 1451 if (watch_primary || watch_clipboard) { 1452 int doprimary = 1, doclipboard = 2, which, own = 0; 1453 double delay = 1.0; 1454 Atom atom; 1455 char *req; 1456 1457 if (XCheckTypedEvent(dpy, SelectionNotify, &xev)) { 1458 if (xev.type == SelectionNotify && 1459 xev.xselection.requestor == selwin && 1460 xev.xselection.property != None && 1461 xev.xselection.target == XA_STRING) { 1462 Atom s = xev.xselection.selection; 1463 if (s == XA_PRIMARY || s == clipboard_atom) { 1464 /* go retrieve it and check it */ 1465 if (now > last_client + sel_waittime 1466 || sent_some_sel) { 1467 selection_send(&xev); 1468 } 1469 } 1470 } 1471 } 1472 /* 1473 * Every second or so, request PRIMARY or CLIPBOARD, 1474 * unless we already own it or there is no owner or we 1475 * have no clients. 1476 * TODO: even at this low rate we should look into 1477 * and performance problems in odds cases (large text, 1478 * modem, etc.) 1479 */ 1480 which = 0; 1481 if (watch_primary && watch_clipboard && ! own_clipboard && 1482 ! own_primary) { 1483 delay = 0.6; 1484 } 1485 if (dnow() > last_request + delay) { 1486 /* 1487 * It is not a good idea to do both at the same 1488 * time so we must choose one: 1489 */ 1490 if (watch_primary && watch_clipboard) { 1491 static int count = 0; 1492 if (own_clipboard) { 1493 which = doprimary; 1494 } else if (own_primary) { 1495 which = doclipboard; 1496 } else if (count++ % 3 == 0) { 1497 which = doclipboard; 1498 } else { 1499 which = doprimary; 1500 } 1501 } else if (watch_primary) { 1502 which = doprimary; 1503 } else if (watch_clipboard) { 1504 which = doclipboard; 1505 } 1506 last_request = dnow(); 1507 } 1508 atom = None; 1509 req = "none"; 1510 if (which == doprimary) { 1511 own = own_primary; 1512 atom = XA_PRIMARY; 1513 req = "PRIMARY"; 1514 } else if (which == doclipboard) { 1515 own = own_clipboard; 1516 atom = clipboard_atom; 1517 req = "CLIPBOARD"; 1518 } 1519 if (which != 0 && ! own && have_clients && 1520 XGetSelectionOwner(dpy, atom) != None && selwin != None) { 1521 XConvertSelection(dpy, atom, XA_STRING, XA_STRING, 1522 selwin, CurrentTime); 1523 if (debug_sel) { 1524 rfbLog("request %s\n", req); 1525 } 1526 } 1527 } 1528 1529 if (own_primary || own_clipboard) { 1530 /* we own PRIMARY or CLIPBOARD, see if someone requested it: */ 1531 trapped_xerror = 0; 1532 old_handler = XSetErrorHandler(trap_xerror); 1533 1534 if (XCheckTypedEvent(dpy, SelectionRequest, &xev)) { 1535 if (own_primary && xev.type == SelectionRequest && 1536 xev.xselectionrequest.selection == XA_PRIMARY) { 1537 selection_request(&xev, "PRIMARY"); 1538 } 1539 if (own_clipboard && xev.type == SelectionRequest && 1540 xev.xselectionrequest.selection == clipboard_atom) { 1541 selection_request(&xev, "CLIPBOARD"); 1542 } 1543 } 1544 1545 /* we own PRIMARY or CLIPBOARD, see if we no longer own it: */ 1546 if (XCheckTypedEvent(dpy, SelectionClear, &xev)) { 1547 if (own_primary && xev.type == SelectionClear && 1548 xev.xselectionclear.selection == XA_PRIMARY) { 1549 own_primary = 0; 1550 if (xcut_str_primary) { 1551 free(xcut_str_primary); 1552 xcut_str_primary = NULL; 1553 } 1554 if (debug_sel) { 1555 rfbLog("Released PRIMARY.\n"); 1556 } 1557 } 1558 if (own_clipboard && xev.type == SelectionClear && 1559 xev.xselectionclear.selection == clipboard_atom) { 1560 own_clipboard = 0; 1561 if (xcut_str_clipboard) { 1562 free(xcut_str_clipboard); 1563 xcut_str_clipboard = NULL; 1564 } 1565 if (debug_sel) { 1566 rfbLog("Released CLIPBOARD.\n"); 1567 } 1568 } 1569 } 1570 1571 XSetErrorHandler(old_handler); 1572 trapped_xerror = 0; 1573 } 1574 1575 if (watch_bell || now > last_bell+1) { 1576 last_bell = now; 1577 check_bell_event(); 1578 } 1579 if (tray_request != None) { 1580 static time_t last_tray_request = 0; 1581 if (now > last_tray_request + 2) { 1582 last_tray_request = now; 1583 if (tray_embed(tray_request, tray_unembed)) { 1584 tray_window = tray_request; 1585 tray_request = None; 1586 } 1587 } 1588 } 1589 1590#ifndef DEBUG_XEVENTS 1591#define DEBUG_XEVENTS 1 1592#endif 1593#if DEBUG_XEVENTS 1594 if (debug_xevents) { 1595 static time_t last_check = 0; 1596 static time_t reminder = 0; 1597 static int freq = 0; 1598 1599 if (! freq) { 1600 if (getenv("X11VNC_REMINDER_RATE")) { 1601 freq = atoi(getenv("X11VNC_REMINDER_RATE")); 1602 } else { 1603 freq = 300; 1604 } 1605 } 1606 1607 if (now > last_check + 1) { 1608 int ev_type_max = 300, ev_size = 400; 1609 XEvent xevs[400]; 1610 int i, tot = XEventsQueued(dpy, QueuedAlready); 1611 1612 if (reminder == 0 || (tot && now > reminder + freq)) { 1613 print_xevent_bases(); 1614 reminder = now; 1615 } 1616 last_check = now; 1617 1618 if (tot) { 1619 fprintf(stderr, "Total events queued: %d\n", 1620 tot); 1621 } 1622 for (i=1; i<ev_type_max; i++) { 1623 int k, n = 0; 1624 while (XCheckTypedEvent(dpy, i, xevs+n)) { 1625 if (++n >= ev_size) { 1626 break; 1627 } 1628 } 1629 if (n) { 1630 fprintf(stderr, " %d%s events of type" 1631 " %d queued\n", n, 1632 (n >= ev_size) ? "+" : "", i); 1633 } 1634 for (k=n-1; k >= 0; k--) { 1635 XPutBackEvent(dpy, xevs+k); 1636 } 1637 } 1638 } 1639 } 1640#endif 1641 1642 if (now > last_sync + 1200) { 1643 /* kludge for any remaining event leaks */ 1644 int bugout = use_xdamage ? 500 : 50; 1645 int qlen, i; 1646 if (last_sync != 0) { 1647 qlen = XEventsQueued(dpy, QueuedAlready); 1648 if (qlen >= bugout) { 1649 rfbLog("event leak: %d queued, " 1650 " calling XSync(dpy, True)\n", qlen); 1651 rfbLog(" for diagnostics run: 'x11vnc -R" 1652 " debug_xevents:1'\n"); 1653 XSync(dpy, True); 1654 } 1655 } 1656 last_sync = now; 1657 1658 /* clear these, we don't want any events on them */ 1659 if (rdpy_ctrl) { 1660 qlen = XEventsQueued(rdpy_ctrl, QueuedAlready); 1661 for (i=0; i<qlen; i++) { 1662 XNextEvent(rdpy_ctrl, &xev); 1663 } 1664 } 1665 if (gdpy_ctrl) { 1666 qlen = XEventsQueued(gdpy_ctrl, QueuedAlready); 1667 for (i=0; i<qlen; i++) { 1668 XNextEvent(gdpy_ctrl, &xev); 1669 } 1670 } 1671 } 1672 X_UNLOCK; 1673 1674#endif /* NO_X11 */ 1675} 1676 1677extern int rawfb_vnc_reflect; 1678/* 1679 * hook called when a VNC client sends us some "XCut" text (rfbClientCutText). 1680 */ 1681void xcut_receive(char *text, int len, rfbClientPtr cl) { 1682 allowed_input_t input; 1683 1684 if (threads_drop_input) { 1685 return; 1686 } 1687 1688 if (unixpw_in_progress) { 1689 rfbLog("xcut_receive: unixpw_in_progress, skipping.\n"); 1690 return; 1691 } 1692 1693 if (!watch_selection) { 1694 return; 1695 } 1696 if (view_only) { 1697 return; 1698 } 1699 if (text == NULL || len == 0) { 1700 return; 1701 } 1702 get_allowed_input(cl, &input); 1703 if (!input.clipboard) { 1704 return; 1705 } 1706 INPUT_LOCK; 1707 1708 if (remote_prefix != NULL && strstr(text, remote_prefix) == text) { 1709 char *result, *rcmd = text + strlen(remote_prefix); 1710 char *tmp = (char *) calloc(len + 8, 1); 1711 1712 if (strstr(rcmd, "cmd=") != rcmd && strstr(rcmd, "qry=") != rcmd) { 1713 strcat(tmp, "qry="); 1714 } 1715 strncat(tmp, rcmd, len - strlen(remote_prefix)); 1716 rfbLog("remote_prefix command: '%s'\n", tmp); 1717 1718 if (use_threads) { 1719 if (client_connect_file) { 1720 FILE *f = fopen(client_connect_file, "w"); 1721 if (f) { 1722 fprintf(f, "%s\n", tmp); 1723 fclose(f); 1724 free(tmp); 1725 INPUT_UNLOCK; 1726 return; 1727 } 1728 } 1729 if (vnc_connect) { 1730 sprintf(x11vnc_remote_str, "%s", tmp); 1731 free(tmp); 1732 INPUT_UNLOCK; 1733 return; 1734 } 1735 } 1736 INPUT_UNLOCK; 1737 1738 1739 result = process_remote_cmd(tmp, 1); 1740 if (result == NULL ) { 1741 result = strdup("null"); 1742 } else if (!strcmp(result, "")) { 1743 free(result); 1744 result = strdup("none"); 1745 } 1746 rfbLog("remote_prefix result: '%s'\n", result); 1747 1748 free(tmp); 1749 tmp = (char *) calloc(strlen(remote_prefix) + strlen(result) + 1, 1); 1750 1751 strcat(tmp, remote_prefix); 1752 strcat(tmp, result); 1753 free(result); 1754 1755 rfbSendServerCutText(screen, tmp, strlen(tmp)); 1756 free(tmp); 1757 1758 return; 1759 } 1760 1761 if (! check_sel_direction("recv", "xcut_receive", text, len)) { 1762 INPUT_UNLOCK; 1763 return; 1764 } 1765 1766#ifdef MACOSX 1767 if (macosx_console) { 1768 macosx_set_sel(text, len); 1769 INPUT_UNLOCK; 1770 return; 1771 } 1772#endif 1773 1774 if (rawfb_vnc_reflect) { 1775 vnc_reflect_send_cuttext(text, len); 1776 INPUT_UNLOCK; 1777 return; 1778 } 1779 1780 RAWFB_RET_VOID 1781 1782#if NO_X11 1783 INPUT_UNLOCK; 1784 return; 1785#else 1786 1787 X_LOCK; 1788 1789 /* associate this text with PRIMARY (and SECONDARY...) */ 1790 if (set_primary && ! own_primary && selwin != None) { 1791 own_primary = 1; 1792 /* we need to grab the PRIMARY selection */ 1793 XSetSelectionOwner(dpy, XA_PRIMARY, selwin, CurrentTime); 1794 XFlush_wr(dpy); 1795 if (debug_sel) { 1796 rfbLog("Own PRIMARY.\n"); 1797 } 1798 } 1799 1800 if (set_clipboard && ! own_clipboard && clipboard_atom != None && selwin != None) { 1801 own_clipboard = 1; 1802 /* we need to grab the CLIPBOARD selection */ 1803 XSetSelectionOwner(dpy, clipboard_atom, selwin, CurrentTime); 1804 XFlush_wr(dpy); 1805 if (debug_sel) { 1806 rfbLog("Own CLIPBOARD.\n"); 1807 } 1808 } 1809 1810 /* duplicate the text string for our own use. */ 1811 if (set_primary) { 1812 if (xcut_str_primary != NULL) { 1813 free(xcut_str_primary); 1814 xcut_str_primary = NULL; 1815 } 1816 xcut_str_primary = (char *) malloc((size_t) (len+1)); 1817 strncpy(xcut_str_primary, text, len); 1818 xcut_str_primary[len] = '\0'; /* make sure null terminated */ 1819 if (debug_sel) { 1820 rfbLog("Set PRIMARY '%s'\n", xcut_str_primary); 1821 } 1822 } 1823 if (set_clipboard) { 1824 if (xcut_str_clipboard != NULL) { 1825 free(xcut_str_clipboard); 1826 xcut_str_clipboard = NULL; 1827 } 1828 xcut_str_clipboard = (char *) malloc((size_t) (len+1)); 1829 strncpy(xcut_str_clipboard, text, len); 1830 xcut_str_clipboard[len] = '\0'; /* make sure null terminated */ 1831 if (debug_sel) { 1832 rfbLog("Set CLIPBOARD '%s'\n", xcut_str_clipboard); 1833 } 1834 } 1835 1836 /* copy this text to CUT_BUFFER0 as well: */ 1837 XChangeProperty(dpy, rootwin, XA_CUT_BUFFER0, XA_STRING, 8, 1838 PropModeReplace, (unsigned char *) text, len); 1839 XFlush_wr(dpy); 1840 1841 X_UNLOCK; 1842 INPUT_UNLOCK; 1843 1844 set_cutbuffer = 1; 1845#endif /* NO_X11 */ 1846} 1847 1848void kbd_release_all_keys(rfbClientPtr cl) { 1849 if (unixpw_in_progress) { 1850 rfbLog("kbd_release_all_keys: unixpw_in_progress, skipping.\n"); 1851 return; 1852 } 1853 if (cl->viewOnly) { 1854 return; 1855 } 1856 1857 RAWFB_RET_VOID 1858 1859#if NO_X11 1860 return; 1861#else 1862 if (use_threads) { 1863 X_LOCK; 1864 } 1865 1866 clear_keys(); 1867 clear_modifiers(0); 1868 1869 if (use_threads) { 1870 X_UNLOCK; 1871 } 1872#endif 1873} 1874 1875void set_single_window(rfbClientPtr cl, int x, int y) { 1876 int ok = 0; 1877 if (no_ultra_ext) { 1878 return; 1879 } 1880 if (unixpw_in_progress) { 1881 rfbLog("set_single_window: unixpw_in_progress, dropping client.\n"); 1882 rfbCloseClient(cl); 1883 return; 1884 } 1885 if (cl->viewOnly) { 1886 return; 1887 } 1888 1889 RAWFB_RET_VOID 1890 1891#if NO_X11 1892 return; 1893#else 1894 if (x==1 && y==1) { 1895 if (subwin) { 1896 subwin = 0x0; 1897 ok = 1; 1898 } 1899 } else { 1900 Window r, c; 1901 int rootx, rooty, wx, wy; 1902 unsigned int mask; 1903 1904 update_x11_pointer_position(x, y); 1905 XSync(dpy, False); 1906 1907 if (XQueryPointer_wr(dpy, rootwin, &r, &c, &rootx, &rooty, 1908 &wx, &wy, &mask)) { 1909 if (c != None) { 1910 subwin = c; 1911 ok = 1; 1912 } 1913 } 1914 } 1915 1916 if (ok) { 1917 check_black_fb(); 1918 do_new_fb(1); 1919 } 1920#endif 1921 1922} 1923void set_server_input(rfbClientPtr cl, int grab) { 1924 if (no_ultra_ext) { 1925 return; 1926 } 1927 if (unixpw_in_progress) { 1928 rfbLog("set_server_input: unixpw_in_progress, dropping client.\n"); 1929 rfbCloseClient(cl); 1930 return; 1931 } 1932 if (cl->viewOnly) { 1933 return; 1934 } 1935 1936 RAWFB_RET_VOID 1937 1938#if NO_X11 1939 return; 1940#else 1941 if (grab) { 1942 if (!no_ultra_dpms) { 1943 set_dpms_mode("enable"); 1944 set_dpms_mode("off"); 1945 force_dpms = 1; 1946 } 1947 1948 process_remote_cmd("cmd=grabkbd", 0); 1949 process_remote_cmd("cmd=grabptr", 0); 1950 1951 } else { 1952 process_remote_cmd("cmd=nograbkbd", 0); 1953 process_remote_cmd("cmd=nograbptr", 0); 1954 1955 if (!no_ultra_dpms) { 1956 force_dpms = 0; 1957 } 1958 } 1959#endif 1960} 1961 1962static int wsock_timeout_sock = -1; 1963 1964static void wsock_timeout (int sig) { 1965 rfbLog("sig: %d, wsock_timeout.\n", sig); 1966 if (wsock_timeout_sock >= 0) { 1967 close(wsock_timeout_sock); 1968 wsock_timeout_sock = -1; 1969 } 1970} 1971 1972static void try_local_chat_window(void) { 1973 int i, port, lsock; 1974 char cmd[100]; 1975 struct sockaddr_in addr; 1976 pid_t pid = -1; 1977#ifdef __hpux 1978 int addrlen = sizeof(addr); 1979#else 1980 socklen_t addrlen = sizeof(addr); 1981#endif 1982 1983 for (i = 0; i < 90; i++) { 1984 /* find an open port */ 1985 port = 7300 + i; 1986 /* XXX ::1 fallback */ 1987 lsock = listen_tcp(port, htonl(INADDR_LOOPBACK), 0); 1988 if (lsock >= 0) { 1989 break; 1990 } 1991 port = 0; 1992 } 1993 1994 if (port == 0) { 1995 return; 1996 } 1997 1998 /* have ssvncvncviewer connect back to us (n.b. sockpair fails) */ 1999 2000 sprintf(cmd, "ssvnc -cmd VNC://localhost:%d -chatonly", port); 2001 2002#if LIBVNCSERVER_HAVE_FORK 2003 pid = fork(); 2004#endif 2005 2006 if (pid == -1) { 2007 perror("fork"); 2008 return; 2009 } else if (pid == 0) { 2010 char *args[4]; 2011 int d; 2012 args[0] = "/bin/sh"; 2013 args[1] = "-c"; 2014 /* "ssvnc -cmd VNC://fd=0 -chatonly"; not working */ 2015 args[2] = cmd; 2016 args[3] = NULL; 2017 2018 set_env("VNCVIEWER_PASSWORD", "moo"); 2019#if !NO_X11 2020 if (dpy != NULL) { 2021 set_env("DISPLAY", DisplayString(dpy)); 2022 } 2023#endif 2024 for (d = 3; d < 256; d++) { 2025 close(d); 2026 } 2027 2028 execvp(args[0], args); 2029 perror("exec"); 2030 exit(1); 2031 } else { 2032 int i, sock = -1; 2033 rfbNewClientHookPtr new_save; 2034 2035 signal(SIGALRM, wsock_timeout); 2036 wsock_timeout_sock = lsock; 2037 2038 alarm(10); 2039 sock = accept(lsock, (struct sockaddr *)&addr, &addrlen); 2040 alarm(0); 2041 2042 signal(SIGALRM, SIG_DFL); 2043 close(lsock); 2044 2045 if (sock < 0) { 2046 return; 2047 } 2048 2049 /* mutex */ 2050 new_save = screen->newClientHook; 2051 screen->newClientHook = new_client_chat_helper; 2052 2053 chat_window_client = create_new_client(sock, 1); 2054 2055 screen->newClientHook = new_save; 2056 2057 if (chat_window_client != NULL) { 2058 rfbPasswordCheckProcPtr pwchk_save = screen->passwordCheck; 2059 rfbBool save_shared1 = screen->alwaysShared; 2060 rfbBool save_shared2 = screen->neverShared; 2061 2062 screen->alwaysShared = TRUE; 2063 screen->neverShared = FALSE; 2064 2065 screen->passwordCheck = password_check_chat_helper; 2066 for (i=0; i<30; i++) { 2067 rfbPE(-1); 2068 if (!chat_window_client) { 2069 break; 2070 } 2071 if (chat_window_client->state == RFB_NORMAL) { 2072 break; 2073 } 2074 } 2075 2076 screen->passwordCheck = pwchk_save; 2077 screen->alwaysShared = save_shared1; 2078 screen->neverShared = save_shared2; 2079 } 2080 } 2081} 2082 2083void set_text_chat(rfbClientPtr cl, int len, char *txt) { 2084 int dochat = 1; 2085 rfbClientIteratorPtr iter; 2086 rfbClientPtr cl2; 2087 unsigned int ulen = (unsigned int) len; 2088 2089 if (no_ultra_ext || ! dochat) { 2090 return; 2091 } 2092 2093 if (unixpw_in_progress) { 2094 rfbLog("set_text_chat: unixpw_in_progress, dropping client.\n"); 2095 rfbCloseClient(cl); 2096 return; 2097 } 2098#if LIBVNCSERVER_HAS_TEXTCHAT 2099 2100 if (chat_window && chat_window_client == NULL && ulen == rfbTextChatOpen) { 2101 try_local_chat_window(); 2102 } 2103 2104 saw_ultra_chat = 1; 2105 2106 iter = rfbGetClientIterator(screen); 2107 while( (cl2 = rfbClientIteratorNext(iter)) ) { 2108 unsigned int ulen = (unsigned int) len; 2109 if (cl2 == cl) { 2110 continue; 2111 } 2112 if (cl2->state != RFB_NORMAL) { 2113 continue; 2114 } 2115 2116 SEND_LOCK(cl2); 2117 2118 if (ulen == rfbTextChatOpen) { 2119 rfbSendTextChatMessage(cl2, rfbTextChatOpen, ""); 2120 } else if (ulen == rfbTextChatClose) { 2121 rfbSendTextChatMessage(cl2, rfbTextChatClose, ""); 2122 /* not clear what is going on WRT close and finished... */ 2123 rfbSendTextChatMessage(cl2, rfbTextChatFinished, ""); 2124 } else if (ulen == rfbTextChatFinished) { 2125 rfbSendTextChatMessage(cl2, rfbTextChatFinished, ""); 2126 } else if (len <= rfbTextMaxSize) { 2127 rfbSendTextChatMessage(cl2, len, txt); 2128 } 2129 2130 SEND_UNLOCK(cl2); 2131 } 2132 rfbReleaseClientIterator(iter); 2133 2134 if (ulen == rfbTextChatClose && cl != NULL) { 2135 /* not clear what is going on WRT close and finished... */ 2136 SEND_LOCK(cl); 2137 rfbSendTextChatMessage(cl, rfbTextChatFinished, ""); 2138 SEND_UNLOCK(cl); 2139 } 2140#endif 2141} 2142 2143int get_keyboard_led_state_hook(rfbScreenInfoPtr s) { 2144 if (s) {} 2145 if (unixpw_in_progress) { 2146 rfbLog("get_keyboard_led_state_hook: unixpw_in_progress, skipping.\n"); 2147 return 0; 2148 } 2149 return 0; 2150} 2151int get_file_transfer_permitted(rfbClientPtr cl) { 2152 allowed_input_t input; 2153 if (unixpw_in_progress) { 2154 rfbLog("get_file_transfer_permitted: unixpw_in_progress, dropping client.\n"); 2155 rfbCloseClient(cl); 2156 return FALSE; 2157 } 2158if (0) fprintf(stderr, "get_file_transfer_permitted called\n"); 2159 if (view_only) { 2160 return FALSE; 2161 } 2162 if (cl->viewOnly) { 2163 return FALSE; 2164 } 2165 get_allowed_input(cl, &input); 2166 if (!input.files) { 2167 return FALSE; 2168 } 2169 if (screen->permitFileTransfer) { 2170 saw_ultra_file = 1; 2171 } 2172 return screen->permitFileTransfer; 2173} 2174 2175 2176