/*
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.

*/
#include "FrameMgr.h"
#include "IIIMPClient.hh"
#include "IMProtoHandler.hh"
#include "IIIMPInputContext.hh"
#include "ICAttribute.hh"
#include "IIIMProtocol.hh"
#include "IMProtocolStructP.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#ifndef	WIN32
#include <unistd.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *read_object(char *, int *);
char *read_ccdef(char *, char *, int*);

char *
read_object(
	    char *path,		/* path */
	    int *length		/* return length */
	    )
{
  FILE *fd;
  int ret;
  struct stat s_buf;
  char *contents;
  *length = 0;

  if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) {
    perror("");
    return 0;
  }
  contents = new char[s_buf.st_size + 1];

  if ((fd = fopen(path, "rb")) == NULL) {
    perror("");
    return 0;
  }
  ret = fread(contents, s_buf.st_size, 1, fd);

  /*
   * if (ret != s_buf.st_size) { printf("size error %d != %d\n",
   * ret, s_buf.st_size); return 0; }
   */
  *length = s_buf.st_size;

#ifdef	DEBUG
  for (int i = 0; i < *length; i++) {
    printf("%x\n", contents[i]);
  }
#endif

  fclose(fd);

  return contents;
}

static int get_path(char *, char *);
static FILE *openfile(char *, char *);

#define	TMPUNIT 1024
#define	BUFSIZE 1024

#ifdef _POSIX_PATH_MAX
#define PATHNAME_MAX _POSIX_PATH_MAX
#else
#define PATHNAME_MAX 1024
#endif

char *
read_ccdef(
	   char *path,
	   char *basepath,
	   int *length
	   )
{
  FILE *fp;
  int ret;
  struct stat s_buf;
  char *tmp;
  char line[PATHNAME_MAX];
  char incfile[PATHNAME_MAX];
  int m = 1;

  if (stat(path, &s_buf) == -1 || !(s_buf.st_mode & S_IREAD)) {
    return 0;
  }

  tmp = (char *) malloc(sizeof(char) * TMPUNIT);
  strcpy(tmp, "");

  if ((fp = fopen(path, "rb")) == NULL) {
    return 0;
  }
  while (fgets((char *) line, 256, fp) != NULL) {
    if (strlen(line) <= 1) {
      continue;
    }
    if (strncmp(line, "#", 1) == 0) {
      continue;
    }
    if (strstr(line, "include")) {
      if (get_path(line, &incfile[0])) {
	FILE *fp2 = openfile(basepath, incfile);
	if (fp2 == NULL) {
#ifdef DEBUG
	  printf("can't open incfile=%s\n", incfile);
#endif
	  continue;
	} else {
	  while (fgets((char *) line, 256, fp2) != NULL) {
	    if (strlen(line) <= 1) {
	      continue;
	    }
	    if (strncmp(line, "#", 1) == 0) {
	      continue;
	    }
	    if (strlen(tmp) + strlen(line) >= TMPUNIT * m) {
	      tmp = (char *) realloc((void *) tmp,
				     sizeof(char) * TMPUNIT * (++m));
	    }
	    strcat(tmp, line);
#ifdef	DEBUG
	    printf("line=[%s]\n", line);
#endif
	  }
	  fclose(fp2);
	}
      } else {
	if (strlen(tmp) + strlen(line) >= TMPUNIT * m) {
	  tmp = (char *) realloc((void *) tmp,
				 sizeof(char) * TMPUNIT * (++m));
	}
	strcat(tmp, line);
#ifdef	DEBUG
	printf("line=[%s]\n", line);
#endif
      }
    } else {
      if (strlen(tmp) + strlen(line) >= TMPUNIT * m) {
	tmp = (char *) realloc((void *) tmp,
			       sizeof(char) * TMPUNIT * (++m));
      }
      strcat(tmp, line);
#ifdef	DEBUG
      printf("line=[%s]\n", line);
#endif
    }
  }
  fclose(fp);

  *length = strlen(tmp);
  return tmp;
}

#define	Token " \n\r\t,\"'"

static int
get_path(
	 char *p,
	 char *path
	 )
{
  char tmp[BUFSIZE];
  char *k;

  strcpy(tmp, p);
  k = strtok(tmp, Token);
  if (k != NULL) {
    if (strncmp(k, "include", 7) == 0) {
      k = strtok(NULL, Token);
      if (k != NULL) {
	strcpy(path, k);
      }
      k = strtok(NULL, Token);
      if (k != NULL) {
	return 0;
      } else {
	return 1;
      }
    }
  }
  return 0;
}

static FILE *
openfile(
	 char *basepath,
	 char *incfile
	 )
{
  char path[PATHNAME_MAX];
#ifdef	WIN32
  if (incfile[0] == '\\') {
#else
    if (incfile[0] == '/') {
#endif
      sprintf(path, "%s", incfile);
    } else {
#ifdef	WIN32
      sprintf(path, "%s\\%s", basepath, incfile);
#else
      sprintf(path, "%s/%s", basepath, incfile);
#endif
    }
    return fopen(path, "r");
}

void
IIIMPClient::SetStringToFrame(FrameMgr fm, UTFCHAR* utf_str,
			      int char_length) {
  CARD8 *str = (CARD8*)utf_str;
  const int one_unit = sizeof(UTFCHAR)/sizeof(char);
  for (CARD8 *strp = str; strp < &str[char_length * one_unit];) {
    CARD8 first_byte, second_byte;
    if (need_swap) {
      second_byte = *strp++;
      first_byte  = *strp++;
    } else {
      first_byte  = *strp++;
      second_byte = *strp++;
    }
    FrameMgrPutToken(fm, first_byte);
    FrameMgrPutToken(fm, second_byte);
  }
}

void
IIIMPClient::SetStringToFrame(FrameMgr fm, char* str,
			      int length) {
  CARD8 first_byte, second_byte;
  if (need_swap) {
    for (char *strp = str; strp < &str[length];) {
      CARD16 c = (CARD16)(*(strp++));
      first_byte = *((CARD8 *)(&c) + 1);
      second_byte = *((CARD8 *)(&c) + 0);
      FrameMgrPutToken(fm, first_byte);
      FrameMgrPutToken(fm, second_byte);
    }
  } else {
    for (char *strp = str; strp < &str[length];) {
      CARD16 c = (CARD16)(*(strp++));
      first_byte = *((CARD8 *)(&c) + 0);
      second_byte = *((CARD8 *)(&c) + 1);
      FrameMgrPutToken(fm, first_byte);
      FrameMgrPutToken(fm, second_byte);
    }
  }
}

unsigned char *
IIIMPClient::create_jarfile_object_frame(IMObjectDescriptorStruct *od,
					 char *contents, int ob_size,
					 unsigned int *buf_size) {
  extern XimFrameRec jarfileobject_fr[];
  FrameMgr fm;

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

  /* set iteration count for list of ic_attribute */
  FrameMgrSetIterCount(fm, od->count_names);

  /* set byte length of BIT16 item in STRING list */
  int i;
  for (i = 0; i < od->count_names; i++) {
    CompoundString name = od->class_names[i];
    int len = strlen((char*)name);
    FrameMgrSetIterCount(fm, len);
  }

  FrameMgrSetSize(fm, ob_size);	// byte length of jar file

  const int total_size = FrameMgrGetTotalSize(fm);
  unsigned char *buffer  = new unsigned char[total_size];
  memset(buffer, 0, total_size);
  FrameMgrSetBuffer(fm, buffer);

  for (i = 0; i < od->count_names; i++) {
    CompoundString name = od->class_names[i];
    int len = strlen((char*)name);
    for (char *strp = name; strp < &(name)[len]; strp++) {
      CARD16 str = (CARD16)*strp;
      CARD8 byte_data;
      byte_data = (str << 8) & 0xff00;
      FrameMgrPutToken(fm, byte_data);
      byte_data = str & 0x00ff;
      FrameMgrPutToken(fm, byte_data);
    }
  }
  FrameMgrPutToken(fm, ob_size);
  FrameMgrPutToken(fm, contents);

  FrameMgrFree(fm);

  *buf_size = total_size;
  return buffer;
}

unsigned char *
IIIMPClient::create_ccdef_object_frame(IMObjectDescriptorStruct *od,
				       char *contents, int ob_size,
				       unsigned int *buf_size) {
  extern XimFrameRec ccdef_fr[];
  FrameMgr fm;

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

  FrameMgrSetIterCount(fm, ob_size);

  const int total_size = FrameMgrGetTotalSize(fm);
  unsigned char *buffer  = new unsigned char[total_size];
  memset(buffer, 0, total_size);
  FrameMgrSetBuffer(fm, buffer);

  SetStringToFrame(fm, contents, ob_size);

  FrameMgrFree(fm);

  *buf_size = total_size;
  return buffer;
}

unsigned char *
IIIMPClient::create_binfile_object_frame(IMObjectDescriptorStruct *od,
					 unsigned int *buf_size) {
  extern XimFrameRec binfileobject_fr[];
  FrameMgr fm;
  int i;

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

  FrameMgrSetIterCount(fm, strlen(od->path));

  const int total_size = FrameMgrGetTotalSize(fm);
  unsigned char *buffer  = new unsigned char[total_size];
  memset(buffer, 0, total_size);
  FrameMgrSetBuffer(fm, buffer);

#ifdef	notdef
  for (i = 0; i < od->count_names; i++) {
    CompoundString name = od->class_names[i];
    int len = strlen((char*)name);
    for (char *strp = name; strp < &(name)[len]; strp++) {
      CARD16 str = (CARD16)*strp;
      CARD8 byte_data;
      byte_data = (str << 8) & 0xff00;
      FrameMgrPutToken(fm, byte_data);
      byte_data = str & 0x00ff;
      FrameMgrPutToken(fm, byte_data);
    }
  }
#endif
  SetStringToFrame(fm, od->path, strlen(od->path));

  FrameMgrFree(fm);

  *buf_size = total_size;
  return buffer;
}

void
IIIMPClient::set_imvalues(IMProtocolStruct *call_data, unsigned char *p) {
  CARD16 input_method_id;
  CARD16 byte_length;
  FrameMgr fm;
  FmStatus status;

  extern XimFrameRec im_setimvalues_fr[], im_setimvalues_reply_fr[];
  XimFrameRec *input_fr = im_setimvalues_fr;
  XimFrameRec *output_fr = im_setimvalues_reply_fr;
  const int IM_OUTPUT_REPLY = IM_SETIMVALUES_REPLY;

  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);

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

  if (byte_length != 0) {
    if (alloc_attr == 0) {
      alloc_attr = IIIMPClient::MAX_ATTRNUM;
      imAttribute_list = new ICAttribute[alloc_attr];
      memset(imAttribute_list, 0, sizeof(ICAttribute) * alloc_attr);
      active_attr = 0;
    }
    int first_im_index = active_attr;
    while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
      void *value;
      int value_length;
      if (active_attr == alloc_attr) {
	alloc_attr += IIIMPClient::MAX_ATTRNUM;
	ICAttribute *temp = imAttribute_list;
	imAttribute_list = new ICAttribute[alloc_attr];
	memset(imAttribute_list, 0, sizeof(ICAttribute) * alloc_attr);
	memmove(imAttribute_list, temp, sizeof(ICAttribute) * active_attr);
	delete [] temp;
      }
      FrameMgrGetToken(fm, imAttribute_list[active_attr].attribute_id);
      FrameMgrGetToken(fm, value_length);
      FrameMgrSetSize(fm, value_length);
      imAttribute_list[active_attr].value_length = value_length;
      FrameMgrGetToken(fm, value);
      imAttribute_list[active_attr].value = new char[value_length];
      memmove(imAttribute_list[active_attr].value, value, value_length);
      active_attr++;
    }
    /* The value from the protocol may need to be byte-swapped */
    for (ICAttribute *imp = &imAttribute_list[first_im_index];
	 imp < &imAttribute_list[active_attr]; imp++) {
      char *tmp_imp_value = (char*) imp->value;
      if (read_imvalue(imp->attribute_id,
		       imp->value_length,
		       imp->value,
		       imp) == 0) {
	if (imp->name == iiim_protocol->IMListName) {
	  ;
	}
	else if (imp->name == iiim_protocol->IMClientName) {
#if !defined(USE_FRAMEMGR_ALWAYS)
	  int left = imp->value_length;
#else /* USE_FRAMEMGR_ALWAYS */
	  int left = imp->value_length/2 - 1; // evil
#endif /* USE_FRAMEMGR_ALWAYS */
	  // LISTofSTRING(applicationName, osName, osArck, osVersion)
	  char *p = (char*)imp->value;
	  size_t len;
	  if (left == 0) continue;
	  application_name = (char*)p;
	  len = strlen(p) + 1; p += len; left -= len;
	  if (left == 0) continue;

	  os_name = (char*)p;
	  len = strlen(p) + 1; p += len; left -= len;
	  if (left == 0) continue;

	  os_arch = (char*)p;
	  len = strlen(p) + 1; p += len; left -= len;
	  if (left == 0) continue;

	  os_version = (char*)p;
	  // LISTofSTRING(display_name, server_vendor) may follow
	  len = strlen(p) + 1; p += len; left -= len;
	  if (left <= 0) continue;

	  xDisplayName = (char*)p;
	  len = strlen(p) + 1; p += len; left -= len;
	  if (left <= 0) continue;

	  xServerVendor = (char*)p;
	}
	else if (imp->name == iiim_protocol->IMObjectListName) {
	  ;
	}
	else if (imp->name == iiim_protocol->IMCCDEFName) {
	  ;
	}
	else if (imp->name == iiim_protocol->IMGUIObjectName) {
	  ;
	}
	else if (imp->name == iiim_protocol->IMLWEObjectName) {
	  ;
	}
      }
      delete [] tmp_imp_value;
      delete [] imp->value;
    }
  }

  /* free FrameMgr */
  FrameMgrFree(fm);

  // IF this IM_SETIMVALUES is sent before the 1st input context is
  // created, send OBJECTDESCRIPTOR to the client

  if (input_context_list.getSize() == 0) {

    // return INPUTMETHODLIST to the client if any
    int count = iiim_protocol->countIME();
    int i;
    extern XimFrameRec inputmethod_fr[];
    int iter_count;
    unsigned char *imelist_buf = (unsigned char*)0;
    unsigned int imelist_size = 0;
    IMEditorStruct ime;
    for (i = 0; i < count; i++) {
      ime = iiim_protocol->getIME(i+1);
      fm = FrameMgrInit(inputmethod_fr, NULL, need_swap);

      iter_count = strlen(ime.domain); // object User
      FrameMgrSetIterCount(fm, iter_count);
      iter_count = ime.name_length;
      FrameMgrSetIterCount(fm, iter_count);

      int lang_count = ime.count_locales;

      /* set iteration count of lang names */
      FrameMgrSetIterCount(fm, lang_count);

      // set byte length of BIT16 item in STRING list
      int j;
      for (j = 0; j < lang_count; j++) {
	CompoundString langp(ime.locales[i]);
	int len = strlen((char*)langp);
	FrameMgrSetIterCount(fm, len);
      }

      const int ime_size = FrameMgrGetTotalSize(fm);
      CompoundString ime_buf = CompoundString(ime_size);
      memset(ime_buf, 0, ime_size);
      FrameMgrSetBuffer(fm, ime_buf);

      FrameMgrPutToken(fm, ime.id);
      SetStringToFrame(fm, ime.domain, strlen(ime.domain));
      SetStringToFrame(fm, ime.name, ime.name_length);

      for (j = 0; j < lang_count; j++) {
	CompoundString langp(ime.locales[i]);
	SetStringToFrame(fm, langp, strlen(langp));
      }

      if (!imelist_buf) {
	imelist_buf = new unsigned char[ime_size];
	imelist_size = ime_size;
	memmove(imelist_buf, ime_buf, ime_size);
      } else {
	unsigned char *temp = new unsigned char[imelist_size + ime_size];
	unsigned char *pTemp = temp;
	memmove(pTemp, imelist_buf, imelist_size);
	pTemp += imelist_size;
	memmove(pTemp, ime_buf, ime_size);
	imelist_size += ime_size;
	delete [] imelist_buf;
	imelist_buf = temp;
      }
      /* free FrameMgr */
      FrameMgrFree(fm);
    }

    // return OBJECTDESCRIPTORLIST to the client
    count = iiim_protocol->countObjectDescriptors();
    extern XimFrameRec objectdescriptor_fr[];
    unsigned char *odlist_buf = (unsigned char*)0;
    unsigned int odlist_size = 0;
    IMObjectDescriptorStruct od;

    CompoundString client_type = getApplicationName();

    for (i = 0; i < count; i++) {
      od = iiim_protocol->getObjectDescriptor(i+1);

      if(strstr((char*)client_type, "JDK")){ /* JAVA */
        if(od.type == IM_DOWNLOADINGOBJECT_BINGUI_TYPE ||
           od.type == IM_DOWNLOADINGOBJECT_BINLWE_TYPE) {
          continue;
        }
      } else { /* from xiiimp.so.2 */
        if(od.type == IM_DOWNLOADINGOBJECT_JARGUI_TYPE ||
           od.type == IM_DOWNLOADINGOBJECT_JARLWE_TYPE) {
          continue;
        }
      }

      fm = FrameMgrInit(objectdescriptor_fr, NULL, need_swap);
      iter_count = strlen(od.domain); // reversed unique domain name
      FrameMgrSetIterCount(fm, iter_count);
      iter_count = od.name_length;
      FrameMgrSetIterCount(fm, iter_count);
      iter_count = 0;		// signature
      FrameMgrSetIterCount(fm, iter_count);
      iter_count = strlen(od.scope); // object User
      FrameMgrSetIterCount(fm, iter_count);

      const int od_size = FrameMgrGetTotalSize(fm);
      CompoundString od_buf = CompoundString(od_size);
      memset(od_buf, 0, od_size);
      FrameMgrSetBuffer(fm, od_buf);

      IMObjectCategory category = IM_GUI_OBJECT;
      FrameMgrPutToken(fm, category);
      FrameMgrPutToken(fm, od.size);
      FrameMgrPutToken(fm, od.type);
      FrameMgrPutToken(fm, od.id);
      SetStringToFrame(fm, od.domain, strlen(od.domain));
      SetStringToFrame(fm, od.name, od.name_length);
      SetStringToFrame(fm, od.signature, strlen(od.signature));
      SetStringToFrame(fm, od.scope, strlen(od.scope));

      if (!odlist_buf) {
	odlist_buf = new unsigned char[od_size];
	odlist_size = od_size;
	memmove(odlist_buf, od_buf, od_size);
      } else {
	unsigned char *temp = new unsigned char[odlist_size + od_size];
	unsigned char *pTemp = temp;
	memmove(pTemp, odlist_buf, odlist_size);
	pTemp += odlist_size;
	memmove(pTemp, od_buf, od_size);
	odlist_size += od_size;
	delete [] odlist_buf;
	odlist_buf = temp;
      }
      /* free FrameMgr */
      FrameMgrFree(fm);
    }

    ICAttribute im_attr[2];
    int n = 0;
    if (imelist_size > 0) {
      im_attr[n].attribute_id = INPUT_METHOD_LIST;
      im_attr[n].value_length = imelist_size;
      im_attr[n].value = (void*)imelist_buf;
      n++;
    }
    if (odlist_size > 0) {
      im_attr[n].attribute_id = OBJECT_DESCRIPTOR_LIST;
      im_attr[n].value_length = odlist_size;
      im_attr[n].value = (void*)odlist_buf;
      n++;
    }
    if (n > 0) {
      send_imvalues_message(input_method_id, IM_SETIMVALUES,
			    im_attr, n);
    }

    delete [] imelist_buf;
    delete [] odlist_buf;
  }

  // Send IM_SETIMVALUES_REPLY to the previous
  // IM_SETIMVALUES from the client.
#if !defined(USE_FRAMEMGR_ALWAYS)
  send_message(input_method_id, 0, IM_OUTPUT_REPLY);
#else /* USE_FRAMEMGR_ALWAYS */
  send_message(input_method_id, 0, output_fr, IM_OUTPUT_REPLY);
#endif /* USE_FRAMEMGR_ALWAYS */

  respond_keepalive = True;
  return;
}

void
IIIMPClient::get_imvalues(IMProtocolStruct *call_data, unsigned char *p) {
  CARD16 input_method_id;
  CARD16 byte_length;
  FrameMgr fm;
  FmStatus status;

  extern XimFrameRec im_getimvalues_fr[], im_getimvalues_reply_fr[];
  XimFrameRec *input_fr = im_getimvalues_fr;
  XimFrameRec *output_fr = im_getimvalues_reply_fr;
  const int IM_OUTPUT_REPLY = IM_GETIMVALUES_REPLY;

  /* create FrameMgr */
  fm = FrameMgrInit(input_fr, (char *)p, need_swap);

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

  CARD16 *attrID_list = NULL;
  int number = 0;
  if (byte_length != 0) {
    attrID_list = (CARD16*)new char[byte_length];
    while (FrameMgrIsIterLoopEnd(fm, &status) == False) {
      FrameMgrGetToken(fm, attrID_list[number]);
      number++;
    }
  }
  /* free FrameMgr */
  FrameMgrFree(fm);


  ICAttribute *im_attr = new ICAttribute[number];
  int i;
  IMObjectDescriptorStruct *od = &(iiim_protocol->getFirstObjectDescriptor());
  memset(im_attr, 0, sizeof(ICAttribute) * number);
  while (od) {
    for (i = 0; i < number; i++) {
      if (im_attr[i].attribute_id) break;
      if (attrID_list[i] == od->id) {
	im_attr[i].attribute_id = od->id;
	char *contents = 0;
	int ob_size = 0;
	unsigned int buf_size;
	unsigned char *buffer;

	switch (od->type) {
	case IM_DOWNLOADINGOBJECT_JARGUI_TYPE:
	case IM_DOWNLOADINGOBJECT_JARLWE_TYPE:
	  contents = read_object(od->path, &ob_size);
	  buffer = create_jarfile_object_frame(od, contents, ob_size,
					       &buf_size);
	  im_attr[i].value_length = buf_size;
	  im_attr[i].value = (void*)buffer;
	  delete [] contents;
	  break;
	case IM_DOWNLOADINGOBJECT_CCDEF_TYPE:
	  contents = read_ccdef(od->path, od->basepath, &ob_size);
	  buffer = create_ccdef_object_frame(od, contents, ob_size,
					     &buf_size);
	  im_attr[i].value_length = buf_size;
	  im_attr[i].value = (void*)buffer;
	  delete [] contents;
	  break;
	case IM_DOWNLOADINGOBJECT_BINGUI_TYPE:
	case IM_DOWNLOADINGOBJECT_BINLWE_TYPE:
	  buffer = create_binfile_object_frame(od, &buf_size);
	  im_attr[i].value_length = buf_size;
	  im_attr[i].value = (void*)buffer;
	  delete [] contents;
	  break;
	case IM_DOWNLOADINGOBJECT_SGUI_TYPE:
	case IM_DOWNLOADINGOBJECT_SLWE_TYPE:
	default:
	  break;
	}
	break;
      }
      
    }
    od = &(iiim_protocol->getNextObjectDescriptor());
  }
  send_imvalues_message(input_method_id, IM_GETIMVALUES_REPLY,
			im_attr, number);
  ICAttribute *attrp;
  for (attrp = im_attr; attrp < &im_attr[number]; attrp++) {
    delete attrp->value;
  }
  delete [] attrID_list;
  delete [] im_attr;
  return;
}

void
IIIMPClient::send_imvalues_message(int input_method_id,
				   int message_type,
				   ICAttribute *im_attr, int n) {
  extern XimFrameRec im_setimvalues_fr[], im_setimvalues_reply_fr[];
  XimFrameRec *input_fr = im_setimvalues_fr;
  XimFrameRec *output_fr = im_setimvalues_reply_fr;
  FrameMgr fm;

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

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

  /* set length of BARRAY item in imattribute_fr*/
  ICAttribute *attrp;
  for (attrp = im_attr; attrp < &im_attr[n]; attrp++) {
    FrameMgrSetSize(fm, attrp->value_length);
  }

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

  unsigned char *replyp = reply.toUchar();

  FrameMgrPutToken(fm, input_method_id);
  replyp += 2 + 2 + 4;		// imid + pad(2) + byte_length

  for (attrp = im_attr; attrp < &im_attr[n]; attrp++) {
    FrameMgrPutToken(fm, attrp->attribute_id); replyp += 2;
    FrameMgrPutToken(fm, attrp->value_length); replyp += 2 + 4; // padding + len
    memmove(replyp, attrp->value, attrp->value_length);
    replyp += attrp->value_length;
    replyp += ((attrp->value_length) % 4);
    FrameMgrSkipToken(fm, 2);	// value, padding
  }
  send_message(message_type, reply, total_size);

  /* free FrameMgr */
  FrameMgrFree(fm);

  if (message_type == IM_SETIMVALUES) {
    // wait IM_SETIMVALUES_REPLY
    get_amessage();
  }

  return;
}
