/*
Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions: The above copyright notice and this
permission notice shall be included in all copies or substantial
portions of the Software.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP OR SUN MICROSYSTEMS, INC. BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE EVEN IF
ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.


Except as contained in this notice, the names of The Open Group and/or
Sun Microsystems, Inc. shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from The Open Group and/or Sun Microsystems,
Inc., as applicable.


X Window System is a trademark of The Open Group

OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
logo, LBX, X Window System, and Xinerama are trademarks of the Open
Group. All other trademarks and registered trademarks mentioned herein
are the property of their respective owners. No right, title or
interest in or to any trademark, service mark, logo or trade name of
Sun Microsystems, Inc. or its licensors is granted.

*/
#if !defined(USE_FRAMEMGR_ALWAYS)
#else /* USE_FRAMEMGR_ALWAYS */
#include "FrameMgr.h"
#endif /* USE_FRAMEMGR_ALWAYS */
#include "IIIMPClient.hh"
#include "IMProtoHandler.hh"
#include "IIIMPInputContext.hh"
#include "InputContext.hh"
#include "IMProtocolStruct.h"
#include "IIIMProtocol.hh"
#include "IMTrans.hh"

#if !defined(USE_FRAMEMGR_ALWAYS)
int
IIIMPClient::string_list_count2(char *p, int str_list_size) {
  char *ptr;
  int num;
  CARD16 str_size;

  num = 0;
  ptr = p;

  if (str_list_size & 0x03) {
    str_list_size &= (~0x03);
  }

  if (False == need_swap) {
    while (4 <= str_list_size) {
      req_get16(ptr, str_size);
      str_list_size -= 2;
      if ((str_size + 2) & 0x03) {	/* padding */
	str_size = (((str_size + 2) & (~0x03)) + 2);
      }
      if (str_list_size < str_size) {
	str_size = str_list_size;
      }

      ptr += str_size;
      str_list_size -= str_size;
      num += 1;
    }
  } else {
    while (4 <= str_list_size) {
      req_get16s(ptr, str_size);
      str_list_size -= 2;
      if ((str_size + 2) & 0x03) {	/* padding */
	str_size = (((str_size + 2) & (~0x03)) + 2);
      }
      if (str_list_size < str_size) {
	str_size = str_list_size;
      }

      ptr += str_size;
      str_list_size -= str_size;
      num += 1;
    }
  }
  return num;
}

char *
IIIMPClient::req_get_ascii_string(
	char * ptr, char ** string, int * size_ret, int * buf_size_ret) {
  char *p;
  int size;
  int len;
  int i;

  req_get16(ptr, size);
  if (NULL != size_ret) {
    *size_ret = size;
  }

  len = (size / 2);
  p = new char[len + 1];
  if (NULL != buf_size_ret) {
    *buf_size_ret = (len + 1);
  }

  for (i = 0; i < len; i++) {
    req_get16(ptr, *(p + i));
  }
  if ((size + 2) & 0x03) {	/* skip padding */
    ptr += (4 - ((size + 2) & 0x03));
  }
  *(p + len) = '\0';

  *string = p;

  return ptr;
}

char *
IIIMPClient::req_get_ascii_string_s(
	char * ptr, char ** string, int * size_ret, int * buf_size_ret) {
  char *p;
  int size;
  int len;
  int i;

  req_get16s(ptr, size);
  if (NULL != size_ret) {
    *size_ret = size;
  }

  len = (size / 2);
  p = new char[len + 1];
  if (NULL != buf_size_ret) {
    *buf_size_ret = (len + 1);
  }

  for (i = 0; i < len; i++) {
    req_get16s(ptr, *(p + i));
  }
  if ((size + 2) & 0x03) {	/* skip padding */
    ptr += (4 - ((size + 2) & 0x03));
  }
  *(p + len) = '\0';

  *string = p;

  return ptr;
}

#else /* USE_FRAMEMGR_ALWAYS */
#endif /* USE_FRAMEMGR_ALWAYS */

void
IIIMPClient::connect(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *data;
  char *ptr;
  int language_num;
  int total_size;
  int string_list_size;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_connect_fr[], im_connect_reply_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD8 byte_order;
  CARD8 protocol_version;
  CARD16 byte_length;

  CARD16 *attributes = (CARD16*)0;
#if !defined(USE_FRAMEMGR_ALWAYS)
  int str_length = 0;
#else /* USE_FRAMEMGR_ALWAYS */
  CARD16 str_length = 0;
#endif /* USE_FRAMEMGR_ALWAYS */

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;

  if (False == need_swap) {
    req_get8(ptr, byte_order);
    req_get8(ptr, protocol_version);
    ptr = req_get_ascii_string(ptr, &data, &str_length, NULL);
    if ((0 == str_length) || (str_length & 0x01)) {
      delete [] data;
      return;	/* something wrong */
    }
    username = data;
    // 'data' was copied to username by CompoundString's copy constructor.
    // so can be deleted.
    delete [] data;
#ifdef DO_AUTHORIZATION
    /* authorization */
    req_get16(ptr, byte_length);
    alloc_auth = string_list_count2(ptr, byte_length);
    if (0 < alloc_auth) {
      authorization_list = new CompoundString[alloc_auth];
    }
    for (i = 0; i < alloc_auth; i++) {
      ptr = req_get_ascii_string(ptr, &data, NULL, NULL);
      *(authorization_list + i) = data;
      delete [] data;
    }
#endif /* DO_AUTHORIZATION */
  } else {
    req_get8s(ptr, byte_order);
    req_get8s(ptr, protocol_version);
    ptr = req_get_ascii_string_s(ptr, &data, &str_length, NULL);
    if ((0 == str_length) || (str_length & 0x01)) {
      delete [] data;
      return;	/* something wrong */
    }
    username = data;
    // 'data' was copied to username by CompoundString's copy constructor.
    // so can be deleted.
    delete [] data;
#ifdef DO_AUTHORIZATION
    /* authorization */
    req_get16s(ptr, byte_length);
    alloc_auth = string_list_count2(ptr, byte_length);
    if (0 < alloc_auth) {
      authorization_list = new CompoundString[alloc_auth];
    }
    for (i = 0; i < alloc_auth; i++) {
      ptr = req_get_ascii_string_s(ptr, &data, NULL, NULL);
      *(authorization_list + i) = data;
      delete [] data;
    }
#endif /* DO_AUTHORIZATION */
  }
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_connect_fr, (char *)p, need_swap);

  /* get data */
  FrameMgrGetToken(fm, byte_order);
  FrameMgrGetToken(fm, protocol_version);

  /* username */
  FrameMgrGetToken(fm, str_length);
  if (str_length == 0) {
    /* something wrong */
    return;
  } else {
    CARD16 str;
    CARD8 byte_data;
    char *buffer = new char[str_length/2 + 1];
    char *usernamep;
    memset(buffer, 0, str_length/2 + 1);
    for (usernamep = buffer; usernamep < &buffer[str_length/2];
	 usernamep++) {
      FrameMgrGetToken(fm, byte_data);
      str = (byte_data << 8) & 0xff00;
      FrameMgrGetToken(fm, byte_data);
      str += byte_data & 0x00ff;
      *usernamep = (char)str;
    }
    *usernamep = (CARD8)0;
    username = buffer;
    // 'buffer' was copied to username by CompoundString's copy constructor.
    // so can be deleted.
    delete [] buffer;
  }

#ifdef DO_AUTHORIZATION
  /* authorization */
  FrameMgrGetToken(fm, byte_length);
  if (byte_length == 0) {
    FrameMgrSetIterCount(fm, 0);
  } else if (byte_length != 0) {
    int length = 0;
    CARD16 str;
    CARD8 byte_data;

    authorization = new char[byte_length/2];
    memset(authorization, 0, byte_length/2);

    number = 0;
    while (length < byte_length && number < byte_length) {
      FrameMgrGetToken(fm, str_length); length += 4;
	    
      for (strp = authorization;
	   strp < &authorization[byte_length/2];strp++) {
	FrameMgrGetToken(fm, byte_data);
	str = (byte_data << 8) & 0xff00;
	FrameMgrGetToken(fm, byte_data);
	str += byte_data & 0x00ff;
	*strp = str;
      }
      if (number >= byte_length) break;
      authorization[number] = (char)0; number++;
      length += str_length + ((4 - (str_length%4)) % 4);
    }
  }
#endif

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  /* Send IM_REGISTER_TRIGGER_KEYS protocol  */

  if (iiim_protocol->countOnKeys() || iiim_protocol->countOffKeys()) {
    register_triggerkeys();
  }

#if !defined(USE_FRAMEMGR_ALWAYS)

  language_num = iiim_protocol->countLanguages();

  total_size = 4;
  total_size += 2;	/* imid */
  total_size += 2;	/* byte length of list of language names */

  string_list_size = 0;
  for (int i = 0; i < language_num; i++) {
    unsigned char *uc;
    int len;
    uc = iiim_protocol->getLang(i + 1).toUchar();
    len = strlen((char *)uc);
    if (len & 0x01) {
      string_list_size += (2 + (2 * len));
    } else {
      string_list_size += (2 + (2 * len) + 2);
    }
  }
  total_size += string_list_size;
  data = new char[total_size];
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, string_list_size);
    for (int i = 0; i < language_num; i++) {
      unsigned char *uc;
      uc = iiim_protocol->getLang(i + 1).toUchar();
      ptr = req_put_ascii_string(ptr, (char *)uc);
    }
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, string_list_size);
    for (int i = 0; i < language_num; i++) {
      unsigned char *uc;
      uc = iiim_protocol->getLang(i + 1).toUchar();
      ptr = req_put_ascii_string_s(ptr, (char *)uc);
    }
  }
  send_message(IM_CONNECT_REPLY, data, total_size);
  delete [] data;

#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_connect_reply_fr, NULL, need_swap);

  int iter_count = iiim_protocol->countLanguages();
  /* set iteration count of lang names */
  FrameMgrSetIterCount(fm, iter_count);

  /* set byte length of BIT16 item in STRING list */
  int i;
  for (i = 0; i < iter_count; i++) {
    CompoundString langp = iiim_protocol->getLang(i+1);
    int len = strlen((char*)langp);
    FrameMgrSetIterCount(fm, len);
  }

  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size, 0);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  /* set input-method ID */
  FrameMgrPutToken(fm, im_id); /* input-method-id */

  for (i = 0; i < iter_count; i++) {
    CompoundString langp = iiim_protocol->getLang(i+1);
    SetStringToFrame(fm, langp, strlen(langp));
  }
  send_message(IM_CONNECT_REPLY, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  if (!iiim_protocol->proto_handler->Authenticate(accept_fd, username)) {
    /* being_deleted = 1; */
    delete this;
  }

}

void
IIIMPClient::dis_connect(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char data[4 + 2 + 2];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_disconnect_fr[], im_disconnect_reply_fr[];
  XimFrameRec *input_fr = im_disconnect_fr;
  XimFrameRec *output_fr = im_disconnect_reply_fr;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id;
  const int IM_OUTPUT_REPLY = IM_DISCONNECT_REPLY;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    ptr = (data + 4);
    req_put16(ptr, input_method_id);
    req_put16(ptr, 0);
  } else {
    req_get16s(ptr, input_method_id);
    ptr = (data + 4);
    req_put16s(ptr, input_method_id);
    req_put16s(ptr, 0);
  }
  send_message(IM_OUTPUT_REPLY, data, (sizeof (data)));

#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);
  /* get data */
  FrameMgrGetToken(fm, input_method_id);

  /* free FrameMgr */
  FrameMgrFree(fm);

  /* create FrameMgr */
  fm = FrameMgrInit(output_fr, NULL, need_swap);
		    
  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size, 0);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, input_method_id);
  send_message(IM_OUTPUT_REPLY, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
}

void
IIIMPClient::set_icfocus(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_seticfocus_fr[], im_seticfocus_reply_fr[];
  XimFrameRec *input_fr = im_seticfocus_fr;
  XimFrameRec *output_fr = im_seticfocus_reply_fr;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id, input_context_id;
  const int IM_OUTPUT_REPLY = IM_SETICFOCUS_REPLY;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    req_get16(ptr, input_context_id);
  } else {
    req_get16s(ptr, input_method_id);
    req_get16s(ptr, input_context_id);
  }
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);

  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  InputContext *ic = &(input_context_list.getItem(input_context_id));
  if (ic) { 
    iiim_protocol->proto_handler->SetICFocus((InputContext*)ic);
 } else {
    // need to treate as an error
  }

#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(input_method_id, input_context_id, IM_OUTPUT_REPLY);
#else /* USE_FRAMEMGR_ALWAYS */
  send_message(input_method_id, input_context_id,
	       output_fr, IM_OUTPUT_REPLY);
#endif /* USE_FRAMEMGR_ALWAYS */
  return;
}
void
IIIMPClient::unset_icfocus(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_unseticfocus_fr[], im_unseticfocus_reply_fr[];
  XimFrameRec *input_fr = im_unseticfocus_fr;
  XimFrameRec *output_fr = im_unseticfocus_reply_fr;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id, input_context_id;
  const int IM_OUTPUT_REPLY = IM_UNSETICFOCUS_REPLY;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    req_get16(ptr, input_context_id);
  } else {
    req_get16s(ptr, input_method_id);
    req_get16s(ptr, input_context_id);
  }
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);

  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  InputContext *ic = &(input_context_list.getItem(input_context_id));
  if (ic) {
    iiim_protocol->proto_handler->UnsetICFocus((InputContext*)ic);
  } else { 
    // need to treate as an error
  }

#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(input_method_id, input_context_id, IM_OUTPUT_REPLY);
#else /* USE_FRAMEMGR_ALWAYS */
  send_message(input_method_id, input_context_id,
	       output_fr, IM_OUTPUT_REPLY);
#endif /* USE_FRAMEMGR_ALWAYS */
  return;
}
void
IIIMPClient::destroy_ic(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_destroyic_fr[], im_destroyic_reply_fr[];
  XimFrameRec *input_fr = im_destroyic_fr;
  XimFrameRec *output_fr = im_destroyic_reply_fr;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id, input_context_id;
  const int IM_OUTPUT_REPLY = IM_DESTROYIC_REPLY;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    req_get16(ptr, input_context_id);
  } else {
    req_get16s(ptr, input_method_id);
    req_get16s(ptr, input_context_id);
  }
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);

  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  InputContext *ic = &(input_context_list.getItem(input_context_id));
  input_context_list.remove(ic);
  if (ic) {
    iiim_protocol->proto_handler->DestroyIC((InputContext*)ic);
  } else { 
    // need to treate as an error
  }

#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(input_method_id, input_context_id, IM_OUTPUT_REPLY);
#else /* USE_FRAMEMGR_ALWAYS */
  send_message(input_method_id, input_context_id,
	       output_fr, IM_OUTPUT_REPLY);
#endif /* USE_FRAMEMGR_ALWAYS */
  if (ic) {
    ((IIIMPInputContext*)ic)->unrealize();
    // ic should be deleted by DESTROY_IC request from IM client
    delete ic;
  }
  return;
}
void
IIIMPClient::reset_ic(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_resetic_fr[], im_resetic_reply_fr[];
  XimFrameRec *input_fr = im_resetic_fr;
  XimFrameRec *output_fr = im_resetic_reply_fr;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id, input_context_id;
  const int IM_OUTPUT_REPLY = IM_RESETIC_REPLY;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    req_get16(ptr, input_context_id);
  } else {
    req_get16s(ptr, input_method_id);
    req_get16s(ptr, input_context_id);
  }
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);
		    
  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  InputContext *ic = &(input_context_list.getItem(input_context_id));
  if (ic) {
    IMText *ret_string =
      iiim_protocol->proto_handler->ResetIC((InputContext*)ic);
    ic->commit_string(ret_string);
  } else { 
    // need to treate as an error
  }
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(input_method_id, input_context_id, IM_OUTPUT_REPLY);
#else /* USE_FRAMEMGR_ALWAYS */
  send_message(input_method_id, input_context_id,
	       output_fr, IM_OUTPUT_REPLY);
#endif /* USE_FRAMEMGR_ALWAYS */
  return;
}

void
IIIMPClient::forward_keyevent(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  IMKeyEventStruct *imkev;
  int n_key;
  int i;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  FmStatus status;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id, input_context_id;
  CARD32 type, byte_length;
  CARD32 *keyevent_list = (CARD32*)0;
  int number;

#if !defined(USE_FRAMEMGR_ALWAYS)
  if (False == need_swap) {
    req_get16(p, input_method_id);
    req_get16(p, input_context_id);
    req_get32(p, type);
    req_get32(p, byte_length);
    if (0 == byte_length) return;
    n_key = (byte_length / (4 * (sizeof (CARD32))));
    imkev = new IMKeyEventStruct[n_key];
    if (NULL == imkev) return;
    for (i = 0; i < n_key; i++) {
      req_get32(p, (imkev + i)->keyCode);
      req_get32(p, (imkev + i)->keyChar);
      req_get32(p, (imkev + i)->modifier);
      req_get32(p, (imkev + i)->time_stamp);
    }
  } else {
    req_get16s(p, input_method_id);
    req_get16s(p, input_context_id);
    req_get32s(p, type);
    req_get32s(p, byte_length);
    if (0 == byte_length) return;
    n_key = (byte_length / (4 * (sizeof (CARD32))));
    imkev = new IMKeyEventStruct[n_key];
    if (NULL == imkev) return;
    for (i = 0; i < n_key; i++) {
      req_get32s(p, (imkev + i)->keyCode);
      req_get32s(p, (imkev + i)->keyChar);
      req_get32s(p, (imkev + i)->modifier);
      req_get32s(p, (imkev + i)->time_stamp);
    }
  }

  InputContext *ic = &(input_context_list.getItem(input_context_id));

  if (NULL == ic) {
    delete [] imkev;
    return;
  }

  IMKeyListEvent keylist_event;
  keylist_event.type = IM_EventKeyList;
  keylist_event.n_operation = 0;
  keylist_event.operation_list = 0;
  keylist_event.n_key = n_key;
  keylist_event.keylist = imkev;

  iiim_protocol->proto_handler->ForwardEvent((InputContext*)ic,
					     (IMInputEvent*)&keylist_event);
  delete [] imkev;

  return;

#else /* USE_FRAMEMGR_ALWAYS */
  extern XimFrameRec im_forward_event_keyevent_fr[];
  XimFrameRec *input_fr = im_forward_event_keyevent_fr;

  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);
  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);
  FrameMgrGetToken(fm, type);

  FrameMgrGetToken(fm, byte_length);

  keyevent_list = (CARD32*)new char[byte_length];
  if (keyevent_list == NULL) {
    return;
  }
  if (byte_length != 0) {
    number = 0;
    while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
      /* get a key event */
      FrameMgrGetToken(fm, keyevent_list[number]);
      number++;
    }
  }

  /* free FrameMgr */
  FrameMgrFree(fm);

  InputContext *ic = &(input_context_list.getItem(input_context_id));

  if (ic) {
    IMKeyListEvent keylist_event;
    keylist_event.type = IM_EventKeyList;
    keylist_event.n_operation = 0;
    keylist_event.operation_list = 0;

    int n_key = byte_length/(4 * sizeof(CARD32));
    IMKeyEventStruct *imkev = new IMKeyEventStruct[n_key];

    keylist_event.n_key = n_key;
    int n = 0;
    number = 0;
    while (number < byte_length/4) { 
      imkev[n].keyCode = keyevent_list[number]; /* keyCode */
      imkev[n].keyChar = keyevent_list[number + 1]; /* keyChar */
      imkev[n].modifier = keyevent_list[number + 2]; /* modifier */
      imkev[n].time_stamp = keyevent_list[number + 3]; /* time_stamp */
      number += 4; n++;
    }
    keylist_event.keylist = imkev;
    iiim_protocol->proto_handler->ForwardEvent((InputContext*)ic,
				       (IMInputEvent*)&keylist_event);
    delete [] imkev;
  } else {
    // need to treate as an error
  }
  delete [] keyevent_list;
  return;
#endif /* USE_FRAMEMGR_ALWAYS */
}
void
IIIMPClient::forward_event(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  unsigned char * pp;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_forward_event_fr[];
  extern XimFrameRec im_forward_event_reply_fr[];
  XimFrameRec *output_fr = im_forward_event_reply_fr;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id, input_context_id;
  CARD32 type;
  const int IM_OUTPUT_REPLY = IM_FORWARD_EVENT_REPLY;

#if !defined(USE_FRAMEMGR_ALWAYS)
  pp = p;
  if (False == need_swap) {
    req_get16(pp, input_method_id);
    req_get16(pp, input_context_id);
    req_get32(pp, type);
  } else {
    req_get16s(pp, input_method_id);
    req_get16s(pp, input_context_id);
    req_get32s(pp, type);
  }
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_forward_event_fr, (char *)p, need_swap);

  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);
  FrameMgrGetToken(fm, type);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  switch (type) {
  case FORWARD_STRING:
    forward_string(call_data, p);
    break;
  case FORWARD_TEXT:
    forward_text(call_data, p);
    break;
  case FORWARD_KEYEVENT:
    forward_keyevent(call_data, p);
    break;
  }

  /* always send a syncroneous reply */
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(input_method_id, input_context_id, IM_OUTPUT_REPLY);
#else /* USE_FRAMEMGR_ALWAYS */
  send_message(input_method_id, input_context_id,
	       output_fr, IM_OUTPUT_REPLY);
#endif /* USE_FRAMEMGR_ALWAYS */
  return;
}
void
IIIMPClient::trigger_notify(IMProtocolStruct *call_data, unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char data[4 + 2 + 2];
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_trigger_notify_fr[], im_trigger_notify_reply_fr[];
  XimFrameRec *input_fr = im_trigger_notify_fr;
  XimFrameRec *output_fr = im_trigger_notify_reply_fr;
#endif /* USE_FRAMEMGR_ALWAYS */
  CARD16 input_method_id, input_context_id;
  CARD16 flag;
  const int IM_OUTPUT_REPLY = IM_TRIGGER_NOTIFY_REPLY;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    req_get16(ptr, input_context_id);
    req_get16(ptr, flag);
  } else {
    req_get16s(ptr, input_method_id);
    req_get16s(ptr, input_context_id);
    req_get16s(ptr, flag);
  }
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);
  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);
  FrameMgrGetToken(fm, flag);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  InputContext *ic = &(input_context_list.getItem(input_context_id));
  if (ic) {
    if (flag == 0)
      iiim_protocol->proto_handler->StartConversion((InputContext*)ic);
    else
      iiim_protocol->proto_handler->EndConversion((InputContext*)ic);
  } else {
    // need to treat as an error
  }

#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(input_method_id, input_context_id, IM_OUTPUT_REPLY);
#else /* USE_FRAMEMGR_ALWAYS */
  send_message(input_method_id, input_context_id,
	       output_fr, IM_OUTPUT_REPLY);
#endif /* USE_FRAMEMGR_ALWAYS */
  return;
}
void
IIIMPClient::preedit_start_reply(IMProtocolStruct *call_data,
				 unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_preedit_start_reply_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMPreeditStruct preedit;
  CARD16 input_method_id, input_context_id;
  int return_value;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    req_get16(ptr, input_context_id);
    req_get16(ptr, return_value);
  } else {
    req_get16s(ptr, input_method_id);
    req_get16s(ptr, input_context_id);
    req_get16s(ptr, return_value);
  }
#ifdef DEBUG
  // cerr << "Preedit Start CB reply" << endl;
  // cerr << "need to set return_value to preedit rendering object" << endl;
#endif
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_preedit_start_reply_fr, (char *)p, need_swap);

  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);
  FrameMgrGetToken(fm, return_value);

#ifdef DEBUG
  // cerr << "Preedit Start CB reply" << endl;
  // cerr << "need to set return_value to preedit rendering object" << endl;
#endif

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return;
}
void
IIIMPClient::preedit_caret_reply(IMProtocolStruct *call_data,
				 unsigned char *p) {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_preedit_caret_reply_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */
  IMPreeditStruct preedit;
  IMPreeditCaretCallbackStruct *caret =
    (IMPreeditCaretCallbackStruct *)&preedit.todo.caret;
  CARD16 input_method_id, input_context_id;
  int caret_position;

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = (char *)p;
  if (False == need_swap) {
    req_get16(ptr, input_method_id);
    req_get16(ptr, input_context_id);
    req_get16(ptr, caret_position);
  } else {
    req_get16s(ptr, input_method_id);
    req_get16s(ptr, input_context_id);
    req_get16s(ptr, caret_position);
  }
#ifdef DEBUG
  // cerr << "Preedit Caret CB reply" << endl;
  // cerr << "need to set caret_position to preedit rendering object" << endl;
#endif
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_preedit_caret_reply_fr, (char *)p, need_swap);

  /* get data */
  FrameMgrGetToken(fm, input_method_id);
  FrameMgrGetToken(fm, input_context_id);
  FrameMgrGetToken(fm, caret_position);

#ifdef DEBUG
  // cerr << "Preedit Caret CB reply" << endl;
  // cerr << "need to set caret_position to preedit rendering object" << endl;
#endif

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  return;
}

void
IIIMPClient::register_triggerkeys() {
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *data;
  char *ptr;
  int total_size;
  CARD32 time_stamp = 0;
  int keycode;
  int modifier;
  IMTriggerKey keyp;
  int i;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_register_triggerkeys_fr[];
#endif /* USE_FRAMEMGR_ALWAYS */

  CARD16 on_key_num = iiim_protocol->countOnKeys();
  CARD16 off_key_num = iiim_protocol->countOffKeys();

  if (on_key_num == 0 && off_key_num == 0) return;

#if !defined(USE_FRAMEMGR_ALWAYS)
  total_size = 4;
  total_size += (2 + 2);
  total_size += 4;				/* byte length of on-keys */
  total_size += ((4 * 4) * on_key_num);		/* trigger keys to turn on */
  total_size += 4;				/* byte length of off-keys */
  total_size += ((4 * 4) * off_key_num);	/* trigger keys to turn off */
  data = new char[total_size];
  ptr = (data + 4);
  if (False == need_swap) {
    req_put16(ptr, im_id);
    req_put16(ptr, 0);		/* padding */
    req_put32(ptr, ((4 * 4) * on_key_num));
    for (i = 0; i < on_key_num; i++) {
      keyp = iiim_protocol->getOnKey(i + 1);
      keycode = keyp.get_keyCode();
      req_put32(ptr, keycode);
      req_put32(ptr, keycode); /* for keychar */
      if ((modifier = keyp.get_modifier()) & (1<<2)) {
        /* Java's control_mask(1<<1) and X's control_mask(1<<2)is
	   different, so it should be changed */
	modifier -= (1<<2);
	modifier |= (1<<1);
      }
      req_put32(ptr, modifier);
      req_put32(ptr, time_stamp);
    }
    req_put32(ptr, ((4 * 4) * off_key_num));
    for (i = 0; i < off_key_num; i++) {
      keyp = iiim_protocol->getOffKey(i + 1);
      keycode = keyp.get_keyCode();
      req_put32(ptr, keycode);
      req_put32(ptr, keycode); /* for keychar */
      if ((modifier = keyp.get_modifier()) & (1<<2)) {
        /* Java's control_mask(1<<1) and X's control_mask(1<<2)is
	   different, so it should be changed */
	modifier -= (1<<2);
	modifier |= (1<<1);
      }
      req_put32(ptr, modifier);
      req_put32(ptr, time_stamp);
    }
  } else {
    req_put16s(ptr, im_id);
    req_put16s(ptr, 0);		/* padding */
    req_put32s(ptr, ((4 * 4) * on_key_num));
    for (i = 0; i < on_key_num; i++) {
      keyp = iiim_protocol->getOnKey(i + 1);
      keycode = keyp.get_keyCode();
      req_put32s(ptr, keycode);
      req_put32s(ptr, keycode); /* for keychar */
      if ((modifier = keyp.get_modifier()) & (1<<2)) {
        /* Java's control_mask(1<<1) and X's control_mask(1<<2)is
	   different, so it should be changed */
	modifier -= (1<<2);
	modifier |= (1<<1);
      }
      req_put32s(ptr, modifier);
      req_put32s(ptr, time_stamp);
    }
    req_put32s(ptr, ((4 * 4) * off_key_num));
    for (i = 0; i < off_key_num; i++) {
      keyp = iiim_protocol->getOffKey(i + 1);
      keycode = keyp.get_keyCode();
      req_put32s(ptr, keycode);
      req_put32s(ptr, keycode); /* for keychar */
      if ((modifier = keyp.get_modifier()) & (1<<2)) {
        /* Java's control_mask(1<<1) and X's control_mask(1<<2)is
	   different, so it should be changed */
	modifier -= (1<<2);
	modifier |= (1<<1);
      }
      req_put32s(ptr, modifier);
      req_put32s(ptr, time_stamp);
    }
  }
  send_message(IM_REGISTER_TRIGGER_KEYS, data, total_size);
  delete [] data;
#else /* USE_FRAMEMGR_ALWAYS */
  /* create FrameMgr */
  fm = FrameMgrInit(im_register_triggerkeys_fr, NULL, need_swap);

  /* set iteration count for on-keys list */
  FrameMgrSetIterCount(fm, on_key_num);
  /* set iteration count for off-keys list */
  FrameMgrSetIterCount(fm, off_key_num);

  /* get total_size */
  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size, 0);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  /* Right now IM_CONNECT_REPLY hasn't been sent to this new client, so
     the input-method-id is still invalid, but it is set to accept_fd
  */
  FrameMgrPutToken(fm, im_id); /* input-method-id */

  CARD32 time_stamp = 0;
  int keycode, modifier;
  IMTriggerKey keyp;
  int i;

  for (i = 0; i < on_key_num; i++) {
    keyp = iiim_protocol->getOnKey(i+1);
    keycode = keyp.get_keyCode();
    FrameMgrPutToken(fm, keycode);
    FrameMgrPutToken(fm, keycode); /* for keychar */
    if ((modifier = keyp.get_modifier()) & (1<<2)) {
      /* Java's control_mask(1<<1) and X's control_mask(1<<2)is
	 different, so it should be changed */
      modifier -= (1<<2);
      modifier |= (1<<1);
    }
    FrameMgrPutToken(fm, modifier);
    FrameMgrPutToken(fm, time_stamp);
  }

  for (i = 0; i < off_key_num; i++) {
    keyp = iiim_protocol->getOffKey(i+1);
    keycode = keyp.get_keyCode();
    FrameMgrPutToken(fm, keycode);
    FrameMgrPutToken(fm, keycode); /* for keychar */
    if ((modifier = keyp.get_modifier()) & (1<<2)) {
      /* Java's control_mask(1<<1) and X's control_mask(1<<2)is
	 different, so it should be changed */
      modifier -= (1<<2);
      modifier |= (1<<1);
    }
    FrameMgrPutToken(fm, modifier);
    FrameMgrPutToken(fm, time_stamp);
  }

  send_message(IM_REGISTER_TRIGGER_KEYS, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */

  return;
}

void
IIIMPClient::send_message(int input_method_id, int input_context_id,
			  int opcode) {
  int	data_len;
  char	buf[4 + 2 + 2];
  char *p;

  /* calculate length */
  buf[0] = opcode;
  buf[1] = 0;
  buf[2] = 0;
  buf[3] = 1;

  p = (buf + 4);

  if (False == need_swap) {
    req_put16(p, input_method_id);
    req_put16(p, input_context_id);
  } else {
    req_put16s(p, input_method_id);
    req_put16s(p, input_context_id);
  }

  write_data(buf, sizeof (buf));

  return;
}
void
IIIMPClient::send_message(int opcode, char * request, int request_len) {
  int data_len;

  data_len = ((request_len - 4) / 4);
  *(request + 0) = opcode;
  *(request + 1) = ((data_len >> 16) & 0xff);
  *(request + 2) = ((data_len >>  8) & 0xff);
  *(request + 3) = ((data_len >>  0) & 0xff);

  write_data(request, request_len);

  return;
}

#if !defined(USE_FRAMEMGR_ALWAYS)
#else /* USE_FRAMEMGR_ALWAYS */
void
IIIMPClient::send_message(int input_method_id, int input_context_id,
			  XimFrameRec *output_fr, int opcode) {
  FrameMgr fm;

  fm = FrameMgrInit(output_fr, NULL, need_swap);
		    
  const int total_size = FrameMgrGetTotalSize(fm);
  CompoundString reply = CompoundString(total_size, 0);
  memset(reply, 0, total_size);
  FrameMgrSetBuffer(fm, reply);

  FrameMgrPutToken(fm, input_method_id);
  FrameMgrPutToken(fm, input_context_id);
  send_message(opcode, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);
}
#endif /* USE_FRAMEMGR_ALWAYS */

void
IIIMPClient::send_message(int opcode, CompoundString& csdata, int data_length) {
  unsigned char *data = csdata.toUchar();
#if !defined(USE_FRAMEMGR_ALWAYS)
  char *ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  FrameMgr fm;
  extern XimFrameRec im_packet_header_fr[];
  int header_size;
  unsigned char *replyp;
  int reply_length;
  long p_len = data_length/4;
  CARD8 length[3];
#endif /* USE_FRAMEMGR_ALWAYS */

#if !defined(USE_FRAMEMGR_ALWAYS)
  ptr = new char[4 + data_length];
  memcpy(ptr + 4, data, data_length);
  send_message(opcode, ptr, 4 + data_length);
  delete [] ptr;
#else /* USE_FRAMEMGR_ALWAYS */
  /* calculate length */
  length[2] = ((p_len >> 16) & 0xff);
  length[1] = ((p_len >> 8) & 0xff);
  length[0] = (p_len & 0xff);

  /* create FrameMgr */
  fm = FrameMgrInit(im_packet_header_fr, NULL, need_swap);

  header_size = FrameMgrGetTotalSize(fm);

  CompoundString reply_hdr = CompoundString(header_size, 0);
  FrameMgrSetBuffer(fm, reply_hdr);

  /* put data */
  FrameMgrPutToken(fm, opcode);
  FrameMgrPutToken(fm, length[2]);
  FrameMgrPutToken(fm, length[1]);
  FrameMgrPutToken(fm, length[0]);

  reply_length = header_size + data_length;

  CompoundString reply = CompoundString(reply_length, 0);
  memmove(reply, reply_hdr, header_size);

  replyp = reply.toUchar();
  replyp += header_size;
  memmove(replyp, data, data_length);

  write_data((char*)reply, reply_length);

  /* free FrameMgr */
  FrameMgrFree(fm);
#endif /* USE_FRAMEMGR_ALWAYS */
  return;
}

