/******************************************************************
 
         Copyright 1994, 1995 by Sun Microsystems, Inc.
         Copyright 1993, 1994 by Hewlett-Packard Company
 
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation, and that the name of Sun Microsystems, Inc.
and Hewlett-Packard not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
Sun Microsystems, Inc. and Hewlett-Packard make no representations about
the suitability of this software for any purpose.  It is provided "as is"
without express or implied warranty.
 
SUN MICROSYSTEMS INC. AND HEWLETT-PACKARD COMPANY DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
SUN MICROSYSTEMS, INC. AND HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
  Author: Hidetoshi Tajima(tajima@Eng.Sun.COM) Sun Microsystems, Inc.
 
******************************************************************/
#include <sys/param.h>
#include <X11/Xlib.h>
#ifndef NEED_EVENTS
#define NEED_EVENTS
#endif
#include <X11/Xproto.h>
#undef NEED_EVENTS
#include "FrameMgr.h"
#include "X11R6IMProtoData.h"
#include "Xi18n.h"
#include "XIC_Interface.h"

extern Xi18nClient *_Xi18nFindClient(Xi18n, CARD16);
extern int _Xi18nNeedSwap(Xi18n i18n_core, CARD16 connect_id);
extern void _Xi18nSendMessage(XIMS ims, CARD16 connect_id,
			      CARD8 major_opcode, CARD8 minor_opcode,
			      unsigned char *data, long length);
extern void _Xi18nSendTriggerKey(XIMS ims, CARD16 connect_id);
extern void _Xi18nChangeIC(XIMS ims, X11R6IMProtocol call_data,
			   unsigned char *p, int create_flag);
extern void _Xi18nGetIC(XIMS ims, X11R6IMProtocol call_data, unsigned char *p);
extern void FilterEvent(int icid, XEvent *event);

void
GetProtocolVersion(CARD16 client_major, CARD16 client_minor,
		   CARD16 *server_major, CARD16 *server_minor)
{
    *server_major = client_major;
    *server_minor = client_minor;
}

static void
ConnectMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p) {
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec connect_fr[], connect_reply_fr[];
    register int total_size;
    CARD16 server_major_version, server_minor_version;
    unsigned char *reply = NULL;
    IMConnectStruct *imconnect =
      (IMConnectStruct*)&call_data->imconnect;
    CARD16 connect_id = call_data->any.connect_id;

    /* create FrameMgr */
    fm = FrameMgrInit(connect_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, imconnect->byte_order);
    FrameMgrGetToken(fm, imconnect->major_version);
    FrameMgrGetToken(fm, imconnect->minor_version);

    /* free FrameMgr */
    FrameMgrFree(fm);

    GetProtocolVersion(imconnect->major_version, imconnect->minor_version,
		       &server_major_version, &server_minor_version);
#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    /* nothing to do here */
#endif

    /* create FrameMgr */
    fm = FrameMgrInit(connect_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, server_major_version);
    FrameMgrPutToken(fm, server_minor_version);

    _Xi18nSendMessage(ims, connect_id, XIM_CONNECT_REPLY,
		      0, reply, total_size);

    XFree(reply);
    /* free FrameMgr */
    FrameMgrFree(fm);
    return;
}

static void
DisConnectMessageProc(XIMS ims, X11R6IMProtocol call_data) {
    Xi18n i18n_core = ims->protocol;
    unsigned char *reply = NULL;
    CARD16 connect_id = call_data->any.connect_id;

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    /* destroy all remaining input contexts for this connection */
#endif

    _Xi18nSendMessage(ims, connect_id, XIM_DISCONNECT_REPLY,
		      0, reply, 0);

    i18n_core->methods.disconnect(ims, connect_id);
    return;
}

static void
OpenMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p) {
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec open_fr[], open_reply_fr[];
    unsigned char *reply = NULL;
    int str_size;
    register int i, total_size;
    CARD16 connect_id = call_data->any.connect_id;
    int str_length;
    char *name;
    IMOpenStruct *imopen =
      (IMOpenStruct *)&call_data->imopen;

    /* create FrameMgr */
    fm = FrameMgrInit(open_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, str_length);
    FrameMgrSetSize(fm, str_length);
    FrameMgrGetToken(fm, name);
    imopen->lang.length = str_length;
    imopen->lang.name = malloc(str_length + 1);
    strncpy(imopen->lang.name, name, str_length);
    imopen->lang.name[str_length] = (char)0;

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    /* nothing to do here */
#endif

    if ((i18n_core->address.imvalue_mask & I18N_ON_KEYS) ||
	(i18n_core->address.imvalue_mask & I18N_OFF_KEYS)) {
	_Xi18nSendTriggerKey(ims, connect_id);
    }
    XFree(imopen->lang.name);

    /* create FrameMgr */
    fm = FrameMgrInit(open_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* set iteration count for list of imattr */
    FrameMgrSetIterCount(fm, i18n_core->address.im_attr_num);

    /* set length of BARRAY item in ximattr_fr */
    for (i = 0; i < i18n_core->address.im_attr_num; i++) {
	str_size = strlen(i18n_core->address.xim_attr[i].name);
	FrameMgrSetSize(fm, str_size);
    }
    /* set iteration count for list of icattr */
    FrameMgrSetIterCount(fm, i18n_core->address.ic_attr_num);
    /* set length of BARRAY item in xicattr_fr */
    for (i = 0; i < i18n_core->address.ic_attr_num; i++) {
	str_size = strlen(i18n_core->address.xic_attr[i].name);
	FrameMgrSetSize(fm, str_size);
    }

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    /* input input-method ID */
    FrameMgrPutToken(fm, connect_id);

    for (i = 0; i < i18n_core->address.im_attr_num; i++) {
	str_size = FrameMgrGetSize(fm);
	FrameMgrPutToken(fm, i18n_core->address.xim_attr[i].attribute_id);
	FrameMgrPutToken(fm, i18n_core->address.xim_attr[i].type);
	FrameMgrPutToken(fm, str_size);
	FrameMgrPutToken(fm, i18n_core->address.xim_attr[i].name);
    }
    for (i = 0; i < i18n_core->address.ic_attr_num; i++) {
	str_size = FrameMgrGetSize(fm);
	FrameMgrPutToken(fm, i18n_core->address.xic_attr[i].attribute_id);
	FrameMgrPutToken(fm, i18n_core->address.xic_attr[i].type);
	FrameMgrPutToken(fm, str_size);
	FrameMgrPutToken(fm, i18n_core->address.xic_attr[i].name);
    }

    _Xi18nSendMessage(ims, connect_id, XIM_OPEN_REPLY,
		      0, reply, total_size);

    XFree(reply);
    /* free FrameMgr */
    FrameMgrFree(fm);
    return;
}

static void
CloseMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p) {
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec close_fr[], close_reply_fr[];
    unsigned char *reply = NULL;
    register int total_size;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(close_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    FrameMgrGetToken(fm, input_method_ID);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    /* nothing to do here */
#endif

    /* create FrameMgr */
    fm = FrameMgrInit(close_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR,
			  0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);

    _Xi18nSendMessage(ims, connect_id, XIM_CLOSE_REPLY,
		      0, reply, total_size);

    XFree(reply);
    /* free FrameMgr */
    FrameMgrFree(fm);
    return;
}

static XIMExt *
MakeExtensionList(Xi18n i18n_core, XIMStr *lib_extension,
		  int number, int *reply_number) {
    XIMExt *ext_list;
    XIMExt *im_ext = (XIMExt *)i18n_core->address.extension;
    int im_ext_len = i18n_core->address.ext_num;
    int i, j;

    *reply_number = 0;

    if (number == 0) {		/* query all extensions */
	*reply_number = im_ext_len;
    } else {
	for (i = 0; i < im_ext_len; i++) {
	    for (j = 0; j < (int)number; j++) 
	      if (!strcmp(lib_extension[j].name, im_ext[i].name)) {
		  (*reply_number)++;
		  break;
	      }
	}
    }

    if (!(*reply_number))
      return NULL;

    ext_list = (XIMExt *)malloc(sizeof(XIMExt) * (*reply_number));
    if (!ext_list)
      return NULL;
    memset(ext_list, 0, sizeof(XIMExt) * (*reply_number));

    if (number == 0) {		/* query all extensions */
	for (i = 0; i < im_ext_len; i++) {
	    ext_list[i].major_opcode = im_ext[i].major_opcode;
	    ext_list[i].minor_opcode = im_ext[i].minor_opcode;
	    ext_list[i].length = im_ext[i].length;
	    ext_list[i].name = malloc(im_ext[i].length + 1);
	    strcpy(ext_list[i].name, im_ext[i].name);
	}
    } else {
	int n = 0;
	for (i = 0; i < im_ext_len; i++) {
	    for (j = 0; j < (int)number; j++)
	      if (!strcmp(lib_extension[j].name, im_ext[i].name)) {
		  ext_list[n].major_opcode = im_ext[i].major_opcode;
		  ext_list[n].minor_opcode = im_ext[i].minor_opcode;
		  ext_list[n].length = im_ext[i].length;
		  ext_list[n].name = malloc(im_ext[i].length + 1);
		  strcpy(ext_list[n].name, im_ext[i].name);
		  n++;
		  break;
	    }
	}
    }
    return ext_list;
}

static void
QueryExtensionMessageProc(XIMS ims, X11R6IMProtocol call_data,
			  unsigned char *p) {
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    FmStatus status;
    extern XimFrameRec query_extension_fr[], query_extension_reply_fr[];
    unsigned char *reply = NULL;
    int str_size;
    register int i, number, total_size;
    int byte_length;
    int reply_number = 0;
    XIMExt *ext_list;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;
    IMQueryExtensionStruct *query_ext =
      (IMQueryExtensionStruct *)&call_data->queryext;
    XPointer listofStr = NULL;
    XPointer listofStr_p = NULL;

    /* create FrameMgr */
    fm = FrameMgrInit(query_extension_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, byte_length);
    if (byte_length > 0) {
	listofStr = (XPointer)malloc(byte_length);
	memset(listofStr, 0, byte_length);
	listofStr_p = listofStr;
    }
    number = 0;
    while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
	char *name;
	CARD8 str_length;
	FrameMgrGetToken(fm, str_length);
	FrameMgrSetSize(fm, str_length);
	memmove(listofStr_p++, &str_length, 1);
	FrameMgrGetToken(fm, name);
	strncpy(listofStr_p, name, str_length);
	listofStr_p += str_length;
	number++;
    }
    query_ext->extension = (XIMStr *)malloc(sizeof(XIMStr) * number);
    memset(query_ext->extension, 0, sizeof(XIMStr) * number);
    query_ext->number = number;
    for (listofStr_p = listofStr,i = 0; i < number; i++) {
	CARD8 str_length;
	str_length = (CARD8)(*listofStr_p++);
	query_ext->extension[i].length = str_length;
	query_ext->extension[i].name = malloc(str_length + 1);
	memmove(query_ext->extension[i].name, listofStr_p, str_length);
	query_ext->extension[i].name[str_length] = (char)0;
	listofStr_p += str_length;
    }

    if (listofStr) XFree(listofStr);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    /* nothing to do here  */
#endif

    /* free FrameMgr */
    FrameMgrFree(fm);

    ext_list = MakeExtensionList(i18n_core, query_ext->extension, number,
				 &reply_number);

    for (i = 0; i < number; i++) {
	XFree(query_ext->extension[i].name);
    }
    XFree(query_ext->extension);

    /* create FrameMgr */
    fm = FrameMgrInit(query_extension_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* set iteration count for list of extensions */
    FrameMgrSetIterCount(fm, reply_number);

    /* set length of BARRAY item in ext_fr */
    for (i = 0; i < reply_number; i++) {
	str_size = strlen(ext_list[i].name);
	FrameMgrSetSize(fm, str_size);
    }

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR,
			  0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);

    for (i = 0; i < reply_number; i++) {
	str_size = FrameMgrGetSize(fm);
	FrameMgrPutToken(fm, ext_list[i].major_opcode);
	FrameMgrPutToken(fm, ext_list[i].minor_opcode);
	FrameMgrPutToken(fm, str_size);
	FrameMgrPutToken(fm, ext_list[i].name);
    }
    _Xi18nSendMessage(ims, connect_id,
		      XIM_QUERY_EXTENSION_REPLY, 0, reply, total_size);
    XFree(reply);
    /* free FrameMgr */
    FrameMgrFree(fm);

    for (i = 0; i < reply_number; i++) {
	XFree(ext_list[i].name);
    }
    XFree((char *)ext_list);
    return;
}

static void
SyncReplyMessageProc(XIMS ims, X11R6IMProtocol call_data,
		     unsigned char *p) {
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec sync_reply_fr[];
    CARD16 connect_id = call_data->any.connect_id;
    Xi18nClient *client = (Xi18nClient *)_Xi18nFindClient(i18n_core,
							  connect_id);
    CARD16 input_method_ID, input_context_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(sync_reply_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, input_context_ID);
    /* free FrameMgr */
    FrameMgrFree(fm);

    client->sync = False;
    return;
}

static void
GetIMValueFromName(Xi18n i18n_core, CARD16 connect_id,
		   char *buf, const char *name, int *length) {
    register int i;
    
    if (!strcmp(name, XNQueryInputStyle)) {
	XIMStyles *styles = (XIMStyles*)&i18n_core->address.input_styles;

	*length = sizeof(CARD16) * 2;	/* count_styles, unused */
	*length += styles->count_styles * sizeof(CARD32);

	if (buf != NULL) {
	    FrameMgr fm;
	    extern XimFrameRec ximstyles_fr[];
	    unsigned char *data = NULL;
	    int total_size;
	    /* create FrameMgr */
	    fm = FrameMgrInit(ximstyles_fr, NULL,
			      _Xi18nNeedSwap(i18n_core, connect_id));

	    /* set iteration count for list of input_style */
	    FrameMgrSetIterCount(fm, styles->count_styles);

	    total_size = FrameMgrGetTotalSize(fm);
	    data = (unsigned char *)malloc(total_size);
	    if (!data) {
		return;
	    }
	    memset(data, 0, total_size);
	    FrameMgrSetBuffer(fm, data);

	    FrameMgrPutToken(fm, styles->count_styles);
	    for (i = 0; i < (int)styles->count_styles; i++) {
		FrameMgrPutToken(fm, styles->supported_styles[i]);
	    }
	    memmove(buf, data, total_size);

	    XFree(data);
	    /* free FrameMgr */
	    FrameMgrFree(fm);
	}
    }
}

static XIMAttribute *
MakeIMAttributeList(Xi18n i18n_core, CARD16 connect_id,
		    CARD16 *list, int *number, int *length) {
    XIMAttribute *attrib_list;
    int list_num;
    XIMAttr *attr = i18n_core->address.xim_attr;
    int list_len = i18n_core->address.im_attr_num;
    register int i, j;
    int value_length;
    int number_ret = 0;

    *length = 0;
    list_num = 0;
    for (i = 0; i < *number; i++) {
	for (j = 0; j < list_len; j++) {
	    if (attr[j].attribute_id == list[i]) {
		list_num++;
		break;
	    }
	}
    }
    attrib_list = (XIMAttribute *)malloc(sizeof(XIMAttribute) * list_num);
    if (!attrib_list)
      return NULL;
    memset(attrib_list, 0, sizeof(XIMAttribute) * list_num);
    number_ret = list_num;
    list_num = 0;
    for (i = 0; i < *number; i++) {
	for (j = 0; j < list_len; j++) {
	    if (attr[j].attribute_id == list[i]) {
		attrib_list[list_num].attribute_id = attr[j].attribute_id;
		attrib_list[list_num].name_length = attr[j].length;
		attrib_list[list_num].name = attr[j].name;
		attrib_list[list_num].type = attr[j].type;
		GetIMValueFromName(i18n_core, connect_id,
				   NULL,
				   attr[j].name, &value_length);
		attrib_list[list_num].value_length = value_length;
		attrib_list[list_num].value = (void *)malloc(value_length);
		memset(attrib_list[list_num].value, 0, value_length);
		GetIMValueFromName(i18n_core, connect_id,
				   attrib_list[list_num].value,
				   attr[j].name, &value_length);
		*length += sizeof(CARD16) * 2;
		*length += value_length;
		*length += IMPAD(value_length);
		list_num++;
		break;
	    }
	}
    }
    *number = number_ret;
    return attrib_list;
}

static void
GetIMValuesMessageProc(XIMS ims, X11R6IMProtocol call_data,
		       unsigned char *p) {
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    FmStatus status;
    extern XimFrameRec get_im_values_fr[], get_im_values_reply_fr[];
    CARD16 byte_length;
    int list_len, total_size;
    unsigned char *reply = NULL;
    int iter_count;
    register int i, j;
    int number;
    CARD16 *im_attrID_list;
    char **name_list;
    CARD16 name_number;
    XIMAttribute *im_attribute_list;
    IMGetIMValuesStruct *getim =
      (IMGetIMValuesStruct *)&call_data->getim;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(get_im_values_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, byte_length);
    im_attrID_list = (CARD16 *)malloc(sizeof(CARD16) * 20);
    memset(im_attrID_list, 0, sizeof(CARD16) * 20);
    name_list = (char **)malloc(sizeof(char *) * 20);
    memset(name_list, 0, sizeof(char *) * 20);
    number = 0;
    while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
	FrameMgrGetToken(fm, im_attrID_list[number]);
	number++;
    }
    /* free FrameMgr */
    FrameMgrFree(fm);

    name_number = 0;
    for (i = 0; i < number; i++) {
	for (j = 0; j < i18n_core->address.im_attr_num; j++)
	  if (i18n_core->address.xim_attr[j].attribute_id == im_attrID_list[i]) {
	      name_list[name_number++] = (char*)i18n_core->address.xim_attr[j].name;
	      break;
	  }
    }

    getim->number = name_number;
    getim->im_attr_list = name_list;

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#endif

    XFree(name_list);

    im_attribute_list = MakeIMAttributeList(i18n_core, connect_id,
					    im_attrID_list,
					    &number, &list_len);
    if (im_attrID_list)
      XFree(im_attrID_list);

    /* create FrameMgr */
    fm = FrameMgrInit(get_im_values_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    iter_count = number;

    /* set iteration count for list of im_attribute */
    FrameMgrSetIterCount(fm, iter_count);

    /* set length of BARRAY item in ximattribute_fr */
    for (i = 0; i < iter_count; i++) {
	FrameMgrSetSize(fm, im_attribute_list[i].value_length);
    }

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);

    for (i = 0; i < iter_count; i++) {
	FrameMgrPutToken(fm, im_attribute_list[i].attribute_id);
	FrameMgrPutToken(fm, im_attribute_list[i].value_length);
	FrameMgrPutToken(fm, im_attribute_list[i].value);
    }
    _Xi18nSendMessage(ims, connect_id,
		      XIM_GET_IM_VALUES_REPLY, 0, reply, total_size);
    XFree(reply);
    /* free FrameMgr */
    FrameMgrFree(fm);

    for (i = 0; i < iter_count; i++) {
	if (im_attribute_list[i].value_length && im_attribute_list[i].value) {
	    XFree(im_attribute_list[i].value);
	}
    }
    XFree(im_attribute_list);
    return;
}

static void
CreateICMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    _Xi18nChangeIC(ims, call_data, p, True);
    return;
}

static void
SetICValuesMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    _Xi18nChangeIC(ims, call_data, p, False);
    return;
}

static void
GetICValuesMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    _Xi18nGetIC(ims, call_data, p);
    return;
}

static void
SetICFocusMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec set_ic_focus_fr[];
    IMChangeFocusStruct *setfocus =
      (IMChangeFocusStruct*)&call_data->changefocus;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;
    Xi18nClient *client = (Xi18nClient *)_Xi18nFindClient(i18n_core,
							  connect_id);

    while (client->pending_commit != NULL) {
      unsigned char *reply = client->pending_commit;
      int total_size = client->pending_commit_size;
      
      _Xi18nSendMessage(ims, connect_id,
			XIM_COMMIT, 0, reply, total_size);
      XFree(client->pending_commit);
      client->pending_commit = NULL;
    }

    /* create FrameMgr */
    fm = FrameMgrInit(set_ic_focus_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, setfocus->icid);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    SetICFocus(setfocus->icid);
#endif

    return;
}

static void
UnsetICFocusMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec unset_ic_focus_fr[];
    IMChangeFocusStruct *unsetfocus =
      (IMChangeFocusStruct*)&call_data->changefocus;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(unset_ic_focus_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, unsetfocus->icid);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    UnsetICFocus(unsetfocus->icid);
#endif

    return;
}

static void
DestroyICMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec destroy_ic_fr[], destroy_ic_reply_fr[];
    register int total_size;
    unsigned char *reply = NULL;
    IMDestroyICStruct *destroy =
      (IMDestroyICStruct*)&call_data->destroyic;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(destroy_ic_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, destroy->icid);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    DestroyIC(destroy->icid);
#endif

    /* create FrameMgr */
    fm = FrameMgrInit(destroy_ic_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);
    FrameMgrPutToken(fm, destroy->icid);

    _Xi18nSendMessage(ims, connect_id,
		      XIM_DESTROY_IC_REPLY, 0, reply, total_size);
    XFree(reply);
    /* free FrameMgr */
    FrameMgrFree(fm);
    return;
}

static void
ResetICMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec reset_ic_fr[], reset_ic_reply_fr[];
    register int total_size;
    unsigned char *reply = NULL;
    IMResetICStruct *resetic =
      (IMResetICStruct*)&call_data->resetic;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;
    char *mb_data = 0;

    /* create FrameMgr */
    fm = FrameMgrInit(reset_ic_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, resetic->icid);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    mb_data = ResetIC(resetic->icid);
    if (mb_data) {
      /* mb_data is native encoding, so need to convert to CT */
      XTextProperty prop;
      XmbTextListToTextProperty(i18n_core->address.dpy, &mb_data,
				1, XCompoundTextStyle, &prop);
      resetic->length = (int)prop.nitems;
      resetic->commit_string = (char*)prop.value;
    } else {
      /* call conversion end */
      /* get it from the results of commit_string */
    }
#endif
    
    /* create FrameMgr */
    fm = FrameMgrInit(reset_ic_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* set length of STRING8 */
    FrameMgrSetSize(fm, resetic->length);

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);
    FrameMgrPutToken(fm, resetic->icid);
    FrameMgrPutToken(fm, resetic->length);
    if (resetic->commit_string && *(resetic->commit_string))
      FrameMgrPutToken(fm, resetic->commit_string);

    _Xi18nSendMessage(ims, connect_id,
		      XIM_RESET_IC_REPLY, 0, reply, total_size);
    /* execute set/unset focus function to redraw status text */
    if (IsFocused(resetic->icid)) {
      SetICFocus(resetic->icid);
    }
    else {
      UnsetICFocus(resetic->icid);
    }
    /* free FrameMgr */
    FrameMgrFree(fm);
    XFree(reply);
    return;
}

static int
WireEventToEvent(Xi18n i18n_core, xEvent *event,
		 CARD16 serial, XEvent *ev)
{
    ev->xany.serial = event->u.u.sequenceNumber & ((unsigned long) 0xffff);
    ev->xany.serial |= serial << 16;
    ev->xany.send_event = False;
    ev->xany.display = i18n_core->address.dpy;
    switch (ev->type = event->u.u.type & 0x7f) {
      case KeyPress:
      case KeyRelease:
	((XKeyEvent *)ev)->keycode = event->u.u.detail;
	((XKeyEvent *)ev)->window = event->u.keyButtonPointer.event;
	/* hack */
	if (event->u.keyButtonPointer.state > Mod5Mask) {
	  /* linux client */
	  ((XKeyEvent *)ev)->state = event->u.keyButtonPointer.state >> 8;
	} else {
	  /* Solaris client */
	  ((XKeyEvent *)ev)->state = event->u.keyButtonPointer.state;
	}
	((XKeyEvent *)ev)->time = event->u.keyButtonPointer.time;
	((XKeyEvent *)ev)->root = event->u.keyButtonPointer.root;
	((XKeyEvent *)ev)->x = event->u.keyButtonPointer.eventX;
	((XKeyEvent *)ev)->y = event->u.keyButtonPointer.eventY;
	((XKeyEvent *)ev)->x_root = 0;
	((XKeyEvent *)ev)->y_root = 0;
	return True;
      default:
	break;
    }
    return False;
}

static void
ForwardEventMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec forward_event_fr[];
    xEvent wire_event;
    IMForwardEventStruct *forward =
      (IMForwardEventStruct*)&call_data->forwardevent;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;
#ifdef FULL_SYNC_MODE
    unsigned char *reply = NULL;
    extern XimFrameRec sync_reply_fr[];
    register int total_size;
#endif

    /* create FrameMgr */
    fm = FrameMgrInit(forward_event_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, forward->icid);
    FrameMgrGetToken(fm, forward->sync_bit);
    FrameMgrGetToken(fm, forward->serial_number);
    p += sizeof(CARD16) * 4;
    memmove(&wire_event, p, sizeof(xEvent));

    /* free FrameMgr */
    FrameMgrFree(fm);

    if (WireEventToEvent(i18n_core, &wire_event,
			 forward->serial_number, &forward->event) == True) {
#ifdef IM_PROTO_HANDLER
      CALL_PROTO_HANDLER;
#else
      FilterEvent(forward->icid, &forward->event);
#endif
    }

#ifdef	FULL_SYNC_MODE
    /* XIM_SYNC_REPLY needs to be sent to IM library */
    fm = FrameMgrInit(sync_reply_fr, NULL,
                      _Xi18nNeedSwap(i18n_core, connect_id));

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
        _Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
        return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);
    FrameMgrPutToken(fm, forward->icid);

    _Xi18nSendMessage(ims, connect_id, XIM_SYNC_REPLY, 0,
                          reply, total_size);

    FrameMgrFree(fm);
    XFree(reply);
#endif
    return;
}

static void
ExtForwardKeyEventMessageProc(XIMS ims, X11R6IMProtocol call_data,
			      unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec ext_forward_keyevent_fr[];
    CARD8 type, keycode;
    CARD16 state;
    CARD32 ev_time, window;
    IMForwardEventStruct *forward =
      (IMForwardEventStruct*)&call_data->forwardevent;
    XEvent *ev = (XEvent *)&forward->event;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(ext_forward_keyevent_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));
    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, forward->icid);
    FrameMgrGetToken(fm, forward->sync_bit);
    FrameMgrGetToken(fm, forward->serial_number);
    FrameMgrGetToken(fm, type);
    FrameMgrGetToken(fm, keycode);
    FrameMgrGetToken(fm, state);
    FrameMgrGetToken(fm, ev_time);
    FrameMgrGetToken(fm, window);

    /* free FrameMgr */
    FrameMgrFree(fm);

    if (type != KeyPress) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    /* make a faked keypress event */
    ev->type = (int)type;
    ev->xany.send_event = True;
    ev->xany.display = i18n_core->address.dpy;
    ev->xany.serial = (unsigned long)forward->serial_number;
    ((XKeyEvent *)ev)->keycode = (unsigned int)keycode;
    ((XKeyEvent *)ev)->state = (unsigned int)state;
    ((XKeyEvent *)ev)->time = (Time)ev_time;
    ((XKeyEvent *)ev)->window = (Window)window;
    ((XKeyEvent *)ev)->root = DefaultRootWindow(ev->xany.display);
    ((XKeyEvent *)ev)->x = 0;
    ((XKeyEvent *)ev)->y = 0;
    ((XKeyEvent *)ev)->x_root = 0;
    ((XKeyEvent *)ev)->y_root = 0;

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    FilterEvent(forward->icid, ev);
#endif
    return;
}

static void
ExtMoveMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec ext_move_fr[];
    IMMoveStruct *extmove =
      (IMMoveStruct*)&call_data->extmove;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(ext_move_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, extmove->icid);
    FrameMgrGetToken(fm, extmove->x);
    FrameMgrGetToken(fm, extmove->y);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    MoveSpot(extmove->icid, extmove->x, extmove->y);
#endif
    return;
}

static void
ExtensionMessageProc(XIMS ims, X11R6IMProtocol call_data, unsigned char *p)
{
    switch (call_data->any.minor_code) {
      case XIM_EXT_FORWARD_KEYEVENT:
	ExtForwardKeyEventMessageProc(ims, call_data, p);
	break;
      case XIM_EXT_MOVE:
	ExtMoveMessageProc(ims, call_data, p);
	break;
    }
}

static void
TriggerNotifyMessageProc(XIMS ims, X11R6IMProtocol call_data,
			 unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec trigger_notify_fr[], trigger_notify_reply_fr[];
    register int total_size;
    unsigned char *reply = NULL;
    IMTriggerNotifyStruct *trigger =
      (IMTriggerNotifyStruct *)&call_data->triggernotify;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;
    CARD32 flag;

    /* create FrameMgr */
    fm = FrameMgrInit(trigger_notify_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, trigger->icid);
    FrameMgrGetToken(fm, trigger->flag);
    FrameMgrGetToken(fm, trigger->key_index);
    FrameMgrGetToken(fm, trigger->event_mask);
    /*
      In order to support Front End Method, this event_mask must be saved
      per clients so that it should be restored by an XIM_EXT_SET_EVENT_MASK
      call when preediting mode is reset to off.
     */

    flag = trigger->flag;

    /* free FrameMgr */
    FrameMgrFree(fm);

    /* create FrameMgr */
    fm = FrameMgrInit(trigger_notify_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);
    FrameMgrPutToken(fm, trigger->icid);

    if (flag == 0) {	/* on key */
#ifndef  FIX_APPLIXWARE_TURBOLINUX42
	/* Applixware will not forward key event when XIM_TRIGGER_NOTIFY_REPLY
	   is sent before SET_MASK */
	_Xi18nSendMessage(ims, connect_id, XIM_TRIGGER_NOTIFY_REPLY, 0,
			  reply, total_size);
#endif
	(ims->methods->preeditStart)(ims, call_data);
    }

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    if (flag == 0) {
      ConversionStart(trigger->icid);
    } else {
      ConversionEnd(trigger->icid);
    }
#endif
    if (flag == 1) {	/* off key */
        (ims->methods->preeditEnd)(ims, call_data);
	_Xi18nSendMessage(ims, connect_id, XIM_TRIGGER_NOTIFY_REPLY, 0,
			  reply, total_size);
    }
#ifdef  FIX_APPLIXWARE_TURBOLINUX42
    if (flag == 0) {	/* on key */
	_Xi18nSendMessage(ims, connect_id, XIM_TRIGGER_NOTIFY_REPLY, 0,
			  reply, total_size);
    }
#endif

    /* free FrameMgr */
    FrameMgrFree(fm);
    XFree(reply);
    return;
}

static INT16
ChooseEncoding(Xi18n i18n_core,
	       IMEncodingNegotiationStruct *enc_nego)
{
    Xi18nAddressRec *address = (Xi18nAddressRec *)&i18n_core->address;
    XIMEncodings *p;
    int i, j;
    int enc_index;

    p = (XIMEncodings*)&address->encoding_list;
    for (i = 0; i < (int)p->count_encodings; i++) {
	for (j = 0; j < (int)enc_nego->encoding_number; j++) {
	    if (!strcmp(p->supported_encodings[i],
			enc_nego->encoding[j].name)) {
		enc_index = j;
		break;
	    }
	}
    }
    /*
      Encoinding Negotiation isn't supported yet in the IMlibrary, so
      rather safe and sound to always return XIM_Default_Encoding_IDX(-1).
     */
    return (INT16)XIM_Default_Encoding_IDX;
}

static void
EncodingNegotiatonMessageProc(XIMS ims, X11R6IMProtocol call_data,
			      unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    FmStatus status;
    CARD16 byte_length;
    extern XimFrameRec encoding_negotiation_fr[];
    extern XimFrameRec encoding_negotiation_reply_fr[];
    register int i, number, total_size;
    unsigned char *reply = NULL;
    IMEncodingNegotiationStruct *enc_nego =
      (IMEncodingNegotiationStruct *)&call_data->encodingnego;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;
    XPointer listofStr = NULL;
    XPointer listofStr_p;

    fm = FrameMgrInit(encoding_negotiation_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    FrameMgrGetToken(fm, input_method_ID);

    /* get ENCODING STR field */
    FrameMgrGetToken(fm, byte_length);
    if (byte_length > 0) {
	listofStr = (XPointer)malloc(byte_length);
	memset(listofStr, 0, byte_length);
	listofStr_p = listofStr;

	number = 0;
	while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
	    char *name;
	    CARD8 str_length;
	    FrameMgrGetToken(fm, str_length);
	    FrameMgrSetSize(fm, str_length);
	    memmove(listofStr_p++, &str_length, 1);
	    FrameMgrGetToken(fm, name);
	    strncpy(listofStr_p, name, str_length);
	    listofStr_p += str_length;
	    number++;
	}
	enc_nego->encoding_number = number;
	if (number > 0) {
	    enc_nego->encoding = (XIMStr *)malloc(sizeof(XIMStr) * number);
	    memset(enc_nego->encoding, 0, sizeof(XIMStr) * number);

	    for (listofStr_p = listofStr,i = 0; i < number; i++) {
		CARD8 str_length;
		str_length = (CARD8)(*listofStr_p++);
		enc_nego->encoding[i].length = str_length;
		enc_nego->encoding[i].name = malloc(str_length + 1);
		memmove(enc_nego->encoding[i].name, listofStr_p, str_length);
		enc_nego->encoding[i].name[str_length] = (char)0;
		listofStr_p += str_length;
	    }
	}
	XFree(listofStr);
    }
    /* get ENCODING INFO field */
    FrameMgrGetToken(fm, byte_length);
    if (byte_length > 0) {
	listofStr = (XPointer)malloc(byte_length);
	memset(listofStr, 0, byte_length);
	listofStr_p = listofStr;

	number = 0;
	while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
	    char *name;
	    CARD8 str_length;
	    FrameMgrGetToken(fm, str_length);
	    FrameMgrSetSize(fm, str_length);
	    memmove(listofStr_p++, &str_length, 1);
	    FrameMgrGetToken(fm, name);
	    strncpy(listofStr_p, name, str_length);
	    listofStr_p += str_length;
	    number++;
	}
	enc_nego->encoding_info_number = number;
	if (number > 0) {
	    enc_nego->encodinginfo = (XIMStr *)
		malloc(sizeof(XIMStr) * number);
	    memset(enc_nego->encoding, 0, sizeof(XIMStr) * number);

	    for (listofStr_p = listofStr, i = 0; i < number; i++) {
		CARD8 str_length;
		str_length = (CARD8)(*listofStr_p++);
		enc_nego->encodinginfo[i].length = str_length;
		enc_nego->encodinginfo[i].name = malloc(str_length + 1);
		memmove(enc_nego->encodinginfo[i].name,
			listofStr_p, str_length);
		enc_nego->encodinginfo[i].name[str_length] = (char)0;
		listofStr_p += str_length;
	    }
	}
    }

    enc_nego->enc_index = ChooseEncoding(i18n_core, enc_nego);
    enc_nego->category = 0;

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#else
    /* nothing to do here */
#endif

    /* free FrameMgr */
    FrameMgrFree(fm);

    /* create FrameMgr */
    fm = FrameMgrInit(encoding_negotiation_reply_fr, NULL,
		      _Xi18nNeedSwap(i18n_core, connect_id));

    total_size = FrameMgrGetTotalSize(fm);
    reply = (unsigned char *)malloc(total_size);
    if (!reply) {
	_Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
	return;
    }
    memset(reply, 0, total_size);
    FrameMgrSetBuffer(fm, reply);

    FrameMgrPutToken(fm, input_method_ID);
    FrameMgrPutToken(fm, enc_nego->category);
    FrameMgrPutToken(fm, enc_nego->enc_index);

    _Xi18nSendMessage(ims, connect_id,
		      XIM_ENCODING_NEGOTIATION_REPLY, 0, reply, total_size);
    XFree(reply);

    /* free data for encoding list */
    if (enc_nego->encoding != NULL) {
	for (i = 0; i < (int)enc_nego->encoding_number; i++) {
	    XFree(enc_nego->encoding[i].name);
	}
	XFree(enc_nego->encoding);
    }
    if (enc_nego->encodinginfo != NULL) {
	for (i = 0; i < (int)enc_nego->encoding_info_number; i++) {
	    XFree(enc_nego->encodinginfo[i].name);
	}
	XFree(enc_nego->encodinginfo);
    }
    /* free FrameMgr */
    FrameMgrFree(fm);
    return;
}

void
PreeditStartReplyMessageProc(XIMS ims, X11R6IMProtocol call_data,
			     unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec preedit_start_reply_fr[];
    IMPreeditCBStruct *preedit_CB =
      (IMPreeditCBStruct*)&call_data->preedit_callback;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(preedit_start_reply_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));
    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, preedit_CB->icid);
    FrameMgrGetToken(fm, preedit_CB->todo.return_value);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#endif

    return;
}

void
PreeditCaretReplyMessageProc(XIMS ims, X11R6IMProtocol call_data,
			     unsigned char *p)
{
    Xi18n i18n_core = ims->protocol;
    FrameMgr fm;
    extern XimFrameRec preedit_caret_reply_fr[];
    IMPreeditCBStruct *preedit_CB =
      (IMPreeditCBStruct*)&call_data->preedit_callback;
    XIMPreeditCaretCallbackStruct *caret =
      (XIMPreeditCaretCallbackStruct *)&preedit_CB->todo.caret;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

    /* create FrameMgr */
    fm = FrameMgrInit(preedit_caret_reply_fr, (char *)p,
		      _Xi18nNeedSwap(i18n_core, connect_id));
    /* get data */
    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, preedit_CB->icid);
    FrameMgrGetToken(fm, caret->position);

    /* free FrameMgr */
    FrameMgrFree(fm);

#ifdef IM_PROTO_HANDLER
    CALL_PROTO_HANDLER;
#endif

    return;
}

void
StrConvReplyMessageProc(XIMS ims, X11R6IMProtocol call_data,
			unsigned char *p)
{
    return;
}

static void
AddQueue(Xi18nClient *client, unsigned char *p) {
    XIMPending	 *new_pend, *last;

    if ((new_pend = (XIMPending *)malloc(sizeof(XIMPending))) == NULL)
      return;
    new_pend->p = p;
    new_pend->next = (XIMPending *)NULL;
    if (!client->pending)
      client->pending = new_pend;
    else {
	for (last = client->pending; last->next; last = last->next);
	last->next = new_pend;
    }
    return;
}

static void
ProcessQueue(XIMS ims, CARD16 connect_id) {
    Xi18n i18n_core = ims->protocol;
    Xi18nClient *client = (Xi18nClient *)_Xi18nFindClient(i18n_core,
							  connect_id);

    while (client->sync == False && client->pending != NULL) {
	XimProtoHdr *hdr = (XimProtoHdr *)client->pending->p;
	unsigned char *p1 = (unsigned char *)(hdr + 1);
	X11R6IMProtocolStruct call_data;

	call_data.major_code = hdr->major_opcode;
	call_data.any.minor_code = hdr->minor_opcode;
	call_data.any.connect_id = connect_id;

	switch (hdr->major_opcode) {
	  case XIM_FORWARD_EVENT:
	    ForwardEventMessageProc(ims, &call_data, p1);
	    break;
	  default:
	    break;
	}
	XFree(hdr);
	{
	    XIMPending *old = client->pending;
	    client->pending = old->next;
	    XFree(old);
	}
    }
    return;
}

void
_Xi18nMessageHandler(XIMS ims, CARD16 connect_id,
		     unsigned char *p, Bool *delete) {
    XimProtoHdr	*hdr = (XimProtoHdr *)p;
    unsigned char *p1 = (unsigned char *)(hdr + 1);
    X11R6IMProtocolStruct call_data;
    Xi18n i18n_core = ims->protocol;
    Xi18nClient *client = (Xi18nClient *)_Xi18nFindClient(i18n_core,
							  connect_id);

    if (hdr == (XimProtoHdr*)NULL) return;

    memset(&call_data, 0, sizeof(X11R6IMProtocolStruct));

    call_data.major_code = hdr->major_opcode;
    call_data.any.minor_code = hdr->minor_opcode;
    call_data.any.connect_id = connect_id;

    switch (call_data.major_code) {
      case XIM_CONNECT:
	ConnectMessageProc(ims, &call_data, p1);
	break;
      case XIM_DISCONNECT:
	DisConnectMessageProc(ims, &call_data);
	break;
      case XIM_OPEN:
	OpenMessageProc(ims, &call_data, p1);
	break;
      case XIM_CLOSE:
	CloseMessageProc(ims, &call_data, p1);
	break;
      case XIM_QUERY_EXTENSION:
	QueryExtensionMessageProc(ims, &call_data, p1);
	break;
      case XIM_GET_IM_VALUES:
	GetIMValuesMessageProc(ims, &call_data, p1);
	break;
      case XIM_CREATE_IC:
	CreateICMessageProc(ims, &call_data, p1);
	break;
      case XIM_SET_IC_VALUES:
	SetICValuesMessageProc(ims, &call_data, p1);
	break;
      case XIM_GET_IC_VALUES:
	GetICValuesMessageProc(ims, &call_data, p1);
	break;
      case XIM_SET_IC_FOCUS:
	SetICFocusMessageProc(ims, &call_data, p1);
	break;
      case XIM_UNSET_IC_FOCUS:
	UnsetICFocusMessageProc(ims, &call_data, p1);
	break;
      case XIM_DESTROY_IC:
	DestroyICMessageProc(ims, &call_data, p1);
	break;
      case XIM_RESET_IC:
	ResetICMessageProc(ims, &call_data, p1);
	break;
      case XIM_FORWARD_EVENT:
	if (client->sync == True) {
	    AddQueue(client, p);
	    *delete = False;
	} else {
	    ForwardEventMessageProc(ims, &call_data, p1);
	}
	break;
      case XIM_EXTENSION:
	ExtensionMessageProc(ims, &call_data, p1);
	break;
      case XIM_SYNC:
	break;
      case XIM_SYNC_REPLY:
	SyncReplyMessageProc(ims, &call_data, p1);
	ProcessQueue(ims, connect_id);
	break;
      case XIM_TRIGGER_NOTIFY:
	TriggerNotifyMessageProc(ims, &call_data, p1);
	break;
      case XIM_ENCODING_NEGOTIATION:
	EncodingNegotiatonMessageProc(ims, &call_data, p1);
	break;
      case XIM_PREEDIT_START_REPLY:
	PreeditStartReplyMessageProc(ims, &call_data, p1);
	break;
      case XIM_PREEDIT_CARET_REPLY:
	PreeditCaretReplyMessageProc(ims, &call_data, p1);
	break;
      case XIM_STR_CONVERSION_REPLY:
	StrConvReplyMessageProc(ims, &call_data, p1);
	break;
      default:
	break;
    }
}
