blob: eaaba2572a8d042392cc59f8f94f5ae612ae6dec [file] [log] [blame]
Bram Moolenaarf87a0402020-04-05 20:21:03 +02001/* 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
18static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr);
19static 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
25server_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";
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +000037 str = replace_termcodes(str, &ptr, REPTERM_DO_LT, NULL);
Bram Moolenaarf87a0402020-04-05 20:21:03 +020038 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 }
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +000058 vim_free(ptr);
Bram Moolenaarf87a0402020-04-05 20:21:03 +020059}
60
61/*
62 * Evaluate an expression that the client sent to a string.
63 */
64 char_u *
65eval_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
Bram Moolenaarb171fb12020-06-24 20:34:03 +020089 res = eval_to_string(expr, TRUE);
Bram Moolenaarf87a0402020-04-05 20:21:03 +020090
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
111sendToLocalVim(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 {
Bram Moolenaar74409f62022-01-01 15:58:22 +0000122 char *err = _(e_invalid_expression_received);
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200123 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 *
148serverConvert(
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
182static 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
188exec_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
228prepare_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
276cmdsrv_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 */
Bram Moolenaarfe154992022-03-22 20:42:12 +0000423 if (argtype == ARGTYPE_EDIT_WAIT)
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200424 {
425 int numFiles = *argc - i - 1;
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200426 char_u *done = alloc(numFiles);
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200427# ifdef FEAT_GUI_MSWIN
428 NOTIFYICONDATA ni;
429 int count = 0;
430 extern HWND message_window;
431# endif
432
433 if (numFiles > 0 && argv[i + 1][0] == '+')
434 // Skip "+cmd" argument, don't wait for it to be edited.
435 --numFiles;
436
437# ifdef FEAT_GUI_MSWIN
438 ni.cbSize = sizeof(ni);
439 ni.hWnd = message_window;
440 ni.uID = 0;
441 ni.uFlags = NIF_ICON|NIF_TIP;
442 ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM");
443 sprintf(ni.szTip, _("%d of %d edited"), count, numFiles);
444 Shell_NotifyIcon(NIM_ADD, &ni);
445# endif
446
447 // Wait for all files to unload in remote
448 vim_memset(done, 0, numFiles);
449 while (memchr(done, 0, numFiles) != NULL)
450 {
K.Takatab0d12e62022-09-08 10:55:38 +0100451 char_u *p;
452 int j;
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200453# 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);
K.Takatab0d12e62022-09-08 10:55:38 +0100462 vim_free(p);
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200463 if (j >= 0 && j < numFiles)
464 {
465# ifdef FEAT_GUI_MSWIN
466 ++count;
467 sprintf(ni.szTip, _("%d of %d edited"),
468 count, numFiles);
469 Shell_NotifyIcon(NIM_MODIFY, &ni);
470# endif
471 done[j] = 1;
472 }
473 }
474# ifdef FEAT_GUI_MSWIN
475 Shell_NotifyIcon(NIM_DELETE, &ni);
476# endif
Bram Moolenaar7d41aa82020-04-26 14:29:56 +0200477 vim_free(done);
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200478 }
479 }
480 else if (STRICMP(argv[i], "--remote-expr") == 0)
481 {
482 if (i == *argc - 1)
483 mainerr_arg_missing((char_u *)argv[i]);
484# ifdef MSWIN
485 // Win32 always works?
486 if (serverSendToVim(sname, (char_u *)argv[i + 1],
487 &res, NULL, 1, 0, FALSE) < 0)
488# else
489 if (xterm_dpy == NULL)
490 mch_errmsg(_("No display: Send expression failed.\n"));
491 else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1],
492 &res, NULL, 1, 0, 1, FALSE) < 0)
493# endif
494 {
495 if (res != NULL && *res != NUL)
496 {
497 // Output error from remote
498 mch_errmsg((char *)res);
499 VIM_CLEAR(res);
500 }
501 mch_errmsg(_(": Send expression failed.\n"));
502 }
503 }
504 else if (STRICMP(argv[i], "--serverlist") == 0)
505 {
506# ifdef MSWIN
507 // Win32 always works?
508 res = serverGetVimNames();
509# else
510 if (xterm_dpy != NULL)
511 res = serverGetVimNames(xterm_dpy);
512# endif
513 if (did_emsg)
514 mch_errmsg("\n");
515 }
516 else if (STRICMP(argv[i], "--servername") == 0)
517 {
518 // Already processed. Take it out of the command line
519 i++;
520 continue;
521 }
522 else
523 {
524 *newArgV++ = argv[i];
525 newArgC++;
526 continue;
527 }
528 didone = TRUE;
529 if (res != NULL && *res != NUL)
530 {
531 mch_msg((char *)res);
532 if (res[STRLEN(res) - 1] != '\n')
533 mch_msg("\n");
534 }
535 vim_free(res);
536 }
537
538 if (didone)
539 {
540 display_errors(); // display any collected messages
541 exit(exiterr); // Mission accomplished - get out
542 }
543
544 // Return back into main()
545 *argc = newArgC;
546 vim_free(sname);
547}
548
549/*
550 * Build a ":drop" command to send to a Vim server.
551 */
552 static char_u *
553build_drop_cmd(
554 int filec,
555 char **filev,
556 int tabs, // Use ":tab drop" instead of ":drop".
557 int sendReply)
558{
559 garray_T ga;
560 int i;
561 char_u *inicmd = NULL;
562 char_u *p;
563 char_u *cdp;
564 char_u *cwd;
565
566 if (filec > 0 && filev[0][0] == '+')
567 {
568 inicmd = (char_u *)filev[0] + 1;
569 filev++;
570 filec--;
571 }
572 // Check if we have at least one argument.
573 if (filec <= 0)
574 mainerr_arg_missing((char_u *)filev[-1]);
575
576 // Temporarily cd to the current directory to handle relative file names.
577 cwd = alloc(MAXPATHL);
578 if (cwd == NULL)
579 return NULL;
580 if (mch_dirname(cwd, MAXPATHL) != OK)
581 {
582 vim_free(cwd);
583 return NULL;
584 }
585 cdp = vim_strsave_escaped_ext(cwd,
586#ifdef BACKSLASH_IN_FILENAME
587 (char_u *)"", // rem_backslash() will tell what chars to escape
588#else
589 PATH_ESC_CHARS,
590#endif
591 '\\', TRUE);
592 vim_free(cwd);
593 if (cdp == NULL)
594 return NULL;
595 ga_init2(&ga, 1, 100);
596 ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
597 ga_concat(&ga, cdp);
598
599 // Call inputsave() so that a prompt for an encryption key works.
Bram Moolenaara9a47d12020-08-09 21:45:52 +0200600 ga_concat(&ga, (char_u *)
601 "<CR>:if exists('*inputsave')|call inputsave()|endif|");
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200602 if (tabs)
603 ga_concat(&ga, (char_u *)"tab ");
604 ga_concat(&ga, (char_u *)"drop");
605 for (i = 0; i < filec; i++)
606 {
607 // On Unix the shell has already expanded the wildcards, don't want to
608 // do it again in the Vim server. On MS-Windows only escape
609 // non-wildcard characters.
610 p = vim_strsave_escaped((char_u *)filev[i],
611#ifdef UNIX
612 PATH_ESC_CHARS
613#else
614 (char_u *)" \t%#"
615#endif
616 );
617 if (p == NULL)
618 {
619 vim_free(ga.ga_data);
620 return NULL;
621 }
622 ga_concat(&ga, (char_u *)" ");
623 ga_concat(&ga, p);
624 vim_free(p);
625 }
Bram Moolenaara9a47d12020-08-09 21:45:52 +0200626 ga_concat(&ga, (char_u *)
627 "|if exists('*inputrestore')|call inputrestore()|endif<CR>");
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200628
629 // The :drop commands goes to Insert mode when 'insertmode' is set, use
630 // CTRL-\ CTRL-N again.
631 ga_concat(&ga, (char_u *)"<C-\\><C-N>");
632
633 // Switch back to the correct current directory (prior to temporary path
634 // switch) unless 'autochdir' is set, in which case it will already be
635 // correct after the :drop command. With line breaks and spaces:
636 // if !exists('+acd') || !&acd
637 // if haslocaldir()
638 // cd -
639 // lcd -
640 // elseif getcwd() ==# 'current path'
641 // cd -
642 // endif
643 // endif
644 ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|");
645 ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '");
646 ga_concat(&ga, cdp);
647 ga_concat(&ga, (char_u *)"'|cd -|endif|endif<CR>");
648 vim_free(cdp);
649
650 if (sendReply)
651 ga_concat(&ga, (char_u *)":call SetupRemoteReplies()<CR>");
652 ga_concat(&ga, (char_u *)":");
653 if (inicmd != NULL)
654 {
Bram Moolenaar54969f42022-02-07 13:56:44 +0000655 // Can't use <CR> after "inicmd", because a "startinsert" would cause
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200656 // the following commands to be inserted as text. Use a "|",
657 // hopefully "inicmd" does allow this...
658 ga_concat(&ga, inicmd);
659 ga_concat(&ga, (char_u *)"|");
660 }
661 // Bring the window to the foreground, goto Insert mode when 'im' set and
662 // clear command line.
663 ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>");
664 ga_append(&ga, NUL);
665 return ga.ga_data;
666}
667
668/*
669 * Make our basic server name: use the specified "arg" if given, otherwise use
670 * the tail of the command "cmd" we were started with.
671 * Return the name in allocated memory. This doesn't include a serial number.
672 */
673 static char_u *
674serverMakeName(char_u *arg, char *cmd)
675{
676 char_u *p;
677
678 if (arg != NULL && *arg != NUL)
679 p = vim_strsave_up(arg);
680 else
681 {
682 p = vim_strsave_up(gettail((char_u *)cmd));
683 // Remove .exe or .bat from the name.
684 if (p != NULL && vim_strchr(p, '.') != NULL)
685 *vim_strchr(p, '.') = NUL;
686 }
687 return p;
688}
689#endif // FEAT_CLIENTSERVER
690
691#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
692 static void
693make_connection(void)
694{
695 if (X_DISPLAY == NULL
696# ifdef FEAT_GUI
697 && !gui.in_use
698# endif
699 )
700 {
701 x_force_connect = TRUE;
702 setup_term_clip();
703 x_force_connect = FALSE;
704 }
705}
706
707 static int
708check_connection(void)
709{
710 make_connection();
711 if (X_DISPLAY == NULL)
712 {
Bram Moolenaarcbadefe2022-01-01 19:33:50 +0000713 emsg(_(e_no_connection_to_x_server));
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200714 return FAIL;
715 }
716 return OK;
717}
718#endif
719
720#ifdef FEAT_CLIENTSERVER
721 static void
722remote_common(typval_T *argvars, typval_T *rettv, int expr)
723{
724 char_u *server_name;
725 char_u *keys;
726 char_u *r = NULL;
727 char_u buf[NUMBUFLEN];
728 int timeout = 0;
729# ifdef MSWIN
730 HWND w;
731# else
732 Window w;
733# endif
734
735 if (check_restricted() || check_secure())
736 return;
737
738# ifdef FEAT_X11
739 if (check_connection() == FAIL)
740 return;
741# endif
742 if (argvars[2].v_type != VAR_UNKNOWN
743 && argvars[3].v_type != VAR_UNKNOWN)
744 timeout = tv_get_number(&argvars[3]);
745
746 server_name = tv_get_string_chk(&argvars[0]);
747 if (server_name == NULL)
748 return; // type error; errmsg already given
749 keys = tv_get_string_buf(&argvars[1], buf);
750# ifdef MSWIN
751 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
752# else
753 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
754 0, TRUE) < 0)
755# endif
756 {
757 if (r != NULL)
758 {
759 emsg((char *)r); // sending worked but evaluation failed
760 vim_free(r);
761 }
762 else
Bram Moolenaarcbadefe2022-01-01 19:33:50 +0000763 semsg(_(e_unable_to_send_to_str), server_name);
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200764 return;
765 }
766
767 rettv->vval.v_string = r;
768
769 if (argvars[2].v_type != VAR_UNKNOWN)
770 {
771 dictitem_T v;
772 char_u str[30];
773 char_u *idvar;
774
775 idvar = tv_get_string_chk(&argvars[2]);
776 if (idvar != NULL && *idvar != NUL)
777 {
778 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
779 v.di_tv.v_type = VAR_STRING;
780 v.di_tv.vval.v_string = vim_strsave(str);
781 set_var(idvar, &v.di_tv, FALSE);
782 vim_free(v.di_tv.vval.v_string);
783 }
784 }
785}
786#endif
787
788#if defined(FEAT_EVAL) || defined(PROTO)
789/*
790 * "remote_expr()" function
791 */
792 void
793f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
794{
795 rettv->v_type = VAR_STRING;
796 rettv->vval.v_string = NULL;
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200797
Bram Moolenaare18acb02022-03-21 20:40:35 +0000798#ifdef FEAT_CLIENTSERVER
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200799 if (in_vim9script()
800 && (check_for_string_arg(argvars, 0) == FAIL
801 || check_for_string_arg(argvars, 1) == FAIL
802 || check_for_opt_string_arg(argvars, 2) == FAIL
803 || (argvars[2].v_type != VAR_UNKNOWN
804 && check_for_opt_number_arg(argvars, 3) == FAIL)))
805 return;
806
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200807 remote_common(argvars, rettv, TRUE);
808#endif
809}
810
811/*
812 * "remote_foreground()" function
813 */
814 void
815f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
816{
817#ifdef FEAT_CLIENTSERVER
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200818 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
819 return;
820
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200821# ifdef MSWIN
822 // On Win32 it's done in this application.
823 {
824 char_u *server_name = tv_get_string_chk(&argvars[0]);
825
826 if (server_name != NULL)
827 serverForeground(server_name);
828 }
829# else
830 // Send a foreground() expression to the server.
831 argvars[1].v_type = VAR_STRING;
832 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
833 argvars[2].v_type = VAR_UNKNOWN;
834 rettv->v_type = VAR_STRING;
835 rettv->vval.v_string = NULL;
836 remote_common(argvars, rettv, TRUE);
837 vim_free(argvars[1].vval.v_string);
838# endif
839#endif
840}
841
842 void
843f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
844{
845#ifdef FEAT_CLIENTSERVER
846 dictitem_T v;
847 char_u *s = NULL;
848# ifdef MSWIN
849 long_u n = 0;
850# endif
851 char_u *serverid;
852
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200853 rettv->vval.v_number = -1;
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200854 if (check_restricted() || check_secure())
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200855 return;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200856
857 if (in_vim9script()
858 && (check_for_string_arg(argvars, 0) == FAIL
859 || check_for_opt_string_arg(argvars, 1) == FAIL))
860 return;
861
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200862 serverid = tv_get_string_chk(&argvars[0]);
863 if (serverid == NULL)
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200864 return; // type error; errmsg already given
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200865# ifdef MSWIN
866 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
867 if (n == 0)
868 rettv->vval.v_number = -1;
869 else
870 {
871 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
872 rettv->vval.v_number = (s != NULL);
873 }
874# else
875 if (check_connection() == FAIL)
876 return;
877
878 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
879 serverStrToWin(serverid), &s);
880# endif
881
882 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
883 {
884 char_u *retvar;
885
886 v.di_tv.v_type = VAR_STRING;
887 v.di_tv.vval.v_string = vim_strsave(s);
888 retvar = tv_get_string_chk(&argvars[1]);
889 if (retvar != NULL)
890 set_var(retvar, &v.di_tv, FALSE);
891 vim_free(v.di_tv.vval.v_string);
892 }
893#else
894 rettv->vval.v_number = -1;
895#endif
896}
897
898 void
899f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
900{
901 char_u *r = NULL;
902
903#ifdef FEAT_CLIENTSERVER
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200904 char_u *serverid;
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200905
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200906 if (in_vim9script()
907 && (check_for_string_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200908 || check_for_opt_number_arg(argvars, 1) == FAIL))
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200909 return;
910
911 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200912 if (serverid != NULL && !check_restricted() && !check_secure())
913 {
914 int timeout = 0;
915# ifdef MSWIN
916 // The server's HWND is encoded in the 'id' parameter
917 long_u n = 0;
918# endif
919
920 if (argvars[1].v_type != VAR_UNKNOWN)
921 timeout = tv_get_number(&argvars[1]);
922
923# ifdef MSWIN
924 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
925 if (n != 0)
926 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
927 if (r == NULL)
928# else
929 if (check_connection() == FAIL
930 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
931 &r, FALSE, timeout) < 0)
932# endif
Bram Moolenaar9a846fb2022-01-01 21:59:18 +0000933 emsg(_(e_unable_to_read_server_reply));
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200934 }
935#endif
936 rettv->v_type = VAR_STRING;
937 rettv->vval.v_string = r;
938}
939
940/*
941 * "remote_send()" function
942 */
943 void
944f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
945{
946 rettv->v_type = VAR_STRING;
947 rettv->vval.v_string = NULL;
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200948
Bram Moolenaare18acb02022-03-21 20:40:35 +0000949#ifdef FEAT_CLIENTSERVER
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200950 if (in_vim9script()
951 && (check_for_string_arg(argvars, 0) == FAIL
952 || check_for_string_arg(argvars, 1) == FAIL
953 || check_for_opt_string_arg(argvars, 2) == FAIL))
954 return;
955
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200956 remote_common(argvars, rettv, FALSE);
957#endif
958}
959
960/*
961 * "remote_startserver()" function
962 */
963 void
964f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
965{
966#ifdef FEAT_CLIENTSERVER
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200967 char_u *server;
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200968
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200969 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
970 return;
971
972 server = tv_get_string_chk(&argvars[0]);
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200973 if (server == NULL)
974 return; // type error; errmsg already given
975 if (serverName != NULL)
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000976 emsg(_(e_already_started_server));
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200977 else
978 {
979# ifdef FEAT_X11
980 if (check_connection() == OK)
981 serverRegisterName(X_DISPLAY, server);
982# else
983 serverSetName(server);
984# endif
985 }
986#else
Bram Moolenaard82a47d2022-01-05 20:24:39 +0000987 emsg(_(e_clientserver_feature_not_available));
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200988#endif
989}
990
991 void
992f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
993{
994#ifdef FEAT_CLIENTSERVER
995 char_u buf[NUMBUFLEN];
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200996 char_u *server;
997 char_u *reply;
Bram Moolenaarf87a0402020-04-05 20:21:03 +0200998
999 rettv->vval.v_number = -1;
Bram Moolenaarf87a0402020-04-05 20:21:03 +02001000 if (check_restricted() || check_secure())
1001 return;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001002
1003 if (in_vim9script()
1004 && (check_for_string_arg(argvars, 0) == FAIL
1005 || check_for_string_arg(argvars, 1) == FAIL))
1006 return;
1007
1008 server = tv_get_string_chk(&argvars[0]);
1009 reply = tv_get_string_buf_chk(&argvars[1], buf);
1010 if (server == NULL || reply == NULL)
1011 return;
1012
Bram Moolenaarf87a0402020-04-05 20:21:03 +02001013# ifdef FEAT_X11
1014 if (check_connection() == FAIL)
1015 return;
1016# endif
1017
1018 if (serverSendReply(server, reply) < 0)
1019 {
Bram Moolenaarcbadefe2022-01-01 19:33:50 +00001020 emsg(_(e_unable_to_send_to_client));
Bram Moolenaarf87a0402020-04-05 20:21:03 +02001021 return;
1022 }
1023 rettv->vval.v_number = 0;
1024#else
1025 rettv->vval.v_number = -1;
1026#endif
1027}
1028
1029 void
1030f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
1031{
1032 char_u *r = NULL;
1033
1034#ifdef FEAT_CLIENTSERVER
1035# ifdef MSWIN
1036 r = serverGetVimNames();
1037# else
1038 make_connection();
1039 if (X_DISPLAY != NULL)
1040 r = serverGetVimNames(X_DISPLAY);
1041# endif
1042#endif
1043 rettv->v_type = VAR_STRING;
1044 rettv->vval.v_string = r;
1045}
1046#endif