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