1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * clientserver.c: functions for Client Server functionality 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_CLIENTSERVER) || defined(PROTO) 17 18 static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr); 19 static char_u *serverMakeName(char_u *arg, char *cmd); 20 21 /* 22 * Replace termcodes such as <CR> and insert as key presses if there is room. 23 */ 24 void 25 server_to_input_buf(char_u *str) 26 { 27 char_u *ptr = NULL; 28 char_u *cpo_save = p_cpo; 29 30 // Set 'cpoptions' the way we want it. 31 // B set - backslashes are *not* treated specially 32 // k set - keycodes are *not* reverse-engineered 33 // < unset - <Key> sequences *are* interpreted 34 // The last but one parameter of replace_termcodes() is TRUE so that the 35 // <lt> sequence is recognised - needed for a real backslash. 36 p_cpo = (char_u *)"Bk"; 37 str = replace_termcodes((char_u *)str, &ptr, REPTERM_DO_LT, NULL); 38 p_cpo = cpo_save; 39 40 if (*ptr != NUL) // trailing CTRL-V results in nothing 41 { 42 /* 43 * Add the string to the input stream. 44 * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes. 45 * 46 * First clear typed characters from the typeahead buffer, there could 47 * be half a mapping there. Then append to the existing string, so 48 * that multiple commands from a client are concatenated. 49 */ 50 if (typebuf.tb_maplen < typebuf.tb_len) 51 del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen); 52 (void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE); 53 54 // Let input_available() know we inserted text in the typeahead 55 // buffer. 56 typebuf_was_filled = TRUE; 57 } 58 vim_free((char_u *)ptr); 59 } 60 61 /* 62 * Evaluate an expression that the client sent to a string. 63 */ 64 char_u * 65 eval_client_expr_to_string(char_u *expr) 66 { 67 char_u *res; 68 int save_dbl = debug_break_level; 69 int save_ro = redir_off; 70 funccal_entry_T funccal_entry; 71 int did_save_funccal = FALSE; 72 73 // Evaluate the expression at the toplevel, don't use variables local to 74 // the calling function. Except when in debug mode. 75 if (!debug_mode) 76 { 77 save_funccal(&funccal_entry); 78 did_save_funccal = TRUE; 79 } 80 81 // Disable debugging, otherwise Vim hangs, waiting for "cont" to be 82 // typed. 83 debug_break_level = -1; 84 redir_off = 0; 85 // Do not display error message, otherwise Vim hangs, waiting for "cont" 86 // to be typed. Do generate errors so that try/catch works. 87 ++emsg_silent; 88 89 res = eval_to_string(expr, TRUE); 90 91 debug_break_level = save_dbl; 92 redir_off = save_ro; 93 --emsg_silent; 94 if (emsg_silent < 0) 95 emsg_silent = 0; 96 if (did_save_funccal) 97 restore_funccal(); 98 99 // A client can tell us to redraw, but not to display the cursor, so do 100 // that here. 101 setcursor(); 102 out_flush_cursor(FALSE, FALSE); 103 104 return res; 105 } 106 107 /* 108 * Evaluate a command or expression sent to ourselves. 109 */ 110 int 111 sendToLocalVim(char_u *cmd, int asExpr, char_u **result) 112 { 113 if (asExpr) 114 { 115 char_u *ret; 116 117 ret = eval_client_expr_to_string(cmd); 118 if (result != NULL) 119 { 120 if (ret == NULL) 121 { 122 char *err = _(e_invexprmsg); 123 size_t len = STRLEN(cmd) + STRLEN(err) + 5; 124 char_u *msg; 125 126 msg = alloc(len); 127 if (msg != NULL) 128 vim_snprintf((char *)msg, len, "%s: \"%s\"", err, cmd); 129 *result = msg; 130 } 131 else 132 *result = ret; 133 } 134 else 135 vim_free(ret); 136 return ret == NULL ? -1 : 0; 137 } 138 server_to_input_buf(cmd); 139 return 0; 140 } 141 142 /* 143 * If conversion is needed, convert "data" from "client_enc" to 'encoding' and 144 * return an allocated string. Otherwise return "data". 145 * "*tofree" is set to the result when it needs to be freed later. 146 */ 147 char_u * 148 serverConvert( 149 char_u *client_enc UNUSED, 150 char_u *data, 151 char_u **tofree) 152 { 153 char_u *res = data; 154 155 *tofree = NULL; 156 if (client_enc != NULL && p_enc != NULL) 157 { 158 vimconv_T vimconv; 159 160 vimconv.vc_type = CONV_NONE; 161 if (convert_setup(&vimconv, client_enc, p_enc) != FAIL 162 && vimconv.vc_type != CONV_NONE) 163 { 164 res = string_convert(&vimconv, data, NULL); 165 if (res == NULL) 166 res = data; 167 else 168 *tofree = res; 169 } 170 convert_setup(&vimconv, NULL, NULL); 171 } 172 return res; 173 } 174 #endif 175 176 #if (defined(FEAT_CLIENTSERVER) && !defined(NO_VIM_MAIN)) || defined(PROTO) 177 178 /* 179 * Common code for the X command server and the Win32 command server. 180 */ 181 182 static char_u *build_drop_cmd(int filec, char **filev, int tabs, int sendReply); 183 184 /* 185 * Do the client-server stuff, unless "--servername ''" was used. 186 */ 187 void 188 exec_on_server(mparm_T *parmp) 189 { 190 if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL) 191 { 192 # ifdef MSWIN 193 // Initialise the client/server messaging infrastructure. 194 serverInitMessaging(); 195 # endif 196 197 /* 198 * When a command server argument was found, execute it. This may 199 * exit Vim when it was successful. Otherwise it's executed further 200 * on. Remember the encoding used here in "serverStrEnc". 201 */ 202 if (parmp->serverArg) 203 { 204 cmdsrv_main(&parmp->argc, parmp->argv, 205 parmp->serverName_arg, &parmp->serverStr); 206 parmp->serverStrEnc = vim_strsave(p_enc); 207 } 208 209 // If we're still running, get the name to register ourselves. 210 // On Win32 can register right now, for X11 need to setup the 211 // clipboard first, it's further down. 212 parmp->servername = serverMakeName(parmp->serverName_arg, 213 parmp->argv[0]); 214 # ifdef MSWIN 215 if (parmp->servername != NULL) 216 { 217 serverSetName(parmp->servername); 218 vim_free(parmp->servername); 219 } 220 # endif 221 } 222 } 223 224 /* 225 * Prepare for running as a Vim server. 226 */ 227 void 228 prepare_server(mparm_T *parmp) 229 { 230 # if defined(FEAT_X11) 231 /* 232 * Register for remote command execution with :serversend and --remote 233 * unless there was a -X or a --servername '' on the command line. 234 * Only register nongui-vim's with an explicit --servername argument, 235 * or when compiling with autoservername. 236 * When running as root --servername is also required. 237 */ 238 if (X_DISPLAY != NULL && parmp->servername != NULL && ( 239 # if defined(FEAT_AUTOSERVERNAME) || defined(FEAT_GUI) 240 ( 241 # if defined(FEAT_AUTOSERVERNAME) 242 1 243 # else 244 gui.in_use 245 # endif 246 # ifdef UNIX 247 && getuid() != ROOT_UID 248 # endif 249 ) || 250 # endif 251 parmp->serverName_arg != NULL)) 252 { 253 (void)serverRegisterName(X_DISPLAY, parmp->servername); 254 vim_free(parmp->servername); 255 TIME_MSG("register server name"); 256 } 257 else 258 serverDelayedStartName = parmp->servername; 259 # endif 260 261 /* 262 * Execute command ourselves if we're here because the send failed (or 263 * else we would have exited above). 264 */ 265 if (parmp->serverStr != NULL) 266 { 267 char_u *p; 268 269 server_to_input_buf(serverConvert(parmp->serverStrEnc, 270 parmp->serverStr, &p)); 271 vim_free(p); 272 } 273 } 274 275 static void 276 cmdsrv_main( 277 int *argc, 278 char **argv, 279 char_u *serverName_arg, 280 char_u **serverStr) 281 { 282 char_u *res; 283 int i; 284 char_u *sname; 285 int ret; 286 int didone = FALSE; 287 int exiterr = 0; 288 char **newArgV = argv + 1; 289 int newArgC = 1, 290 Argc = *argc; 291 int argtype; 292 #define ARGTYPE_OTHER 0 293 #define ARGTYPE_EDIT 1 294 #define ARGTYPE_EDIT_WAIT 2 295 #define ARGTYPE_SEND 3 296 int silent = FALSE; 297 int tabs = FALSE; 298 # ifndef FEAT_X11 299 HWND srv; 300 # else 301 Window srv; 302 303 setup_term_clip(); 304 # endif 305 306 sname = serverMakeName(serverName_arg, argv[0]); 307 if (sname == NULL) 308 return; 309 310 /* 311 * Execute the command server related arguments and remove them 312 * from the argc/argv array; We may have to return into main() 313 */ 314 for (i = 1; i < Argc; i++) 315 { 316 res = NULL; 317 if (STRCMP(argv[i], "--") == 0) // end of option arguments 318 { 319 for (; i < *argc; i++) 320 { 321 *newArgV++ = argv[i]; 322 newArgC++; 323 } 324 break; 325 } 326 327 if (STRICMP(argv[i], "--remote-send") == 0) 328 argtype = ARGTYPE_SEND; 329 else if (STRNICMP(argv[i], "--remote", 8) == 0) 330 { 331 char *p = argv[i] + 8; 332 333 argtype = ARGTYPE_EDIT; 334 while (*p != NUL) 335 { 336 if (STRNICMP(p, "-wait", 5) == 0) 337 { 338 argtype = ARGTYPE_EDIT_WAIT; 339 p += 5; 340 } 341 else if (STRNICMP(p, "-silent", 7) == 0) 342 { 343 silent = TRUE; 344 p += 7; 345 } 346 else if (STRNICMP(p, "-tab", 4) == 0) 347 { 348 tabs = TRUE; 349 p += 4; 350 } 351 else 352 { 353 argtype = ARGTYPE_OTHER; 354 break; 355 } 356 } 357 } 358 else 359 argtype = ARGTYPE_OTHER; 360 361 if (argtype != ARGTYPE_OTHER) 362 { 363 if (i == *argc - 1) 364 mainerr_arg_missing((char_u *)argv[i]); 365 if (argtype == ARGTYPE_SEND) 366 { 367 *serverStr = (char_u *)argv[i + 1]; 368 i++; 369 } 370 else 371 { 372 *serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1, 373 tabs, argtype == ARGTYPE_EDIT_WAIT); 374 if (*serverStr == NULL) 375 { 376 // Probably out of memory, exit. 377 didone = TRUE; 378 exiterr = 1; 379 break; 380 } 381 Argc = i; 382 } 383 # ifdef FEAT_X11 384 if (xterm_dpy == NULL) 385 { 386 mch_errmsg(_("No display")); 387 ret = -1; 388 } 389 else 390 ret = serverSendToVim(xterm_dpy, sname, *serverStr, 391 NULL, &srv, 0, 0, 0, silent); 392 # else 393 // Win32 always works? 394 ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent); 395 # endif 396 if (ret < 0) 397 { 398 if (argtype == ARGTYPE_SEND) 399 { 400 // Failed to send, abort. 401 mch_errmsg(_(": Send failed.\n")); 402 didone = TRUE; 403 exiterr = 1; 404 } 405 else if (!silent) 406 // Let vim start normally. 407 mch_errmsg(_(": Send failed. Trying to execute locally\n")); 408 break; 409 } 410 411 # ifdef FEAT_GUI_MSWIN 412 // Guess that when the server name starts with "g" it's a GUI 413 // server, which we can bring to the foreground here. 414 // Foreground() in the server doesn't work very well. 415 if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G') 416 SetForegroundWindow(srv); 417 # endif 418 419 /* 420 * For --remote-wait: Wait until the server did edit each 421 * file. Also detect that the server no longer runs. 422 */ 423 if (ret >= 0 && argtype == ARGTYPE_EDIT_WAIT) 424 { 425 int numFiles = *argc - i - 1; 426 int j; 427 char_u *done = alloc(numFiles); 428 char_u *p; 429 # ifdef FEAT_GUI_MSWIN 430 NOTIFYICONDATA ni; 431 int count = 0; 432 extern HWND message_window; 433 # endif 434 435 if (numFiles > 0 && argv[i + 1][0] == '+') 436 // Skip "+cmd" argument, don't wait for it to be edited. 437 --numFiles; 438 439 # ifdef FEAT_GUI_MSWIN 440 ni.cbSize = sizeof(ni); 441 ni.hWnd = message_window; 442 ni.uID = 0; 443 ni.uFlags = NIF_ICON|NIF_TIP; 444 ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM"); 445 sprintf(ni.szTip, _("%d of %d edited"), count, numFiles); 446 Shell_NotifyIcon(NIM_ADD, &ni); 447 # endif 448 449 // Wait for all files to unload in remote 450 vim_memset(done, 0, numFiles); 451 while (memchr(done, 0, numFiles) != NULL) 452 { 453 # ifdef MSWIN 454 p = serverGetReply(srv, NULL, TRUE, TRUE, 0); 455 if (p == NULL) 456 break; 457 # else 458 if (serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0) 459 break; 460 # endif 461 j = atoi((char *)p); 462 if (j >= 0 && j < numFiles) 463 { 464 # ifdef FEAT_GUI_MSWIN 465 ++count; 466 sprintf(ni.szTip, _("%d of %d edited"), 467 count, numFiles); 468 Shell_NotifyIcon(NIM_MODIFY, &ni); 469 # endif 470 done[j] = 1; 471 } 472 } 473 # ifdef FEAT_GUI_MSWIN 474 Shell_NotifyIcon(NIM_DELETE, &ni); 475 # endif 476 vim_free(done); 477 } 478 } 479 else if (STRICMP(argv[i], "--remote-expr") == 0) 480 { 481 if (i == *argc - 1) 482 mainerr_arg_missing((char_u *)argv[i]); 483 # ifdef MSWIN 484 // Win32 always works? 485 if (serverSendToVim(sname, (char_u *)argv[i + 1], 486 &res, NULL, 1, 0, FALSE) < 0) 487 # else 488 if (xterm_dpy == NULL) 489 mch_errmsg(_("No display: Send expression failed.\n")); 490 else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1], 491 &res, NULL, 1, 0, 1, FALSE) < 0) 492 # endif 493 { 494 if (res != NULL && *res != NUL) 495 { 496 // Output error from remote 497 mch_errmsg((char *)res); 498 VIM_CLEAR(res); 499 } 500 mch_errmsg(_(": Send expression failed.\n")); 501 } 502 } 503 else if (STRICMP(argv[i], "--serverlist") == 0) 504 { 505 # ifdef MSWIN 506 // Win32 always works? 507 res = serverGetVimNames(); 508 # else 509 if (xterm_dpy != NULL) 510 res = serverGetVimNames(xterm_dpy); 511 # endif 512 if (did_emsg) 513 mch_errmsg("\n"); 514 } 515 else if (STRICMP(argv[i], "--servername") == 0) 516 { 517 // Already processed. Take it out of the command line 518 i++; 519 continue; 520 } 521 else 522 { 523 *newArgV++ = argv[i]; 524 newArgC++; 525 continue; 526 } 527 didone = TRUE; 528 if (res != NULL && *res != NUL) 529 { 530 mch_msg((char *)res); 531 if (res[STRLEN(res) - 1] != '\n') 532 mch_msg("\n"); 533 } 534 vim_free(res); 535 } 536 537 if (didone) 538 { 539 display_errors(); // display any collected messages 540 exit(exiterr); // Mission accomplished - get out 541 } 542 543 // Return back into main() 544 *argc = newArgC; 545 vim_free(sname); 546 } 547 548 /* 549 * Build a ":drop" command to send to a Vim server. 550 */ 551 static char_u * 552 build_drop_cmd( 553 int filec, 554 char **filev, 555 int tabs, // Use ":tab drop" instead of ":drop". 556 int sendReply) 557 { 558 garray_T ga; 559 int i; 560 char_u *inicmd = NULL; 561 char_u *p; 562 char_u *cdp; 563 char_u *cwd; 564 565 if (filec > 0 && filev[0][0] == '+') 566 { 567 inicmd = (char_u *)filev[0] + 1; 568 filev++; 569 filec--; 570 } 571 // Check if we have at least one argument. 572 if (filec <= 0) 573 mainerr_arg_missing((char_u *)filev[-1]); 574 575 // Temporarily cd to the current directory to handle relative file names. 576 cwd = alloc(MAXPATHL); 577 if (cwd == NULL) 578 return NULL; 579 if (mch_dirname(cwd, MAXPATHL) != OK) 580 { 581 vim_free(cwd); 582 return NULL; 583 } 584 cdp = vim_strsave_escaped_ext(cwd, 585 #ifdef BACKSLASH_IN_FILENAME 586 (char_u *)"", // rem_backslash() will tell what chars to escape 587 #else 588 PATH_ESC_CHARS, 589 #endif 590 '\\', TRUE); 591 vim_free(cwd); 592 if (cdp == NULL) 593 return NULL; 594 ga_init2(&ga, 1, 100); 595 ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd "); 596 ga_concat(&ga, cdp); 597 598 // Call inputsave() so that a prompt for an encryption key works. 599 ga_concat(&ga, (char_u *)"<CR>:if exists('*inputsave')|call inputsave()|endif|"); 600 if (tabs) 601 ga_concat(&ga, (char_u *)"tab "); 602 ga_concat(&ga, (char_u *)"drop"); 603 for (i = 0; i < filec; i++) 604 { 605 // On Unix the shell has already expanded the wildcards, don't want to 606 // do it again in the Vim server. On MS-Windows only escape 607 // non-wildcard characters. 608 p = vim_strsave_escaped((char_u *)filev[i], 609 #ifdef UNIX 610 PATH_ESC_CHARS 611 #else 612 (char_u *)" \t%#" 613 #endif 614 ); 615 if (p == NULL) 616 { 617 vim_free(ga.ga_data); 618 return NULL; 619 } 620 ga_concat(&ga, (char_u *)" "); 621 ga_concat(&ga, p); 622 vim_free(p); 623 } 624 ga_concat(&ga, (char_u *)"|if exists('*inputrestore')|call inputrestore()|endif<CR>"); 625 626 // The :drop commands goes to Insert mode when 'insertmode' is set, use 627 // CTRL-\ CTRL-N again. 628 ga_concat(&ga, (char_u *)"<C-\\><C-N>"); 629 630 // Switch back to the correct current directory (prior to temporary path 631 // switch) unless 'autochdir' is set, in which case it will already be 632 // correct after the :drop command. With line breaks and spaces: 633 // if !exists('+acd') || !&acd 634 // if haslocaldir() 635 // cd - 636 // lcd - 637 // elseif getcwd() ==# 'current path' 638 // cd - 639 // endif 640 // endif 641 ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|"); 642 ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '"); 643 ga_concat(&ga, cdp); 644 ga_concat(&ga, (char_u *)"'|cd -|endif|endif<CR>"); 645 vim_free(cdp); 646 647 if (sendReply) 648 ga_concat(&ga, (char_u *)":call SetupRemoteReplies()<CR>"); 649 ga_concat(&ga, (char_u *)":"); 650 if (inicmd != NULL) 651 { 652 // Can't use <CR> after "inicmd", because an "startinsert" would cause 653 // the following commands to be inserted as text. Use a "|", 654 // hopefully "inicmd" does allow this... 655 ga_concat(&ga, inicmd); 656 ga_concat(&ga, (char_u *)"|"); 657 } 658 // Bring the window to the foreground, goto Insert mode when 'im' set and 659 // clear command line. 660 ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>"); 661 ga_append(&ga, NUL); 662 return ga.ga_data; 663 } 664 665 /* 666 * Make our basic server name: use the specified "arg" if given, otherwise use 667 * the tail of the command "cmd" we were started with. 668 * Return the name in allocated memory. This doesn't include a serial number. 669 */ 670 static char_u * 671 serverMakeName(char_u *arg, char *cmd) 672 { 673 char_u *p; 674 675 if (arg != NULL && *arg != NUL) 676 p = vim_strsave_up(arg); 677 else 678 { 679 p = vim_strsave_up(gettail((char_u *)cmd)); 680 // Remove .exe or .bat from the name. 681 if (p != NULL && vim_strchr(p, '.') != NULL) 682 *vim_strchr(p, '.') = NUL; 683 } 684 return p; 685 } 686 #endif // FEAT_CLIENTSERVER 687 688 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) 689 static void 690 make_connection(void) 691 { 692 if (X_DISPLAY == NULL 693 # ifdef FEAT_GUI 694 && !gui.in_use 695 # endif 696 ) 697 { 698 x_force_connect = TRUE; 699 setup_term_clip(); 700 x_force_connect = FALSE; 701 } 702 } 703 704 static int 705 check_connection(void) 706 { 707 make_connection(); 708 if (X_DISPLAY == NULL) 709 { 710 emsg(_("E240: No connection to the X server")); 711 return FAIL; 712 } 713 return OK; 714 } 715 #endif 716 717 #ifdef FEAT_CLIENTSERVER 718 static void 719 remote_common(typval_T *argvars, typval_T *rettv, int expr) 720 { 721 char_u *server_name; 722 char_u *keys; 723 char_u *r = NULL; 724 char_u buf[NUMBUFLEN]; 725 int timeout = 0; 726 # ifdef MSWIN 727 HWND w; 728 # else 729 Window w; 730 # endif 731 732 if (check_restricted() || check_secure()) 733 return; 734 735 # ifdef FEAT_X11 736 if (check_connection() == FAIL) 737 return; 738 # endif 739 if (argvars[2].v_type != VAR_UNKNOWN 740 && argvars[3].v_type != VAR_UNKNOWN) 741 timeout = tv_get_number(&argvars[3]); 742 743 server_name = tv_get_string_chk(&argvars[0]); 744 if (server_name == NULL) 745 return; // type error; errmsg already given 746 keys = tv_get_string_buf(&argvars[1], buf); 747 # ifdef MSWIN 748 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0) 749 # else 750 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout, 751 0, TRUE) < 0) 752 # endif 753 { 754 if (r != NULL) 755 { 756 emsg((char *)r); // sending worked but evaluation failed 757 vim_free(r); 758 } 759 else 760 semsg(_("E241: Unable to send to %s"), server_name); 761 return; 762 } 763 764 rettv->vval.v_string = r; 765 766 if (argvars[2].v_type != VAR_UNKNOWN) 767 { 768 dictitem_T v; 769 char_u str[30]; 770 char_u *idvar; 771 772 idvar = tv_get_string_chk(&argvars[2]); 773 if (idvar != NULL && *idvar != NUL) 774 { 775 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w); 776 v.di_tv.v_type = VAR_STRING; 777 v.di_tv.vval.v_string = vim_strsave(str); 778 set_var(idvar, &v.di_tv, FALSE); 779 vim_free(v.di_tv.vval.v_string); 780 } 781 } 782 } 783 #endif 784 785 #if defined(FEAT_EVAL) || defined(PROTO) 786 /* 787 * "remote_expr()" function 788 */ 789 void 790 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv) 791 { 792 rettv->v_type = VAR_STRING; 793 rettv->vval.v_string = NULL; 794 #ifdef FEAT_CLIENTSERVER 795 remote_common(argvars, rettv, TRUE); 796 #endif 797 } 798 799 /* 800 * "remote_foreground()" function 801 */ 802 void 803 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 804 { 805 #ifdef FEAT_CLIENTSERVER 806 # ifdef MSWIN 807 // On Win32 it's done in this application. 808 { 809 char_u *server_name = tv_get_string_chk(&argvars[0]); 810 811 if (server_name != NULL) 812 serverForeground(server_name); 813 } 814 # else 815 // Send a foreground() expression to the server. 816 argvars[1].v_type = VAR_STRING; 817 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()"); 818 argvars[2].v_type = VAR_UNKNOWN; 819 rettv->v_type = VAR_STRING; 820 rettv->vval.v_string = NULL; 821 remote_common(argvars, rettv, TRUE); 822 vim_free(argvars[1].vval.v_string); 823 # endif 824 #endif 825 } 826 827 void 828 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv) 829 { 830 #ifdef FEAT_CLIENTSERVER 831 dictitem_T v; 832 char_u *s = NULL; 833 # ifdef MSWIN 834 long_u n = 0; 835 # endif 836 char_u *serverid; 837 838 if (check_restricted() || check_secure()) 839 { 840 rettv->vval.v_number = -1; 841 return; 842 } 843 serverid = tv_get_string_chk(&argvars[0]); 844 if (serverid == NULL) 845 { 846 rettv->vval.v_number = -1; 847 return; // type error; errmsg already given 848 } 849 # ifdef MSWIN 850 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n); 851 if (n == 0) 852 rettv->vval.v_number = -1; 853 else 854 { 855 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0); 856 rettv->vval.v_number = (s != NULL); 857 } 858 # else 859 if (check_connection() == FAIL) 860 return; 861 862 rettv->vval.v_number = serverPeekReply(X_DISPLAY, 863 serverStrToWin(serverid), &s); 864 # endif 865 866 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) 867 { 868 char_u *retvar; 869 870 v.di_tv.v_type = VAR_STRING; 871 v.di_tv.vval.v_string = vim_strsave(s); 872 retvar = tv_get_string_chk(&argvars[1]); 873 if (retvar != NULL) 874 set_var(retvar, &v.di_tv, FALSE); 875 vim_free(v.di_tv.vval.v_string); 876 } 877 #else 878 rettv->vval.v_number = -1; 879 #endif 880 } 881 882 void 883 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) 884 { 885 char_u *r = NULL; 886 887 #ifdef FEAT_CLIENTSERVER 888 char_u *serverid = tv_get_string_chk(&argvars[0]); 889 890 if (serverid != NULL && !check_restricted() && !check_secure()) 891 { 892 int timeout = 0; 893 # ifdef MSWIN 894 // The server's HWND is encoded in the 'id' parameter 895 long_u n = 0; 896 # endif 897 898 if (argvars[1].v_type != VAR_UNKNOWN) 899 timeout = tv_get_number(&argvars[1]); 900 901 # ifdef MSWIN 902 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n); 903 if (n != 0) 904 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout); 905 if (r == NULL) 906 # else 907 if (check_connection() == FAIL 908 || serverReadReply(X_DISPLAY, serverStrToWin(serverid), 909 &r, FALSE, timeout) < 0) 910 # endif 911 emsg(_("E277: Unable to read a server reply")); 912 } 913 #endif 914 rettv->v_type = VAR_STRING; 915 rettv->vval.v_string = r; 916 } 917 918 /* 919 * "remote_send()" function 920 */ 921 void 922 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv) 923 { 924 rettv->v_type = VAR_STRING; 925 rettv->vval.v_string = NULL; 926 #ifdef FEAT_CLIENTSERVER 927 remote_common(argvars, rettv, FALSE); 928 #endif 929 } 930 931 /* 932 * "remote_startserver()" function 933 */ 934 void 935 f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED) 936 { 937 #ifdef FEAT_CLIENTSERVER 938 char_u *server = tv_get_string_chk(&argvars[0]); 939 940 if (server == NULL) 941 return; // type error; errmsg already given 942 if (serverName != NULL) 943 emsg(_("E941: already started a server")); 944 else 945 { 946 # ifdef FEAT_X11 947 if (check_connection() == OK) 948 serverRegisterName(X_DISPLAY, server); 949 # else 950 serverSetName(server); 951 # endif 952 } 953 #else 954 emsg(_("E942: +clientserver feature not available")); 955 #endif 956 } 957 958 void 959 f_server2client(typval_T *argvars UNUSED, typval_T *rettv) 960 { 961 #ifdef FEAT_CLIENTSERVER 962 char_u buf[NUMBUFLEN]; 963 char_u *server = tv_get_string_chk(&argvars[0]); 964 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf); 965 966 rettv->vval.v_number = -1; 967 if (server == NULL || reply == NULL) 968 return; 969 if (check_restricted() || check_secure()) 970 return; 971 # ifdef FEAT_X11 972 if (check_connection() == FAIL) 973 return; 974 # endif 975 976 if (serverSendReply(server, reply) < 0) 977 { 978 emsg(_("E258: Unable to send to client")); 979 return; 980 } 981 rettv->vval.v_number = 0; 982 #else 983 rettv->vval.v_number = -1; 984 #endif 985 } 986 987 void 988 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) 989 { 990 char_u *r = NULL; 991 992 #ifdef FEAT_CLIENTSERVER 993 # ifdef MSWIN 994 r = serverGetVimNames(); 995 # else 996 make_connection(); 997 if (X_DISPLAY != NULL) 998 r = serverGetVimNames(X_DISPLAY); 999 # endif 1000 #endif 1001 rettv->v_type = VAR_STRING; 1002 rettv->vval.v_string = r; 1003 } 1004 #endif 1005