1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * X command server by Flemming Madsen 5 * 6 * Do ":help uganda" in Vim to read copying and usage conditions. 7 * Do ":help credits" in Vim to see a list of people who contributed. 8 * See README.txt for an overview of the Vim source code. 9 * 10 * if_xcmdsrv.c: Functions for passing commands through an X11 display. 11 * 12 */ 13 14 #include "vim.h" 15 #include "version.h" 16 17 #if defined(FEAT_CLIENTSERVER) || defined(PROTO) 18 19 # ifdef FEAT_X11 20 # include <X11/Intrinsic.h> 21 # include <X11/Xatom.h> 22 # endif 23 24 /* 25 * This file provides procedures that implement the command server 26 * functionality of Vim when in contact with an X11 server. 27 * 28 * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution. 29 * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4 30 */ 31 32 /* 33 * Copyright (c) 1989-1993 The Regents of the University of California. 34 * All rights reserved. 35 * 36 * Permission is hereby granted, without written agreement and without 37 * license or royalty fees, to use, copy, modify, and distribute this 38 * software and its documentation for any purpose, provided that the 39 * above copyright notice and the following two paragraphs appear in 40 * all copies of this software. 41 * 42 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR 43 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT 44 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF 45 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 * 47 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 48 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 49 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 50 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO 51 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 52 */ 53 54 55 /* 56 * When a result is being awaited from a sent command, one of 57 * the following structures is present on a list of all outstanding 58 * sent commands. The information in the structure is used to 59 * process the result when it arrives. You're probably wondering 60 * how there could ever be multiple outstanding sent commands. 61 * This could happen if Vim instances invoke each other recursively. 62 * It's unlikely, but possible. 63 */ 64 65 typedef struct PendingCommand 66 { 67 int serial; /* Serial number expected in result. */ 68 int code; /* Result Code. 0 is OK */ 69 char_u *result; /* String result for command (malloc'ed). 70 * NULL means command still pending. */ 71 struct PendingCommand *nextPtr; 72 /* Next in list of all outstanding commands. 73 * NULL means end of list. */ 74 } PendingCommand; 75 76 static PendingCommand *pendingCommands = NULL; 77 /* List of all commands currently 78 * being waited for. */ 79 80 /* 81 * The information below is used for communication between processes 82 * during "send" commands. Each process keeps a private window, never 83 * even mapped, with one property, "Comm". When a command is sent to 84 * an interpreter, the command is appended to the comm property of the 85 * communication window associated with the interp's process. Similarly, 86 * when a result is returned from a sent command, it is also appended 87 * to the comm property. 88 * 89 * Each command and each result takes the form of ASCII text. For a 90 * command, the text consists of a nul character followed by several 91 * nul-terminated ASCII strings. The first string consists of a 92 * single letter: 93 * "c" for an expression 94 * "k" for keystrokes 95 * "r" for reply 96 * "n" for notification. 97 * Subsequent strings have the form "option value" where the following options 98 * are supported: 99 * 100 * -r commWindow serial 101 * 102 * This option means that a response should be sent to the window 103 * whose X identifier is "commWindow" (in hex), and the response should 104 * be identified with the serial number given by "serial" (in decimal). 105 * If this option isn't specified then the send is asynchronous and 106 * no response is sent. 107 * 108 * -n name 109 * "Name" gives the name of the application for which the command is 110 * intended. This option must be present. 111 * 112 * -E encoding 113 * Encoding name used for the text. This is the 'encoding' of the 114 * sender. The receiver may want to do conversion to his 'encoding'. 115 * 116 * -s script 117 * "Script" is the script to be executed. This option must be 118 * present. Taken as a series of keystrokes in a "k" command where 119 * <Key>'s are expanded 120 * 121 * The options may appear in any order. The -n and -s options must be 122 * present, but -r may be omitted for asynchronous RPCs. For compatibility 123 * with future releases that may add new features, there may be additional 124 * options present; as long as they start with a "-" character, they will 125 * be ignored. 126 * 127 * A result also consists of a zero character followed by several null- 128 * terminated ASCII strings. The first string consists of the single 129 * letter "r". Subsequent strings have the form "option value" where 130 * the following options are supported: 131 * 132 * -s serial 133 * Identifies the command for which this is the result. It is the 134 * same as the "serial" field from the -s option in the command. This 135 * option must be present. 136 * 137 * -r result 138 * "Result" is the result string for the script, which may be either 139 * a result or an error message. If this field is omitted then it 140 * defaults to an empty string. 141 * 142 * -c code 143 * 0: for OK. This is the default. 144 * 1: for error: Result is the last error 145 * 146 * -i errorInfo 147 * -e errorCode 148 * Not applicable for Vim 149 * 150 * Options may appear in any order, and only the -s option must be 151 * present. As with commands, there may be additional options besides 152 * these; unknown options are ignored. 153 */ 154 155 /* 156 * Maximum size property that can be read at one time by 157 * this module: 158 */ 159 160 #define MAX_PROP_WORDS 100000 161 162 struct ServerReply 163 { 164 Window id; 165 garray_T strings; 166 }; 167 static garray_T serverReply = { 0, 0, 0, 0, 0 }; 168 enum ServerReplyOp { SROP_Find, SROP_Add, SROP_Delete }; 169 170 typedef int (*EndCond)(void *); 171 172 struct x_cmdqueue 173 { 174 char_u *propInfo; 175 long_u len; 176 struct x_cmdqueue *next; 177 struct x_cmdqueue *prev; 178 }; 179 180 typedef struct x_cmdqueue x_queue_T; 181 182 /* dummy node, header for circular queue */ 183 static x_queue_T head = {NULL, 0, NULL, NULL}; 184 185 /* 186 * Forward declarations for procedures defined later in this file: 187 */ 188 189 static Window LookupName(Display *dpy, char_u *name, int delete, char_u **loose); 190 static int SendInit(Display *dpy); 191 static int DoRegisterName(Display *dpy, char_u *name); 192 static void DeleteAnyLingerer(Display *dpy, Window w); 193 static int GetRegProp(Display *dpy, char_u **regPropp, long_u *numItemsp, int domsg); 194 static int WaitForPend(void *p); 195 static int WindowValid(Display *dpy, Window w); 196 static void ServerWait(Display *dpy, Window w, EndCond endCond, void *endData, int localLoop, int seconds); 197 static int AppendPropCarefully(Display *display, Window window, Atom property, char_u *value, int length); 198 static int x_error_check(Display *dpy, XErrorEvent *error_event); 199 static int IsSerialName(char_u *name); 200 static void save_in_queue(char_u *buf, long_u len); 201 static void server_parse_message(Display *dpy, char_u *propInfo, long_u numItems); 202 203 /* Private variables for the "server" functionality */ 204 static Atom registryProperty = None; 205 static Atom vimProperty = None; 206 static int got_x_error = FALSE; 207 208 static char_u *empty_prop = (char_u *)""; /* empty GetRegProp() result */ 209 210 /* 211 * Associate an ASCII name with Vim. Try real hard to get a unique one. 212 * Returns FAIL or OK. 213 */ 214 int 215 serverRegisterName( 216 Display *dpy, /* display to register with */ 217 char_u *name) /* the name that will be used as a base */ 218 { 219 int i; 220 int res; 221 char_u *p = NULL; 222 223 res = DoRegisterName(dpy, name); 224 if (res < 0) 225 { 226 i = 1; 227 do 228 { 229 if (res < -1 || i >= 1000) 230 { 231 msg_attr(_("Unable to register a command server name"), 232 HL_ATTR(HLF_W)); 233 return FAIL; 234 } 235 if (p == NULL) 236 p = alloc(STRLEN(name) + 10); 237 if (p == NULL) 238 { 239 res = -10; 240 continue; 241 } 242 sprintf((char *)p, "%s%d", name, i++); 243 res = DoRegisterName(dpy, p); 244 } 245 while (res < 0) 246 ; 247 vim_free(p); 248 } 249 return OK; 250 } 251 252 static int 253 DoRegisterName(Display *dpy, char_u *name) 254 { 255 Window w; 256 XErrorHandler old_handler; 257 #define MAX_NAME_LENGTH 100 258 char_u propInfo[MAX_NAME_LENGTH + 20]; 259 260 if (commProperty == None) 261 { 262 if (SendInit(dpy) < 0) 263 return -2; 264 } 265 266 /* 267 * Make sure the name is unique, and append info about it to 268 * the registry property. It's important to lock the server 269 * here to prevent conflicting changes to the registry property. 270 * WARNING: Do not step through this while debugging, it will hangup the X 271 * server! 272 */ 273 XGrabServer(dpy); 274 w = LookupName(dpy, name, FALSE, NULL); 275 if (w != (Window)0) 276 { 277 Status status; 278 int dummyInt; 279 unsigned int dummyUns; 280 Window dummyWin; 281 282 /* 283 * The name is currently registered. See if the commWindow 284 * associated with the name exists. If not, or if the commWindow 285 * is *our* commWindow, then just unregister the old name (this 286 * could happen if an application dies without cleaning up the 287 * registry). 288 */ 289 old_handler = XSetErrorHandler(x_error_check); 290 status = XGetGeometry(dpy, w, &dummyWin, &dummyInt, &dummyInt, 291 &dummyUns, &dummyUns, &dummyUns, &dummyUns); 292 (void)XSetErrorHandler(old_handler); 293 if (status != Success && w != commWindow) 294 { 295 XUngrabServer(dpy); 296 XFlush(dpy); 297 return -1; 298 } 299 (void)LookupName(dpy, name, /*delete=*/TRUE, NULL); 300 } 301 sprintf((char *)propInfo, "%x %.*s", (int_u)commWindow, 302 MAX_NAME_LENGTH, name); 303 old_handler = XSetErrorHandler(x_error_check); 304 got_x_error = FALSE; 305 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8, 306 PropModeAppend, propInfo, STRLEN(propInfo) + 1); 307 XUngrabServer(dpy); 308 XSync(dpy, False); 309 (void)XSetErrorHandler(old_handler); 310 311 if (!got_x_error) 312 { 313 #ifdef FEAT_EVAL 314 set_vim_var_string(VV_SEND_SERVER, name, -1); 315 #endif 316 serverName = vim_strsave(name); 317 #ifdef FEAT_TITLE 318 need_maketitle = TRUE; 319 #endif 320 return 0; 321 } 322 return -2; 323 } 324 325 #if defined(FEAT_GUI) || defined(PROTO) 326 /* 327 * Clean out new ID from registry and set it as comm win. 328 * Change any registered window ID. 329 */ 330 void 331 serverChangeRegisteredWindow( 332 Display *dpy, /* Display to register with */ 333 Window newwin) /* Re-register to this ID */ 334 { 335 char_u propInfo[MAX_NAME_LENGTH + 20]; 336 337 commWindow = newwin; 338 339 /* Always call SendInit() here, to make sure commWindow is marked as a Vim 340 * window. */ 341 if (SendInit(dpy) < 0) 342 return; 343 344 /* WARNING: Do not step through this while debugging, it will hangup the X 345 * server! */ 346 XGrabServer(dpy); 347 DeleteAnyLingerer(dpy, newwin); 348 if (serverName != NULL) 349 { 350 /* Reinsert name if we was already registered */ 351 (void)LookupName(dpy, serverName, /*delete=*/TRUE, NULL); 352 sprintf((char *)propInfo, "%x %.*s", 353 (int_u)newwin, MAX_NAME_LENGTH, serverName); 354 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8, 355 PropModeAppend, (char_u *)propInfo, 356 STRLEN(propInfo) + 1); 357 } 358 XUngrabServer(dpy); 359 } 360 #endif 361 362 /* 363 * Send to an instance of Vim via the X display. 364 * Returns 0 for OK, negative for an error. 365 */ 366 int 367 serverSendToVim( 368 Display *dpy, /* Where to send. */ 369 char_u *name, /* Where to send. */ 370 char_u *cmd, /* What to send. */ 371 char_u **result, /* Result of eval'ed expression */ 372 Window *server, /* Actual ID of receiving app */ 373 Bool asExpr, /* Interpret as keystrokes or expr ? */ 374 int timeout, /* seconds to wait or zero */ 375 Bool localLoop, /* Throw away everything but result */ 376 int silent) /* don't complain about no server */ 377 { 378 Window w; 379 char_u *property; 380 int length; 381 int res; 382 static int serial = 0; /* Running count of sent commands. 383 * Used to give each command a 384 * different serial number. */ 385 PendingCommand pending; 386 char_u *loosename = NULL; 387 388 if (result != NULL) 389 *result = NULL; 390 if (name == NULL || *name == NUL) 391 name = (char_u *)"GVIM"; /* use a default name */ 392 393 if (commProperty == None && dpy != NULL) 394 { 395 if (SendInit(dpy) < 0) 396 return -1; 397 } 398 399 /* Execute locally if no display or target is ourselves */ 400 if (dpy == NULL || (serverName != NULL && STRICMP(name, serverName) == 0)) 401 return sendToLocalVim(cmd, asExpr, result); 402 403 /* 404 * Bind the server name to a communication window. 405 * 406 * Find any survivor with a serialno attached to the name if the 407 * original registrant of the wanted name is no longer present. 408 * 409 * Delete any lingering names from dead editors. 410 */ 411 while (TRUE) 412 { 413 w = LookupName(dpy, name, FALSE, &loosename); 414 /* Check that the window is hot */ 415 if (w != None) 416 { 417 if (!WindowValid(dpy, w)) 418 { 419 LookupName(dpy, loosename ? loosename : name, 420 /*DELETE=*/TRUE, NULL); 421 vim_free(loosename); 422 continue; 423 } 424 } 425 break; 426 } 427 if (w == None) 428 { 429 if (!silent) 430 semsg(_(e_noserver), name); 431 return -1; 432 } 433 else if (loosename != NULL) 434 name = loosename; 435 if (server != NULL) 436 *server = w; 437 438 /* 439 * Send the command to target interpreter by appending it to the 440 * comm window in the communication window. 441 * Length must be computed exactly! 442 */ 443 length = STRLEN(name) + STRLEN(p_enc) + STRLEN(cmd) + 14; 444 property = (char_u *)alloc((unsigned)length + 30); 445 446 sprintf((char *)property, "%c%c%c-n %s%c-E %s%c-s %s", 447 0, asExpr ? 'c' : 'k', 0, name, 0, p_enc, 0, cmd); 448 if (name == loosename) 449 vim_free(loosename); 450 /* Add a back reference to our comm window */ 451 serial++; 452 sprintf((char *)property + length, "%c-r %x %d", 453 0, (int_u)commWindow, serial); 454 /* Add length of what "-r %x %d" resulted in, skipping the NUL. */ 455 length += STRLEN(property + length + 1) + 1; 456 457 res = AppendPropCarefully(dpy, w, commProperty, property, length + 1); 458 vim_free(property); 459 if (res < 0) 460 { 461 emsg(_("E248: Failed to send command to the destination program")); 462 return -1; 463 } 464 465 if (!asExpr) /* There is no answer for this - Keys are sent async */ 466 return 0; 467 468 /* 469 * Register the fact that we're waiting for a command to 470 * complete (this is needed by SendEventProc and by 471 * AppendErrorProc to pass back the command's results). 472 */ 473 pending.serial = serial; 474 pending.code = 0; 475 pending.result = NULL; 476 pending.nextPtr = pendingCommands; 477 pendingCommands = &pending; 478 479 ServerWait(dpy, w, WaitForPend, &pending, localLoop, 480 timeout > 0 ? timeout : 600); 481 482 /* 483 * Unregister the information about the pending command 484 * and return the result. 485 */ 486 if (pendingCommands == &pending) 487 pendingCommands = pending.nextPtr; 488 else 489 { 490 PendingCommand *pcPtr; 491 492 for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr) 493 if (pcPtr->nextPtr == &pending) 494 { 495 pcPtr->nextPtr = pending.nextPtr; 496 break; 497 } 498 } 499 if (result != NULL) 500 *result = pending.result; 501 else 502 vim_free(pending.result); 503 504 return pending.code == 0 ? 0 : -1; 505 } 506 507 static int 508 WaitForPend(void *p) 509 { 510 PendingCommand *pending = (PendingCommand *) p; 511 return pending->result != NULL; 512 } 513 514 /* 515 * Return TRUE if window "w" exists and has a "Vim" property on it. 516 */ 517 static int 518 WindowValid(Display *dpy, Window w) 519 { 520 XErrorHandler old_handler; 521 Atom *plist; 522 int numProp; 523 int i; 524 525 old_handler = XSetErrorHandler(x_error_check); 526 got_x_error = 0; 527 plist = XListProperties(dpy, w, &numProp); 528 XSync(dpy, False); 529 XSetErrorHandler(old_handler); 530 if (plist == NULL || got_x_error) 531 return FALSE; 532 533 for (i = 0; i < numProp; i++) 534 if (plist[i] == vimProperty) 535 { 536 XFree(plist); 537 return TRUE; 538 } 539 XFree(plist); 540 return FALSE; 541 } 542 543 /* 544 * Enter a loop processing X events & polling chars until we see a result 545 */ 546 static void 547 ServerWait( 548 Display *dpy, 549 Window w, 550 EndCond endCond, 551 void *endData, 552 int localLoop, 553 int seconds) 554 { 555 time_t start; 556 time_t now; 557 XEvent event; 558 559 #define UI_MSEC_DELAY 50 560 #define SEND_MSEC_POLL 500 561 #ifndef HAVE_SELECT 562 struct pollfd fds; 563 564 fds.fd = ConnectionNumber(dpy); 565 fds.events = POLLIN; 566 #else 567 fd_set fds; 568 struct timeval tv; 569 570 tv.tv_sec = 0; 571 tv.tv_usec = SEND_MSEC_POLL * 1000; 572 FD_ZERO(&fds); 573 FD_SET(ConnectionNumber(dpy), &fds); 574 #endif 575 576 time(&start); 577 while (TRUE) 578 { 579 while (XCheckWindowEvent(dpy, commWindow, PropertyChangeMask, &event)) 580 serverEventProc(dpy, &event, 1); 581 server_parse_messages(); 582 583 if (endCond(endData) != 0) 584 break; 585 if (!WindowValid(dpy, w)) 586 break; 587 time(&now); 588 if (seconds >= 0 && (now - start) >= seconds) 589 break; 590 591 #ifdef FEAT_TIMERS 592 check_due_timer(); 593 #endif 594 595 /* Just look out for the answer without calling back into Vim */ 596 if (localLoop) 597 { 598 #ifndef HAVE_SELECT 599 if (poll(&fds, 1, SEND_MSEC_POLL) < 0) 600 break; 601 #else 602 if (select(FD_SETSIZE, &fds, NULL, NULL, &tv) < 0) 603 break; 604 #endif 605 } 606 else 607 { 608 if (got_int) 609 break; 610 ui_delay((long)UI_MSEC_DELAY, TRUE); 611 ui_breakcheck(); 612 } 613 } 614 } 615 616 617 /* 618 * Fetch a list of all the Vim instance names currently registered for the 619 * display. 620 * 621 * Returns a newline separated list in allocated memory or NULL. 622 */ 623 char_u * 624 serverGetVimNames(Display *dpy) 625 { 626 char_u *regProp; 627 char_u *entry; 628 char_u *p; 629 long_u numItems; 630 int_u w; 631 garray_T ga; 632 633 if (registryProperty == None) 634 { 635 if (SendInit(dpy) < 0) 636 return NULL; 637 } 638 639 /* 640 * Read the registry property. 641 */ 642 if (GetRegProp(dpy, ®Prop, &numItems, TRUE) == FAIL) 643 return NULL; 644 645 /* 646 * Scan all of the names out of the property. 647 */ 648 ga_init2(&ga, 1, 100); 649 for (p = regProp; (long_u)(p - regProp) < numItems; p++) 650 { 651 entry = p; 652 while (*p != 0 && !isspace(*p)) 653 p++; 654 if (*p != 0) 655 { 656 w = None; 657 sscanf((char *)entry, "%x", &w); 658 if (WindowValid(dpy, (Window)w)) 659 { 660 ga_concat(&ga, p + 1); 661 ga_concat(&ga, (char_u *)"\n"); 662 } 663 while (*p != 0) 664 p++; 665 } 666 } 667 if (regProp != empty_prop) 668 XFree(regProp); 669 ga_append(&ga, NUL); 670 return ga.ga_data; 671 } 672 673 /* ---------------------------------------------------------- 674 * Reply stuff 675 */ 676 677 static struct ServerReply * 678 ServerReplyFind(Window w, enum ServerReplyOp op) 679 { 680 struct ServerReply *p; 681 struct ServerReply e; 682 int i; 683 684 p = (struct ServerReply *) serverReply.ga_data; 685 for (i = 0; i < serverReply.ga_len; i++, p++) 686 if (p->id == w) 687 break; 688 if (i >= serverReply.ga_len) 689 p = NULL; 690 691 if (p == NULL && op == SROP_Add) 692 { 693 if (serverReply.ga_growsize == 0) 694 ga_init2(&serverReply, sizeof(struct ServerReply), 1); 695 if (ga_grow(&serverReply, 1) == OK) 696 { 697 p = ((struct ServerReply *) serverReply.ga_data) 698 + serverReply.ga_len; 699 e.id = w; 700 ga_init2(&e.strings, 1, 100); 701 mch_memmove(p, &e, sizeof(e)); 702 serverReply.ga_len++; 703 } 704 } 705 else if (p != NULL && op == SROP_Delete) 706 { 707 ga_clear(&p->strings); 708 mch_memmove(p, p + 1, (serverReply.ga_len - i - 1) * sizeof(*p)); 709 serverReply.ga_len--; 710 } 711 712 return p; 713 } 714 715 /* 716 * Convert string to windowid. 717 * Issue an error if the id is invalid. 718 */ 719 Window 720 serverStrToWin(char_u *str) 721 { 722 unsigned id = None; 723 724 sscanf((char *)str, "0x%x", &id); 725 if (id == None) 726 semsg(_("E573: Invalid server id used: %s"), str); 727 728 return (Window)id; 729 } 730 731 /* 732 * Send a reply string (notification) to client with id "name". 733 * Return -1 if the window is invalid. 734 */ 735 int 736 serverSendReply(char_u *name, char_u *str) 737 { 738 char_u *property; 739 int length; 740 int res; 741 Display *dpy = X_DISPLAY; 742 Window win = serverStrToWin(name); 743 744 if (commProperty == None) 745 { 746 if (SendInit(dpy) < 0) 747 return -2; 748 } 749 if (!WindowValid(dpy, win)) 750 return -1; 751 752 length = STRLEN(p_enc) + STRLEN(str) + 14; 753 if ((property = (char_u *)alloc((unsigned)length + 30)) != NULL) 754 { 755 sprintf((char *)property, "%cn%c-E %s%c-n %s%c-w %x", 756 0, 0, p_enc, 0, str, 0, (unsigned int)commWindow); 757 /* Add length of what "%x" resulted in. */ 758 length += STRLEN(property + length); 759 res = AppendPropCarefully(dpy, win, commProperty, property, length + 1); 760 vim_free(property); 761 return res; 762 } 763 return -1; 764 } 765 766 static int 767 WaitForReply(void *p) 768 { 769 Window *w = (Window *) p; 770 771 return ServerReplyFind(*w, SROP_Find) != NULL; 772 } 773 774 /* 775 * Wait for replies from id (win) 776 * When "timeout" is non-zero wait up to this many seconds. 777 * Return 0 and the malloc'ed string when a reply is available. 778 * Return -1 if the window becomes invalid while waiting. 779 */ 780 int 781 serverReadReply( 782 Display *dpy, 783 Window win, 784 char_u **str, 785 int localLoop, 786 int timeout) 787 { 788 int len; 789 char_u *s; 790 struct ServerReply *p; 791 792 ServerWait(dpy, win, WaitForReply, &win, localLoop, 793 timeout > 0 ? timeout : -1); 794 795 if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0) 796 { 797 *str = vim_strsave(p->strings.ga_data); 798 len = STRLEN(*str) + 1; 799 if (len < p->strings.ga_len) 800 { 801 s = (char_u *) p->strings.ga_data; 802 mch_memmove(s, s + len, p->strings.ga_len - len); 803 p->strings.ga_len -= len; 804 } 805 else 806 { 807 /* Last string read. Remove from list */ 808 ga_clear(&p->strings); 809 ServerReplyFind(win, SROP_Delete); 810 } 811 return 0; 812 } 813 return -1; 814 } 815 816 /* 817 * Check for replies from id (win). 818 * Return TRUE and a non-malloc'ed string if there is. Else return FALSE. 819 */ 820 int 821 serverPeekReply(Display *dpy, Window win, char_u **str) 822 { 823 struct ServerReply *p; 824 825 if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0) 826 { 827 if (str != NULL) 828 *str = p->strings.ga_data; 829 return 1; 830 } 831 if (!WindowValid(dpy, win)) 832 return -1; 833 return 0; 834 } 835 836 837 /* 838 * Initialize the communication channels for sending commands and receiving 839 * results. 840 */ 841 static int 842 SendInit(Display *dpy) 843 { 844 XErrorHandler old_handler; 845 846 /* 847 * Create the window used for communication, and set up an 848 * event handler for it. 849 */ 850 old_handler = XSetErrorHandler(x_error_check); 851 got_x_error = FALSE; 852 853 if (commProperty == None) 854 commProperty = XInternAtom(dpy, "Comm", False); 855 if (vimProperty == None) 856 vimProperty = XInternAtom(dpy, "Vim", False); 857 if (registryProperty == None) 858 registryProperty = XInternAtom(dpy, "VimRegistry", False); 859 860 if (commWindow == None) 861 { 862 commWindow = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), 863 getpid(), 0, 10, 10, 0, 864 WhitePixel(dpy, DefaultScreen(dpy)), 865 WhitePixel(dpy, DefaultScreen(dpy))); 866 XSelectInput(dpy, commWindow, PropertyChangeMask); 867 /* WARNING: Do not step through this while debugging, it will hangup 868 * the X server! */ 869 XGrabServer(dpy); 870 DeleteAnyLingerer(dpy, commWindow); 871 XUngrabServer(dpy); 872 } 873 874 /* Make window recognizable as a vim window */ 875 XChangeProperty(dpy, commWindow, vimProperty, XA_STRING, 876 8, PropModeReplace, (char_u *)VIM_VERSION_SHORT, 877 (int)STRLEN(VIM_VERSION_SHORT) + 1); 878 879 XSync(dpy, False); 880 (void)XSetErrorHandler(old_handler); 881 882 return got_x_error ? -1 : 0; 883 } 884 885 /* 886 * Given a server name, see if the name exists in the registry for a 887 * particular display. 888 * 889 * If the given name is registered, return the ID of the window associated 890 * with the name. If the name isn't registered, then return 0. 891 * 892 * Side effects: 893 * If the registry property is improperly formed, then it is deleted. 894 * If "delete" is non-zero, then if the named server is found it is 895 * removed from the registry property. 896 */ 897 static Window 898 LookupName( 899 Display *dpy, /* Display whose registry to check. */ 900 char_u *name, /* Name of a server. */ 901 int delete, /* If non-zero, delete info about name. */ 902 char_u **loose) /* Do another search matching -999 if not found 903 Return result here if a match is found */ 904 { 905 char_u *regProp, *entry; 906 char_u *p; 907 long_u numItems; 908 int_u returnValue; 909 910 /* 911 * Read the registry property. 912 */ 913 if (GetRegProp(dpy, ®Prop, &numItems, FALSE) == FAIL) 914 return 0; 915 916 /* 917 * Scan the property for the desired name. 918 */ 919 returnValue = (int_u)None; 920 entry = NULL; /* Not needed, but eliminates compiler warning. */ 921 for (p = regProp; (long_u)(p - regProp) < numItems; ) 922 { 923 entry = p; 924 while (*p != 0 && !isspace(*p)) 925 p++; 926 if (*p != 0 && STRICMP(name, p + 1) == 0) 927 { 928 sscanf((char *)entry, "%x", &returnValue); 929 break; 930 } 931 while (*p != 0) 932 p++; 933 p++; 934 } 935 936 if (loose != NULL && returnValue == (int_u)None && !IsSerialName(name)) 937 { 938 for (p = regProp; (long_u)(p - regProp) < numItems; ) 939 { 940 entry = p; 941 while (*p != 0 && !isspace(*p)) 942 p++; 943 if (*p != 0 && IsSerialName(p + 1) 944 && STRNICMP(name, p + 1, STRLEN(name)) == 0) 945 { 946 sscanf((char *)entry, "%x", &returnValue); 947 *loose = vim_strsave(p + 1); 948 break; 949 } 950 while (*p != 0) 951 p++; 952 p++; 953 } 954 } 955 956 /* 957 * Delete the property, if that is desired (copy down the 958 * remainder of the registry property to overlay the deleted 959 * info, then rewrite the property). 960 */ 961 if (delete && returnValue != (int_u)None) 962 { 963 int count; 964 965 while (*p != 0) 966 p++; 967 p++; 968 count = numItems - (p - regProp); 969 if (count > 0) 970 mch_memmove(entry, p, count); 971 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 972 8, PropModeReplace, regProp, 973 (int)(numItems - (p - entry))); 974 XSync(dpy, False); 975 } 976 977 if (regProp != empty_prop) 978 XFree(regProp); 979 return (Window)returnValue; 980 } 981 982 /* 983 * Delete any lingering occurrence of window id. We promise that any 984 * occurrence is not ours since it is not yet put into the registry (by us) 985 * 986 * This is necessary in the following scenario: 987 * 1. There is an old windowid for an exit'ed vim in the registry 988 * 2. We get that id for our commWindow but only want to send, not register. 989 * 3. The window will mistakenly be regarded valid because of own commWindow 990 */ 991 static void 992 DeleteAnyLingerer( 993 Display *dpy, /* Display whose registry to check. */ 994 Window win) /* Window to remove */ 995 { 996 char_u *regProp, *entry = NULL; 997 char_u *p; 998 long_u numItems; 999 int_u wwin; 1000 1001 /* 1002 * Read the registry property. 1003 */ 1004 if (GetRegProp(dpy, ®Prop, &numItems, FALSE) == FAIL) 1005 return; 1006 1007 /* Scan the property for the window id. */ 1008 for (p = regProp; (long_u)(p - regProp) < numItems; ) 1009 { 1010 if (*p != 0) 1011 { 1012 sscanf((char *)p, "%x", &wwin); 1013 if ((Window)wwin == win) 1014 { 1015 int lastHalf; 1016 1017 /* Copy down the remainder to delete entry */ 1018 entry = p; 1019 while (*p != 0) 1020 p++; 1021 p++; 1022 lastHalf = numItems - (p - regProp); 1023 if (lastHalf > 0) 1024 mch_memmove(entry, p, lastHalf); 1025 numItems = (entry - regProp) + lastHalf; 1026 p = entry; 1027 continue; 1028 } 1029 } 1030 while (*p != 0) 1031 p++; 1032 p++; 1033 } 1034 1035 if (entry != NULL) 1036 { 1037 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, 1038 XA_STRING, 8, PropModeReplace, regProp, 1039 (int)(p - regProp)); 1040 XSync(dpy, False); 1041 } 1042 1043 if (regProp != empty_prop) 1044 XFree(regProp); 1045 } 1046 1047 /* 1048 * Read the registry property. Delete it when it's formatted wrong. 1049 * Return the property in "regPropp". "empty_prop" is used when it doesn't 1050 * exist yet. 1051 * Return OK when successful. 1052 */ 1053 static int 1054 GetRegProp( 1055 Display *dpy, 1056 char_u **regPropp, 1057 long_u *numItemsp, 1058 int domsg) /* When TRUE give error message. */ 1059 { 1060 int result, actualFormat; 1061 long_u bytesAfter; 1062 Atom actualType; 1063 XErrorHandler old_handler; 1064 1065 *regPropp = NULL; 1066 old_handler = XSetErrorHandler(x_error_check); 1067 got_x_error = FALSE; 1068 1069 result = XGetWindowProperty(dpy, RootWindow(dpy, 0), registryProperty, 0L, 1070 (long)MAX_PROP_WORDS, False, 1071 XA_STRING, &actualType, 1072 &actualFormat, numItemsp, &bytesAfter, 1073 regPropp); 1074 1075 XSync(dpy, FALSE); 1076 (void)XSetErrorHandler(old_handler); 1077 if (got_x_error) 1078 return FAIL; 1079 1080 if (actualType == None) 1081 { 1082 /* No prop yet. Logically equal to the empty list */ 1083 *numItemsp = 0; 1084 *regPropp = empty_prop; 1085 return OK; 1086 } 1087 1088 /* If the property is improperly formed, then delete it. */ 1089 if (result != Success || actualFormat != 8 || actualType != XA_STRING) 1090 { 1091 if (*regPropp != NULL) 1092 XFree(*regPropp); 1093 XDeleteProperty(dpy, RootWindow(dpy, 0), registryProperty); 1094 if (domsg) 1095 emsg(_("E251: VIM instance registry property is badly formed. Deleted!")); 1096 return FAIL; 1097 } 1098 return OK; 1099 } 1100 1101 1102 /* 1103 * This procedure is invoked by the various X event loops throughout Vims when 1104 * a property changes on the communication window. This procedure reads the 1105 * property and enqueues command requests and responses. If immediate is true, 1106 * it runs the event immediately instead of enqueuing it. Immediate can cause 1107 * unintended behavior and should only be used for code that blocks for a 1108 * response. 1109 */ 1110 void 1111 serverEventProc( 1112 Display *dpy, 1113 XEvent *eventPtr, /* Information about event. */ 1114 int immediate) /* Run event immediately. Should mostly be 0. */ 1115 { 1116 char_u *propInfo; 1117 int result, actualFormat; 1118 long_u numItems, bytesAfter; 1119 Atom actualType; 1120 1121 if (eventPtr != NULL) 1122 { 1123 if (eventPtr->xproperty.atom != commProperty 1124 || eventPtr->xproperty.state != PropertyNewValue) 1125 return; 1126 } 1127 1128 /* 1129 * Read the comm property and delete it. 1130 */ 1131 propInfo = NULL; 1132 result = XGetWindowProperty(dpy, commWindow, commProperty, 0L, 1133 (long)MAX_PROP_WORDS, True, 1134 XA_STRING, &actualType, 1135 &actualFormat, &numItems, &bytesAfter, 1136 &propInfo); 1137 1138 /* If the property doesn't exist or is improperly formed then ignore it. */ 1139 if (result != Success || actualType != XA_STRING || actualFormat != 8) 1140 { 1141 if (propInfo != NULL) 1142 XFree(propInfo); 1143 return; 1144 } 1145 if (immediate) 1146 server_parse_message(dpy, propInfo, numItems); 1147 else 1148 save_in_queue(propInfo, numItems); 1149 } 1150 1151 /* 1152 * Saves x clientserver commands in a queue so that they can be called when 1153 * vim is idle. 1154 */ 1155 static void 1156 save_in_queue(char_u *propInfo, long_u len) 1157 { 1158 x_queue_T *node; 1159 1160 node = (x_queue_T *)alloc(sizeof(x_queue_T)); 1161 if (node == NULL) 1162 return; /* out of memory */ 1163 node->propInfo = propInfo; 1164 node->len = len; 1165 1166 if (head.next == NULL) /* initialize circular queue */ 1167 { 1168 head.next = &head; 1169 head.prev = &head; 1170 } 1171 1172 /* insert node at tail of queue */ 1173 node->next = &head; 1174 node->prev = head.prev; 1175 head.prev->next = node; 1176 head.prev = node; 1177 } 1178 1179 /* 1180 * Parses queued clientserver messages. 1181 */ 1182 void 1183 server_parse_messages(void) 1184 { 1185 x_queue_T *node; 1186 1187 if (!X_DISPLAY) 1188 return; /* cannot happen? */ 1189 while (head.next != NULL && head.next != &head) 1190 { 1191 node = head.next; 1192 head.next = node->next; 1193 node->next->prev = node->prev; 1194 server_parse_message(X_DISPLAY, node->propInfo, node->len); 1195 vim_free(node); 1196 } 1197 } 1198 1199 /* 1200 * Returns a non-zero value if there are clientserver messages waiting 1201 * int the queue. 1202 */ 1203 int 1204 server_waiting(void) 1205 { 1206 return head.next != NULL && head.next != &head; 1207 } 1208 1209 /* 1210 * Prases a single clientserver message. A single message may contain multiple 1211 * commands. 1212 * "propInfo" will be freed. 1213 */ 1214 static void 1215 server_parse_message( 1216 Display *dpy, 1217 char_u *propInfo, /* A string containing 0 or more X commands */ 1218 long_u numItems) /* The size of propInfo in bytes. */ 1219 { 1220 char_u *p; 1221 int code; 1222 char_u *tofree; 1223 1224 /* 1225 * Several commands and results could arrive in the property at 1226 * one time; each iteration through the outer loop handles a 1227 * single command or result. 1228 */ 1229 for (p = propInfo; (long_u)(p - propInfo) < numItems; ) 1230 { 1231 /* 1232 * Ignore leading NULs; each command or result starts with a 1233 * NUL so that no matter how badly formed a preceding command 1234 * is, we'll be able to tell that a new command/result is 1235 * starting. 1236 */ 1237 if (*p == 0) 1238 { 1239 p++; 1240 continue; 1241 } 1242 1243 if ((*p == 'c' || *p == 'k') && (p[1] == 0)) 1244 { 1245 Window resWindow; 1246 char_u *name, *script, *serial, *end; 1247 Bool asKeys = *p == 'k'; 1248 char_u *enc; 1249 1250 /* 1251 * This is an incoming command from some other application. 1252 * Iterate over all of its options. Stop when we reach 1253 * the end of the property or something that doesn't look 1254 * like an option. 1255 */ 1256 p += 2; 1257 name = NULL; 1258 resWindow = None; 1259 serial = (char_u *)""; 1260 script = NULL; 1261 enc = NULL; 1262 while ((long_u)(p - propInfo) < numItems && *p == '-') 1263 { 1264 switch (p[1]) 1265 { 1266 case 'r': 1267 end = skipwhite(p + 2); 1268 resWindow = 0; 1269 while (vim_isxdigit(*end)) 1270 { 1271 resWindow = 16 * resWindow + (long_u)hex2nr(*end); 1272 ++end; 1273 } 1274 if (end == p + 2 || *end != ' ') 1275 resWindow = None; 1276 else 1277 { 1278 p = serial = end + 1; 1279 clientWindow = resWindow; /* Remember in global */ 1280 } 1281 break; 1282 case 'n': 1283 if (p[2] == ' ') 1284 name = p + 3; 1285 break; 1286 case 's': 1287 if (p[2] == ' ') 1288 script = p + 3; 1289 break; 1290 case 'E': 1291 if (p[2] == ' ') 1292 enc = p + 3; 1293 break; 1294 } 1295 while (*p != 0) 1296 p++; 1297 p++; 1298 } 1299 1300 if (script == NULL || name == NULL) 1301 continue; 1302 1303 if (serverName != NULL && STRICMP(name, serverName) == 0) 1304 { 1305 script = serverConvert(enc, script, &tofree); 1306 if (asKeys) 1307 server_to_input_buf(script); 1308 else 1309 { 1310 char_u *res; 1311 1312 res = eval_client_expr_to_string(script); 1313 if (resWindow != None) 1314 { 1315 garray_T reply; 1316 1317 /* Initialize the result property. */ 1318 ga_init2(&reply, 1, 100); 1319 (void)ga_grow(&reply, 50 + STRLEN(p_enc)); 1320 sprintf(reply.ga_data, "%cr%c-E %s%c-s %s%c-r ", 1321 0, 0, p_enc, 0, serial, 0); 1322 reply.ga_len = 14 + STRLEN(p_enc) + STRLEN(serial); 1323 1324 /* Evaluate the expression and return the result. */ 1325 if (res != NULL) 1326 ga_concat(&reply, res); 1327 else 1328 { 1329 ga_concat(&reply, (char_u *)_(e_invexprmsg)); 1330 ga_append(&reply, 0); 1331 ga_concat(&reply, (char_u *)"-c 1"); 1332 } 1333 ga_append(&reply, NUL); 1334 (void)AppendPropCarefully(dpy, resWindow, commProperty, 1335 reply.ga_data, reply.ga_len); 1336 ga_clear(&reply); 1337 } 1338 vim_free(res); 1339 } 1340 vim_free(tofree); 1341 } 1342 } 1343 else if (*p == 'r' && p[1] == 0) 1344 { 1345 int serial, gotSerial; 1346 char_u *res; 1347 PendingCommand *pcPtr; 1348 char_u *enc; 1349 1350 /* 1351 * This is a reply to some command that we sent out. Iterate 1352 * over all of its options. Stop when we reach the end of the 1353 * property or something that doesn't look like an option. 1354 */ 1355 p += 2; 1356 gotSerial = 0; 1357 res = (char_u *)""; 1358 code = 0; 1359 enc = NULL; 1360 while ((long_u)(p - propInfo) < numItems && *p == '-') 1361 { 1362 switch (p[1]) 1363 { 1364 case 'r': 1365 if (p[2] == ' ') 1366 res = p + 3; 1367 break; 1368 case 'E': 1369 if (p[2] == ' ') 1370 enc = p + 3; 1371 break; 1372 case 's': 1373 if (sscanf((char *)p + 2, " %d", &serial) == 1) 1374 gotSerial = 1; 1375 break; 1376 case 'c': 1377 if (sscanf((char *)p + 2, " %d", &code) != 1) 1378 code = 0; 1379 break; 1380 } 1381 while (*p != 0) 1382 p++; 1383 p++; 1384 } 1385 1386 if (!gotSerial) 1387 continue; 1388 1389 /* 1390 * Give the result information to anyone who's 1391 * waiting for it. 1392 */ 1393 for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr) 1394 { 1395 if (serial != pcPtr->serial || pcPtr->result != NULL) 1396 continue; 1397 1398 pcPtr->code = code; 1399 res = serverConvert(enc, res, &tofree); 1400 if (tofree == NULL) 1401 res = vim_strsave(res); 1402 pcPtr->result = res; 1403 break; 1404 } 1405 } 1406 else if (*p == 'n' && p[1] == 0) 1407 { 1408 Window win = 0; 1409 unsigned int u; 1410 int gotWindow; 1411 char_u *str; 1412 struct ServerReply *r; 1413 char_u *enc; 1414 1415 /* 1416 * This is a (n)otification. Sent with serverreply_send in Vim 1417 * script. Execute any autocommand and save it for later retrieval 1418 */ 1419 p += 2; 1420 gotWindow = 0; 1421 str = (char_u *)""; 1422 enc = NULL; 1423 while ((long_u)(p - propInfo) < numItems && *p == '-') 1424 { 1425 switch (p[1]) 1426 { 1427 case 'n': 1428 if (p[2] == ' ') 1429 str = p + 3; 1430 break; 1431 case 'E': 1432 if (p[2] == ' ') 1433 enc = p + 3; 1434 break; 1435 case 'w': 1436 if (sscanf((char *)p + 2, " %x", &u) == 1) 1437 { 1438 win = u; 1439 gotWindow = 1; 1440 } 1441 break; 1442 } 1443 while (*p != 0) 1444 p++; 1445 p++; 1446 } 1447 1448 if (!gotWindow) 1449 continue; 1450 str = serverConvert(enc, str, &tofree); 1451 if ((r = ServerReplyFind(win, SROP_Add)) != NULL) 1452 { 1453 ga_concat(&(r->strings), str); 1454 ga_append(&(r->strings), NUL); 1455 } 1456 { 1457 char_u winstr[30]; 1458 1459 sprintf((char *)winstr, "0x%x", (unsigned int)win); 1460 apply_autocmds(EVENT_REMOTEREPLY, winstr, str, TRUE, curbuf); 1461 } 1462 vim_free(tofree); 1463 } 1464 else 1465 { 1466 /* 1467 * Didn't recognize this thing. Just skip through the next 1468 * null character and try again. 1469 * Even if we get an 'r'(eply) we will throw it away as we 1470 * never specify (and thus expect) one 1471 */ 1472 while (*p != 0) 1473 p++; 1474 p++; 1475 } 1476 } 1477 XFree(propInfo); 1478 } 1479 1480 /* 1481 * Append a given property to a given window, but set up an X error handler so 1482 * that if the append fails this procedure can return an error code rather 1483 * than having Xlib panic. 1484 * Return: 0 for OK, -1 for error 1485 */ 1486 static int 1487 AppendPropCarefully( 1488 Display *dpy, /* Display on which to operate. */ 1489 Window window, /* Window whose property is to be modified. */ 1490 Atom property, /* Name of property. */ 1491 char_u *value, /* Characters to append to property. */ 1492 int length) /* How much to append */ 1493 { 1494 XErrorHandler old_handler; 1495 1496 old_handler = XSetErrorHandler(x_error_check); 1497 got_x_error = FALSE; 1498 XChangeProperty(dpy, window, property, XA_STRING, 8, 1499 PropModeAppend, value, length); 1500 XSync(dpy, False); 1501 (void) XSetErrorHandler(old_handler); 1502 return got_x_error ? -1 : 0; 1503 } 1504 1505 1506 /* 1507 * Another X Error handler, just used to check for errors. 1508 */ 1509 static int 1510 x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED) 1511 { 1512 got_x_error = TRUE; 1513 return 0; 1514 } 1515 1516 /* 1517 * Check if "str" looks like it had a serial number appended. 1518 * Actually just checks if the name ends in a digit. 1519 */ 1520 static int 1521 IsSerialName(char_u *str) 1522 { 1523 int len = STRLEN(str); 1524 1525 return (len > 1 && vim_isdigit(str[len - 1])); 1526 } 1527 #endif /* FEAT_CLIENTSERVER */ 1528