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