1/*
2 * Copyright (c) 1991, 1992, Oracle and/or its affiliates.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23/******************************************************************
24
25           Copyright 1992, 1993, 1994 by FUJITSU LIMITED
26
27Permission to use, copy, modify, distribute, and sell this software
28and its documentation for any purpose is hereby granted without fee,
29provided that the above copyright notice appear in all copies and
30that both that copyright notice and this permission notice appear
31in supporting documentation, and that the name of FUJITSU LIMITED
32not be used in advertising or publicity pertaining to distribution
33of the software without specific, written prior permission.
34FUJITSU LIMITED makes no representations about the suitability of
35this software for any purpose.
36It is provided "as is" without express or implied warranty.
37
38FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
39INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
40EVENT SHALL FUJITSU LIMITED 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
50******************************************************************/
51
52#ifdef HAVE_CONFIG_H
53#include <config.h>
54#endif
55#include "Xlibint.h"
56#include "Xlcint.h"
57#include "Ximint.h"
58
59static Bool
60_XimCreateICCheck(
61    Xim          im,
62    INT16        len,
63    XPointer	 data,
64    XPointer     arg)
65{
66    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
67    CARD8	 major_opcode = *((CARD8 *)data);
68    CARD8	 minor_opcode = *((CARD8 *)data + 1);
69    XIMID	 imid = buf_s[0];
70
71    if ((major_opcode == XIM_CREATE_IC_REPLY)
72     && (minor_opcode == 0)
73     && (imid == im->private.proto.imid))
74	return True;
75    if ((major_opcode == XIM_ERROR)
76     && (minor_opcode == 0)
77     && (buf_s[2] & XIM_IMID_VALID)
78     && (imid == im->private.proto.imid))
79	return True;
80    return False;
81}
82
83#ifdef XIM_CONNECTABLE
84Bool
85_XimReCreateIC(ic)
86    Xic			 ic;
87{
88    Xim			 im = (Xim)ic->core.im;
89    Xic			 save_ic;
90    XIMResourceList	 res;
91    unsigned int         num;
92    XIMStyle		 input_style = ic->core.input_style;
93    XimDefICValues	 ic_values;
94    INT16		 len;
95    CARD16		*buf_s;
96    char		*tmp;
97    CARD32		 tmp_buf32[BUFSIZE/4];
98    char		*tmp_buf = (char *)tmp_buf32;
99    char		*buf;
100    int			 buf_size;
101    char		*data;
102    int			 data_len;
103    int			 ret_len;
104    int			 total;
105    int			 idx;
106    CARD32		 reply32[BUFSIZE/4];
107    char		*reply = (char *)reply32;
108    XPointer		 preply;
109    int			 ret_code;
110
111    if (!(save_ic = Xmalloc(sizeof(XicRec))))
112	return False;
113    memcpy((char *)save_ic, (char *)ic, sizeof(XicRec));
114
115    ic->core.filter_events = im->private.proto.forward_event_mask;
116    ic->private.proto.forward_event_mask =
117				im->private.proto.forward_event_mask;
118    ic->private.proto.synchronous_event_mask =
119				im->private.proto.synchronous_event_mask;
120
121    num = im->core.ic_num_resources;
122    buf_size = sizeof(XIMResource) * num;
123    if (!(res = Xmalloc(buf_size)))
124	goto ErrorOnReCreateIC;
125    (void)memcpy((char *)res, (char *)im->core.ic_resources, buf_size);
126    ic->private.proto.ic_resources     = res;
127    ic->private.proto.ic_num_resources = num;
128
129    num = im->private.proto.ic_num_inner_resources;
130    buf_size = sizeof(XIMResource) * num;
131    if (!(res = Xmalloc(buf_size)))
132	goto ErrorOnReCreateIC;
133    (void)memcpy((char *)res,
134			(char *)im->private.proto.ic_inner_resources, buf_size);
135    ic->private.proto.ic_inner_resources     = res;
136    ic->private.proto.ic_num_inner_resources = num;
137
138    _XimSetICMode(ic->private.proto.ic_resources,
139			ic->private.proto.ic_num_resources, input_style);
140
141    _XimSetICMode(ic->private.proto.ic_inner_resources,
142			ic->private.proto.ic_num_inner_resources, input_style);
143
144    _XimGetCurrentICValues(ic, &ic_values);
145    buf = tmp_buf;
146    buf_size = XIM_HEADER_SIZE + sizeof(CARD16) + sizeof(INT16);
147    data_len = BUFSIZE - buf_size;
148    total = 0;
149    idx = 0;
150    for (;;) {
151	data = &buf[buf_size];
152	if (!_XimEncodeSavedICATTRIBUTE(ic, ic->private.proto.ic_resources,
153		ic->private.proto.ic_num_resources, &idx, data, data_len,
154		&ret_len, (XPointer)&ic_values, XIM_CREATEIC)) {
155	    if (buf != tmp_buf)
156		Xfree(buf);
157	    goto ErrorOnReCreateIC;
158	}
159
160	total += ret_len;
161	if (idx == -1) {
162	    break;
163	}
164
165	buf_size += ret_len;
166	if (buf == tmp_buf) {
167	    if (!(tmp = Xmalloc(buf_size + data_len))) {
168		goto ErrorOnReCreateIC;
169	    }
170	    memcpy(tmp, buf, buf_size);
171	    buf = tmp;
172	} else {
173	    if (!(tmp = Xrealloc(buf, (buf_size + data_len)))) {
174		Xfree(buf);
175		goto ErrorOnReCreateIC;
176	    }
177	    buf = tmp;
178	}
179    }
180
181    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
182    buf_s[0] = im->private.proto.imid;
183    buf_s[1] = (INT16)total;
184
185    len = (INT16)(sizeof(CARD16) + sizeof(INT16) + total);
186    _XimSetHeader((XPointer)buf, XIM_CREATE_IC, 0, &len);
187    if (!(_XimWrite(im, len, (XPointer)buf))) {
188	if (buf != tmp_buf)
189	    Xfree(buf);
190	goto ErrorOnReCreateIC;
191    }
192    _XimFlush(im);
193    if (buf != tmp_buf)
194	Xfree(buf);
195    ic->private.proto.waitCallback = True;
196    buf_size = BUFSIZE;
197    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
198						 _XimCreateICCheck, 0);
199    if (ret_code == XIM_TRUE) {
200	preply = reply;
201    } else if (ret_code == XIM_OVERFLOW) {
202	if (len <= 0) {
203	    preply = reply;
204	} else {
205	    buf_size = (int)len;
206	    preply = Xmalloc(buf_size);
207	    ret_code = _XimRead(im, &len, preply, buf_size,
208						 _XimCreateICCheck, 0);
209	    if (ret_code != XIM_TRUE) {
210		Xfree(preply);
211		ic->private.proto.waitCallback = False;
212		goto ErrorOnReCreateIC;
213	    }
214	}
215    } else {
216	ic->private.proto.waitCallback = False;
217	goto ErrorOnReCreateIC;
218    }
219    ic->private.proto.waitCallback = False;
220    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
221    if (*((CARD8 *)preply) == XIM_ERROR) {
222	_XimProcError(im, 0, (XPointer)&buf_s[3]);
223	if (reply != preply)
224	    Xfree(preply);
225	goto ErrorOnReCreateIC;
226    }
227
228    ic->private.proto.icid = buf_s[1];		/* icid */
229    if (reply != preply)
230	Xfree(preply);
231
232    _XimRegisterFilter(ic);
233    MARK_IC_CONNECTED(ic);
234
235    Xfree(save_ic->private.proto.ic_resources);
236    Xfree(save_ic->private.proto.ic_inner_resources);
237    Xfree(save_ic);
238    return True;
239
240ErrorOnReCreateIC:
241    memcpy((char *)ic, (char *)save_ic, sizeof(XicRec));
242    Xfree(save_ic);
243    return False;
244}
245
246static char *
247_XimDelayModeGetICValues(ic, arg)
248    Xic			 ic;
249    XIMArg		*arg;
250{
251    XimDefICValues	 ic_values;
252
253    _XimGetCurrentICValues(ic, &ic_values);
254    return  _XimGetICValueData(ic, (XPointer)&ic_values,
255				ic->private.proto.ic_resources,
256				ic->private.proto.ic_num_resources,
257				arg, XIM_GETICVALUES);
258}
259#endif /* XIM_CONNECTABLE */
260
261static Bool
262_XimGetICValuesCheck(
263    Xim          im,
264    INT16        len,
265    XPointer	 data,
266    XPointer     arg)
267{
268    Xic		 ic = (Xic)arg;
269    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
270    CARD8	 major_opcode = *((CARD8 *)data);
271    CARD8	 minor_opcode = *((CARD8 *)data + 1);
272    XIMID	 imid = buf_s[0];
273    XICID	 icid = buf_s[1];
274
275    if ((major_opcode == XIM_GET_IC_VALUES_REPLY)
276     && (minor_opcode == 0)
277     && (imid == im->private.proto.imid)
278     && (icid == ic->private.proto.icid))
279	return True;
280    if ((major_opcode == XIM_ERROR)
281     && (minor_opcode == 0)
282     && (buf_s[2] & XIM_IMID_VALID)
283     && (imid == im->private.proto.imid)
284     && (buf_s[2] & XIM_ICID_VALID)
285     && (icid == ic->private.proto.icid))
286	return True;
287    return False;
288}
289
290static char *
291_XimProtoGetICValues(
292    XIC			 xic,
293    XIMArg		*arg)
294{
295    Xic			 ic = (Xic)xic;
296    Xim			 im = (Xim)ic->core.im;
297    register XIMArg	*p;
298    register XIMArg	*pp;
299    register int	 n;
300    CARD8		*buf;
301    CARD16		*buf_s;
302    INT16		 len;
303    CARD32		 reply32[BUFSIZE/4];
304    char		*reply = (char *)reply32;
305    XPointer		 preply = NULL;
306    int			 buf_size;
307    int			 ret_code;
308    char		*makeid_name;
309    char		*decode_name;
310    CARD16		*data = NULL;
311    INT16		 data_len = 0;
312
313#ifndef XIM_CONNECTABLE
314    if (!IS_IC_CONNECTED(ic))
315	return arg->name;
316#else
317    if (!IS_IC_CONNECTED(ic)) {
318	if (IS_CONNECTABLE(im)) {
319	    if (_XimConnectServer(im)) {
320		if (!_XimReCreateIC(ic)) {
321		    _XimDelayModeSetAttr(im);
322	            return _XimDelayModeGetICValues(ic, arg);
323		}
324	    } else {
325	        return _XimDelayModeGetICValues(ic, arg);
326	    }
327        } else {
328	    return arg->name;
329        }
330    }
331#endif /* XIM_CONNECTABLE */
332
333    for (n = 0, p = arg; p && p->name; p++) {
334	n++;
335	if ((strcmp(p->name, XNPreeditAttributes) == 0)
336	 || (strcmp(p->name, XNStatusAttributes) == 0)) {
337	     n++;
338	     for (pp = (XIMArg *)p->value; pp && pp->name; pp++)
339	 	n++;
340	}
341    }
342
343    if (!n)
344	return (char *)NULL;
345
346    buf_size =  sizeof(CARD16) * n;
347    buf_size += XIM_HEADER_SIZE
348	     + sizeof(CARD16)
349	     + sizeof(CARD16)
350	     + sizeof(INT16)
351	     + XIM_PAD(2 + buf_size);
352
353    if (!(buf = Xcalloc(buf_size, 1)))
354	return arg->name;
355    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
356
357    makeid_name = _XimMakeICAttrIDList(ic, ic->private.proto.ic_resources,
358				ic->private.proto.ic_num_resources, arg,
359				&buf_s[3], &len, XIM_GETICVALUES);
360
361    if (len > 0) {
362	buf_s[0] = im->private.proto.imid;		/* imid */
363	buf_s[1] = ic->private.proto.icid;		/* icid */
364	buf_s[2] = len;				/* length of ic-attr-id */
365	len += sizeof(INT16);                       /* sizeof length of attr */
366	XIM_SET_PAD(&buf_s[2], len);		/* pad */
367	len += sizeof(CARD16)			/* sizeof imid */
368	     + sizeof(CARD16);			/* sizeof icid */
369
370	_XimSetHeader((XPointer)buf, XIM_GET_IC_VALUES, 0, &len);
371	if (!(_XimWrite(im, len, (XPointer)buf))) {
372	    Xfree(buf);
373	    return arg->name;
374	}
375	_XimFlush(im);
376	Xfree(buf);
377	buf_size = BUFSIZE;
378	ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
379				 _XimGetICValuesCheck, (XPointer)ic);
380	if (ret_code == XIM_TRUE) {
381	    preply = reply;
382	} else if (ret_code == XIM_OVERFLOW) {
383	    if (len <= 0) {
384		preply = reply;
385	    } else {
386		buf_size = (int)len;
387		preply = Xmalloc(len);
388		ret_code = _XimRead(im, &len, preply, buf_size,
389				_XimGetICValuesCheck, (XPointer)ic);
390		if (ret_code != XIM_TRUE) {
391		    if (preply != reply)
392		        Xfree(preply);
393		    return arg->name;
394		}
395	    }
396	} else {
397	    return arg->name;
398	}
399	buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
400	if (*((CARD8 *)preply) == XIM_ERROR) {
401	    _XimProcError(im, 0, (XPointer)&buf_s[3]);
402	    if (reply != preply)
403		Xfree(preply);
404	    return arg->name;
405	}
406	data = &buf_s[4];
407	data_len = buf_s[2];
408    }
409    else if (len < 0) {
410	return arg->name;
411    }
412
413    decode_name = _XimDecodeICATTRIBUTE(ic, ic->private.proto.ic_resources,
414			ic->private.proto.ic_num_resources, data, data_len,
415			arg, XIM_GETICVALUES);
416    if (reply != preply)
417	Xfree(preply);
418
419    if (decode_name)
420	return decode_name;
421    else
422	return makeid_name;
423}
424
425#ifdef XIM_CONNECTABLE
426static Bool
427_XimCheckNestQuarkList(quark_list, num_quark, quark, separator)
428    XrmQuark		*quark_list;
429    int			 num_quark;
430    XrmQuark		 quark;
431    XrmQuark		 separator;
432{
433    register int	 i;
434
435    for (i = 0; i < num_quark; i++) {
436	if (quark_list[i] == separator) {
437	    break;
438	}
439	if (quark_list[i] == quark) {
440	    return True;
441	}
442    }
443    return False;
444}
445
446static Bool
447_XimCheckNestedQuarkList(quark_list, idx, num_quark, arg, separator)
448    XrmQuark		**quark_list;
449    int			  idx;
450    int			 *num_quark;
451    XIMArg		 *arg;
452    XrmQuark		  separator;
453{
454    XrmQuark		 *q_list = *quark_list;
455    int			  n_quark = *num_quark;
456    register XIMArg	 *p;
457    XrmQuark		  quark;
458    XrmQuark		 *tmp;
459    register int	  i;
460
461    for (p = arg; p && p->name; p++) {
462	quark = XrmStringToQuark(p->name);
463	if (_XimCheckNestQuarkList(&q_list[idx], n_quark - idx,
464							quark, separator)) {
465	    continue;
466	}
467	if (!(tmp = Xmalloc((sizeof(XrmQuark) * (n_quark + 1))))) {
468	    *quark_list = q_list;
469	    *num_quark = n_quark;
470	    return False;
471	}
472	n_quark++;
473	for (i = 0; i < idx; i++) {
474	    tmp[i] = q_list[i];
475	}
476	tmp[i] = quark;
477	for (i = idx  + 1; i < n_quark; i++) {
478	    tmp[i] = q_list[i - 1];
479	}
480	q_list = tmp;
481    }
482    *quark_list = q_list;
483    *num_quark = n_quark;
484    return True;
485}
486
487static Bool
488_XimCheckICQuarkList(quark_list, num_quark, quark, idx)
489    XrmQuark		*quark_list;
490    int			 num_quark;
491    XrmQuark		 quark;
492    int			*idx;
493{
494    register int	 i;
495
496    for (i = 0; i < num_quark; i++) {
497	if (quark_list[i] == quark) {
498	    *idx = i;
499	    return True;
500	}
501    }
502    return False;
503}
504
505static Bool
506_XimSaveICValues(ic, arg)
507    Xic			 ic;
508    XIMArg		*arg;
509{
510    register XIMArg	*p;
511    register int	 n;
512    XrmQuark		*quark_list;
513    XrmQuark		*tmp;
514    XrmQuark		 quark;
515    int			 num_quark;
516    XrmQuark		 pre_quark;
517    XrmQuark		 sts_quark;
518    XrmQuark		 separator;
519    int			 idx;
520
521    pre_quark = XrmStringToQuark(XNPreeditAttributes);
522    sts_quark = XrmStringToQuark(XNStatusAttributes);
523    separator = XrmStringToQuark(XNSeparatorofNestedList);
524
525    if (quark_list = ic->private.proto.saved_icvalues) {
526	num_quark = ic->private.proto.num_saved_icvalues;
527	for (p = arg; p && p->name; p++) {
528	    quark = XrmStringToQuark(p->name);
529	    if ((quark == pre_quark) || (quark == sts_quark)) {
530	        if (!_XimCheckICQuarkList(quark_list, num_quark, quark, &idx)) {
531		    register XIMArg	*pp;
532		    int			 nn;
533		    XrmQuark		*q_list;
534
535		    for (pp = (XIMArg *)p->value, nn = 0;
536						pp && pp->name; pp++, nn++);
537	            if (!(tmp = Xrealloc(quark_list,
538				(sizeof(XrmQuark) * (num_quark + nn + 2))))) {
539		        ic->private.proto.saved_icvalues = quark_list;
540		        ic->private.proto.num_saved_icvalues = num_quark;
541		        return False;
542	            }
543	            quark_list = tmp;
544		    q_list = &quark_list[num_quark];
545	            num_quark += nn + 2;
546		    *q_list++ = quark;
547		    for (pp = (XIMArg *)p->value;
548					pp && pp->name; pp++, quark_list++) {
549			*q_list = XrmStringToQuark(pp->name);
550		    }
551		    *q_list = separator;
552		} else {
553		    if (!_XimCheckNestedQuarkList(&quark_list, idx + 1,
554				&num_quark, (XIMArg *)p->value, separator)) {
555		        ic->private.proto.saved_icvalues = quark_list;
556		        ic->private.proto.num_saved_icvalues = num_quark;
557		        return False;
558		    }
559		}
560	    } else {
561	        if (_XimCheckICQuarkList(quark_list, num_quark, quark, &idx)) {
562		    continue;
563	        }
564	        if (!(tmp = Xrealloc(quark_list,
565				(sizeof(XrmQuark) * (num_quark + 1))))) {
566		    ic->private.proto.saved_icvalues = quark_list;
567		    ic->private.proto.num_saved_icvalues = num_quark;
568		    return False;
569	        }
570	        quark_list = tmp;
571	        quark_list[num_quark] = quark;
572	        num_quark++;
573	    }
574	}
575	ic->private.proto.saved_icvalues = quark_list;
576	ic->private.proto.num_saved_icvalues = num_quark;
577	return True;
578    }
579
580    for (p = arg, n = 0; p && p->name; p++, n++) {
581	if ((!strcmp(p->name, XNPreeditAttributes))
582	 || (!strcmp(p->name, XNStatusAttributes))) {
583	    register XIMArg	*pp;
584	    int			 nn;
585
586	    for (pp = (XIMArg *)p->value, nn = 0; pp && pp->name; pp++, nn++);
587	    n += nn + 1;
588	}
589    }
590
591    if (!(quark_list = Xmalloc(sizeof(XrmQuark) * n))) {
592	return False;
593    }
594
595    ic->private.proto.saved_icvalues = quark_list;
596    ic->private.proto.num_saved_icvalues = n;
597    for (p = arg; p && p->name; p++, quark_list++) {
598	*quark_list = XrmStringToQuark(p->name);
599	if ((*quark_list == pre_quark) || (*quark_list == sts_quark)) {
600	    register XIMArg	*pp;
601
602	    quark_list++;
603	    for (pp = (XIMArg *)p->value; pp && pp->name; pp++, quark_list++) {
604		*quark_list = XrmStringToQuark(pp->name);
605	    }
606	    *quark_list = separator;
607	}
608    }
609    return True;
610}
611
612static char *
613_XimDelayModeSetICValues(ic, arg)
614    Xic			 ic;
615    XIMArg		*arg;
616{
617    XimDefICValues	 ic_values;
618    char		*name;
619
620    _XimGetCurrentICValues(ic, &ic_values);
621    name = _XimSetICValueData(ic, (XPointer)&ic_values,
622			ic->private.proto.ic_resources,
623			ic->private.proto.ic_num_resources,
624			arg, XIM_SETICVALUES, False);
625    _XimSetCurrentICValues(ic, &ic_values);
626    return name;
627}
628#endif /* XIM_CONNECTABLE */
629
630static Bool
631_XimSetICValuesCheck(
632    Xim          im,
633    INT16        len,
634    XPointer	 data,
635    XPointer     arg)
636{
637    Xic		 ic = (Xic)arg;
638    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
639    CARD8	 major_opcode = *((CARD8 *)data);
640    CARD8	 minor_opcode = *((CARD8 *)data + 1);
641    XIMID	 imid = buf_s[0];
642    XICID	 icid = buf_s[1];
643
644    if ((major_opcode == XIM_SET_IC_VALUES_REPLY)
645     && (minor_opcode == 0)
646     && (imid == im->private.proto.imid)
647     && (icid == ic->private.proto.icid))
648	return True;
649    if ((major_opcode == XIM_ERROR)
650     && (minor_opcode == 0)
651     && (buf_s[2] & XIM_IMID_VALID)
652     && (imid == im->private.proto.imid)
653     && (buf_s[2] & XIM_ICID_VALID)
654     && (icid == ic->private.proto.icid))
655	return True;
656    return False;
657}
658
659static char *
660_XimProtoSetICValues(
661    XIC			 xic,
662    XIMArg		*arg)
663{
664    Xic			 ic = (Xic)xic;
665    Xim			 im = (Xim)ic->core.im;
666    XimDefICValues	 ic_values;
667    INT16		 len;
668    CARD16		*buf_s;
669    char		*tmp;
670    CARD32		 tmp_buf32[BUFSIZE/4];
671    char		*tmp_buf = (char *)tmp_buf32;
672    char		*buf;
673    int			 buf_size;
674    char		*data;
675    int			 data_len;
676    int			 ret_len;
677    int			 total;
678    XIMArg		*arg_ret;
679    CARD32		 reply32[BUFSIZE/4];
680    char		*reply = (char *)reply32;
681    XPointer		 preply = NULL;
682    int			 ret_code;
683    BITMASK32		 flag = 0L;
684    char		*name;
685    char		*tmp_name = (arg) ? arg->name : NULL;
686
687#ifndef XIM_CONNECTABLE
688    if (!IS_IC_CONNECTED(ic))
689	return tmp_name;
690#else
691    if (!_XimSaveICValues(ic, arg))
692	return NULL;
693
694    if (!IS_IC_CONNECTED(ic)) {
695	if (IS_CONNECTABLE(im)) {
696	    if (_XimConnectServer(im)) {
697	        if (!_XimReCreateIC(ic)) {
698		    _XimDelayModeSetAttr(im);
699	            return _XimDelayModeSetICValues(ic, arg);
700		}
701	    } else {
702	        return _XimDelayModeSetICValues(ic, arg);
703	    }
704        } else {
705	    return tmp_name;
706        }
707    }
708#endif /* XIM_CONNECTABLE */
709
710    _XimGetCurrentICValues(ic, &ic_values);
711    memset(tmp_buf, 0, sizeof(tmp_buf32));
712    buf = tmp_buf;
713    buf_size = XIM_HEADER_SIZE
714	+ sizeof(CARD16) + sizeof(CARD16) + sizeof(INT16) + sizeof(CARD16);
715    data_len = BUFSIZE - buf_size;
716    total = 0;
717    arg_ret = arg;
718    for (;;) {
719	data = &buf[buf_size];
720	if ((name = _XimEncodeICATTRIBUTE(ic, ic->private.proto.ic_resources,
721			ic->private.proto.ic_num_resources, arg, &arg_ret,
722			data, data_len, &ret_len, (XPointer)&ic_values,
723			&flag, XIM_SETICVALUES))) {
724	    break;
725	}
726
727	total += ret_len;
728	if (!(arg = arg_ret)) {
729	    break;
730	}
731
732	buf_size += ret_len;
733	if (buf == tmp_buf) {
734	    if (!(tmp = Xcalloc(buf_size + data_len, 1))) {
735		return tmp_name;
736	    }
737	    memcpy(tmp, buf, buf_size);
738	    buf = tmp;
739	} else {
740	    if (!(tmp = Xrealloc(buf, (buf_size + data_len)))) {
741		Xfree(buf);
742		return tmp_name;
743	    }
744            memset(&tmp[buf_size], 0, data_len);
745	    buf = tmp;
746	}
747    }
748    _XimSetCurrentICValues(ic, &ic_values);
749
750    if (!total) {
751        return tmp_name;
752    }
753
754    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
755
756#ifdef EXT_MOVE
757    if (_XimExtenMove(im, ic, flag, &buf_s[4], (INT16)total))
758	return name;
759#endif
760
761    buf_s[0] = im->private.proto.imid;
762    buf_s[1] = ic->private.proto.icid;
763    buf_s[2] = (INT16)total;
764    buf_s[3] = 0;
765    len = (INT16)(sizeof(CARD16) + sizeof(CARD16)
766				+ sizeof(INT16) + sizeof(CARD16) + total);
767
768    _XimSetHeader((XPointer)buf, XIM_SET_IC_VALUES, 0, &len);
769    if (!(_XimWrite(im, len, (XPointer)buf))) {
770	if (buf != tmp_buf)
771	    Xfree(buf);
772	return tmp_name;
773    }
774    _XimFlush(im);
775    if (buf != tmp_buf)
776	Xfree(buf);
777    ic->private.proto.waitCallback = True;
778    buf_size = BUFSIZE;
779    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
780					_XimSetICValuesCheck, (XPointer)ic);
781    if (ret_code == XIM_TRUE) {
782	preply = reply;
783    } else if (ret_code == XIM_OVERFLOW) {
784	buf_size = (int)len;
785	preply = Xmalloc(buf_size);
786	ret_code = _XimRead(im, &len, preply, buf_size,
787					_XimSetICValuesCheck, (XPointer)ic);
788	if (ret_code != XIM_TRUE) {
789	    Xfree(preply);
790	    ic->private.proto.waitCallback = False;
791	    return tmp_name;
792	}
793    } else {
794	ic->private.proto.waitCallback = False;
795	return tmp_name;
796    }
797    ic->private.proto.waitCallback = False;
798    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
799    if (*((CARD8 *)preply) == XIM_ERROR) {
800	_XimProcError(im, 0, (XPointer)&buf_s[3]);
801	if (reply != preply)
802	    Xfree(preply);
803	return tmp_name;
804    }
805    if (reply != preply)
806	Xfree(preply);
807
808    return name;
809}
810
811static Bool
812_XimDestroyICCheck(
813    Xim          im,
814    INT16        len,
815    XPointer	 data,
816    XPointer     arg)
817{
818    Xic		 ic = (Xic)arg;
819    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
820    CARD8	 major_opcode = *((CARD8 *)data);
821    CARD8	 minor_opcode = *((CARD8 *)data + 1);
822    XIMID	 imid = buf_s[0];
823    XICID	 icid = buf_s[1];
824    Bool	 ret = False;
825
826    if ((major_opcode == XIM_DESTROY_IC_REPLY)
827     && (minor_opcode == 0)
828     && (imid == im->private.proto.imid)
829     && (icid == ic->private.proto.icid))
830	ret = True;
831    if ((major_opcode == XIM_ERROR)
832     && (minor_opcode == 0)
833     && (buf_s[2] & XIM_IMID_VALID)
834     && (imid == im->private.proto.imid)
835     && (buf_s[2] & XIM_ICID_VALID)
836     && (icid == ic->private.proto.icid))
837        ret = False;
838    return ret;
839}
840
841static void
842_XimProtoICFree(
843    Xic		 ic)
844{
845#ifdef XIM_CONNECTABLE
846    Xim		 im = (Xim)ic->core.im;
847#endif
848
849
850    Xfree(ic->private.proto.preedit_font);
851    ic->private.proto.preedit_font = NULL;
852
853
854    Xfree(ic->private.proto.status_font);
855    ic->private.proto.status_font = NULL;
856
857    if (ic->private.proto.commit_info) {
858	_XimFreeCommitInfo(ic);
859	ic->private.proto.commit_info = NULL;
860    }
861
862    Xfree(ic->private.proto.ic_inner_resources);
863    ic->private.proto.ic_inner_resources = NULL;
864
865
866#ifdef XIM_CONNECTABLE
867    if (IS_SERVER_CONNECTED(im) && IS_RECONNECTABLE(im)) {
868	return;
869    }
870#endif /* XIM_CONNECTABLE */
871
872
873    Xfree(ic->private.proto.saved_icvalues);
874    ic->private.proto.saved_icvalues = NULL;
875
876
877    Xfree(ic->private.proto.ic_resources);
878    ic->private.proto.ic_resources = NULL;
879
880
881    Xfree(ic->core.hotkey);
882    ic->core.hotkey = NULL;
883
884
885    return;
886}
887
888static void
889_XimProtoDestroyIC(
890    XIC		 xic)
891{
892    Xic		 ic = (Xic)xic;
893    Xim	 	 im = (Xim)ic->core.im;
894    CARD32	 buf32[BUFSIZE/4];
895    CARD8	*buf = (CARD8 *)buf32;
896    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
897    INT16	 len;
898    CARD32	 reply32[BUFSIZE/4];
899    char	*reply = (char *)reply32;
900    XPointer	 preply;
901    int		 buf_size;
902    int		 ret_code;
903
904    if (IS_SERVER_CONNECTED(im)) {
905	buf_s[0] = im->private.proto.imid;		/* imid */
906	buf_s[1] = ic->private.proto.icid;		/* icid */
907
908	len = sizeof(CARD16)			/* sizeof imid */
909	    + sizeof(CARD16);			/* sizeof icid */
910
911	_XimSetHeader((XPointer)buf, XIM_DESTROY_IC, 0, &len);
912	(void)_XimWrite(im, len, (XPointer)buf);
913	_XimFlush(im);
914	buf_size = BUFSIZE;
915	ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
916					_XimDestroyICCheck, (XPointer)ic);
917	if (ret_code == XIM_OVERFLOW) {
918	    buf_size = len;
919	    preply = Xmalloc(buf_size);
920	    (void)_XimRead(im, &len, preply, buf_size,
921					_XimDestroyICCheck, (XPointer)ic);
922	    Xfree(preply);
923	}
924    }
925    UNMARK_IC_CONNECTED(ic);
926    _XimUnregisterFilter(ic);
927    _XimProtoICFree(ic);
928    return;
929}
930
931/*
932 * Some functions require the request queue from the server to be flushed
933 * so that the ordering of client initiated status changes and those requested
934 * by the server is well defined.
935 * _XimSync() would be the function of choice here as it should get a
936 * XIM_SYNC_REPLY back from the server.
937 * This however isn't implemented in the piece of junk that is used by most
938 * input servers as the server side protocol if to XIM.
939 * Since this code is not shipped as a library together with the client side
940 * XIM code but is duplicated by every input server around the world there
941 * is no easy fix to this but this ugly hack below.
942 * Obtaining an IC value from the server sends a request and empties out the
943 * event/server request queue until the answer to this request is found.
944 * Thus it is guaranteed that any pending server side request gets processed.
945 * This is what the hack below is doing.
946 */
947
948static void
949BrokenSyncWithServer(XIC xic)
950{
951    CARD32 dummy;
952    XGetICValues(xic, XNFilterEvents, &dummy, NULL);
953}
954
955static void
956_XimProtoSetFocus(
957    XIC		 xic)
958{
959    Xic		 ic = (Xic)xic;
960    Xim		 im = (Xim)ic->core.im;
961    CARD32	 buf32[BUFSIZE/4];
962    CARD8	*buf = (CARD8 *)buf32;
963    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
964    INT16	 len;
965
966#ifndef XIM_CONNECTABLE
967    if (!IS_IC_CONNECTED(ic))
968	return;
969#else
970    if (!IS_IC_CONNECTED(ic)) {
971	if (IS_CONNECTABLE(im)) {
972	    if (_XimConnectServer(im)) {
973		if (!_XimReCreateIC(ic)) {
974		    _XimDelayModeSetAttr(im);
975		    return;
976		}
977	    } else {
978		return;
979	    }
980	} else {
981	    return;
982	}
983    }
984#endif /* XIM_CONNECTABLE */
985    BrokenSyncWithServer(xic);
986
987    buf_s[0] = im->private.proto.imid;		/* imid */
988    buf_s[1] = ic->private.proto.icid;		/* icid */
989
990    len = sizeof(CARD16)			/* sizeof imid */
991	+ sizeof(CARD16);			/* sizeof icid */
992
993    _XimSetHeader((XPointer)buf, XIM_SET_IC_FOCUS, 0, &len);
994    (void)_XimWrite(im, len, (XPointer)buf);
995    _XimFlush(im);
996
997    _XimRegisterFilter(ic);
998    return;
999}
1000
1001static void
1002_XimProtoUnsetFocus(
1003    XIC		 xic)
1004{
1005    Xic		 ic = (Xic)xic;
1006    Xim		 im = (Xim)ic->core.im;
1007    CARD32	 buf32[BUFSIZE/4];
1008    CARD8	*buf = (CARD8 *)buf32;
1009    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
1010    INT16	 len;
1011
1012#ifndef XIM_CONNECTABLE
1013    if (!IS_IC_CONNECTED(ic))
1014	return;
1015#else
1016    if (!IS_IC_CONNECTED(ic)) {
1017	if (IS_CONNECTABLE(im)) {
1018	    if (_XimConnectServer(im)) {
1019		if (!_XimReCreateIC(ic)) {
1020		    _XimDelayModeSetAttr(im);
1021		    return;
1022		}
1023	    } else {
1024		return;
1025	    }
1026	} else {
1027	    return;
1028	}
1029    }
1030#endif /* XIM_CONNECTABLE */
1031
1032    BrokenSyncWithServer(xic);
1033
1034    buf_s[0] = im->private.proto.imid;		/* imid */
1035    buf_s[1] = ic->private.proto.icid;		/* icid */
1036
1037    len = sizeof(CARD16)			/* sizeof imid */
1038	+ sizeof(CARD16);			/* sizeof icid */
1039
1040    _XimSetHeader((XPointer)buf, XIM_UNSET_IC_FOCUS, 0, &len);
1041    (void)_XimWrite(im, len, (XPointer)buf);
1042    _XimFlush(im);
1043
1044    _XimUnregisterFilter(ic);
1045    return;
1046}
1047
1048static Bool
1049_XimResetICCheck(
1050    Xim          im,
1051    INT16        len,
1052    XPointer	 data,
1053    XPointer     arg)
1054{
1055    Xic		 ic = (Xic)arg;
1056    CARD16	*buf_s = (CARD16 *)((CARD8 *)data + XIM_HEADER_SIZE);
1057    CARD8	 major_opcode = *((CARD8 *)data);
1058    CARD8	 minor_opcode = *((CARD8 *)data + 1);
1059    XIMID	 imid = buf_s[0];
1060    XICID	 icid = buf_s[1];
1061
1062    if ((major_opcode == XIM_RESET_IC_REPLY)
1063     && (minor_opcode == 0)
1064     && (imid == im->private.proto.imid)
1065     && (icid == ic->private.proto.icid))
1066	return True;
1067    if ((major_opcode == XIM_ERROR)
1068     && (minor_opcode == 0)
1069     && (buf_s[2] & XIM_IMID_VALID)
1070     && (imid == im->private.proto.imid)
1071     && (buf_s[2] & XIM_ICID_VALID)
1072     && (icid == ic->private.proto.icid))
1073	return True;
1074    return False;
1075}
1076
1077static char *
1078_XimProtoReset(
1079    XIC		 xic,
1080    char *     (*retfunc) (Xim im, Xic ic, XPointer buf) )
1081{
1082    Xic		 ic = (Xic)xic;
1083    Xim	 	 im = (Xim)ic->core.im;
1084    CARD32	 buf32[BUFSIZE/4];
1085    CARD8	*buf = (CARD8 *)buf32;
1086    CARD16	*buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
1087    INT16	 len;
1088    CARD32	 reply32[BUFSIZE/4];
1089    char	*reply = (char *)reply32;
1090    XPointer	 preply;
1091    int		 buf_size;
1092    int		 ret_code;
1093    char	*commit;
1094
1095    if (!IS_IC_CONNECTED(ic))
1096	return (char *)NULL;
1097
1098    buf_s[0] = im->private.proto.imid;		/* imid */
1099    buf_s[1] = ic->private.proto.icid;		/* icid */
1100
1101    len = sizeof(CARD16)			/* sizeof imid */
1102	+ sizeof(CARD16);			/* sizeof icid */
1103
1104    _XimSetHeader((XPointer)buf, XIM_RESET_IC, 0, &len);
1105    if (!(_XimWrite(im, len, (XPointer)buf)))
1106	return NULL;
1107    _XimFlush(im);
1108    ic->private.proto.waitCallback = True;
1109    buf_size = BUFSIZE;
1110    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
1111    					_XimResetICCheck, (XPointer)ic);
1112    if (ret_code == XIM_TRUE) {
1113    	preply = reply;
1114    } else if (ret_code == XIM_OVERFLOW) {
1115    	if (len < 0) {
1116    	    preply = reply;
1117    	} else {
1118    	    buf_size = len;
1119	    preply = Xmalloc(buf_size);
1120    	    ret_code = _XimRead(im, &len, preply, buf_size,
1121    					_XimResetICCheck, (XPointer)ic);
1122    	    if (ret_code != XIM_TRUE) {
1123		Xfree(preply);
1124    		ic->private.proto.waitCallback = False;
1125    		return NULL;
1126    	    }
1127    	}
1128    } else {
1129	ic->private.proto.waitCallback = False;
1130	return NULL;
1131    }
1132    ic->private.proto.waitCallback = False;
1133    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
1134    if (*((CARD8 *)preply) == XIM_ERROR) {
1135	_XimProcError(im, 0, (XPointer)&buf_s[3]);
1136    	if (reply != preply)
1137    	    free(preply);
1138	return NULL;
1139    }
1140
1141    commit = retfunc(im, ic, (XPointer)&buf_s[2]);
1142
1143    if (reply != preply)
1144    	Xfree(preply);
1145    return commit;
1146}
1147
1148static char *
1149_XimCommitedMbString(
1150    Xim			 im,
1151    Xic			 ic,
1152    XPointer		 buf)
1153{
1154    CARD16		*buf_s = (CARD16 *)buf;
1155    XimCommitInfo	 info;
1156    int			 len;
1157    int			 new_len;
1158    char		*commit;
1159    char		*new_commit = NULL;
1160    char		*str;
1161    Status		 status;
1162
1163    len = 0;
1164    for (info = ic->private.proto.commit_info; info; info = info->next)
1165	len += info->string_len;
1166    len += buf_s[0];
1167    if ( len == 0 )
1168	return( NULL );
1169
1170    if (!(commit = Xmalloc(len + 1)))
1171	goto Error_On_Reset;
1172
1173    str = commit;
1174    for (info = ic->private.proto.commit_info; info; info = info->next) {
1175	(void)memcpy(str, info->string, info->string_len);
1176	str += info->string_len;
1177    }
1178    (void)memcpy(str, (char *)&buf_s[1], buf_s[0]);
1179    commit[len] = '\0';
1180
1181    new_len = im->methods->ctstombs((XIM)im, commit, len, NULL, 0, &status);
1182    if (status != XLookupNone) {
1183	if (!(new_commit = Xmalloc(new_len + 1))) {
1184	    Xfree(commit);
1185	    goto Error_On_Reset;
1186	}
1187	(void)im->methods->ctstombs((XIM)im, commit, len,
1188						new_commit, new_len, NULL);
1189	new_commit[new_len] = '\0';
1190    }
1191    Xfree(commit);
1192
1193Error_On_Reset:
1194    _XimFreeCommitInfo( ic );
1195    return new_commit;
1196}
1197
1198static char *
1199_XimProtoMbReset(
1200    XIC		 xic)
1201{
1202    return _XimProtoReset(xic, _XimCommitedMbString);
1203}
1204
1205static wchar_t *
1206_XimCommitedWcString(
1207    Xim		 im,
1208    Xic		 ic,
1209    XPointer	 buf)
1210{
1211    CARD16		*buf_s = (CARD16 *)buf;
1212    XimCommitInfo	 info;
1213    int			 len;
1214    int			 new_len;
1215    char		*commit;
1216    wchar_t		*new_commit = (wchar_t *)NULL;
1217    char		*str;
1218    Status		 status;
1219
1220    len = 0;
1221    for (info = ic->private.proto.commit_info; info; info = info->next)
1222	len += info->string_len;
1223    len += buf_s[0];
1224    if ( len == 0 )
1225	return( (wchar_t *)NULL );
1226
1227    if (!(commit = Xmalloc(len + 1)))
1228	goto Error_On_Reset;
1229
1230    str = commit;
1231    for (info = ic->private.proto.commit_info; info; info = info->next) {
1232	(void)memcpy(str, info->string, info->string_len);
1233	str += info->string_len;
1234    }
1235    (void)memcpy(str, (char *)&buf_s[1], buf_s[0]);
1236    commit[len] = '\0';
1237
1238    new_len = im->methods->ctstowcs((XIM)im, commit, len, NULL, 0, &status);
1239    if (status != XLookupNone) {
1240	if (!(new_commit =
1241		     (wchar_t *)Xmalloc(sizeof(wchar_t) * (new_len + 1)))) {
1242	    Xfree(commit);
1243	    goto Error_On_Reset;
1244	}
1245	(void)im->methods->ctstowcs((XIM)im, commit, len,
1246						new_commit, new_len, NULL);
1247	new_commit[new_len] = (wchar_t)'\0';
1248    }
1249    Xfree(commit);
1250
1251Error_On_Reset:
1252    _XimFreeCommitInfo( ic );
1253    return new_commit;
1254}
1255
1256static wchar_t *
1257_XimProtoWcReset(
1258    XIC		 xic)
1259{
1260    return (wchar_t *) _XimProtoReset(xic,
1261			(char * (*) (Xim, Xic, XPointer)) _XimCommitedWcString);
1262}
1263
1264static char *
1265_XimCommitedUtf8String(
1266    Xim			 im,
1267    Xic			 ic,
1268    XPointer		 buf)
1269{
1270    CARD16		*buf_s = (CARD16 *)buf;
1271    XimCommitInfo	 info;
1272    int			 len;
1273    int			 new_len;
1274    char		*commit;
1275    char		*new_commit = NULL;
1276    char		*str;
1277    Status		 status;
1278
1279    len = 0;
1280    for (info = ic->private.proto.commit_info; info; info = info->next)
1281	len += info->string_len;
1282    len += buf_s[0];
1283    if ( len == 0 )
1284	return( NULL );
1285
1286    if (!(commit = Xmalloc(len + 1)))
1287	goto Error_On_Reset;
1288
1289    str = commit;
1290    for (info = ic->private.proto.commit_info; info; info = info->next) {
1291	(void)memcpy(str, info->string, info->string_len);
1292	str += info->string_len;
1293    }
1294    (void)memcpy(str, (char *)&buf_s[1], buf_s[0]);
1295    commit[len] = '\0';
1296
1297    new_len = im->methods->ctstoutf8((XIM)im, commit, len, NULL, 0, &status);
1298    if (status != XLookupNone) {
1299	if (!(new_commit = Xmalloc(new_len + 1))) {
1300	    Xfree(commit);
1301	    goto Error_On_Reset;
1302	}
1303	(void)im->methods->ctstoutf8((XIM)im, commit, len,
1304						new_commit, new_len, NULL);
1305	new_commit[new_len] = '\0';
1306    }
1307    Xfree(commit);
1308
1309Error_On_Reset:
1310    _XimFreeCommitInfo( ic );
1311    return new_commit;
1312}
1313
1314static char *
1315_XimProtoUtf8Reset(
1316    XIC		 xic)
1317{
1318    return _XimProtoReset(xic, _XimCommitedUtf8String);
1319}
1320
1321static XICMethodsRec ic_methods = {
1322    _XimProtoDestroyIC,		/* destroy */
1323    _XimProtoSetFocus,		/* set_focus */
1324    _XimProtoUnsetFocus,	/* unset_focus */
1325    _XimProtoSetICValues,	/* set_values */
1326    _XimProtoGetICValues,	/* get_values */
1327    _XimProtoMbReset,		/* mb_reset */
1328    _XimProtoWcReset,		/* wc_reset */
1329    _XimProtoUtf8Reset,		/* utf8_reset */
1330    _XimProtoMbLookupString,	/* mb_lookup_string */
1331    _XimProtoWcLookupString,	/* wc_lookup_string */
1332    _XimProtoUtf8LookupString	/* utf8_lookup_string */
1333};
1334
1335static Bool
1336_XimGetInputStyle(
1337    XIMArg		*arg,
1338    XIMStyle		*input_style)
1339{
1340    register XIMArg	*p;
1341
1342    for (p = arg; p && p->name; p++) {
1343	if (!(strcmp(p->name, XNInputStyle))) {
1344	    *input_style = (XIMStyle)p->value;
1345	    return True;
1346	}
1347    }
1348    return False;
1349}
1350
1351#ifdef XIM_CONNECTABLE
1352static Bool
1353_XimDelayModeCreateIC(
1354    Xic			 ic,
1355    XIMArg		*values,
1356    XIMResourceList	 res,
1357    unsigned int	 num)
1358{
1359    Xim			 im = (Xim)ic->core.im;
1360    XimDefICValues	 ic_values;
1361    int			 len;
1362    XIMStyle		 input_style;
1363
1364    bzero((char *)&ic_values, sizeof(XimDefICValues));
1365    _XimGetCurrentICValues(ic, &ic_values);
1366    if (!(_XimGetInputStyle(values, &input_style)))
1367	return False;
1368
1369    _XimSetICMode(res, num, input_style);
1370
1371    if (_XimSetICValueData(ic, (XPointer)&ic_values, res, num,
1372					values, XIM_CREATEIC, False)) {
1373	return False;
1374    }
1375    _XimSetCurrentICValues(ic, &ic_values);
1376    if (!_XimSetICDefaults(ic, (XPointer)&ic_values,
1377					XIM_SETICDEFAULTS, res, num)) {
1378	return False;
1379    }
1380    ic_values.filter_events = KeyPressMask;
1381    _XimSetCurrentICValues(ic, &ic_values);
1382    _XimRegisterFilter(ic);
1383
1384    return True;
1385}
1386
1387Bool
1388_XimReconnectModeCreateIC(ic)
1389    Xic			 ic;
1390{
1391    Xim			 im = (Xim)ic->core.im;
1392    int			 len;
1393    XIMStyle		 input_style = ic->core.input_style;
1394    XIMResourceList	 res;
1395    unsigned int	 num;
1396
1397    num = im->core.ic_num_resources;
1398    len = sizeof(XIMResource) * num;
1399    if (!(res = Xmalloc(len)))
1400	return False;
1401    (void)memcpy((char *)res, (char *)im->core.ic_resources, len);
1402    ic->private.proto.ic_resources     = res;
1403    ic->private.proto.ic_num_resources = num;
1404
1405    _XimSetICMode(res, num, input_style);
1406
1407    ic->core.filter_events = KeyPressMask;
1408
1409    return True;
1410}
1411#endif /* XIM_CONNECTABLE */
1412
1413XIC
1414_XimProtoCreateIC(
1415    XIM			 xim,
1416    XIMArg		*arg)
1417{
1418    Xim			 im = (Xim)xim;
1419    Xic			 ic;
1420    XimDefICValues	 ic_values;
1421    XIMResourceList	 res;
1422    unsigned int         num;
1423    XIMStyle		 input_style;
1424    INT16		 len;
1425    CARD16		*buf_s;
1426    char		*tmp;
1427    CARD32		 tmp_buf32[BUFSIZE/4];
1428    char		*tmp_buf = (char *)tmp_buf32;
1429    char		*buf;
1430    int			 buf_size;
1431    char		*data;
1432    int			 data_len;
1433    int			 ret_len;
1434    int			 total;
1435    XIMArg		*arg_ret;
1436    CARD32		 reply32[BUFSIZE/4];
1437    char		*reply = (char *)reply32;
1438    XPointer		 preply;
1439    int			 ret_code;
1440
1441#ifdef XIM_CONNECTABLE
1442    if (!IS_SERVER_CONNECTED(im) && !IS_CONNECTABLE(im))
1443	return (XIC)NULL;
1444#else
1445    if (!IS_SERVER_CONNECTED(im))
1446	return (XIC)NULL;
1447#endif /* XIM_CONNECTABLE */
1448
1449    if (!(_XimGetInputStyle(arg, &input_style)))
1450	return (XIC)NULL;
1451
1452    if ((ic = Xcalloc(1, sizeof(XicRec))) == (Xic)NULL)
1453	return (XIC)NULL;
1454
1455    ic->methods = &ic_methods;
1456    ic->core.im = (XIM)im;
1457    ic->core.input_style = input_style;
1458
1459    num = im->core.ic_num_resources;
1460    len = sizeof(XIMResource) * num;
1461    if (!(res = Xmalloc(len)))
1462	goto ErrorOnCreatingIC;
1463    (void)memcpy((char *)res, (char *)im->core.ic_resources, len);
1464    ic->private.proto.ic_resources     = res;
1465    ic->private.proto.ic_num_resources = num;
1466
1467#ifdef XIM_CONNECTABLE
1468    if (!_XimSaveICValues(ic, arg))
1469	return False;
1470
1471    if (!IS_SERVER_CONNECTED(im)) {
1472	if (!_XimConnectServer(im)) {
1473	    if (_XimDelayModeCreateIC(ic, arg, res, num)) {
1474		return (XIC)ic;
1475	    }
1476	    goto ErrorOnCreatingIC;
1477	}
1478    }
1479#endif /* XIM_CONNECTABLE */
1480
1481    ic->core.filter_events = im->private.proto.forward_event_mask;
1482    ic->private.proto.forward_event_mask =
1483				im->private.proto.forward_event_mask;
1484    ic->private.proto.synchronous_event_mask =
1485				im->private.proto.synchronous_event_mask;
1486
1487    num = im->private.proto.ic_num_inner_resources;
1488    len = sizeof(XIMResource) * num;
1489    if (!(res = Xmalloc(len)))
1490	goto ErrorOnCreatingIC;
1491    (void)memcpy((char *)res,
1492			 (char *)im->private.proto.ic_inner_resources, len);
1493    ic->private.proto.ic_inner_resources     = res;
1494    ic->private.proto.ic_num_inner_resources = num;
1495
1496    _XimSetICMode(ic->private.proto.ic_resources,
1497			ic->private.proto.ic_num_resources, input_style);
1498
1499    _XimSetICMode(ic->private.proto.ic_inner_resources,
1500			ic->private.proto.ic_num_inner_resources, input_style);
1501
1502    _XimGetCurrentICValues(ic, &ic_values);
1503    buf = tmp_buf;
1504    buf_size = XIM_HEADER_SIZE + sizeof(CARD16) + sizeof(INT16);
1505    data_len = BUFSIZE - buf_size;
1506    total = 0;
1507    arg_ret = arg;
1508    for (;;) {
1509	data = &buf[buf_size];
1510	if (_XimEncodeICATTRIBUTE(ic, ic->private.proto.ic_resources,
1511		ic->private.proto.ic_num_resources, arg, &arg_ret, data,
1512		data_len, &ret_len, (XPointer)&ic_values, 0, XIM_CREATEIC)) {
1513	    goto ErrorOnCreatingIC;
1514	}
1515
1516	total += ret_len;
1517	if (!(arg = arg_ret)) {
1518	    break;
1519	}
1520
1521	buf_size += ret_len;
1522	if (buf == tmp_buf) {
1523	    if (!(tmp = Xmalloc(buf_size + data_len))) {
1524	        goto ErrorOnCreatingIC;
1525	    }
1526	    memcpy(tmp, buf, buf_size);
1527	    buf = tmp;
1528	} else {
1529	    if (!(tmp = Xrealloc(buf, (buf_size + data_len)))) {
1530		Xfree(buf);
1531	        goto ErrorOnCreatingIC;
1532	    }
1533	    buf = tmp;
1534	}
1535    }
1536    _XimSetCurrentICValues(ic, &ic_values);
1537
1538    if (!(_XimCheckCreateICValues(ic->private.proto.ic_resources,
1539					ic->private.proto.ic_num_resources)))
1540	goto ErrorOnCreatingIC;
1541
1542    _XimRegisterFilter(ic);
1543
1544    buf_s = (CARD16 *)&buf[XIM_HEADER_SIZE];
1545    buf_s[0] = im->private.proto.imid;
1546    buf_s[1] = (INT16)total;
1547
1548    len = (INT16)(sizeof(CARD16) + sizeof(INT16) + total);
1549    _XimSetHeader((XPointer)buf, XIM_CREATE_IC, 0, &len);
1550    if (!(_XimWrite(im, len, (XPointer)buf))) {
1551	if (buf != tmp_buf)
1552	    Xfree(buf);
1553	goto ErrorOnCreatingIC;
1554    }
1555    _XimFlush(im);
1556    if (buf != tmp_buf)
1557	Xfree(buf);
1558    ic->private.proto.waitCallback = True;
1559    buf_size = BUFSIZE;
1560    ret_code = _XimRead(im, &len, (XPointer)reply, buf_size,
1561						 _XimCreateICCheck, 0);
1562    if (ret_code == XIM_TRUE) {
1563	preply = reply;
1564    } else if (ret_code == XIM_OVERFLOW) {
1565	if (len <= 0) {
1566	    preply = reply;
1567	} else {
1568	    buf_size = (int)len;
1569	    preply = Xmalloc(buf_size);
1570	    ret_code = _XimRead(im, &len, preply, buf_size,
1571						 _XimCreateICCheck, 0);
1572	    if (ret_code != XIM_TRUE) {
1573		Xfree(preply);
1574		ic->private.proto.waitCallback = False;
1575		goto ErrorOnCreatingIC;
1576	    }
1577	}
1578    } else {
1579	ic->private.proto.waitCallback = False;
1580	goto ErrorOnCreatingIC;
1581    }
1582    ic->private.proto.waitCallback = False;
1583    buf_s = (CARD16 *)((char *)preply + XIM_HEADER_SIZE);
1584    if (*((CARD8 *)preply) == XIM_ERROR) {
1585	_XimProcError(im, 0, (XPointer)&buf_s[3]);
1586	if (reply != preply)
1587	    Xfree(preply);
1588	goto ErrorOnCreatingIC;
1589    }
1590
1591    ic->private.proto.icid = buf_s[1];		/* icid */
1592    if (reply != preply)
1593	Xfree(preply);
1594    MARK_IC_CONNECTED(ic);
1595    return (XIC)ic;
1596
1597ErrorOnCreatingIC:
1598    _XimUnregisterFilter(ic);
1599
1600    Xfree(ic->private.proto.ic_resources);
1601    Xfree(ic->private.proto.ic_inner_resources);
1602    Xfree(ic);
1603    return (XIC)NULL;
1604}
1605