/******************************************************************

         Copyright 1993, 1994 by Hewlett-Packard Company

Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose without fee is hereby granted,
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 Hewlett-Packard not
be used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
Hewlett-Packard Company makes no representations about the suitability
of this software for any purpose.
It is provided "as is" without express or implied warranty.

HEWLETT-PACKARD COMPANY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
IN NO EVENT SHALL 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	Hewlett-Packard Company.
			(tajima@kobe.hp.com)
******************************************************************/
#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 "IMdkit.h"
#include "Xi18n.h"

#if NeedFunctionPrototypes
extern Xi18nClient *_Xi18nFindClient(Xi18n, CARD16);
#else
extern Xi18nClient *_Xi18nFindClient();
#endif

static void
#if NeedFunctionPrototypes
GetProtocolVersion(CARD16 client_major, CARD16 client_minor,
		   CARD16 *server_major, CARD16 *server_minor)
#else
GetProtocolVersion(client_major, client_minor, server_major, server_minor)
CARD16 client_major;
CARD16 client_minor;
CARD16 *server_major;
CARD16 *server_minor;
#endif
{
    *server_major = client_major;
    *server_minor = client_minor;
}

static void
#if NeedFunctionPrototypes
ConnectMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
ConnectMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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 PROTOCOL_RICH
    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
#endif /* PROTOCOL_RICH */

    /* 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
#if NeedFunctionPrototypes
DisConnectMessageProc(XIMS ims, IMProtocol *call_data)
#else
DisConnectMessageProc(ims, call_data)
XIMS ims;
IMProtocol *call_data;
#endif
{
    Xi18n i18n_core = ims->protocol;
    unsigned char *reply = NULL;
    CARD16 connect_id = call_data->any.connect_id;

#ifdef PROTOCOL_RICH
    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
#endif /* PROTOCOL_RICH */

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

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

static void
#if NeedFunctionPrototypes
OpenMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
OpenMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;

    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
#if NeedFunctionPrototypes
CloseMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
CloseMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;

    /* 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 *
#if NeedFunctionPrototypes
MakeExtensionList(Xi18n i18n_core, XIMStr *lib_extension,
		  int number, int *reply_number)
#else
MakeExtensionList(i18n_core, lib_extension, number, reply_number)
Xi18n i18n_core;
XIMStr *lib_extension;
int number;
int *reply_number;
#endif
{
    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
#if NeedFunctionPrototypes
QueryExtensionMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
QueryExtensionMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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;
    IMQueryExtensionStruct *query_ext =
      (IMQueryExtensionStruct *)&call_data->queryext;
    CARD16 connect_id = call_data->any.connect_id;
    CARD16 input_method_ID;

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

    FrameMgrGetToken(fm, input_method_ID);
    FrameMgrGetToken(fm, byte_length);
    query_ext->extension = (XIMStr *)malloc(sizeof(XIMStr) * 10);
    memset(query_ext->extension, 0, sizeof(XIMStr) * 10);
    number = 0;
    while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
	char *name;
	int str_length;
	FrameMgrGetToken(fm, str_length);
	FrameMgrSetSize(fm, str_length);
	query_ext->extension[number].length = str_length;
	FrameMgrGetToken(fm, name);
	query_ext->extension[number].name = malloc(str_length + 1);
	strncpy(query_ext->extension[number].name, name, str_length);
	query_ext->extension[number].name[str_length] = (char)0;
	number++;
    }
    query_ext->number = number;

#ifdef PROTOCOL_RICH
    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
#endif /* PROTOCOL_RICH */

    /* 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
#if NeedFunctionPrototypes
SyncReplyMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
SyncReplyMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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
#if NeedFunctionPrototypes
GetIMValueFromName(Xi18n i18n_core, CARD16 connect_id,
		   char *buf, char *name, int *length)
#else
GetIMValueFromName(i18n_core, connect_id, buf, name, length)
Xi18n i18n_core;
CARD16 connect_id;
char *buf;
char *name;
int *length;
#endif
{
    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 input_styles_fr[];
	    unsigned char *data = NULL;
	    int total_size;
	    /* create FrameMgr */
	    fm = FrameMgrInit(input_styles_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);
	    /* free FrameMgr */
	    FrameMgrFree(fm);
	}
    }
}

static XIMAttribute *
#if NeedFunctionPrototypes
MakeIMAttributeList(Xi18n i18n_core, CARD16 connect_id,
		    CARD16 *list, int *number, int *length)
#else
MakeIMAttributeList(i18n_core, connect_id, list, number, length)
Xi18n i18n_core;
CARD16 connect_id;
CARD16 *list;
int *number;
int *length;
#endif
{
    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
#if NeedFunctionPrototypes
GetIMValuesMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
GetIMValuesMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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++] = i18n_core->address.xim_attr[j].name;
	      break;
	  }
    }

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

#ifdef PROTOCOL_RICH
    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
#endif /* PROTOCOL_RICH */

    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);

    XFree(im_attribute_list);
    return;
}

static void
#if NeedFunctionPrototypes
CreateICMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
CreateICMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    _Xi18nChangeIC(ims, call_data, p, True);
    return;
}

static void
#if NeedFunctionPrototypes
SetICValuesMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
SetICValuesMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    _Xi18nChangeIC(ims, call_data, p, False);
    return;
}

static void
#if NeedFunctionPrototypes
GetICValuesMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
GetICValuesMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    _Xi18nGetIC(ims, call_data, p);
    return;
}

static void
#if NeedFunctionPrototypes
SetICFocusMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
SetICFocusMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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;

    /* 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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
    return;
}

static void
#if NeedFunctionPrototypes
UnsetICFocusMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
UnsetICFocusMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
    return;
}

static void
#if NeedFunctionPrototypes
DestroyICMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
DestroyICMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;

    /* 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);
    /* free FrameMgr */
    FrameMgrFree(fm);
    return;
}

static void
#if NeedFunctionPrototypes
ResetICMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
ResetICMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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;

    /* 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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;

    /* 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->commit_string);

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

static int
#if NeedFunctionPrototypes
WireEventToEvent(Xi18n i18n_core, xEvent *event,
		 CARD16 serial, XEvent *ev)
#else
WireEventToEvent(i18n_core, event, serial, ev)
Xi18n i18n_core;
xEvent *event;			/* wire protocol event */
CARD16 serial;
XEvent *ev;
#endif
{
    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;
	((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
#if NeedFunctionPrototypes
ForwardEventMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
ForwardEventMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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;

    /* 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) {
	if (i18n_core->address.improto)
	  if (!(i18n_core->address.improto(ims, call_data)))
	    return;
    }
    return;
}

static void
#if NeedFunctionPrototypes
ExtForwardKeyEventMessageProc(XIMS ims, IMProtocol *call_data,
			      unsigned char *p)
#else
ExtForwardKeyEventMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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;

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
    return;
}

static void
#if NeedFunctionPrototypes
ExtMoveMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
ExtMoveMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
    return;
}

static void
#if NeedFunctionPrototypes
ExtensionMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
#else
ExtensionMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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
#if NeedFunctionPrototypes
TriggerNotifyMessageProc(XIMS ims, IMProtocol *call_data,
			 unsigned char *p)
#else
TriggerNotifyMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    /* NOTE:
         XIM_TRIGGER_NOTIFY_REPLY should be sent before XIM_SET_EVENT_MASK
       in case of XIM_TRIGGER_NOTIFY(flag == ON), while it should be
       sent after XIM_SET_EVENT_MASK in case of
       XIM_TRIGGER_NOTIFY(flag == OFF).
       */
    if (flag == 0) {	/* on key */
	_Xi18nSendMessage(ims, connect_id, XIM_TRIGGER_NOTIFY_REPLY, 0,
			  reply, total_size);
	IMPreeditStart(ims, (XPointer)call_data);
    }
    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;

    if (flag == 1) {	/* off key */
	IMPreeditEnd(ims, (XPointer)call_data);
	_Xi18nSendMessage(ims, connect_id, XIM_TRIGGER_NOTIFY_REPLY, 0,
			  reply, total_size);
    }
    /* free FrameMgr */
    FrameMgrFree(fm);
    XFree(reply);
    return;
}

static INT16
#if NeedFunctionPrototypes
ChooseEncoding(Xi18n i18n_core,
	       IMEncodingNegotiationStruct *enc_nego)
#else
ChooseEncoding(i18n_core, enc_nego)
Xi18n i18n_core;
IMEncodingNegotiationStruct *enc_nego;
#endif
{
    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;
#if 0
    return (INT16)enc_index;
#endif
}

static void
#if NeedFunctionPrototypes
EncodingNegotiatonMessageProc(XIMS ims, IMProtocol *call_data,
			      unsigned char *p)
#else
EncodingNegotiatonMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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, 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;

    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) {
	enc_nego->encoding = (XIMStr *)malloc(sizeof(XIMStr) * 10);
	memset(enc_nego->encoding, 0, sizeof(XIMStr) * 10);
	i = 0;
	while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
	    char *name;
	    int str_length;
	    FrameMgrGetToken(fm, str_length);
	    FrameMgrSetSize(fm, str_length);
	    enc_nego->encoding[i].length = str_length;
	    FrameMgrGetToken(fm, name);
	    enc_nego->encoding[i].name = malloc(str_length + 1);
	    strncpy(enc_nego->encoding[i].name, name, str_length);
	    enc_nego->encoding[i].name[str_length] = (char)0;
	    i++;
	}
	enc_nego->encoding_number = i;
    }
    /* get ENCODING INFO field */
    FrameMgrGetToken(fm, byte_length);
    if (byte_length > 0) {
	enc_nego->encodinginfo = (XIMStr *)malloc(sizeof(XIMStr) * 10);
	memset(enc_nego->encoding, 0, sizeof(XIMStr) * 10);
	i = 0;
	while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
	    char *name;
	    int str_length;
	    FrameMgrGetToken(fm, str_length);
	    FrameMgrSetSize(fm, str_length);
	    enc_nego->encodinginfo[i].length = str_length;
	    FrameMgrGetToken(fm, name);
	    enc_nego->encodinginfo[i].name = malloc(str_length + 1);
	    strncpy(enc_nego->encodinginfo[i].name, name, str_length);
	    enc_nego->encodinginfo[i].name[str_length] = (char)0;
	    i++;
	}
	enc_nego->encoding_info_number = i;
    }

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

#ifdef PROTOCOL_RICH
    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
#endif /* PROTOCOL_RICH */

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

void
#if NeedFunctionPrototypes
PreeditStartReplyMessageProc(XIMS ims, IMProtocol *call_data,
			     unsigned char *p)
#else
PreeditStartReplyMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
    return;
}

void
#if NeedFunctionPrototypes
PreeditCaretReplyMessageProc(XIMS ims, IMProtocol *call_data,
			     unsigned char *p)
#else
PreeditCaretReplyMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    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);

    if (i18n_core->address.improto)
      if (!(i18n_core->address.improto(ims, call_data)))
	return;
    return;
}

void
#if NeedFunctionPrototypes
StrConvReplyMessageProc(XIMS ims, IMProtocol *call_data,
			unsigned char *p)
#else
StrConvReplyMessageProc(ims, call_data, p)
XIMS ims;
IMProtocol *call_data;
unsigned char *p;
#endif
{
    return;
}

static void
#if NeedFunctionPrototypes
AddQueue(Xi18nClient *client, unsigned char *p)
#else
AddQueue(client, p)
Xi18nClient *client;
unsigned char *p;
#endif
{
    XIMPending	 *new, *last;

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

static void
#if NeedFunctionPrototypes
ProcessQueue(XIMS ims, CARD16 connect_id)
#else
ProcessQueue(ims, connect_id)
XIMS ims;
CARD16 connect_id;
#endif
{
    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);
	IMProtocol 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
#if NeedFunctionPrototypes
_Xi18nMessageHandler(XIMS ims, CARD16 connect_id,
		     unsigned char *p, Bool *delete)
#else
_Xi18nMessageHandler(ims, connect_id, p, delete)
XIMS ims;
CARD16 connect_id;
unsigned char *p;
Bool *delete;
#endif
{
    XimProtoHdr	*hdr = (XimProtoHdr *)p;
    unsigned char *p1 = (unsigned char *)(hdr + 1);
    IMProtocol call_data;
    Xi18n i18n_core = ims->protocol;
    Xi18nClient *client = (Xi18nClient *)_Xi18nFindClient(i18n_core,
							  connect_id);

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

    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;
    }
}
