1/*
2 * Copyright (c) 1990, 1991, 1992, Oracle and/or its affiliates.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24/******************************************************************
25         Copyright 1992, 1993, 1994 by FUJITSU LIMITED
26         Copyright 1993, 1994 by Sony Corporation
27
28Permission to use, copy, modify, and distribute this software and its
29documentation for any purpose and without fee is hereby granted,
30provided that the above copyright notice appear in all copies and that
31both that copyright notice and this permission notice appear in
32supporting documentation, and that the names of Digital, FUJITSU
33LIMITED and Sony Corporation not be used in advertising or publicity
34pertaining to distribution of the software without specific, written
35prior permission.
36
37DIGITAL, FUJITSU LIMITED AND SONY CORPORATION DISCLAIMS ALL WARRANTIES
38WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
39MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL, FUJITSU LIMITED
40AND SONY CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44PERFORMANCE OF THIS SOFTWARE.
45
46  Author: Hideki Hiura (hhiura@Sun.COM) Sun Microsystems, Inc.
47          Takashi Fujiwara     FUJITSU LIMITED
48                               fujiwara@a80.tech.yk.fujitsu.co.jp
49          Makoto Wakamatsu     Sony Corporation
50                               makoto@sm.sony.co.jp
51
52******************************************************************/
53
54#ifdef HAVE_CONFIG_H
55#include <config.h>
56#endif
57#include <X11/Xatom.h>
58#include "Xlibint.h"
59#include "Xlcint.h"
60#include "XlcPublic.h"
61#include "XlcPubI.h"
62#include "XimTrInt.h"
63#include "Ximint.h"
64
65#include <limits.h>
66#include <stdlib.h>
67#include <strings.h>
68
69int
70_XimCheckDataSize(
71    XPointer	 buf,
72    int		 len)
73{
74    CARD16	*buf_s = (CARD16 *)buf;
75
76    if(len < XIM_HEADER_SIZE)
77	return -1;
78    return  buf_s[1];
79}
80
81void
82_XimSetHeader(
83    XPointer	 buf,
84    CARD8	 major_opcode,
85    CARD8	 minor_opcode,
86    INT16	*len
87)
88{
89    CARD8	*buf_b = (CARD8 *)buf;
90    CARD16	*buf_s = (CARD16 *)buf;
91
92    buf_b[0] = major_opcode;
93    buf_b[1] = minor_opcode;
94    buf_s[1] = ((*len) / 4);
95    *len += XIM_HEADER_SIZE;
96    return;
97}
98
99char
100_XimGetMyEndian(void)
101{
102    CARD16	 test_card = 1;
103
104    if(*((char *)&test_card))
105	return LITTLEENDIAN;
106    else
107	return BIGENDIAN;
108}
109
110static Bool
111_XimCheckServerName(
112    Xim		   im,
113    char	  *str)
114{
115    char	  *server_name = im->core.im_name;
116    int		   len;
117    int		   str_len;
118    int		   category_len = strlen(XIM_SERVER_CATEGORY);
119    char	  *pp;
120    register char *p;
121
122    if(server_name && *server_name)
123	len = strlen(server_name);
124    else
125	return True;
126
127    if((int)strlen(str) < category_len)
128	return False;
129
130    if(strncmp(str, XIM_SERVER_CATEGORY, category_len))
131	return False;
132
133    pp = &str[category_len];
134
135    for(;;) {
136	for(p = pp; (*p != ',') && (*p); p++);
137	str_len = (int)(p - pp);
138
139	if((len == str_len) && (!strncmp(pp, server_name, len)))
140	    break;
141	if(!(*p))
142	    return False;
143	pp = p + 1;
144    }
145    return True;
146}
147
148static char *
149_XimCheckLocaleName(
150    Xim		   im,
151    char	  *address,
152    int		   address_len,
153    char	  *locale_name[],
154    int		   len)
155{
156    int		   category_len;
157    char	  *pp;
158    register char *p;
159    register int   n;
160    Bool           finish = False;
161
162    category_len = strlen(XIM_LOCAL_CATEGORY);
163    if(address_len < category_len)
164	return (char*)NULL;
165
166    if(strncmp(address, XIM_LOCAL_CATEGORY, category_len))
167	return (char*)NULL;
168
169    pp = &address[category_len];
170
171    for(;;) {
172	for( p = pp; *p && *p != ','; p++);
173	if (!*p)
174	    finish = True;
175	address_len = (int)(p - pp);
176	*p = '\0';
177
178	for( n = 0; n < len; n++ )
179	    if( locale_name[n] && !_XlcCompareISOLatin1( pp, locale_name[n] ) )
180		return locale_name[n];
181	if (finish)
182	    break;
183	pp = p + 1;
184    }
185    return (char *)NULL;
186}
187
188static Bool
189_XimCheckTransport(
190    char	  *address,
191    int		   address_len,
192    const char	  *transport,
193    int		   len,
194    char	 **trans_addr)
195{
196    int		   category_len = strlen(XIM_TRANSPORT_CATEGORY);
197    char	  *pp;
198    register char *p;
199
200    if(address_len < category_len)
201	return False;
202
203    if(strncmp(address, XIM_TRANSPORT_CATEGORY, category_len))
204	return False;
205
206    pp = &address[category_len];
207
208    for(;;) {
209	*trans_addr = pp;
210
211	for(p = pp; (*p != '/') && (*p != ',') && (*p); p++);
212	if(*p == ',') {
213	    pp = p + 1;
214	    continue;
215	}
216	if(!(*p))
217	    return False;
218
219	address_len = (int)(p - pp);
220
221	if((len == address_len) && (!strncmp(pp, transport, len)))
222	    break;
223	pp = p + 1;
224    }
225    pp = p + 1;
226    for(p = pp; (*p != ',') && (*p); p++);
227    if (*p)
228	*p = '\0';
229    return True;
230}
231
232static Bool
233_CheckSNEvent(
234    Display		*display,
235    XEvent		*xevent,
236    XPointer		 arg)
237{
238    XSelectionEvent	*event = (XSelectionEvent *)xevent;
239    Window		 window = *(Window*)arg;
240
241    if((event->type == SelectionNotify) && (window == event->requestor))
242	return True;
243    return False;
244}
245
246static Bool
247_XimGetSelectionNotify(
248    Display		 *display,
249    Window		  window,
250    Atom		  target,
251    char		**ret_address)
252{
253    XEvent		  event;
254    XSelectionEvent	 *ev = (XSelectionEvent *)&event;
255    Atom		  actual_type;
256    int			  actual_format;
257    unsigned long	  nitems, bytes_after;
258
259    for(;;) {
260	XIfEvent(display, &event, _CheckSNEvent, (XPointer)&window);
261	if((ev->type == SelectionNotify) && (window == ev->requestor))
262	    break;
263    }
264
265    if(ev->property == (Atom)None)
266	return False;
267    if( XGetWindowProperty( display, window, target, 0L, 1000000L,
268			    True, target, &actual_type, &actual_format,
269			    &nitems, &bytes_after,
270			    (unsigned char **)&*ret_address ) != Success )
271	return False;
272    return True;
273}
274
275static Bool
276_XimPreConnectionIM(
277    Xim			 im,
278    Atom		 selection)
279{
280    Display		*display = im->core.display;
281    Atom		 locales, transport;
282    char		*address;
283    XLCd		 lcd;
284    char		*language;
285    char		*territory;
286    char		*codeset;
287    char		*trans_addr;
288    char		*locale_name[4], *locale;
289    int			 llen, tlen, clen;
290    register int	 i;
291    Window		 window;
292    char		*str;
293
294    if(!(lcd = im->core.lcd))
295	return False;
296
297    for( i = 0; i < 4; i++ )
298	locale_name[i] = NULL;
299    /* requestor window */
300    if(!(window = XCreateSimpleWindow(display, DefaultRootWindow(display),
301			 				0, 0, 1, 1, 1, 0, 0)))
302	return False;
303
304    /* server name check */
305    if( !(str = XGetAtomName( display, selection )) )
306	goto Error;
307    if(!_XimCheckServerName(im, str)) {
308	XFree( (XPointer)str );
309	goto Error;
310    }
311    XFree( (XPointer)str );
312
313    /* locale name check */
314    _XGetLCValues(lcd, XlcNLanguage, &language, XlcNTerritory, &territory,
315                    XlcNCodeset, &codeset, NULL);
316    llen = strlen( language );
317    tlen = territory ? strlen( territory ): 0;
318    clen = codeset ? strlen( codeset ): 0;
319
320    if( tlen != 0  &&  clen != 0 ) {
321	if( (locale_name[0] = Xmalloc(llen+tlen+clen+3)) != NULL )
322	    sprintf( locale_name[0], "%s_%s.%s", language, territory, codeset );
323    }
324    if( clen != 0 ) {
325	if( (locale_name[1] = Xmalloc(llen+clen+2)) != NULL )
326	    sprintf( locale_name[1], "%s.%s", language, codeset );
327	else
328	    goto Error;
329    }
330    if( tlen != 0 ) {
331	if( (locale_name[2] = Xmalloc(llen+tlen+2)) != NULL )
332	    sprintf( locale_name[2], "%s_%s", language, territory );
333	else
334	    goto Error;
335    }
336    if( (locale_name[3] = strdup(language)) == NULL )
337	goto Error;
338    if((locales = XInternAtom(display, XIM_LOCALES, True)) == (Atom)None)
339	goto Error;
340
341    XConvertSelection(display, selection, locales, locales, window,
342		      CurrentTime);
343    if(!(_XimGetSelectionNotify(display, window, locales, &address)))
344	goto Error;
345
346    if((locale = _XimCheckLocaleName(im, address, strlen(address), locale_name,
347				     4)) == NULL) {
348	XFree((XPointer)address);
349	goto Error;
350    }
351    im->private.proto.locale_name = locale;
352    for( i = 0; i < 4; i++ ) {
353	if( locale_name[i] != NULL  &&  locale_name[i] != locale ) {
354	    XFree( locale_name[i] );
355	    locale_name[i] = NULL;
356	}
357    }
358    XFree((XPointer)address);
359
360    /* transport check */
361    if((transport = XInternAtom(display, XIM_TRANSPORT, True)) == (Atom)None)
362	goto Error;
363
364    XConvertSelection(display, selection, transport, transport, window,
365		      CurrentTime);
366    if(!_XimGetSelectionNotify(display, window, transport, &address))
367	goto Error;
368
369    for(i = 0; _XimTransportRec[i].transportname ; i++) {
370	if( _XimCheckTransport(address, strlen(address),
371				_XimTransportRec[i].transportname,
372				strlen(_XimTransportRec[i].transportname),
373				 &trans_addr)) {
374	    if( _XimTransportRec[i].config(im, trans_addr) ) {
375		XFree((XPointer)address);
376		XDestroyWindow(display, window);
377		return True;
378	    }
379	}
380    }
381
382    XFree((XPointer)address);
383Error:
384    for( i = 0; i < 4; i++ )
385	if( locale_name[i] != NULL )
386	    XFree( locale_name[i] );
387    XDestroyWindow(display, window);
388    return False;
389}
390
391static Bool
392_XimPreConnect(
393    Xim		    im)
394{
395    Display	   *display = im->core.display;
396    Atom	    imserver;
397    Atom	    actual_type;
398    int		    actual_format;
399    unsigned long   nitems;
400    unsigned long   bytes_after;
401    unsigned char  *prop_return;
402    Atom	   *atoms;
403    Window	    im_window = 0;
404    register int    i;
405    const char	   *env_enable_fabricated_order;
406
407    if((imserver = XInternAtom(display, XIM_SERVERS, True)) == (Atom)None)
408	return False;
409
410    if(XGetWindowProperty(display, RootWindow(display, 0),
411			imserver, 0L, 1000000L, False, XA_ATOM, &actual_type,
412			&actual_format, &nitems, &bytes_after,
413			&prop_return) != Success)
414	return False;
415
416    if( (actual_type != XA_ATOM) || (actual_format != 32) ) {
417	if( nitems )
418	    XFree((XPointer)prop_return);
419	return False;
420    }
421
422    atoms = (Atom *)prop_return;
423    for(i = 0; i < nitems; i++) {
424	if((im_window = XGetSelectionOwner(display, atoms[i])) == (Window)None)
425	    continue;
426
427	if(_XimPreConnectionIM(im, atoms[i]))
428	    break;
429    }
430
431    XFree((XPointer)prop_return);
432    if(i >= nitems)
433	return False;
434
435    im->private.proto.im_window = im_window;
436    im->private.proto.fabricated_serial = 0;
437    im->private.proto.fabricated_time = 0;
438    im->private.proto.enable_fabricated_order = True;
439    env_enable_fabricated_order = getenv("LIBX11_ENABLE_FABRICATED_ORDER");
440    if (env_enable_fabricated_order && *env_enable_fabricated_order) {
441	if (!strncasecmp(env_enable_fabricated_order, "0", 2) ||
442	    !strncasecmp(env_enable_fabricated_order, "false", 6)) {
443	    im->private.proto.enable_fabricated_order = False;
444	}
445    }
446    return True;
447}
448
449static Bool
450_XimGetAuthProtocolNames(
451    Xim		 im,
452    CARD16	*buf,
453    CARD8	*num,
454    INT16	*len)
455{
456    if (!IS_USE_AUTHORIZATION_FUNC(im)) {
457	*num = 0;
458	*len = 0;
459	return True;
460    }
461    /*
462     * Not yet
463     */
464    return True;
465}
466
467static Bool
468_XimSetAuthReplyData(
469    Xim		 im,
470    XPointer	 buf,
471    INT16	*len)
472{
473    /*
474     * Not yet
475     */
476    *len = 0;
477    return True;
478}
479
480static Bool
481_XimSetAuthNextData(
482    Xim		 im,
483    XPointer	 buf,
484    INT16	*len)
485{
486    /*
487     * Not yet
488     */
489    *len = 0;
490    return True;
491}
492
493static Bool
494_XimSetAuthRequiredData(
495    Xim		 im,
496    XPointer	 buf,
497    INT16	*len)
498{
499    /*
500     * Not yet
501     */
502    *len = 0;
503    return True;
504}
505
506static Bool
507_XimCheckAuthSetupData(
508    Xim		 im,
509    XPointer	 buf)
510{
511    /*
512     * Not yet
513     */
514    return True;
515}
516
517static Bool
518_XimCheckAuthNextData(
519    Xim		 im,
520    XPointer	 buf)
521{
522    /*
523     * Not yet
524     */
525    return True;
526}
527
528#define	NO_MORE_AUTH	2
529#define	GOOD_AUTH	1
530#define	BAD_AUTH	0
531
532static int
533_XimClientAuthCheck(
534    Xim		 im,
535    XPointer	 buf)
536{
537    /*
538     * Not yet
539     */
540    return NO_MORE_AUTH;
541}
542
543static void
544_XimAuthNG(
545    Xim		 im)
546{
547    CARD32	 buf32[BUFSIZE/4];
548    CARD8	*buf = (CARD8 *)buf32;
549    INT16	 len = 0;
550
551    _XimSetHeader((XPointer)buf, XIM_AUTH_NG, 0, &len);
552    (void)_XimWrite(im, len, (XPointer)buf);
553    _XimFlush(im);
554    return;
555}
556
557static Bool
558_XimAllRecv(
559    Xim		 im,
560    INT16	 len,
561    XPointer	 data,
562    XPointer	 arg)
563{
564    return True;
565}
566
567#define	CLIENT_WAIT1		1
568#define	CLIENT_WAIT2		2
569
570static Bool
571_XimConnection(
572    Xim		 im)
573{
574    CARD32	 buf32[BUFSIZE/4];
575    CARD8	*buf = (CARD8 *)buf32;
576    CARD8	*buf_b = &buf[XIM_HEADER_SIZE];
577    CARD16	*buf_s = (CARD16 *)((XPointer)buf_b);
578    INT16	 len;
579    CARD8	 num;
580    CARD32	 reply32[BUFSIZE/4];
581    char	*reply = (char *)reply32;
582    XPointer	 preply;
583    int		 buf_size;
584    int		 ret_code;
585    CARD8	 major_opcode;
586    int		 wait_mode;
587    int		 ret;
588
589    if(!(_XimConnect(im)))	/* Transport Connect */
590	return False;
591
592    if(!_XimDispatchInit(im))
593	return False;
594
595    _XimRegProtoIntrCallback(im, XIM_ERROR, 0, _XimErrorCallback, (XPointer)im);
596
597    if(!_XimGetAuthProtocolNames(im, &buf_s[4], &num, &len))
598	return False;
599
600    im->private.proto.protocol_major_version = PROTOCOLMAJORVERSION;
601    im->private.proto.protocol_minor_version = PROTOCOLMINORVERSION;
602
603    buf_b[0] = _XimGetMyEndian();
604    buf_b[1] = 0;
605    buf_s[1] = PROTOCOLMAJORVERSION;
606    buf_s[2] = PROTOCOLMINORVERSION;
607    buf_s[3] = num;
608    len  += sizeof(CARD8)
609          + sizeof(CARD8)
610          + sizeof(CARD16)
611          + sizeof(CARD16)
612          + sizeof(CARD16);
613
614    major_opcode = XIM_CONNECT;
615    wait_mode = (IS_USE_AUTHORIZATION_FUNC(im)) ? CLIENT_WAIT1 : CLIENT_WAIT2;
616
617    for(;;) {
618	_XimSetHeader((XPointer)buf, major_opcode, 0, &len);
619	if (!(_XimWrite(im, len, (XPointer)buf)))
620	    return False;
621	_XimFlush(im);
622	buf_size = BUFSIZE;
623	ret_code = _XimRead(im, &len, reply, buf_size, _XimAllRecv, 0);
624	if(ret_code == XIM_TRUE) {
625	    preply = reply;
626	} else if(ret_code == XIM_OVERFLOW) {
627	    if(len <= 0) {
628		preply = reply;
629	    } else {
630		buf_size = len;
631		preply = Xmalloc(buf_size);
632		ret_code = _XimRead(im, &len, preply, buf_size, _XimAllRecv, 0);
633		if(ret_code != XIM_TRUE) {
634		    Xfree(preply);
635		    return False;
636		}
637	    }
638	} else
639	    return False;
640
641	major_opcode = *((CARD8 *)preply);
642	buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
643
644	if (wait_mode == CLIENT_WAIT1) {
645	    if (major_opcode == XIM_AUTH_REQUIRED) {
646		ret = _XimClientAuthCheck(im, (XPointer)buf_s);
647		if(reply != preply)
648		    Xfree(preply);
649		if (ret == NO_MORE_AUTH) {
650		    if (!(_XimSetAuthReplyData(im,
651				(XPointer)&buf[XIM_HEADER_SIZE], &len))) {
652			_XimAuthNG(im);
653			return False;
654		    }
655		    major_opcode = XIM_AUTH_REPLY;
656		    wait_mode = CLIENT_WAIT2;
657		} else if (ret == GOOD_AUTH) {
658		    if (!(_XimSetAuthNextData(im,
659				(XPointer)&buf[XIM_HEADER_SIZE], &len))) {
660			_XimAuthNG(im);
661			return False;
662		    }
663		    major_opcode = XIM_AUTH_NEXT;
664		} else {	/* BAD_AUTH */
665		    _XimAuthNG(im);
666		    return False;
667		}
668	    } else {
669		if(reply != preply)
670		    Xfree(preply);
671		_XimAuthNG(im);
672		return False;
673	    }
674	} else {	/* CLIENT_WAIT2 */
675	    if (major_opcode == XIM_CONNECT_REPLY) {
676		break;
677	    } else if (major_opcode == XIM_AUTH_SETUP) {
678		if (!(_XimCheckAuthSetupData(im, (XPointer)buf_s))) {
679		    _XimAuthNG(im);
680		    return False;
681		}
682		if(reply != preply)
683		    Xfree(preply);
684		if (!(_XimSetAuthRequiredData(im,
685				(XPointer)&buf[XIM_HEADER_SIZE], &len))) {
686		    _XimAuthNG(im);
687		    return False;
688		}
689		major_opcode = XIM_AUTH_REQUIRED;
690	    } else if (major_opcode == XIM_AUTH_NEXT) {
691		if (!(_XimCheckAuthNextData(im, (XPointer)buf_s))) {
692		    _XimAuthNG(im);
693		    return False;
694		}
695		if(reply != preply)
696		    Xfree(preply);
697		if (!(_XimSetAuthRequiredData(im,
698				(XPointer)&buf[XIM_HEADER_SIZE], &len))) {
699		    _XimAuthNG(im);
700		    return False;
701		}
702		major_opcode = XIM_AUTH_REQUIRED;
703	    } else if (major_opcode == XIM_AUTH_NG) {
704		if(reply != preply)
705		    Xfree(preply);
706		return False;
707	    } else {
708		_XimAuthNG(im);
709		if(reply != preply)
710		    Xfree(preply);
711		return False;
712	    }
713	}
714    }
715
716    if (!( buf_s[0] == im->private.proto.protocol_major_version
717        && buf_s[1] == im->private.proto.protocol_minor_version)) {
718	if(reply != preply)
719	    Xfree(preply);
720	return False;
721    }
722    if(reply != preply)
723	Xfree(preply);
724    MARK_SERVER_CONNECTED(im);
725
726    _XimRegProtoIntrCallback(im, XIM_REGISTER_TRIGGERKEYS, 0,
727				 _XimRegisterTriggerKeysCallback, (XPointer)im);
728    return True;
729}
730
731static Bool
732_XimDisconnectCheck(
733    Xim		 im,
734    INT16	 len,
735    XPointer	 data,
736    XPointer	 arg)
737{
738    CARD8	 major_opcode = *((CARD8 *)data);
739    CARD8	 minor_opcode = *((CARD8 *)data + 1);
740
741    if ((major_opcode == XIM_DISCONNECT_REPLY)
742     && (minor_opcode == 0))
743	return True;
744    if ((major_opcode == XIM_ERROR)
745     && (minor_opcode == 0))
746	return True;
747    return False;
748}
749
750static Bool
751_XimDisconnect(
752    Xim		 im)
753{
754    CARD32	 buf32[BUFSIZE/4];
755    CARD8	*buf = (CARD8 *)buf32;
756    INT16	 len = 0;
757    CARD32	 reply32[BUFSIZE/4];
758    char	*reply = (char *)reply32;
759    XPointer	 preply;
760    int		 buf_size;
761    int		 ret_code;
762
763    if (IS_SERVER_CONNECTED(im)) {
764	_XimSetHeader((XPointer)buf, XIM_DISCONNECT, 0, &len);
765	if (!(_XimWrite(im, len, (XPointer)buf)))
766	    return False;
767	_XimFlush(im);
768	buf_size = BUFSIZE;
769	ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
770						_XimDisconnectCheck, 0);
771	if(ret_code == XIM_OVERFLOW) {
772	    if(len > 0) {
773		buf_size = len;
774		preply = Xmalloc(buf_size);
775		ret_code = _XimRead(im, &len, preply, buf_size,
776						 _XimDisconnectCheck, 0);
777		Xfree(preply);
778		if(ret_code != XIM_TRUE)
779		    return False;
780	    }
781	} else if(ret_code == XIM_FALSE)
782	    return False;
783
784    }
785    if (!(_XimShutdown(im)))	/* Transport shutdown */
786	return False;
787    return True;
788}
789
790static Bool
791_XimOpenCheck(
792    Xim		 im,
793    INT16	 len,
794    XPointer	 data,
795    XPointer	 arg)
796{
797    CARD8	 major_opcode = *((CARD8 *)data);
798    CARD8	 minor_opcode = *((CARD8 *)data + 1);
799
800    if ((major_opcode == XIM_OPEN_REPLY)
801     && (minor_opcode == 0))
802	return True;
803    if ((major_opcode == XIM_ERROR)
804     && (minor_opcode == 0))
805	return True;
806    return False;
807}
808
809static Bool
810_XimOpen(
811    Xim			 im)
812{
813    CARD32		 buf32[BUFSIZE/4];
814    CARD8		*buf = (CARD8 *)buf32;
815    CARD8		*buf_b = &buf[XIM_HEADER_SIZE];
816    CARD16		*buf_s;
817    INT16		 len;
818    CARD32		 reply32[BUFSIZE/4];
819    char		*reply = (char *)reply32;
820    XPointer		 preply;
821    int			 buf_size;
822    int			 ret_code;
823    char		*locale_name;
824    size_t		 locale_len;
825
826    locale_name = im->private.proto.locale_name;
827    locale_len = strlen(locale_name);
828    if (locale_len > UCHAR_MAX)
829      return False;
830    memset(buf32, 0, sizeof(buf32));
831    buf_b[0] = (BYTE)locale_len;		/* length of locale name */
832    memcpy(&buf_b[1], locale_name, locale_len);	   /* locale name */
833    len = (INT16)(locale_len + sizeof(BYTE));	   /* sizeof length */
834    XIM_SET_PAD(buf_b, len);			   /* pad */
835
836    _XimSetHeader((XPointer)buf, XIM_OPEN, 0, &len);
837    if (!(_XimWrite(im, len, (XPointer)buf)))
838	return False;
839    _XimFlush(im);
840    buf_size = BUFSIZE;
841    ret_code = _XimRead(im, &len, reply, buf_size,
842					_XimOpenCheck, 0);
843    if(ret_code == XIM_TRUE) {
844	preply = reply;
845    } else if(ret_code == XIM_OVERFLOW) {
846	if(len <= 0) {
847	    preply = reply;
848	} else {
849	    buf_size = len;
850	    preply = Xmalloc(buf_size);
851	    ret_code = _XimRead(im, &len, preply, buf_size,
852					_XimOpenCheck, 0);
853	    if(ret_code != XIM_TRUE) {
854		Xfree(preply);
855		return False;
856	    }
857	}
858    } else
859	return False;
860    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
861    if (*((CARD8 *)preply) == XIM_ERROR) {
862	_XimProcError(im, 0, (XPointer)&buf_s[3]);
863	if(reply != preply)
864	    Xfree(preply);
865	return False;
866    }
867
868    im->private.proto.imid = buf_s[0];		/* imid */
869
870    if (!(_XimGetAttributeID(im, &buf_s[1]))) {
871	if(reply != preply)
872	    Xfree(preply);
873	return False;
874    }
875    if(reply != preply)
876	Xfree(preply);
877
878    if (!(_XimSetInnerIMResourceList(&(im->private.proto.im_inner_resources),
879				&(im->private.proto.im_num_inner_resources))))
880	return False;
881
882    if (!(_XimSetInnerICResourceList(&(im->private.proto.ic_inner_resources),
883				&(im->private.proto.ic_num_inner_resources))))
884	return False;
885
886    _XimSetIMMode(im->core.im_resources, im->core.im_num_resources);
887    _XimSetIMMode(im->private.proto.im_inner_resources,
888				im->private.proto.im_num_inner_resources);
889
890    /* Transport Callback */
891    _XimRegProtoIntrCallback(im, XIM_SET_EVENT_MASK, 0,
892				 _XimSetEventMaskCallback, (XPointer)im);
893    _XimRegProtoIntrCallback(im, XIM_FORWARD_EVENT, 0,
894				 _XimForwardEventCallback, (XPointer)im);
895    _XimRegProtoIntrCallback(im, XIM_COMMIT, 0,
896				 _XimCommitCallback, (XPointer)im);
897    _XimRegProtoIntrCallback(im, XIM_SYNC, 0,
898				 _XimSyncCallback, (XPointer)im);
899
900    if(!_XimExtension(im))
901	return False;
902
903    /* register a hook for callback protocols */
904    _XimRegisterDispatcher(im, _XimCbDispatch, (XPointer)im);
905
906    return True;
907}
908
909static Bool
910_XimCloseCheck(
911    Xim		 im,
912    INT16	 len,
913    XPointer	 data,
914    XPointer	 arg)
915{
916    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
917    CARD8	 major_opcode = *((CARD8 *)data);
918    CARD8	 minor_opcode = *((CARD8 *)data + 1);
919    XIMID	 imid = buf_s[0];
920
921    if ((major_opcode == XIM_CLOSE_REPLY)
922     && (minor_opcode == 0)
923     && (imid == im->private.proto.imid))
924	return True;
925    if ((major_opcode == XIM_ERROR)
926     && (minor_opcode == 0)
927     && (buf_s[2] & XIM_IMID_VALID)
928     && (imid == im->private.proto.imid))
929	return True;
930    return False;
931}
932
933static Bool
934_XimClose(
935    Xim		 im)
936{
937    CARD32	 buf32[BUFSIZE/4];
938    CARD8	*buf = (CARD8 *)buf32;
939    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
940    INT16	 len;
941    CARD32	 reply32[BUFSIZE/4];
942    char	*reply = (char *)reply32;
943    XPointer	 preply;
944    int		 buf_size;
945    int		 ret_code;
946
947    if (!IS_SERVER_CONNECTED(im))
948	return True;
949
950    buf_s[0] = im->private.proto.imid;		/* imid */
951    buf_s[1] = 0;				/* unused */
952    len = sizeof(CARD16)			/* sizeof imid */
953        + sizeof(CARD16);			/* sizeof unused */
954
955    _XimSetHeader((XPointer)buf, XIM_CLOSE, 0, &len);
956    if (!(_XimWrite(im, len, (XPointer)buf)))
957	return False;
958    _XimFlush(im);
959    buf_size = BUFSIZE;
960    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
961						_XimCloseCheck, 0);
962    if(ret_code == XIM_TRUE) {
963	preply = reply;
964    } else if(ret_code == XIM_OVERFLOW) {
965	if(len <= 0) {
966	    preply = reply;
967	} else {
968	    buf_size = len;
969	    preply = Xmalloc(buf_size);
970	    ret_code = _XimRead(im, &len, preply, buf_size, _XimCloseCheck, 0);
971	    if(ret_code != XIM_TRUE) {
972		Xfree(preply);
973		return False;
974	    }
975	}
976    } else
977	return False;
978    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
979    if (*((CARD8 *)preply) == XIM_ERROR) {
980	_XimProcError(im, 0, (XPointer)&buf_s[3]);
981	if(reply != preply)
982	    Xfree(preply);
983	return False;
984    }
985
986    if(reply != preply)
987	Xfree(preply);
988    return True;
989}
990
991void
992_XimProtoIMFree(
993    Xim		  im)
994{
995    /* XIMPrivateRec */
996
997    Xfree(im->private.proto.im_onkeylist);
998    im->private.proto.im_onkeylist = NULL;
999
1000    Xfree(im->private.proto.im_offkeylist);
1001    im->private.proto.im_offkeylist = NULL;
1002
1003    if (im->private.proto.intrproto) {
1004      _XimFreeProtoIntrCallback(im);
1005      im->private.proto.intrproto = NULL;
1006    }
1007
1008    Xfree(im->private.proto.im_inner_resources);
1009    im->private.proto.im_inner_resources = NULL;
1010
1011    Xfree(im->private.proto.ic_inner_resources);
1012    im->private.proto.ic_inner_resources = NULL;
1013
1014    Xfree(im->private.proto.hold_data);
1015    im->private.proto.hold_data = NULL;
1016
1017    Xfree(im->private.proto.locale_name);
1018    im->private.proto.locale_name = NULL;
1019
1020    if (im->private.proto.ctom_conv) {
1021	_XlcCloseConverter(im->private.proto.ctom_conv);
1022	im->private.proto.ctom_conv = NULL;
1023    }
1024    if (im->private.proto.ctow_conv) {
1025	_XlcCloseConverter(im->private.proto.ctow_conv);
1026	im->private.proto.ctow_conv = NULL;
1027    }
1028    if (im->private.proto.ctoutf8_conv) {
1029	_XlcCloseConverter(im->private.proto.ctoutf8_conv);
1030	im->private.proto.ctoutf8_conv = NULL;
1031    }
1032    if (im->private.proto.cstomb_conv) {
1033	_XlcCloseConverter(im->private.proto.cstomb_conv);
1034	im->private.proto.cstomb_conv = NULL;
1035    }
1036    if (im->private.proto.cstowc_conv) {
1037	_XlcCloseConverter(im->private.proto.cstowc_conv);
1038	im->private.proto.cstowc_conv = NULL;
1039    }
1040    if (im->private.proto.cstoutf8_conv) {
1041	_XlcCloseConverter(im->private.proto.cstoutf8_conv);
1042	im->private.proto.cstoutf8_conv = NULL;
1043    }
1044    if (im->private.proto.ucstoc_conv) {
1045	_XlcCloseConverter(im->private.proto.ucstoc_conv);
1046	im->private.proto.ucstoc_conv = NULL;
1047    }
1048    if (im->private.proto.ucstoutf8_conv) {
1049	_XlcCloseConverter(im->private.proto.ucstoutf8_conv);
1050	im->private.proto.ucstoutf8_conv = NULL;
1051    }
1052
1053#ifdef XIM_CONNECTABLE
1054    if (!IS_SERVER_CONNECTED(im) && IS_RECONNECTABLE(im)) {
1055	return;
1056    }
1057#endif /* XIM_CONNECTABLE */
1058
1059    Xfree(im->private.proto.saved_imvalues);
1060    im->private.proto.saved_imvalues = NULL;
1061
1062    Xfree(im->private.proto.default_styles);
1063    im->private.proto.default_styles = NULL;
1064
1065    /* core */
1066
1067    Xfree(im->core.res_name);
1068    im->core.res_name = NULL;
1069
1070    Xfree(im->core.res_class);
1071    im->core.res_class = NULL;
1072
1073    Xfree(im->core.im_values_list);
1074    im->core.im_values_list = NULL;
1075
1076    Xfree(im->core.ic_values_list);
1077    im->core.ic_values_list = NULL;
1078
1079    Xfree(im->core.im_name);
1080    im->core.im_name = NULL;
1081
1082    Xfree(im->core.styles);
1083    im->core.styles = NULL;
1084
1085    Xfree(im->core.im_resources);
1086    im->core.im_resources = NULL;
1087
1088    Xfree(im->core.ic_resources);
1089    im->core.ic_resources = NULL;
1090
1091    return;
1092}
1093
1094static Status
1095_XimProtoCloseIM(
1096    XIM		 xim)
1097{
1098    Xim		 im = (Xim)xim;
1099    XIC		 ic;
1100    XIC		 next;
1101    Status	 status;
1102
1103    ic = im->core.ic_chain;
1104    while (ic) {
1105	(*ic->methods->destroy) (ic);
1106	next = ic->core.next;
1107#ifdef XIM_CONNECTABLE
1108	if (!(!IS_SERVER_CONNECTED(im) && IS_RECONNECTABLE(im))) {
1109	    Xfree (ic);
1110	}
1111#else
1112	Xfree (ic);
1113#endif /* XIM_CONNECTABLE */
1114	ic = next;
1115    }
1116#ifdef XIM_CONNECTABLE
1117    if (!(!IS_SERVER_CONNECTED(im) && IS_RECONNECTABLE(im)))
1118	im->core.ic_chain = NULL;
1119#else
1120    im->core.ic_chain = NULL;
1121#endif
1122
1123    _XimUnregisterServerFilter(im);
1124    _XimResetIMInstantiateCallback(im);
1125    status = (Status)_XimClose(im);
1126    status = (Status)_XimDisconnect(im) && status;
1127    _XimProtoIMFree(im);
1128#ifdef XIM_CONNECTABLE
1129    if (!IS_SERVER_CONNECTED(im) && IS_RECONNECTABLE(im)) {
1130	_XimReconnectModeSetAttr(im);
1131        for (ic = im->core.ic_chain; ic; ic = ic->core.next) {
1132	    _XimReconnectModeCreateIC(ic);
1133        }
1134	return 0;
1135    }
1136#endif /* XIM_CONNECTABLE */
1137    _XimDestroyIMStructureList(im);
1138    return status;
1139}
1140
1141#ifdef XIM_CONNECTABLE
1142static Bool
1143_XimCheckIMQuarkList(
1144    XrmQuark		*quark_list,
1145    int			 num_quark,
1146    XrmQuark		 quark)
1147{
1148    register int	 i;
1149
1150    for (i = 0; i < num_quark; i++) {
1151	if (quark_list[i] == quark) {
1152	    return True;
1153	}
1154    }
1155    return False;
1156}
1157
1158static Bool
1159_XimSaveIMValues(
1160    Xim			 im,
1161    XIMArg		*arg)
1162{
1163    register XIMArg	*p;
1164    register int	 n;
1165    XrmQuark		*quark_list;
1166    XrmQuark		*tmp;
1167    XrmQuark		 quark;
1168    int			 num_quark;
1169
1170    if (quark_list = im->private.proto.saved_imvalues) {
1171	num_quark = im->private.proto.num_saved_imvalues;
1172	for (p = arg; p && p->name; p++) {
1173	    quark = XrmStringToQuark(p->name);
1174	    if (_XimCheckIMQuarkList(quark_list, num_quark, quark)) {
1175		continue;
1176	    }
1177	    if (!(tmp = Xrealloc(quark_list,
1178				(sizeof(XrmQuark) * (num_quark + 1))))) {
1179		im->private.proto.saved_imvalues = quark_list;
1180		im->private.proto.num_saved_imvalues = num_quark;
1181		return False;
1182	    }
1183	    num_quark++;
1184	    quark_list = tmp;
1185	    quark_list[num_quark] = quark;
1186	}
1187	im->private.proto.saved_imvalues = quark_list;
1188	im->private.proto.num_saved_imvalues = num_quark;
1189	return True;
1190    }
1191
1192    for (p = arg, n = 0; p && p->name; p++, n++);
1193
1194    if (!(quark_list = Xmalloc(sizeof(XrmQuark) * n))) {
1195	return False;
1196    }
1197
1198    im->private.proto.saved_imvalues = quark_list;
1199    im->private.proto.num_saved_imvalues = n;
1200    for (p = arg; p && p->name; p++, quark_list++) {
1201	*quark_list = XrmStringToQuark(p->name);
1202    }
1203
1204    return True;
1205}
1206
1207static char *
1208_XimDelayModeSetIMValues(
1209    Xim			 im,
1210    XIMArg		*arg)
1211{
1212    XimDefIMValues	 im_values;
1213    char		*name;
1214    XIMArg		*values;
1215
1216    _XimGetCurrentIMValues(im, &im_values);
1217    name = _XimSetIMValueData(im, (XPointer)&im_values, values,
1218		im->core.im_resources, im->core.im_num_resources);
1219    _XimSetCurrentIMValues(im, &im_values);
1220
1221    return name;
1222}
1223#endif /* XIM_CONNECTABLE */
1224
1225static Bool
1226_XimSetIMValuesCheck(
1227    Xim          im,
1228    INT16        len,
1229    XPointer	 data,
1230    XPointer     arg)
1231{
1232    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
1233    CARD8	 major_opcode = *((CARD8 *)data);
1234    CARD8	 minor_opcode = *((CARD8 *)data + 1);
1235    XIMID	 imid = buf_s[0];
1236
1237    if ((major_opcode == XIM_SET_IM_VALUES_REPLY)
1238     && (minor_opcode == 0)
1239     && (imid == im->private.proto.imid))
1240	return True;
1241    if ((major_opcode == XIM_ERROR)
1242     && (minor_opcode == 0)
1243     && (buf_s[2] & XIM_IMID_VALID)
1244     && (imid == im->private.proto.imid))
1245	return True;
1246    return False;
1247}
1248
1249static char *
1250_XimProtoSetIMValues(
1251    XIM			 xim,
1252    XIMArg		*arg)
1253{
1254    Xim			 im = (Xim)xim;
1255    XimDefIMValues	 im_values;
1256    INT16		 len;
1257    CARD16		*buf_s;
1258    char		*tmp;
1259    CARD32		 tmp_buf32[BUFSIZE/4];
1260    char		*tmp_buf = (char *)tmp_buf32;
1261    char		*buf;
1262    int			 buf_size;
1263    char		*data;
1264    int			 data_len;
1265    int			 ret_len;
1266    int			 total;
1267    XIMArg		*arg_ret;
1268    CARD32		 reply32[BUFSIZE/4];
1269    char		*reply = (char *)reply32;
1270    XPointer		 preply;
1271    int			 ret_code;
1272    char		*name;
1273
1274#ifndef XIM_CONNECTABLE
1275    if (!IS_SERVER_CONNECTED(im))
1276	return arg->name;
1277#else
1278    if (!_XimSaveIMValues(im, arg))
1279	return arg->name;
1280
1281    if (!IS_SERVER_CONNECTED(im)) {
1282	if (IS_CONNECTABLE(im)) {
1283	    if (!_XimConnectServer(im)) {
1284	        return _XimDelayModeSetIMValues(im, arg);
1285	    }
1286        } else {
1287	    return arg->name;
1288        }
1289    }
1290#endif /* XIM_CONNECTABLE */
1291
1292    _XimGetCurrentIMValues(im, &im_values);
1293    memset(tmp_buf, 0, sizeof(tmp_buf32));
1294    buf = tmp_buf;
1295    buf_size = XIM_HEADER_SIZE + sizeof(CARD16) + sizeof(INT16);
1296    data_len = BUFSIZE - buf_size;
1297    total = 0;
1298    arg_ret = arg;
1299    for (;;) {
1300	data = &buf[buf_size];
1301	if ((name = _XimEncodeIMATTRIBUTE(im, im->core.im_resources,
1302		im->core.im_num_resources, arg, &arg_ret, data, data_len,
1303		&ret_len, (XPointer)&im_values, XIM_SETIMVALUES))) {
1304	    break;
1305	}
1306
1307	total += ret_len;
1308	if (!(arg = arg_ret)) {
1309	    break;
1310	}
1311
1312	buf_size += ret_len;
1313	if (buf == tmp_buf) {
1314	    if (!(tmp = Xcalloc(buf_size + data_len, 1))) {
1315		return arg->name;
1316	    }
1317	    memcpy(tmp, buf, buf_size);
1318	    buf = tmp;
1319	} else {
1320	    if (!(tmp = Xrealloc(buf, (buf_size + data_len)))) {
1321		Xfree(buf);
1322		return arg->name;
1323	    }
1324            memset(&tmp[buf_size], 0, data_len);
1325	    buf = tmp;
1326	}
1327    }
1328    _XimSetCurrentIMValues(im, &im_values);
1329
1330    if (!total) {
1331        if (buf != tmp_buf)
1332	    Xfree(buf);
1333        return (char *)NULL;
1334    }
1335
1336    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
1337    buf_s[0] = im->private.proto.imid;
1338    buf_s[1] = (INT16)total;
1339
1340    len = (INT16)(sizeof(CARD16) + sizeof(INT16) + total);
1341    _XimSetHeader((XPointer)buf, XIM_SET_IM_VALUES, 0, &len);
1342    if (!(_XimWrite(im, len, (XPointer)buf))) {
1343	if (buf != tmp_buf)
1344	    Xfree(buf);
1345	return arg->name;
1346    }
1347    _XimFlush(im);
1348    if (buf != tmp_buf)
1349	Xfree(buf);
1350    buf_size = BUFSIZE;
1351    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
1352					 _XimSetIMValuesCheck, 0);
1353    if(ret_code == XIM_TRUE) {
1354	preply = reply;
1355    } else if(ret_code == XIM_OVERFLOW) {
1356	if(len <= 0) {
1357	    preply = reply;
1358	} else {
1359	    buf_size = (int)len;
1360	    preply = Xmalloc(buf_size);
1361	    ret_code = _XimRead(im, &len, reply, buf_size,
1362					_XimSetIMValuesCheck, 0);
1363	    if(ret_code != XIM_TRUE) {
1364		Xfree(preply);
1365		return arg->name;
1366	    }
1367	}
1368    } else
1369	return arg->name;
1370    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
1371    if (*((CARD8 *)preply) == XIM_ERROR) {
1372	_XimProcError(im, 0, (XPointer)&buf_s[3]);
1373	if(reply != preply)
1374	    Xfree(preply);
1375	return arg->name;
1376    }
1377    if(reply != preply)
1378	Xfree(preply);
1379
1380    return name;
1381}
1382
1383#ifdef XIM_CONNECTABLE
1384static char *
1385_XimDelayModeGetIMValues(
1386    Xim			 im,
1387    XIMArg		*arg)
1388{
1389    XimDefIMValues	 im_values;
1390
1391    _XimGetCurrentIMValues(im, &im_values);
1392    return(_XimGetIMValueData(im, (XPointer)&im_values, arg,
1393			im->core.im_resources, im->core.im_num_resources));
1394}
1395#endif /* XIM_CONNECTABLE */
1396
1397static Bool
1398_XimGetIMValuesCheck(
1399    Xim          im,
1400    INT16        len,
1401    XPointer	 data,
1402    XPointer     arg)
1403{
1404    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
1405    CARD8	 major_opcode = *((CARD8 *)data);
1406    CARD8	 minor_opcode = *((CARD8 *)data + 1);
1407    XIMID	 imid = buf_s[0];
1408
1409    if ((major_opcode == XIM_GET_IM_VALUES_REPLY)
1410     && (minor_opcode == 0)
1411     && (imid == im->private.proto.imid))
1412	return True;
1413    if ((major_opcode == XIM_ERROR)
1414     && (minor_opcode == 0)
1415     && (buf_s[2] & XIM_IMID_VALID)
1416     && (imid == im->private.proto.imid))
1417	return True;
1418    return False;
1419}
1420
1421static char *
1422_XimProtoGetIMValues(
1423    XIM			 xim,
1424    XIMArg		*arg)
1425{
1426    Xim			 im = (Xim)xim;
1427    register XIMArg	*p;
1428    register int	 n;
1429    CARD8		*buf;
1430    CARD16		*buf_s;
1431    INT16		 len;
1432    CARD32		 reply32[BUFSIZE/4];
1433    char		*reply = (char *)reply32;
1434    XPointer		 preply = NULL;
1435    int			 buf_size;
1436    int			 ret_code;
1437    char		*makeid_name;
1438    char		*decode_name;
1439    CARD16		*data = NULL;
1440    INT16		 data_len = 0;
1441
1442#ifndef XIM_CONNECTABLE
1443    if (!IS_SERVER_CONNECTED(im))
1444	return arg->name;
1445#else
1446    if (!IS_SERVER_CONNECTED(im)) {
1447	if (IS_CONNECTABLE(im)) {
1448	    if (!_XimConnectServer(im)) {
1449	        return _XimDelayModeGetIMValues(im, arg);
1450	    }
1451        } else {
1452	    return arg->name;
1453        }
1454    }
1455#endif /* XIM_CONNECTABLE */
1456
1457    for (n = 0, p = arg; p->name; p++)
1458	n++;
1459
1460    if (!n)
1461	return (char *)NULL;
1462
1463    buf_size =  sizeof(CARD16) * n;
1464    buf_size += XIM_HEADER_SIZE
1465	     + sizeof(CARD16)
1466	     + sizeof(INT16)
1467	     + XIM_PAD(buf_size);
1468
1469    if (!(buf = Xcalloc(buf_size, 1)))
1470	return arg->name;
1471    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
1472
1473    makeid_name = _XimMakeIMAttrIDList(im, im->core.im_resources,
1474				im->core.im_num_resources, arg,
1475				&buf_s[2], &len, XIM_GETIMVALUES);
1476
1477    if (len) {
1478	buf_s[0] = im->private.proto.imid;	/* imid */
1479	buf_s[1] = len;				/* length of im-attr-id */
1480	XIM_SET_PAD(&buf_s[2], len);		/* pad */
1481	len += sizeof(CARD16)			/* sizeof imid */
1482	     + sizeof(INT16);			/* sizeof length of attr */
1483
1484	_XimSetHeader((XPointer)buf, XIM_GET_IM_VALUES, 0, &len);
1485	if (!(_XimWrite(im, len, (XPointer)buf))) {
1486	    Xfree(buf);
1487	    return arg->name;
1488	}
1489	_XimFlush(im);
1490	Xfree(buf);
1491    	buf_size = BUFSIZE;
1492    	ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
1493    						_XimGetIMValuesCheck, 0);
1494	if(ret_code == XIM_TRUE) {
1495	    preply = reply;
1496	} else if(ret_code == XIM_OVERFLOW) {
1497	    if(len <= 0) {
1498		preply = reply;
1499	    } else {
1500		buf_size = len;
1501		preply = Xmalloc(buf_size);
1502		ret_code = _XimRead(im, &len, preply, buf_size,
1503						_XimGetIMValuesCheck, 0);
1504		if(ret_code != XIM_TRUE) {
1505		    Xfree(preply);
1506		    return arg->name;
1507		}
1508	    }
1509	} else
1510	    return arg->name;
1511	buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
1512	if (*((CARD8 *)preply) == XIM_ERROR) {
1513	    _XimProcError(im, 0, (XPointer)&buf_s[3]);
1514	    if(reply != preply)
1515		Xfree(preply);
1516	    return arg->name;
1517	}
1518	data = &buf_s[2];
1519	data_len = buf_s[1];
1520    }
1521    decode_name = _XimDecodeIMATTRIBUTE(im, im->core.im_resources,
1522			im->core.im_num_resources, data, data_len,
1523			arg, XIM_GETIMVALUES);
1524    if (reply != preply)
1525	Xfree(preply);
1526
1527    if (decode_name)
1528	return decode_name;
1529    else
1530	return makeid_name;
1531}
1532
1533static XIMMethodsRec     im_methods = {
1534    _XimProtoCloseIM,           /* close */
1535    _XimProtoSetIMValues,       /* set_values */
1536    _XimProtoGetIMValues,       /* get_values */
1537    _XimProtoCreateIC,          /* create_ic */
1538    _Ximctstombs,		/* ctstombs */
1539    _Ximctstowcs,		/* ctstowcs */
1540    _Ximctstoutf8		/* ctstoutf8 */
1541};
1542
1543static Bool
1544_XimSetEncodingByName(
1545    Xim		  im,
1546    char	**buf,
1547    int		 *len)
1548{
1549    char	*encoding = (char *)NULL;
1550    int		 encoding_len;
1551    int		 compound_len;
1552    BYTE	*ret;
1553
1554    _XGetLCValues(im->core.lcd, XlcNCodeset, &encoding, NULL);
1555    if (!encoding) {
1556	*buf = (char *)NULL;
1557	*len = 0;
1558	return True;
1559    }
1560    encoding_len = strlen(encoding);
1561    compound_len = strlen("COMPOUND_TEXT");
1562    *len = encoding_len + sizeof(BYTE) + compound_len + sizeof(BYTE);
1563    if (!(ret = Xmalloc(*len))) {
1564	return False;
1565    }
1566    *buf = (char *)ret;
1567
1568    ret[0] = (BYTE)encoding_len;
1569    memcpy(&ret[1], encoding, encoding_len);
1570    ret += (encoding_len + sizeof(BYTE));
1571    ret[0] = (BYTE)compound_len;
1572    memcpy(&ret[1], "COMPOUND_TEXT", compound_len);
1573    return True;
1574}
1575
1576static Bool
1577_XimSetEncodingByDetail(
1578    Xim		 im,
1579    char	**buf,
1580    int		 *len)
1581{
1582    *len = 0;
1583    *buf = NULL;
1584    return True;
1585}
1586
1587static Bool
1588_XimGetEncoding(
1589    Xim		 im,
1590    CARD16	*buf,
1591    char	*name,
1592    int		 name_len,
1593    char	*detail,
1594    int		 detail_len)
1595{
1596    XLCd	 lcd = im->core.lcd;
1597    CARD16	 category = buf[0];
1598    CARD16	 idx = buf[1];
1599    int		 len;
1600    XlcConv	 ctom_conv = NULL;
1601    XlcConv	 ctow_conv = NULL;
1602    XlcConv	 ctoutf8_conv = NULL;
1603    XlcConv	 conv;
1604    XimProtoPrivateRec *private = &im->private.proto;
1605
1606    if (idx == (CARD16)XIM_Default_Encoding_IDX) { /* XXX */
1607	if (!(ctom_conv = _XlcOpenConverter(lcd,
1608				 XlcNCompoundText, lcd, XlcNMultiByte)))
1609	    return False;
1610	if (!(ctow_conv = _XlcOpenConverter(lcd,
1611				 XlcNCompoundText, lcd, XlcNWideChar)))
1612	    return False;
1613	if (!(ctoutf8_conv = _XlcOpenConverter(lcd,
1614				 XlcNCompoundText, lcd, XlcNUtf8String)))
1615	    return False;
1616    }
1617
1618    if (category == XIM_Encoding_NameCategory) {
1619	while (name_len > 0) {
1620	    len = (int)name[0];
1621	    if (!strncmp(&name[1], "COMPOUND_TEXT", len)) {
1622		if (!(ctom_conv = _XlcOpenConverter(lcd,
1623				 XlcNCompoundText, lcd, XlcNMultiByte)))
1624		    return False;
1625		if (!(ctow_conv = _XlcOpenConverter(lcd,
1626				 XlcNCompoundText, lcd, XlcNWideChar)))
1627		    return False;
1628		if (!(ctoutf8_conv = _XlcOpenConverter(lcd,
1629				 XlcNCompoundText, lcd, XlcNUtf8String)))
1630		    return False;
1631		break;
1632	    } else {
1633		/*
1634		 * Not yet
1635		 */
1636	    }
1637	    len += sizeof(BYTE);
1638	    name_len -= len;
1639	    name += len;
1640	}
1641    } else if (category == XIM_Encoding_DetailCategory) {
1642	/*
1643	 * Not yet
1644	 */
1645    } else {
1646	return False;
1647    }
1648
1649    private->ctom_conv = ctom_conv;
1650    private->ctow_conv = ctow_conv;
1651    private->ctoutf8_conv = ctoutf8_conv;
1652
1653    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNMultiByte)))
1654	return False;
1655    private->cstomb_conv = conv;
1656
1657    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNWideChar)))
1658	return False;
1659    private->cstowc_conv = conv;
1660
1661    if (!(conv = _XlcOpenConverter(lcd,	XlcNCharSet, lcd, XlcNUtf8String)))
1662	return False;
1663    private->cstoutf8_conv = conv;
1664
1665    if (!(conv = _XlcOpenConverter(lcd,	XlcNUcsChar, lcd, XlcNChar)))
1666	return False;
1667    private->ucstoc_conv = conv;
1668
1669    if (!(conv = _XlcOpenConverter(lcd,	XlcNUcsChar, lcd, XlcNUtf8String)))
1670	return False;
1671    private->ucstoutf8_conv = conv;
1672
1673    return True;
1674}
1675
1676static Bool
1677_XimEncodingNegoCheck(
1678    Xim		 im,
1679    INT16	 len,
1680    XPointer	 data,
1681    XPointer	 arg)
1682{
1683    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
1684    CARD8	 major_opcode = *((CARD8 *)data);
1685    CARD8	 minor_opcode = *((CARD8 *)data + 1);
1686    XIMID	 imid = buf_s[0];
1687
1688    if ((major_opcode == XIM_ENCODING_NEGOTIATION_REPLY)
1689     && (minor_opcode == 0)
1690     && (imid == im->private.proto.imid))
1691	return True;
1692    if ((major_opcode == XIM_ERROR)
1693     && (minor_opcode == 0)
1694     && (buf_s[2] & XIM_IMID_VALID)
1695     && (imid == im->private.proto.imid))
1696	return True;
1697    return False;
1698}
1699
1700static Bool
1701_XimEncodingNegotiation(
1702    Xim		 im)
1703{
1704    char	*name_ptr = 0;
1705    int		 name_len = 0;
1706    char	*detail_ptr = 0;
1707    int		 detail_len = 0;
1708    CARD8	*buf;
1709    CARD16	*buf_s;
1710    INT16	 len;
1711    CARD32	 reply32[BUFSIZE/4];
1712    char	*reply = (char *)reply32;
1713    XPointer	 preply;
1714    int		 buf_size;
1715    int		 ret_code;
1716
1717    if (!(_XimSetEncodingByName(im, &name_ptr, &name_len)))
1718	return False;
1719
1720    if (!(_XimSetEncodingByDetail(im, &detail_ptr, &detail_len)))
1721	goto free_name_ptr;
1722
1723    len = sizeof(CARD16)
1724	+ sizeof(INT16)
1725	+ name_len
1726	+ XIM_PAD(name_len)
1727	+ sizeof(INT16)
1728	+ sizeof(CARD16)
1729	+ detail_len;
1730
1731    if (!(buf = Xcalloc(1, XIM_HEADER_SIZE + len)))
1732	goto free_detail_ptr;
1733
1734    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
1735
1736    buf_s[0] = im->private.proto.imid;
1737    buf_s[1] = (INT16)name_len;
1738    if (name_ptr)
1739	(void)memcpy((char *)&buf_s[2], name_ptr, name_len);
1740    XIM_SET_PAD(&buf_s[2], name_len);
1741    buf_s = (CARD16 *)((char *)&buf_s[2] + name_len);
1742    buf_s[0] = detail_len;
1743    buf_s[1] = 0;
1744    if (detail_ptr)
1745	(void)memcpy((char *)&buf_s[2], detail_ptr, detail_len);
1746
1747    _XimSetHeader((XPointer)buf, XIM_ENCODING_NEGOTIATION, 0, &len);
1748    if (!(_XimWrite(im, len, (XPointer)buf))) {
1749	Xfree(buf);
1750	goto free_detail_ptr;
1751    }
1752    _XimFlush(im);
1753    Xfree(buf);
1754    buf_size = BUFSIZE;
1755    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
1756					_XimEncodingNegoCheck, 0);
1757    if(ret_code == XIM_TRUE) {
1758	preply = reply;
1759    } else if(ret_code == XIM_OVERFLOW) {
1760	if(len <= 0) {
1761	    preply = reply;
1762	} else {
1763	    buf_size = len;
1764	    preply = Xmalloc(buf_size);
1765	    ret_code = _XimRead(im, &len, preply, buf_size,
1766					_XimEncodingNegoCheck, 0);
1767	    if(ret_code != XIM_TRUE)
1768		goto free_preply;
1769	}
1770    } else
1771	goto free_detail_ptr;
1772    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
1773    if (*((CARD8 *)preply) == XIM_ERROR) {
1774	_XimProcError(im, 0, (XPointer)&buf_s[3]);
1775	goto free_preply;
1776    }
1777
1778    if (!(_XimGetEncoding(im, &buf_s[1], name_ptr, name_len,
1779						detail_ptr, detail_len)))
1780	goto free_preply;
1781
1782    Xfree(name_ptr);
1783    Xfree(detail_ptr);
1784
1785    if(reply != preply)
1786	Xfree(preply);
1787
1788    return True;
1789
1790free_preply:
1791    if (reply != preply)
1792	Xfree(preply);
1793
1794free_detail_ptr:
1795    Xfree(detail_ptr);
1796
1797free_name_ptr:
1798    Xfree(name_ptr);
1799
1800    return False;
1801}
1802
1803#ifdef XIM_CONNECTABLE
1804static Bool
1805_XimSendSavedIMValues(
1806    Xim			 im)
1807{
1808    XimDefIMValues	 im_values;
1809    INT16		 len;
1810    CARD16		*buf_s;
1811    char		*tmp;
1812    CARD32		 tmp_buf32[BUFSIZE/4];
1813    char		*tmp_buf = (char *)tmp_buf32;
1814    char		*buf;
1815    int			 buf_size;
1816    char		*data;
1817    int			 data_len;
1818    int			 ret_len;
1819    int			 total;
1820    int			 idx;
1821    CARD32		 reply32[BUFSIZE/4];
1822    char		*reply = (char *)reply32;
1823    XPointer		 preply;
1824    int			 ret_code;
1825
1826    _XimGetCurrentIMValues(im, &im_values);
1827    memset(tmp_buf, 0, sizeof(tmp_buf32));
1828    buf = tmp_buf;
1829    buf_size = XIM_HEADER_SIZE + sizeof(CARD16) + sizeof(INT16);
1830    data_len = BUFSIZE - buf_size;
1831    total = 0;
1832    idx = 0;
1833    for (;;) {
1834	data = &buf[buf_size];
1835	if (!_XimEncodeSavedIMATTRIBUTE(im, im->core.im_resources,
1836		im->core.im_num_resources, &idx, data, data_len,
1837		&ret_len, (XPointer)&im_values, XIM_SETIMVALUES)) {
1838	    if (buf != tmp_buf)
1839		Xfree(buf);
1840	    return False;
1841	}
1842
1843	total += ret_len;
1844	if (idx == -1) {
1845	    break;
1846	}
1847
1848	buf_size += ret_len;
1849	if (buf == tmp_buf) {
1850	    if (!(tmp = Xcalloc(buf_size + data_len, 1))) {
1851		return False;
1852	    }
1853	    memcpy(tmp, buf, buf_size);
1854	    buf = tmp;
1855	} else {
1856	    if (!(tmp = Xrealloc(buf, (buf_size + data_len)))) {
1857		Xfree(buf);
1858		return False;
1859	    }
1860            memset(&tmp[buf_size], 0, data_len);
1861	    buf = tmp;
1862	}
1863    }
1864
1865    if (!total)
1866	return True;
1867
1868    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
1869    buf_s[0] = im->private.proto.imid;
1870    buf_s[1] = (INT16)total;
1871
1872    len = (INT16)(sizeof(CARD16) + sizeof(INT16) + total);
1873    _XimSetHeader((XPointer)buf, XIM_SET_IM_VALUES, 0, &len);
1874    if (!(_XimWrite(im, len, (XPointer)buf))) {
1875	if (buf != tmp_buf)
1876	    Xfree(buf);
1877	return False;
1878    }
1879    _XimFlush(im);
1880    if (buf != tmp_buf)
1881	Xfree(buf);
1882    buf_size = BUFSIZE;
1883    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
1884    					 _XimSetIMValuesCheck, 0);
1885    if(ret_code == XIM_TRUE) {
1886	preply = reply;
1887    } else if(ret_code == XIM_OVERFLOW) {
1888	if(len <= 0) {
1889	    preply = reply;
1890	} else {
1891	    buf_size = (int)len;
1892	    preply = Xmalloc(buf_size);
1893	    ret_code = _XimRead(im, &len, reply, buf_size,
1894					_XimSetIMValuesCheck, 0);
1895    	    if(ret_code != XIM_TRUE) {
1896		Xfree(preply);
1897		return False;
1898	    }
1899	}
1900    } else
1901	return False;
1902
1903    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
1904    if (*((CARD8 *)preply) == XIM_ERROR) {
1905	_XimProcError(im, 0, (XPointer)&buf_s[3]);
1906    	if(reply != preply)
1907	    Xfree(preply);
1908	return False;
1909    }
1910    if(reply != preply)
1911	Xfree(preply);
1912
1913    return True;
1914}
1915
1916static void
1917_XimDelayModeIMFree(
1918    Xim		 im)
1919{
1920    if (im->core.im_resources) {
1921	Xfree(im->core.im_resources);
1922	im->core.im_resources = NULL;
1923    }
1924    if (im->core.ic_resources) {
1925	Xfree(im->core.ic_resources);
1926	im->core.ic_resources = NULL;
1927    }
1928    if (im->core.im_values_list) {
1929	Xfree(im->core.im_values_list);
1930	im->core.im_values_list = NULL;
1931    }
1932    if (im->core.ic_values_list) {
1933	Xfree(im->core.ic_values_list);
1934	im->core.ic_values_list = NULL;
1935    }
1936    return;
1937}
1938
1939Bool
1940_XimConnectServer(
1941    Xim		 im)
1942{
1943    Xim		 save_im;
1944
1945    if (!(save_im = Xmalloc(sizeof(XimRec))))
1946	return False;
1947    memcpy((char *)save_im, (char *)im, sizeof(XimRec));
1948
1949    if (_XimPreConnect(im) && _XimConnection(im)
1950			&& _XimOpen(im) && _XimEncodingNegotiation(im)) {
1951	if (_XimSendSavedIMValues(im)) {
1952	    _XimDelayModeIMFree(save_im);
1953	    _XimRegisterServerFilter(im);
1954	    Xfree(save_im);
1955	    return True;
1956	}
1957    }
1958    memcpy((char *)im, (char *)save_im, sizeof(XimRec));
1959    Xfree(save_im);
1960    return False;
1961}
1962
1963Bool
1964_XimDelayModeSetAttr(
1965    Xim			 im)
1966{
1967    XimDefIMValues	 im_values;
1968
1969    if(!_XimSetIMResourceList(&im->core.im_resources,
1970						&im->core.im_num_resources)) {
1971	return False;
1972    }
1973    if(!_XimSetICResourceList(&im->core.ic_resources,
1974						&im->core.ic_num_resources)) {
1975	return False;
1976    }
1977
1978    _XimSetIMMode(im->core.im_resources, im->core.im_num_resources);
1979
1980    _XimGetCurrentIMValues(im, &im_values);
1981    if(!_XimSetLocalIMDefaults(im, (XPointer)&im_values,
1982			im->core.im_resources, im->core.im_num_resources)) {
1983	return False;
1984    }
1985    _XimSetCurrentIMValues(im, &im_values);
1986    if (im->private.proto.default_styles) {
1987        if (im->core.styles)
1988	    Xfree(im->core.styles);
1989        im->core.styles = im->private.proto.default_styles;
1990    }
1991
1992    return True;
1993}
1994
1995static Bool
1996_XimReconnectModeSetAttr(
1997    Xim			 im)
1998{
1999    XimDefIMValues	 im_values;
2000
2001    if(!_XimSetIMResourceList(&im->core.im_resources,
2002						&im->core.im_num_resources)) {
2003	return False;
2004    }
2005    if(!_XimSetICResourceList(&im->core.ic_resources,
2006						&im->core.ic_num_resources)) {
2007	return False;
2008    }
2009
2010    _XimSetIMMode(im->core.im_resources, im->core.im_num_resources);
2011
2012    if (im->private.proto.default_styles) {
2013        if (im->core.styles)
2014	    Xfree(im->core.styles);
2015        im->core.styles = im->private.proto.default_styles;
2016    }
2017
2018    return True;
2019}
2020#endif /* XIM_CONNECTABLE */
2021
2022Bool
2023_XimProtoOpenIM(
2024    Xim		 im)
2025{
2026    _XimInitialResourceInfo();
2027
2028    im->methods = &im_methods;
2029
2030#ifdef XIM_CONNECTABLE
2031    _XimSetProtoResource(im);
2032#endif /* XIM_CONNECTABLE */
2033
2034    if (_XimPreConnect(im)) {
2035	if (_XimConnection(im) && _XimOpen(im) && _XimEncodingNegotiation(im)) {
2036	    _XimRegisterServerFilter(im);
2037	    return True;
2038	}
2039	_XimShutdown(im);
2040#ifdef XIM_CONNECTABLE
2041    } else if (IS_DELAYBINDABLE(im)) {
2042	if (_XimDelayModeSetAttr(im))
2043	    return True;
2044#endif /* XIM_CONNECTABLE */
2045    }
2046    _XimProtoIMFree(im);
2047    return False;
2048}
2049