#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include "IMAccept.hh"
#include "IIIMP_IMState.hh"
#include "IIIMP_ICState.hh"
#include "IIIMProtocol.hh"
#include "IIIMPTrans.hh"
#include "IIIMPUtil.hh"
#include "IIIMP_hotkey_profile.hh"

IIIMP_IMState::UserIMStateMap IIIMP_IMState::user_imstate_map;

bool
IIIMP_IMState::parse_user_name(
    const u16string& uname,
    u16string& username,
    u16string& password,
    string& hostname
)
{
    unsigned int pos_at, pos_sharp;
    u16string hname_u16;

    pos_at = uname.find('@');
    if (pos_at == u16string::npos) {
	hname_u16 = "";
	pos_sharp = uname.find('#');
	if (pos_sharp == u16string::npos) {
	    username = uname;
	    password = "";
	} else {
	    username = uname.substr(0, pos_sharp);
	    password = uname.substr(pos_sharp + 1);
	}
    } else {
	username = uname.substr(0, pos_at);
	pos_sharp = uname.find('#', pos_at);
	if (pos_sharp == u16string::npos) {
	    hname_u16 = uname.substr(pos_at + 1);
	    password = "";
	} else {
	    hname_u16 = uname.substr(pos_at + 1, pos_sharp - pos_at - 1);
	    password = uname.substr(pos_sharp + 1);
	}
    }
    UserHostPair user_host_pair = make_pair(username, hostname);
    user_imstate_map.insert(make_pair(user_host_pair, this));
    if (!hname_u16.get_charstr()) return false;
    hostname = hname_u16.get_charstr();

    return true;
}

bool
IIIMP_IMState::send(
    IIIMP_message *pmes,
    bool deletep
)
{
    if (!pmes) return false;
    // TODO...
    pimt->send(pmes);
    if (deletep)
	iiimp_message_delete(pimt->get_data_s(), pmes);
    return true;
}

bool
IIIMP_IMState::send_protocol_version(
    int client_proto_version
)
{
    if (client_proto_version > get_current_protocol_version())
	client_proto_version = get_current_protocol_version();

    // For version 2 clients or older ones,
    // we must not send IM_PROTOCOL_VERSION.
    if (client_proto_version <= 2)
	return true;

    IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
    if (!send(iiimp_protocol_version_new(pdata_s, get_im_id(), client_proto_version),
	      true))
	return false;

    return true;
}

bool
IIIMP_IMState::send_trigger_keys()
{
    int i;
    int profile_id = get_hotkey_profile()->get_default_hotkey_profile_id();
    const IMKeySpecList *keylist = get_hotkey_profile()->retrieve_trigger_keys(profile_id);

    if (keylist != NULL) {
	IIIMP_keyevent_list *pion;
	IIIMP_keyevent_list *pioff;
	IIIMP_keyevent *keys = new IIIMP_keyevent[keylist->size()];
	IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
	IMKeySpecList::const_iterator it;

	for (i = 0, it = keylist->begin(); it != keylist->end(), i < keylist->size(); it++, i++) {
	    keys[i].keycode = it->get_keycode();
	    keys[i].keychar = it->get_keychar();
	    keys[i].modifier = it->get_modifier();
	    keys[i].time_stamp = it->get_timestamp();
	}
	pion = iiimp_keyevent_list_new(pdata_s, i, keys);
	pioff = iiimp_keyevent_list_new(pdata_s, i, keys);
	delete[] keys;
	if (!pion || !pioff) {
	    if (pion)
		iiimp_keyevent_list_delete(pdata_s, pion);
	    if (pioff)
		iiimp_keyevent_list_delete(pdata_s, pioff);
	    return false;
	}
	if (!send(iiimp_register_trigger_keys_new(pdata_s, get_im_id(), pion, pioff), true))
	    return false;

	return true;
    }

    return false;
}

bool
IIIMP_IMState::send_hotkeys(
    const u16string& curr_input_lang,
    HotKeyList *hlist
)
{
    IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
    HOTKEY_LIST *hklist = (HOTKEY_LIST *)NULL;
    int i, profile_id, num_profiles, n_hotkeys;
    IMKeySpecList onkeys;
    IMKeySpecList offkeys;
    IIIMP_card16 scope_and_profile_id;
    IMHotkeyProfileStruct *hkps = const_cast<IMHotkeyProfileStruct *>(get_imhandler()->get_hotkey_profiles(&num_profiles));
    IMHotkeyStruct *hks;
    HotKeyList *tmp;

    if (hlist != NULL) {
	for (tmp = hlist; tmp != NULL; tmp = tmp->next) {
	    LOG_DEBUG("Registering a trigger key <%s[%d]>%s[%d]", tmp->hotkey->modifiers, tmp->hotkey->modmask, tmp->hotkey->key, tmp->hotkey->keycode);
	    onkeys.push_back(IMKeySpec(tmp->hotkey->keycode, 0, tmp->hotkey->modmask, 0));
	}
    } else {
	get_imhandler()->get_triggerkeys(onkeys, offkeys);
	onkeys.push_back(IMKeySpec(IM_VK_KANJI, 0, 0, 0));
	onkeys.push_back(IMKeySpec(IM_VK_KANJI, 0, IM_ALT_MASK, 0));
	if (strstr(curr_input_lang.get_charstr(), (char *)"ja") ||
	    strstr(curr_input_lang.get_charstr(), (char *)"ko")) {
	    LOG_DEBUG("For ja/ko locale clients, Shift+space is enabled for hotkey\n");
	    onkeys.push_back(IMKeySpec(IM_VK_SPACE, 0, IM_SHIFT_MASK, 0));
	}
    }
    hks = get_hotkey_profile()->get_super_hotkeys(onkeys, curr_input_lang.get_charstr(), &n_hotkeys);
    get_hotkey_profile()->init_hotkey_profile_list(hkps, num_profiles);
    get_hotkey_profile()->add_super_hotkey_profiles(curr_input_lang, hks, n_hotkeys);
    num_profiles = get_hotkey_profile()->get_num_profiles();
    for (int i = 0; i < n_hotkeys; i++) {
	free(hks[i].label);
	delete [] hks[i].keys;
    }
    delete [] hks;

    for (i = 0; i < num_profiles; i++) {
	hklist = get_hotkey_profile()->retrive_hotkeys(pdata_s, i, &profile_id);
	scope_and_profile_id = (GLOBAL_HOTKEY << 15) | profile_id;
	if (!send(iiimp_register_hotkeys_new(pdata_s, get_im_id(), scope_and_profile_id, hklist), true))
	    return false;
	scope_and_profile_id = 0;
	hklist = (HOTKEY_LIST *)NULL;
    }
    return true;
}

bool
IIIMP_IMState::switch_hotkey_profile()
{
    IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
    IIIMP_card16 scope_and_profile_id;
    IIIMP_card16 profile_id = get_hotkey_profile()->get_default_hotkey_profile_id();
    LOG_DEBUG("Switching Hotkey Profile to default [%d]\n", profile_id);
    scope_and_profile_id = (GLOBAL_HOTKEY << 15) | profile_id;
    if (!send(iiimp_select_hotkey_profile_new(pdata_s, get_im_id(), scope_and_profile_id), true))
	return false;
    return true;
}

bool
IIIMP_IMState::message_proc(
    void *x_pmes
)
{
    IIIMP_message *pmes = (IIIMP_message*) x_pmes;
    IMState *pimns;

    switch (pmes->opcode) {
      case IM_CONNECT:
      {
	  IMAccept *pima = get_imaccept();
	  IMHandler *pimh;
	  const IMLangList *planglist;
	  u16string username, password;
	  string hostname;
	  int proto_version = pmes->v.connect.protocol_version;

	  if (!parse_user_name(CONV_IIIMP_STR(pmes->v.connect.user_name),
			       username,
			       password,
			       hostname))
	      return false;
	  pimh = pima->request_connect(pimt->get_fd(),
				       username,
				       hostname,
				       password,
				       IMAuthList());
	  if (!pimh) break;

	  // Authentication is completed.  Now start communication!
	  send_protocol_version(proto_version);

	  planglist = pimh->get_langlist(NULL);

	  {
	      IIIMP_string *phead, *pcur = NULL, *pstr;
	      IMLangList::const_iterator it;
	      u16string langid;

	      phead = NULL;
	      for (it = planglist->begin(); it != planglist->end(); it++) {
		  langid = it->get_id();
		  pstr = iiimp_string_new(pimt->get_data_s(),
					  langid.size(),
					  langid.data());
		  // memory error
		  if (!pstr) break;
		  if (!phead) phead = pstr;
		  else pcur->next = pstr;
		  pcur = pstr;
	      }
	      if (!send(iiimp_connect_reply_new(pimt->get_data_s(),
						get_im_id(),
						phead),
			true))
		  return false;
	  }
	  
	  pimns = new IIIMP_IMState_Identified(this, pimh, proto_version);

	  // send_trigger_keys();

	  // send_hotkeys();

          // switch_hotkey_profile();
 
	  change_state(*pimns);

	  break;
      }
      default:
       LOG_ERROR("Invalid opcode:%d.  (Authentication is requied.)", pmes->opcode);
       return false;
    }
    return true;
}

void
IIIMP_IMState::destroy()
{
    UserIMStateMap::iterator it;

    for (it = IIIMP_IMState::user_imstate_map.begin(); it != IIIMP_IMState::user_imstate_map.end(); ++it) {
	if (it->second == this)
	    user_imstate_map.erase(it);
    }

    delete get_iiimptrans();
    IMState::destroy();
}

IIIMP_IMState::IIIMP_IMState(
    IIIMProtocol *pimp,
    IIIMPTrans *x_pimt,
    int proto_version
) :
    IMState(1, pimp, NULL, proto_version)
{
    pimt = x_pimt;
}

IIIMP_imattribute *
IIIMP_IMState_Identified::
create_object_descriptors()
{
    const IMObjectWithDescList *podlist = get_imhandler()->get_imobjectdesclist();

    if (!podlist) return NULL;

    IIIMP_imattribute *pima = NULL;
    IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
    IIIMP_string *pidomain = NULL, *pihrn = NULL, *pisig = NULL, *piscope = NULL;
    IIIMP_object_descriptor *piodh, *piod = NULL, *piod2;
    IIIMP_card16 predefined;

    IMObjectWithDescList::const_iterator it;
    IMObjectWithDesc *pod;

    piodh = NULL;
    for (it = podlist->begin(); it != podlist->end(); it++) {
	pod = *it;
	if (pod->get_category() < 0) continue;
	predefined = convert_IMObject_type_to_iiimp_predefined_attribid(pod->get_type());

	pidomain = pihrn = pisig = piscope = NULL;

	pidomain = iiimp_string_new(pdata_s,
				    pod->get_domain().size(),
				    pod->get_domain().data());
	pihrn = iiimp_string_new(pdata_s,
				 pod->get_hrn().size(),
				 pod->get_hrn().data());
	pisig = iiimp_string_new(pdata_s,
				 pod->get_signature().size(),
				 pod->get_signature().data());
	piscope = iiimp_string_new(pdata_s,
				   pod->get_scope().size(),
				   pod->get_scope().data());

	if (!pidomain || !pihrn || !pisig || !piscope) {
	    goto memory_error;
	}
	piod2 = iiimp_object_descriptor_new(pdata_s,
					    pod->get_category(),
					    pod->get_object_size(),
					    predefined, pod->get_attribid(),
					    pidomain, pihrn, pisig, piscope);
	if (!piod2) goto memory_error;

	if (!piodh) {
	    piodh = piod2;
	} else {
	    piod->next = piod2;
	}
	piod = piod2;
    }

    if (!piodh) return NULL;

    pima = iiimp_imattribute_object_descriptor_new(pdata_s,
						   IIIMP_IMATTRIBUTE_OBJECT_DESCRIPTOR_LIST,
						   0, piodh);
    if (!pima) goto memory_error;

    return pima;

memory_error:
    if (pima) {
	iiimp_imattribute_delete(pdata_s, pima);
    } else {
	if (pidomain) iiimp_string_delete(pdata_s, pidomain);
	if (pihrn) iiimp_string_delete(pdata_s, pihrn);
	if (pisig) iiimp_string_delete(pdata_s, pisig);
	if (piscope) iiimp_string_delete(pdata_s, piscope);
	for (piod = piodh; piod; piod = piod->next) {
	    iiimp_object_descriptor_delete(pdata_s, piod);
	}
    }
    // TODO!! we have to throw an exception.
    return NULL;
}

IIIMP_language*
IIIMP_IMState_Identified::
create_language_list(
    const IMLangList *plangs
)
{
    IIIMP_language *pil = NULL, *pil2, *pilh;
    IIIMP_string *pihrn, *piid;
    u16string langid;
    IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
    IMLangList::const_iterator it;

    if (!plangs) return NULL;

    pilh = NULL;
    for (it = plangs->begin(); it != plangs->end(); it++) {
	pihrn = piid = NULL;

	pihrn = iiimp_string_new(pdata_s,
				 it->get_hrn().size(),
				 it->get_hrn().data());
	if (!pihrn) goto memory_error;

	langid = it->get_id();
	piid = iiimp_string_new(pdata_s,
				langid.size(),
				langid.data());
	if (!piid) {
	    iiimp_string_delete(pdata_s, pihrn);
	    goto memory_error;
	}

	pil2 = iiimp_language_new(pdata_s, pihrn, piid);
	
	if (!pil2) {
	    iiimp_string_delete(pdata_s, pihrn);
	    iiimp_string_delete(pdata_s, piid);
	    goto memory_error;
	}

	if (!pilh) {
	    pilh = pil2;
	} else {
	    pil->next = pil2;
	}
	pil = pil2;
    }

    return pilh;

memory_error:
    if (pilh) iiimp_language_delete(pdata_s, pilh);
    // TODO!! we have to throw an exception.
    return NULL;
}

IIIMP_imattribute*
IIIMP_IMState_Identified::
create_input_method_descriptors()
{
    const IMDescriptorList *pimdlist = get_imhandler()->get_imdesclist(NULL);

    if (!pimdlist) return NULL;

    IIIMP_imattribute *pima = NULL;
    IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
    IIIMP_string *pidname, *pihrn, *pidomain;
    IIIMP_inputmethod_descriptor *pimdh, *pimd = NULL, *pimd2;
    IIIMP_language *pil;

    IMDescriptorList::const_iterator it;

    pimdh = NULL;

    for (it = pimdlist->begin(); it != pimdlist->end(); it++) {
	pidname = pihrn = NULL;

	pidname = iiimp_string_new(pdata_s,
				   it->get_imname().size(),
				   it->get_imname().data());

	pihrn = iiimp_string_new(pdata_s,
				 it->get_hrn().size(),
				 it->get_hrn().data());

	/* Currently adopt an empty string
	   as reverse domain name. */
	pidomain = iiimp_string_new(pdata_s, 0, NULL);

	if (!pidname || !pihrn || !pidomain) {
	    goto memory_error;
	}

	pil = create_language_list(it->get_languages());
	pimd2 = iiimp_inputmethod_descriptor_new(pdata_s,
						 it->get_attribid(),
						 pidname,
						 pihrn,
						 pil,
						 pidomain);

	if (!pimd2) goto memory_error;

	if (!pimdh) {
	    pimdh = pimd2;
	} else {
	    pimd->next = pimd2;
	}
	pimd = pimd2;
    }
    if (!pimdh) return NULL;

    pima = iiimp_imattribute_inputmethod_descriptor_new(pdata_s,
							IIIMP_IMATTRIBUTE_INPUT_METHOD_LIST,
							0, pimdh);
    if (!pima) goto memory_error;

    return pima;

memory_error:
    if (pima) {
	iiimp_imattribute_delete(pdata_s, pima);
    } else {
	if (pidname) iiimp_string_delete(pdata_s, pidname);
	if (pihrn) iiimp_string_delete(pdata_s, pihrn);
	if (pidomain) iiimp_string_delete(pdata_s, pidomain);
	for (pimd = pimdh; pimd; pimd = pimd->next) {
	    iiimp_inputmethod_descriptor_delete(pdata_s, pimd);
	}
    }
    // TODO!! we have to throw an exception.
    return NULL;
}

bool
IIIMP_IMState_Identified::
set_data_to_client()
{
    IIIMP_imattribute *pima, *pima_objdesc, *pima_imdesc;

    pima_objdesc = create_object_descriptors();

    if (check_protocol_version(3))
	/* Send it only to clients of version 3 or later. */
	pima_imdesc = create_input_method_descriptors();
    else
	pima_imdesc = NULL;

    if (pima_objdesc) {
	pima = pima_objdesc;
	pima->next = pima_imdesc;
    } else {
	pima = pima_imdesc;
    }

    if (!send(iiimp_setimvalues_new(get_iiimptrans()->get_data_s(),
				    get_im_id(), pima), true))
	return false;
    return true;
}

IIIMP_imattribute*
IIIMP_IMState_Identified::get_imattribute(
    IIIMP_card16 id
)
{
    IIIMP_imattribute *pimattr;
    IIIMP_data_s *pdata_s = get_iiimptrans()->get_data_s();
    IMObject *pobj = IMObjectMgr::get_instance()->get_object_from_attribid(id);
    if (!pobj || !pobj->downloadablep()) return NULL;
    switch (pobj->get_type()) {
      case IMObject::BINARY_GUI:
      case IMObject::BINARY_LWE:
      {
	  IIIMP_binaryfile_object *pbobj;
	  IIIMP_string *pipath;
	  IMObjectWithDesc *pod = (IMObjectWithDesc*) pobj;

	  pipath = iiimp_string_new(pdata_s,
				    pod->get_path().size(),
				    pod->get_path().data());
	  if (!pipath) goto memory_error;
	  pbobj = iiimp_binaryfile_object_new(pdata_s, pipath);
	  if (!pbobj) {
	      iiimp_string_delete(pdata_s, pipath);
	      goto memory_error;
	  }
	  if (pobj->get_type() == IMObject::BINARY_GUI) {
	      pimattr = iiimp_imattribute_binary_gui_object_new(pdata_s,
								id, id,
								pbobj);
	  } else {
	      pimattr = iiimp_imattribute_binary_light_weight_engine_new(pdata_s,
									 id, id,
									 pbobj);
	  }
	  if (!pimattr) {
	      iiimp_binaryfile_object_delete(pdata_s, pbobj);
	      goto memory_error;
	  }
      }
      break;
      case IMObject::JAVA_GUI:
      case IMObject::JAVA_LWE:
      {
	  IIIMP_jarfile_object *pjobj;
	  IIIMP_string *piclassnamesh, *piclassnames = NULL, *piclassnames2;
	  IMObjectWithDesc *pod = (IMObjectWithDesc*) pobj;

	  const CARD8BIT *pbr = pod->get_binary_representation();
	  if (!pbr) return NULL;

	  piclassnamesh = NULL;
	  const list<u16string> &classes = pod->get_classes();
	  list<u16string>::const_iterator it;
	  for (it = classes.begin(); it != classes.end(); it++) {
	      piclassnames2 = iiimp_string_new(pdata_s,
					       it->size(),
					       it->data());
	      if (!piclassnames2) {
		  if (piclassnamesh)
		      iiimp_string_delete(pdata_s, piclassnamesh);
		  goto memory_error;
	      }
	      if (!piclassnamesh) {
		  piclassnamesh = piclassnames2;
	      } else {
		  piclassnames->next = piclassnames2;
	      }
	      piclassnames = piclassnames2;
	  }
	  pjobj = iiimp_jarfile_object_new(pdata_s, piclassnamesh,
					   pod->get_object_size(),
					   pbr);
	  if (!pjobj) {
	      iiimp_string_delete(pdata_s, piclassnamesh);
	      goto memory_error;
	  }
	  if (pobj->get_type() == IMObject::JAVA_GUI) {
	      pimattr = iiimp_imattribute_jar_gui_object_new(pdata_s, id, id, pjobj);
	  } else {
	      pimattr = iiimp_imattribute_jar_light_weight_engine_object_new(pdata_s,
									     id, id,
									     pjobj);
	  }
	  if (!pimattr) {
	      iiimp_jarfile_object_delete(pdata_s, pjobj);
	      goto memory_error;
	  }
      }
      break;

      default:
       return NULL;
    }

    return pimattr;

memory_error:
    // TODO: throw exception.
    return NULL;
}

bool
IIIMP_IMState_Identified::message_proc(
    void *message
)
{
    IIIMP_message *pmes = (IIIMP_message*) message;

    switch (pmes->opcode) {
      case IM_GETIMVALUES:
      {
	  IIIMP_imattribute *pimattrh, *pimattr = NULL, *pimattr2;
	  IIIMP_card16_list *pcl = pmes->v.getimvalues.attr_list;
	  IIIMP_card16 *ptr = pcl->ptr;
	  pimattrh = NULL;
	  for (int i = 0; i < pcl->count; i++, ptr++) {
	      pimattr2 = get_imattribute(*ptr);
	      if (!pimattr2) continue;
	      if (!pimattrh) {
		  pimattrh = pimattr2;
	      } else {
		  pimattr->next = pimattr2;
	      }
	      pimattr = pimattr2;
	  }
	  if (!send(iiimp_getimvalues_reply_new(get_iiimptrans()->get_data_s(),
						get_im_id(),
						pimattrh),
		    true))
	      return false;
	  break;
      }
      break;
      case IM_SETIMVALUES:
      {
	  IIIMP_imattribute *pima = pmes->v.setimvalues.attr_list;
	  switch(pima->id) {
	    case IIIMP_IMATTRIBUTE_CLIENT_DESCRIPTOR:
	    {
		IIIMP_client_descriptor *pcd = pima->value.client_descriptor;

		IMHandler::ClientAttrList attrs;
		if (pcd->type) {
		    attrs.push_back(IMHandler::ClientAttr(IMHandler::CLIENT_NAME,
							  CONV_IIIMP_STR(pcd->type)));
		}
		if (pcd->os_name) {
		    attrs.push_back(IMHandler::ClientAttr(IMHandler::OS_NAME,
							  CONV_IIIMP_STR(pcd->os_name)));
		}
		if (pcd->arch) {
		    attrs.push_back(IMHandler::ClientAttr(IMHandler::OS_ARCH,
							  CONV_IIIMP_STR(pcd->arch)));
		}
		if (pcd->version) {
		    attrs.push_back(IMHandler::ClientAttr(IMHandler::OS_VERSION,
							  CONV_IIIMP_STR(pcd->version)));
		}
		if (pcd->X_display_name) {
		    attrs.push_back(IMHandler::ClientAttr(IMHandler::X_DISPLAY_NAME,
							  CONV_IIIMP_STR(pcd->X_display_name)));
		}
		if (pcd->X_server_vendor) {
		    attrs.push_back(IMHandler::ClientAttr(IMHandler::X_SERVER_VENDOR,
							  CONV_IIIMP_STR(pcd->X_server_vendor)));
		}

		if (!(get_imhandler()->set_client_info(attrs)))
		    return false;

		set_data_to_client();

		if (!send(iiimp_setimvalues_reply_new(get_iiimptrans()->get_data_s(),
						      get_im_id()),
			  true))
		    return false;
		break;
	    }

	    default:
	     LOG_ERROR("Unknown attribid:%d.", pima->id);
	     return false;
	  }
      }
      break;

      case IM_CREATEIC:
      {
	  IIIMP_icattribute *pattr = pmes->v.createic.attr_list;
	  ICAttribute icattr = convert_iiimp_icattr(pattr);
	  ICHandler *pich = get_imhandler()->createic(icattr);
	  if (!pich) {
	      LOG_ERROR("Fail to create new ic (ICHandler).");
	      return false;
	  }
	  CARD16BIT ic_id;
	  if (!new_ic_id(ic_id)) return false;
	  IIIMP_ICState *pics = IIIMP_ICState::create(ic_id, this, pich);
	  if (!pics) {
	      pich->destroy(NULL);
	      LOG_ERROR("Fail to create new ic (IIIMP_ICState).");
	      return false;
	  }
	  add_icstate(pics);

	  if (!send(iiimp_createic_reply_new(get_iiimptrans()->get_data_s(),
					     get_im_id(),
					     ic_id),
		    true))
	      return false;

          u16string curr_input_lang = icattr.get_inputlanguage();

          if (!get_register_hotkey_flag()) {
	      iml_desktop_t *idt = pich->get_current_desktop();
	      IIIMLEXMLConf *uconf = NULL;
	      HotKeyList *hlist = NULL;
	      string conffile = ".iiim/le.xml.conf";

#if 0 /* disable reading the user-specific configuration ATM */
	      /* load the user-specific configuration */
	      uconf = iiim_le_xmlconf_new(conffile.c_str());
	      if (uconf) {
		  iiim_le_xmlconf_load_with_nsio(uconf, idt);
		  hlist = iiim_le_xmlconf_get_hotkey_list(uconf, curr_input_lang.get_charstr());
	      }
#endif
	      if (hlist == NULL) {
		  /* try to read the global configuration */
		  if (uconf)
		      iiim_le_xmlconf_free(uconf);
		  uconf = iiim_le_xmlconf_new(XMLCONFDIR "/le.xml.conf");
		  if (uconf) {
			  iiim_le_xmlconf_load_file(uconf);
			  hlist = iiim_le_xmlconf_get_hotkey_list(uconf, curr_input_lang.get_charstr());
		  }
	      }
	      send_hotkeys(curr_input_lang, hlist);
	      send_trigger_keys();
	      iiim_le_xmlconf_free(uconf);

	      switch_hotkey_profile();
	      set_register_hotkey_flag(true);
          }
      }
      break;

      case IM_DISCONNECT:
      {
	  // reset_state() will delete `this'.
	  bool flag;
	  CARD16BIT im_id = get_im_id();
	  IIIMPTrans *ptrans = get_iiimptrans();

	  cleanup_ic();
	  
	  flag = send(iiimp_disconnect_reply_new(ptrans->get_data_s(),
						 im_id),
		      true);
	  reset_state();
	  if (!flag) return false;
      }
      break;

      case IM_SETIMVALUES_REPLY:
       // reply message.  Currently, simply ignore it.
       break;

      default:
       LOG_ERROR("Invalid opcode:%d.  (Authentication is requied.)", pmes->opcode);
       return false;
    }
    return true;
}

IIIMP_IMState_Identified::IIIMP_IMState_Identified(
    IIIMP_IMState *pimt,
    IMHandler *pimh,
    int proto_version
) : IIIMP_IMState(*pimt, proto_version)
{
    set_imhandler(pimh);
}

IIIMP_IMState *
IIIMP_IMState::get_imstate_from_desktop(
    iml_desktop_t *desktop
)
{
    UserIMStateMap::iterator it;

    for (it = IIIMP_IMState::user_imstate_map.begin(); it != IIIMP_IMState::user_imstate_map.end(); ++it) {
      const UserHostPair& p = it->first;
      u16string username = p.first;
      string hostname = p.second;
      if (strcmp(desktop->user_name, username.get_charstr()) == 0 &&
	  strcmp(desktop->host_name, hostname.c_str()) == 0) {
	return it->second;
      }
    }

    return NULL;
}

int 
open_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    int oflag,
    mode_t mode,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_open *iiimp_open;
    IIIMP_utf8string *iiimp_fname;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_fname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
				       (strlen(path) + 1),
				       (const IIIMP_card8 *)path);
    if (!iiimp_fname) return -1;

    iiimp_open = iiimp_open_new(xims->get_iiimptrans()->get_data_s(),
				ns_id,
				mode,
				iiimp_fname);

    send_message = iiimp_file_operation_new(
	xims->get_iiimptrans()->get_data_s(),
	xims->get_im_id(),
	IIIMP_FILE_OPERATION_TYPE_OPEN,
	iiimp_open);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_OPEN_REPLY) {
	IIIMP_open_reply *p = (IIIMP_open_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int 
read_ns(
    iml_desktop_t *desktop,
    int ns_id,
    void *ptr,
    size_t size,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_read *iiimp_read;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_read = iiimp_read_new(xims->get_iiimptrans()->get_data_s(), 
				ns_id, size);
    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_READ,
					    iiimp_read);
    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
	if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
	        xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
	}
    }
    if (!ptr) return -1;

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_READ_REPLY) {
	IIIMP_read_reply *p = (IIIMP_read_reply *)receive_message->v.file_operation_reply.value;
	memcpy((char *)ptr, (char *)p->object, p->size);
	*ns_errno = p->ns_errno;
	return p->size;
    }
    return -1;
}

int
write_ns(
    iml_desktop_t *desktop,
    int ns_id,
    void *ptr,
    size_t size,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_write *iiimp_write;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_write = iiimp_write_new(xims->get_iiimptrans()->get_data_s(),
                                  ns_id, size, ptr);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(), xims->get_im_id(), IIIMP_FILE_OPERATION_TYPE_WRITE, iiimp_write);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
        receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }
    if (!ptr) return -1;

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_WRITE_REPLY) {
	IIIMP_write_reply *p = (IIIMP_write_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->size;
    }
    
    return -1;
}

int
update_supported_langlist_for_le(
    iml_desktop_t *desktop,
    IMLEName *lename,
    IMLocale *locales,
    int nLocales
)
{
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);

    if (xims == NULL)
	return false;
    // Update LEMgr's IMDescriptorList

    xims->get_imhandler()->update_imdesclist(lename, locales, nLocales);

    // TODO!! Send the updated IMDescriptorList to Client using IM_SETIMVALUES
    // IIIMP_IMState_Identified *xims_id = new IIIMP_IMState_Identified(xims, xims->get_imhandler(), xims->get_current_protocol_version());
    // xims_id->set_data_to_client();
    // receive_message = xims->get_iiimptrans()->receive();

    return true;
}

// Method to switch hotkey profile from LE

int 
switch_le_profile(
    iml_desktop_t *desktop,
    int le_profile_id, 
    IMLEName *lename
)   
{   
    IIIMP_message *send_message;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    int default_profile_id;
    int profile_id;
    IIIMP_card16 scope_and_profile_id;

    if (xims == NULL)
	return false;
    default_profile_id = xims->get_hotkey_profile()->get_default_hotkey_profile_id();
    profile_id = xims->get_hotkey_profile()->get_unique_profile_id(le_profile_id, lename);
    
    if (profile_id < 0) {
	profile_id = default_profile_id;
    }

    LOG_DEBUG("IIIMP_IMState: LE [%s] switching profile to [%d]\n",lename->id, profile_id);

    // Switch to LE's profile
    scope_and_profile_id = (GLOBAL_HOTKEY << 15) | profile_id;
    send_message = iiimp_select_hotkey_profile_new(xims->get_iiimptrans()->get_data_s(), xims->get_im_id(), scope_and_profile_id);
    if (!xims->send(send_message, true)) return false;

    return true;
}

int 
close_ns(
    iml_desktop_t *desktop,
    int ns_id,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_close *iiimp_close;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_close = iiimp_close_new(xims->get_iiimptrans()->get_data_s(),
                                  ns_id);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(), xims->get_im_id(), IIIMP_FILE_OPERATION_TYPE_CLOSE, iiimp_close);
    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_CLOSE_REPLY) {
	IIIMP_close_reply *p = (IIIMP_close_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return 1;
}

char **
opendir_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    int *nitems,
    int *pns_id,
    int ***d_reclen,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_opendir *iiimp_opendir;
    IIIMP_utf8string *iiimp_dirname;
    char **d_name;
    unsigned int i,j;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return NULL;
    iiimp_dirname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                         (strlen(path) + 1),
                                         (const IIIMP_card8 *)path);
    if (!iiimp_dirname) return (char **)NULL;

    iiimp_opendir = iiimp_opendir_new(xims->get_iiimptrans()->get_data_s(),
                                      ns_id, iiimp_dirname);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(), xims->get_im_id(), IIIMP_FILE_OPERATION_TYPE_OPENDIR, iiimp_opendir);

    if(!xims->send(send_message, true)) return (char **)NULL;

    for (;;) {
        receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_OPENDIR_REPLY) {
	IIIMP_opendir_reply *por = (IIIMP_opendir_reply *)receive_message->v.file_operation_reply.value;
	*nitems = por->nitems;
	*pns_id = por->ns_id;
	*ns_errno = por->ns_errno;
	if (*nitems > 0) {
	    IIIMP_utf8string *p = por->d_name;
	    d_name = (char **) calloc (*nitems, (sizeof (char *)));
	    *d_reclen = (int **) calloc(*nitems, sizeof(int *));
	    for (i=0; NULL != p; p=p->next, i++) {
		d_name[i] = (char *) calloc((p->len + 1), sizeof(char));
		(*d_reclen)[i] = (int *) calloc(1, sizeof(int));
		(*d_reclen)[i] = (int *) p->len;
		for (j=0; j<p->len; j++) {
		    d_name[i][j] = p->ptr[j];
		}
	    }
	    return d_name;
	}
    }
    return (char **)NULL;
}

int
closedir_ns(
    iml_desktop_t *desktop,
    int ns_id,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_closedir *iiimp_closedir;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_closedir = iiimp_closedir_new(xims->get_iiimptrans()->get_data_s(),
                                        ns_id);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_CLOSEDIR,
					    iiimp_closedir);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
        receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }
    
    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_CLOSEDIR_REPLY) {
	IIIMP_closedir_reply *p = (IIIMP_closedir_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int 
mkdir_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    mode_t mode,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_mkdir *iiimp_mkdir;
    IIIMP_utf8string *iiimp_dirname;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_dirname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                         (strlen(path) + 1),
                                         (const IIIMP_card8 *)path);
    if (!iiimp_dirname) return -1;

    iiimp_mkdir = iiimp_mkdir_new(xims->get_iiimptrans()->get_data_s(),
				  ns_id, mode, iiimp_dirname);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_MKDIR,
					    iiimp_mkdir);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_MKDIR_REPLY) {
	IIIMP_mkdir_reply *p = (IIIMP_mkdir_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int 
rmdir_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_rmdir *iiimp_rmdir;
    IIIMP_utf8string *iiimp_dirname;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_dirname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                         (strlen(path) + 1),
                                         (const IIIMP_card8 *)path);
    if (!iiimp_dirname) return -1;

    iiimp_rmdir = iiimp_rmdir_new(xims->get_iiimptrans()->get_data_s(),
                                  ns_id, iiimp_dirname);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_RMDIR,
					    iiimp_rmdir);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_RMDIR_REPLY) {
	IIIMP_rmdir_reply *p = (IIIMP_rmdir_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int 
symlink_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *dpath,
    char *spath,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_symlink *iiimp_symlink;
    IIIMP_utf8string *iiimp_dname;
    IIIMP_utf8string *iiimp_sname;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_dname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                       (strlen(dpath) + 1),
				       (const IIIMP_card8 *)dpath);
				   
    if (!iiimp_dname) return -1;

    iiimp_sname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                       (strlen(spath) + 1),
                                       (const IIIMP_card8 *)spath);
				       
    if (!iiimp_sname) return -1;

    iiimp_symlink = iiimp_symlink_new(xims->get_iiimptrans()->get_data_s(),
                                      ns_id, iiimp_dname, iiimp_sname);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_SYMLINK,
					    iiimp_symlink);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_SYMLINK_REPLY) {
	IIIMP_symlink_reply *p = (IIIMP_symlink_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int
stat_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    struct stat *buf,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_stat *iiimp_stat;
    IIIMP_utf8string *iiimp_dirname;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_dirname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                         (strlen(path) + 1),
                                         (const IIIMP_card8 *)path);
    if (!iiimp_dirname) return -1;

    iiimp_stat = iiimp_stat_new(xims->get_iiimptrans()->get_data_s(),
				ns_id, iiimp_dirname);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_STAT,
					    iiimp_stat);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
        receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !! \n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_STAT_REPLY) {
	IIIMP_stat_reply *p = (IIIMP_stat_reply *)receive_message->v.file_operation_reply.value;
	if (p->ns_id < 0) {
	    return p->ns_id;
	}

	(*buf).st_mode = p->stat_buf->s_mode;
	(*buf).st_nlink = p->stat_buf->s_nlink;
	(*buf).st_uid = p->stat_buf->s_uid;
	(*buf).st_gid = p->stat_buf->s_gid;
	(*buf).st_atime = p->stat_buf->s_atime;
	(*buf).st_mtime = p->stat_buf->s_mtime;
	(*buf).st_ctime = p->stat_buf->s_ctime;
	(*buf).st_blksize = p->stat_buf->s_blksize;
	(*buf).st_dev = p->stat_buf->s_dev;
	(*buf).st_rdev = p->stat_buf->s_rdev;
	(*buf).st_ino = p->stat_buf->s_ino;
	(*buf).st_size = p->stat_buf->s_size;
	(*buf).st_blocks = p->stat_buf->s_blocks;

	*ns_errno =  p->ns_errno;
	return p->ns_id;
    }

    return -1;
}

int
lstat_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    struct stat *buf,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_lstat *iiimp_lstat;
    IIIMP_utf8string *iiimp_dirname;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_dirname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                         (strlen(path) + 1),
                                         (const IIIMP_card8 *)path);
    if (!iiimp_dirname) return -1;

    iiimp_lstat = iiimp_lstat_new(xims->get_iiimptrans()->get_data_s(),
				  ns_id, iiimp_dirname);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_LSTAT,
					    iiimp_lstat);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
        receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_LSTAT_REPLY) {
	IIIMP_lstat_reply *p = (IIIMP_lstat_reply *)receive_message->v.file_operation_reply.value;
	if (p->ns_id < 0) {
	    return p->ns_id;
	}

	(*buf).st_mode = p->stat_buf->s_mode;
	(*buf).st_nlink = p->stat_buf->s_nlink;
	(*buf).st_uid = p->stat_buf->s_uid;
	(*buf).st_gid = p->stat_buf->s_gid;
	(*buf).st_atime = p->stat_buf->s_atime;
	(*buf).st_mtime = p->stat_buf->s_mtime;
	(*buf).st_ctime = p->stat_buf->s_ctime;
	(*buf).st_blksize = p->stat_buf->s_blksize;
	(*buf).st_dev = p->stat_buf->s_dev;
	(*buf).st_rdev = p->stat_buf->s_rdev;
	(*buf).st_ino = p->stat_buf->s_ino;
	(*buf).st_size = p->stat_buf->s_size;
	(*buf).st_blocks = p->stat_buf->s_blocks;

	*ns_errno =  p->ns_errno;
	return p->ns_id;
    }

    return -1;
}

int
fstat_ns(
    iml_desktop_t *desktop,
    int ns_id,
    struct stat *buf,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_fstat *iiimp_fstat;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_fstat = iiimp_fstat_new(xims->get_iiimptrans()->get_data_s(),
				  ns_id);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_FSTAT,
					    iiimp_fstat);
    if(!xims->send(send_message, true)) return -1;

    for (;;) {
        receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_FSTAT_REPLY) {
	IIIMP_fstat_reply *p = (IIIMP_fstat_reply *)receive_message->v.file_operation_reply.value;
	if (p->ns_id < 0) {
	    return p->ns_id;
	}

	(*buf).st_mode = p->stat_buf->s_mode;
	(*buf).st_nlink = p->stat_buf->s_nlink;
	(*buf).st_uid = p->stat_buf->s_uid;
	(*buf).st_gid = p->stat_buf->s_gid;
	(*buf).st_atime = p->stat_buf->s_atime;
	(*buf).st_mtime = p->stat_buf->s_mtime;
	(*buf).st_ctime = p->stat_buf->s_ctime;
	(*buf).st_blksize = p->stat_buf->s_blksize;
	(*buf).st_dev = p->stat_buf->s_dev;
	(*buf).st_rdev = p->stat_buf->s_rdev;
	(*buf).st_ino = p->stat_buf->s_ino;
	(*buf).st_size = p->stat_buf->s_size;
	(*buf).st_blocks = p->stat_buf->s_blocks;

	*ns_errno =  p->ns_errno;
	return p->ns_id;
    }

    return -1;
}

int   
ftruncate_ns(
    iml_desktop_t *desktop,
    int ns_id, 
    off_t length,
    int *ns_errno
)           
{               
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_ftruncate *iiimp_ftruncate;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;
    
    if (xims == NULL)
	return -1;
    iiimp_ftruncate = iiimp_ftruncate_new(xims->get_iiimptrans()->get_data_s(),    
					  ns_id, length);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_FTRUNCATE,
					    iiimp_ftruncate);

    if(!xims->send(send_message, true)) return -1;
    
    for (;;) {
        receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
            if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
                LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
                break;
            } else {
                xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
            }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_FTRUNCATE_REPLY) {
	IIIMP_ftruncate_reply *p = (IIIMP_ftruncate_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int 
creat_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    mode_t mode,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_creat *iiimp_creat;
    IIIMP_utf8string *iiimp_fname;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_fname = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                       (strlen(path) + 1),
				       (const IIIMP_card8 *)path);
    if (!iiimp_fname) return -1;

    iiimp_creat = iiimp_creat_new(xims->get_iiimptrans()->get_data_s(),
				  ns_id, mode, iiimp_fname);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_CREAT,
					    iiimp_creat);
    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_CREAT_REPLY) {
	IIIMP_creat_reply *p = (IIIMP_creat_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

off_t 
lseek_ns(
    iml_desktop_t *desktop,
    int ns_id,
    off_t offset,
    int whence,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_lseek *iiimp_lseek;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_lseek = iiimp_lseek_new(xims->get_iiimptrans()->get_data_s(),
				  ns_id, offset, whence);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_LSEEK,
					    iiimp_lseek);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_LSEEK) {
	IIIMP_lseek_reply *p = (IIIMP_lseek_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->offset;
    }
    return -1;
}

int 
unlink_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_unlink *iiimp_unlink;
    IIIMP_utf8string *iiimp_path;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_path = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                      (strlen(path) + 1),
				      (const IIIMP_card8 *)path);
    if (!iiimp_path) return -1;

    iiimp_unlink = iiimp_unlink_new(xims->get_iiimptrans()->get_data_s(),
				    ns_id, iiimp_path);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_UNLINK,
					    iiimp_unlink);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_UNLINK_REPLY) {
	IIIMP_unlink_reply *p = (IIIMP_unlink_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int 
rename_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *old_name,
    char *new_name,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_rename *iiimp_rename;
    IIIMP_utf8string *iiimp_old_name;
    IIIMP_utf8string *iiimp_new_name;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_old_name = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                          (strlen(old_name) + 1),
				          (const IIIMP_card8 *)old_name);
    if (!iiimp_old_name) return -1;

    iiimp_new_name = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                          (strlen(new_name) + 1),
				          (const IIIMP_card8 *)new_name);
    if (!iiimp_new_name) return -1;

    iiimp_rename = iiimp_rename_new(xims->get_iiimptrans()->get_data_s(),
				    ns_id, 
				    iiimp_old_name, 
				    iiimp_new_name);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_RENAME,
					    iiimp_rename);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_RENAME_REPLY) {
	IIIMP_rename_reply *p = (IIIMP_rename_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

int 
fcntl_ns(
    iml_desktop_t *desktop,
    int ns_id,
    int cmd,
    int arg,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_fcntl *iiimp_fcntl;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_fcntl = iiimp_fcntl_new(xims->get_iiimptrans()->get_data_s(),
				  ns_id, cmd, arg);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_FCNTL,
					    iiimp_fcntl);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_FCNTL_REPLY) {
	IIIMP_fcntl_reply *p = (IIIMP_fcntl_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->return_value;
    }
    return -1;
}

int 
truncate_ns(
    iml_desktop_t *desktop,
    int ns_id,
    char *path,
    off_t length,
    int *ns_errno
)
{
    IIIMP_message *send_message;
    IIIMP_message *receive_message;
    IIIMP_truncate *iiimp_truncate;
    IIIMP_utf8string *iiimp_path;
    IIIMP_IMState *xims = IIIMP_IMState::get_imstate_from_desktop(desktop);
    *ns_errno = 0;

    if (xims == NULL)
	return -1;
    iiimp_path = iiimp_utf8string_new(xims->get_iiimptrans()->get_data_s(),
                                      (strlen(path) + 1),
				      (const IIIMP_card8 *)path);
    if (!iiimp_path) return -1;

    iiimp_truncate = iiimp_truncate_new(xims->get_iiimptrans()->get_data_s(),
					ns_id, iiimp_path, length);

    send_message = iiimp_file_operation_new(xims->get_iiimptrans()->get_data_s(),
					    xims->get_im_id(),
					    IIIMP_FILE_OPERATION_TYPE_TRUNCATE,
					    iiimp_truncate);

    if(!xims->send(send_message, true)) return -1;

    for (;;) {
	receive_message = xims->get_iiimptrans()->receive();
        if (receive_message) {
	    if (receive_message->opcode == IM_FILE_OPERATION_REPLY) {
		LOG_DEBUG("Got IM_FILE_OPERATION_REPLY !!\n");
		break;
	    } else {
		xims->dispatch(receive_message->im_id, receive_message->ic_id, receive_message);
	    }
        }
    }

    if (receive_message->v.file_operation_reply.type == IIIMP_FILE_OPERATION_TYPE_TRUNCATE_REPLY) {
	IIIMP_truncate_reply *p = (IIIMP_truncate_reply *)receive_message->v.file_operation_reply.value;
	*ns_errno = p->ns_errno;
	return p->ns_id;
    }
    return -1;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
