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