/*  esecannaserver --- pseudo canna server that wraps another IME.
 *  Copyright (C) 1999-2000 Yasuhiro Take
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  ree Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
#include <sys/types.h>

#include "def.h"
#include "misc.h"
#include "wnn.h"

typedef struct _wnn_t {
  char *wnnserver; /* 接続する Wnn が動いているホスト名 */
  char *wnnrc; /* 初期化ファイルを指定 */
  char create_dic; /* 辞書、頻度ファイルがなかったときに、作るかどうか */
} wnn_t;

typedef struct _context_t {
  struct _context_t *prev, *next;
  short context_num;

  int client_id;

  struct wnn_buf *wnnid;
  short max_bun;
  
} context_t;

static context_t *cx_top;
static client_t *client;

#define WW_ERROR16(_buf) { \
  cannaheader_t *he; \
  he = (cannaheader_t *)(_buf); \
  he->datalen = LSBMSB16(2); \
  he->err.e16 = LSBMSB16(-1); \
}

#define WW_ERROR8(_buf) { \
  cannaheader_t *he; \
  he = (cannaheader_t *)(_buf); \
  he->datalen = LSBMSB16(1); \
  he->err.e8 = -1; \
}

/*
 * wrapper functions から使われる ユーティリティ関数s
 */

/* コンテキスト関連 */

static short ww_new_context(int id)
{
  context_t *cx, *new;
  short cx_num;
  
  if ((new = (context_t *)calloc(1, sizeof(context_t))) == NULL)
    return -1;
  
  cx = cx_top;
  if (cx) {
    while (cx->next) cx = cx->next;
    cx->next = new;
    new->prev = cx;
  } else {
    cx_top = new;
  }

  cx_num = 1;
  for (;;) {
    cx = cx_top;

    for (;;) {
      if (cx == NULL) {
	new->context_num = cx_num;
	new->client_id = id;
	new->wnnid = NULL;
	return cx_num;
      }
      
      if (cx->context_num == cx_num) {
	cx_num++;
	break;
      }

      cx = cx->next;
    }
  }
}

static context_t *ww_get_context(short cx_num)
{
  context_t *cx;
  
  if (cx_num == -1)
    return NULL;

  cx = cx_top;

  while (cx) {
    if (cx->context_num == cx_num)
      return cx;
    cx = cx->next;
  }

  return NULL;
}

static int ww_clear_context(short cx_num)
{
  context_t *cx;
  
  cx = ww_get_context(cx_num);

  /* FIX: CLEAR PROC */

  return 0;
}

static int ww_free_context(short cx_num)
{
  context_t *cx;

  cx = ww_get_context(cx_num);
  ww_clear_context(cx_num);
  
  if (cx->prev)
    cx->prev->next = cx->next;
  else
    cx_top = cx->next;
  if (cx->next)
    cx->next->prev = cx->prev;

  free(cx);

  return 0;
}

/*
 * Wnn から呼ばれる関数
 */

static int ww_wnn_message(char *s)
{
  m_msg("WNN MESSAGE: %s\n", s);
  return 0;
}

/*
 *
 */

static int ww_open_wnn(int id, context_t *cx, char *envname)
{
  wnn_t *wnn = client[id].data.wnn;
  
  if (cx->wnnid == NULL) {
    if (wnn->create_dic && id != WNN_ROOT_CLIENT)
      cx->wnnid = jl_open_lang(envname, wnn->wnnserver, "ja_JP", wnn->wnnrc, 
			       WNN_CREATE, ww_wnn_message, WNN_TIMEOUT);
    else
      cx->wnnid = jl_open_lang(envname, wnn->wnnserver, "ja_JP", wnn->wnnrc, 
			       WNN_NO_CREATE, ww_wnn_message, WNN_TIMEOUT);
  }

  return 0;
}

static int ww_close_wnn(context_t *cx)
{
  if (cx->wnnid) {
    jl_dic_save_all(cx->wnnid);
    jl_close(cx->wnnid);
  }

  return 0;
}

/*
 * ww_convert_wcs() - かんなで使われるワイドキャラクタと, うんぬで使われる
 *                  - ワイドキャラクタを相互変換。
 */

static ushort *ww_convert_wcs(ushort *src, int len)
{
  int i;
  ushort *dst;
  static buffer_t zbuf;
  
  buffer_check(&zbuf, len * 2 + 2);

  dst = (ushort *)(zbuf.buf);

  for (i = 0; i < len; i++) {
#ifndef WORDS_BIGENDIAN
    dst[i] = ((src[i] << 8) & 0xff00);
    dst[i] |= ((src[i] >> 8) & 0xff);
#else
    dst[i] = src[i];
#endif
  }

  dst[i] = 0;

  return dst;
}

/*
 * ww_after_conversion() - 変換後呼ぶ。指定文節からの各文節の最優先候補を得る。
 *                       - nbun...文節数: bun...指定文節
 */

static ushort *ww_after_conversion(context_t *cx, int nbun, int bun,int *len_r)
{
  int len, pnt;
  int i;
  ushort *ret, *usp;
  w_char *wcp;
  static buffer_t zbuf, zbuf2;

  cx->max_bun = nbun;

  /* まず、全部足したときの長さを得ておく */
  len = 0;
  for (i = bun; i < nbun; i++)
    len += jl_kanji_len(cx->wnnid, i, i + 1) + 1;

  buffer_check(&zbuf, len * 2);
  ret = (ushort *)zbuf.buf;

  len = pnt = 0;
  for (i = bun; i < nbun; i++) {
    len = jl_kanji_len(cx->wnnid, i, i + 1) + 1;

    buffer_check(&zbuf2, len * 2);
    wcp = (w_char *)zbuf2.buf;

    jl_get_kanji(cx->wnnid, i, i + 1, wcp);

    usp = ww_convert_wcs(wcp, len - 1);

    memcpy(&ret[pnt], usp, len * 2);
    pnt += len;
  }

  *len_r = pnt;

  return ret;
}

/*
 * ww_get_cand_*() - 
 */

static int ww_get_cand_num;

static int ww_get_cand_init(context_t *cx, int bun_no)
{
  int hint;

  hint = 0;
  hint |= (bun_no > 0) ? WNN_USE_MAE : 0;
  hint |= (bun_no < cx->max_bun - 1) ? WNN_USE_ATO : 0;

  if (jl_zenkouho_dai(cx->wnnid, bun_no, bun_no + 1, hint, WNN_UNIQ) >= 0) {
    ww_get_cand_num = jl_zenkouho_suu(cx->wnnid);

    return ww_get_cand_num;
  }

  return -1;
}

static ushort *ww_get_cand(context_t *cx, int koho_no, int *len_r)
{
  int len;
  ushort *ret;
  w_char buf[256];
  
  if (0 < ww_get_cand_num && 0 <= koho_no && koho_no < ww_get_cand_num) {
    jl_get_zenkouho_kanji(cx->wnnid, koho_no, buf);

    len = cannawcstrlen((ushort *)buf); /* wnn の w_char と canna の wcs は
					   あんまし、変わらんのでこうする */
    
    ret = ww_convert_wcs((ushort *)buf, len);
    *len_r = len;

    return ret;
  }

  return NULL;
}

/*
 * ww_get_yomi() -
 */

static ushort *ww_get_yomi(context_t *cx, int bun_no, int *len_r)
{
  w_char buf[256];
  ushort *ret;
  int len;

  if ((len = jl_get_yomi(cx->wnnid, bun_no, bun_no + 1, buf)) >= 0) {
    ret = ww_convert_wcs(buf, len);
    
    *len_r = len;
  } else {
    ret = NULL;
    *len_r = 0;
  }

  return ret;
}

/*
 * ww_read_conf_file() - /etc/esecannarc ~/.esecannarc を読む
 */

static int ww_read_conf_file(int id, char *conffilepath)
{
  FILE *fp;
  char buf[1024];
  char *ope, *val;
  int i, ret = 0;
  wnn_t *wnn = client[id].data.wnn;

  if ((fp = fopen(conffilepath, "r")) == NULL) {
    m_msg("Cannot open Conffile %s.\n", conffilepath);
    return -1;
  }

  while (fgets(buf, 1024, fp)) {
    if (buf[0] != '#' && m_conf1_parse(buf, &ope, &val) == 0) {
      m_conf_string(ope, "WNN6.Server", val, &(wnn->wnnserver));
      m_conf_string(ope, "WNN6.WnnRc", val, &(wnn->wnnrc));
      
      i = M_CONF_YESNO(ope, "WNN6.CreateDic", val);
      if (i) wnn->create_dic = i - 1;
    }
  }

  fclose(fp);

  return ret;
}
/*
 * ww_config_client() - client の設定をする
 */

static int ww_config_client(int id, char *conffile)
{
  wnn_t *wnn;

  if ((wnn = client[id].data.wnn = calloc(1, sizeof(wnn_t))) == NULL) {
    m_msg("Out of Memory.\n");
    return -1;
  }

  if (ww_read_conf_file(id, conffile) == -1)
    return -1;

  if (wnn->wnnserver == NULL || wnn->wnnrc == NULL) {
    m_msg("Server or WnnRc not specified.\n");
    return -1;
  }

  return 0;
}

/*
 * 外に公開する関数s
 */

int wnnwrapper_dl_started(client_t *cl)
{
  client = cl;

  m_msg("Module: %s\n", ESECANNA_MODULE_VERSION);

  return 0;
}

int wnnwrapper_init_rootclient()
{
  short cx_num;
  context_t *cx;
  
  m_msg("Initializing root client for Wnn6.\n");

  if (ww_config_client(WNN_ROOT_CLIENT, ESECANNA_RC_PATH) == -1) {
    m_msg("No conffile found. Aborting.\n");
    return -1;
  }

  if ((cx_num = ww_new_context(WNN_ROOT_CLIENT)) == -1) {
    m_msg("Out of Memory.\n");
    return -1;
  }

  cx = ww_get_context(cx_num);

  ww_open_wnn(WNN_ROOT_CLIENT, cx, "esecanna");

  if (cx->wnnid == NULL || jl_isconnect(cx->wnnid) == 0) {
    m_msg("Cannot connect to jserver. Aborting.\n");
    return -1;
  }

  m_msg("Initialize succeeded.\n");

  return 0;
}

int wnnwrapper_end_client(int id)
{
  context_t *cx, *cx2;
  
  cx = cx_top;

  while (cx) {
    if (cx->client_id == id) {
      cx2 = cx->next;

      ww_close_wnn(cx);
      ww_free_context(cx->context_num);

      cx = cx2;
    } else
      cx = cx->next;
  }

  return 0;
}

int wnnwrapper_end_rootclient()
{
  wnnwrapper_end_client(WNN_ROOT_CLIENT);
  
  return 0;
}

int wnnwrapper_clear_client_data(int id)
{
  wnn_t *wnn = client[id].data.wnn;

  MYFREE(wnn->wnnserver);
  MYFREE(wnn->wnnrc);

  MYFREE(client[id].data.wnn);
  
  return 0;
}

/*
 * 「かんな」を Wnn で wrapping する関数s
 */

int wnnwrapper_initialize(int id, char *conffile)
{
  if (ww_config_client(id, conffile) == 0)
    return ww_new_context(id);
  
  return -1;
}

int wnnwrapper_finalize(int id, buffer_t *cbuf)
{
  cannaheader_t *header;
  
  client[id].need_terminate = TRUE; /* main.c で終了処理をしてもらう */
    
  header = (cannaheader_t *)cbuf->buf;
  header->type = 0x02;
  header->extra = 0;
  header->datalen = LSBMSB16(1);
  header->err.e8 = 0;

  return 1;
}

int wnnwrapper_create_context(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  short *sp = (short *)cbuf->buf;
  short cx_num;

  cx_num = ww_new_context(id);
  
  header->type = 0x03;
  header->extra = 0;
  header->datalen = LSBMSB16(2);
  
  sp[2] = LSBMSB16(cx_num);

  return 1;
}

int wnnwrapper_duplicate_context(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  short *sp = (short *)cbuf->buf;
  short cx_n_new, cx_n_orig;
  
  cx_n_orig = LSBMSB16(sp[2]);
  cx_n_new = ww_new_context(id);

  header->type = 0x04;
  header->extra = 0;
  header->datalen = LSBMSB16(2);
  
  sp[2] = LSBMSB16(cx_n_new);

  return 1;
}

int wnnwrapper_close_context(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  short *sp = (short *)cbuf->buf;
  short cx_num;
  context_t *cx;
  
  cx_num = LSBMSB16(sp[2]);
  cx = ww_get_context(cx_num);

  ww_close_wnn(cx);
  ww_free_context(cx->context_num);
  
  header->type = 0x05;
  header->extra = 0;
  header->datalen = LSBMSB16(1);
  header->err.e8 = 0;
  
  return 1;
}


int wnnwrapper_define_word(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;

  header->datalen = LSBMSB16(1);
  header->err.e8 = -1;
  
  return 0;
}

int wnnwrapper_delete_word(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;

  header->datalen = LSBMSB16(1);
  header->err.e8 = -1;
  
  return 0;
}

int wnnwrapper_begin_convert(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  ushort *sp = (ushort *)cbuf->buf;
  ushort *cyomi, *wyomi, *ckoho;
  int *ip = (int *)cbuf->buf;
  int cmode, nbun, len;
  ushort cx_num, datalen;
  context_t *cx;
  
  cx_num = LSBMSB16(sp[4]);
  cmode = LSBMSB32(ip[1]);
  cyomi = &sp[5];

  cx = ww_get_context(cx_num);

  if (cx->wnnid == NULL)
    ww_open_wnn(id, cx, client[cx->client_id].user);

  if (cx->wnnid) {
    len = cannawcstrlen(cyomi);
    wyomi = ww_convert_wcs(cyomi, len);

    nbun = jl_fi_ren_conv(cx->wnnid, wyomi, 0, -1, 0);

    if (nbun > 0) {
      ckoho = ww_after_conversion(cx, nbun, 0, &len);

      datalen = 2 + len * 2 + 2;

      buffer_check(cbuf, 4 + datalen);
      header = (cannaheader_t *)cbuf->buf;
      sp = (ushort *)cbuf->buf;

      header->type = 0x0f;
      header->extra = 0;
      header->datalen = LSBMSB16(datalen);
      sp[2] = LSBMSB16(nbun);
      memcpy(&(sp[3]), ckoho, len * 2);
      sp[3 + len] = 0;

      return 1;
    }
  }

  header->datalen = LSBMSB16(2);
  header->err.e16 = LSBMSB16(-1);

  return 1;
}

int wnnwrapper_end_convert(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  short *sp = (short *)cbuf->buf;
  int *ip = (int *)cbuf->buf;
  short cx_num;
  short bun_num;
  context_t *cx;
  
  cx_num = LSBMSB16(sp[2]);
  bun_num = LSBMSB16(sp[3]);
  cx = ww_get_context(cx_num);

  if (cx->wnnid) {
    int i;
    
    for (i = 0; i < bun_num; i++) {
      jl_dai_top(cx->wnnid, i);
      jl_set_jikouho_dai(cx->wnnid, LSBMSB16(sp[6 + i]));
    }
    /*    jl_update_hindo(cx->wnnid, 0, -1); for Wnn4 */
    jl_optimize_fi(cx->wnnid, 0, -1);
    jl_kill(cx->wnnid, 0, -1);
  }
  
  ww_clear_context(cx_num);

  header->type = 0x10;
  header->extra = 0;
  header->datalen = LSBMSB16(1);
  header->err.e8 = 0;
  
  return 1;
}

int wnnwrapper_get_candidacy_list(int id, buffer_t *cbuf)
{
  context_t *cx;
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  ushort *sp = (short *)cbuf->buf;
  int bun_no, koho_num, len, pnt, errflag = 0, i;
  short cx_num, datalen;
  ushort *ckoho;
  
  cx_num = LSBMSB16(sp[2]);
  bun_no = LSBMSB16(sp[3]);

  cx = ww_get_context(cx_num);

  datalen = 6;
  pnt = 6;

  if (cx->wnnid) {
    /* KOHOS */
    
    if ((koho_num = ww_get_cand_init(cx, bun_no)) > 0) {
      for (i = 0; i < koho_num; i++) {
	if ((ckoho = ww_get_cand(cx, i, &len)) != NULL && errflag == 0) {
	  len *= 2;
	  len += 2;
	  
	  datalen += len;
	  
	  buffer_check(cbuf, datalen);

	  memcpy(&(cbuf->buf[pnt]), ckoho, len);
	  pnt += len;
	} else {
	  errflag = 1;
	}
      }
    }

    /* YOMI */

    /*
    if ((ckoho = ww_get_yomi(cx, bun_no, &len)) != NULL && errflag == 0) {
      len *= 2;
      len += 2;

      datalen += len;

      buffer_check(cbuf, datalen);

      memcpy(&(cbuf->buf[pnt]), ckoho, len);
      pnt += len;
      koho_num++;
    }
    */
    
    if (errflag == 0) {
      datalen += 2;
      buffer_check(cbuf, datalen);
      header = (cannaheader_t *)cbuf->buf;
      sp = (ushort *)cbuf->buf;
      
      cbuf->buf[pnt++] = 0;
      cbuf->buf[pnt++] = 0;
      
      sp[2] = LSBMSB16(koho_num);

      header->type = 0x11;
      header->extra = 0;
      header->datalen = LSBMSB16(datalen);

      return 1;
    }
  }

  header->datalen = LSBMSB16(2);
  header->err.e16 = LSBMSB16(-1);

  return 1;
}

int wnnwrapper_get_yomi(int id, buffer_t *cbuf)
{
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  ushort *sp = (short *)cbuf->buf;
  ushort *cyomi;
  short cx_num, bun_no, datalen;
  context_t *cx;
  int len, byte;

  cx_num = LSBMSB16(sp[2]);
  bun_no = LSBMSB16(sp[3]);

  cx = ww_get_context(cx_num);

  if ((cyomi = ww_get_yomi(cx, bun_no, &len)) != NULL) {
    byte = (len + 1) * 2;
    
    datalen = 2 + byte;

    buffer_check(cbuf, datalen + 4);
    sp = (ushort *)cbuf->buf;
    header = (cannaheader_t *)cbuf->buf;

    header->type = 0x12;
    header->extra = 0;
    header->datalen = LSBMSB16(datalen);
    sp[2] = LSBMSB16(len);

    memcpy(&(cbuf->buf[6]), cyomi, byte);
  } else {
    header->type = 0x12;
    header->extra = 0;
    header->datalen = LSBMSB16(2);
    header->err.e16 = LSBMSB16(-1);
  }
    
  return 1;
}

int wnnwrapper_subst_yomi(int id, buffer_t *cbuf)
{
  WW_ERROR16(cbuf);
  return 1;
}

int wnnwrapper_store_yomi(int id, buffer_t *cbuf)
{
  WW_ERROR16(cbuf);
  return 1;
}

int wnnwrapper_store_range(int id, buffer_t *cbuf)
{
  WW_ERROR8(cbuf);
  return 1;
}

int wnnwrapper_get_lastyomi(int id, buffer_t *cbuf)
{
  WW_ERROR16(cbuf);
  return 1;
}

int wnnwrapper_flush_yomi(int id, buffer_t *cbuf)
{
  WW_ERROR16(cbuf);
  return 1;
}

int wnnwrapper_remove_yomi(int id, buffer_t *cbuf)
{
  WW_ERROR16(cbuf);
  return 1;
}

int wnnwrapper_get_simplekanji(int id, buffer_t *cbuf)
{
  WW_ERROR16(cbuf);
  return 1;
}

int wnnwrapper_resize_pause(int id, buffer_t *cbuf)
{
  int newyomilen, oldyomilen;
  short cannayomilen, bun_no, cx_num, datalen;
  int nbun, len;
  short *sp = (short *)cbuf->buf;
  ushort *ckoho;
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  context_t *cx;
  
  cx_num = LSBMSB16(sp[2]);
  bun_no = LSBMSB16(sp[3]);
  cannayomilen = LSBMSB16(sp[4]);

  cx = ww_get_context(cx_num);

  if (cx->wnnid != NULL && ww_get_yomi(cx, bun_no, &oldyomilen) != NULL) {
    newyomilen = 0;
    if (cannayomilen == -1) { /* 文節伸ばし */
      if (bun_no + 1 >= cx->max_bun)
	newyomilen = 0;
      else
	newyomilen = oldyomilen + 1;
    } else if (cannayomilen == -2) { /* 文節縮め */
      if (oldyomilen == 1)
	newyomilen = 0;
      else
	newyomilen = oldyomilen - 1;
    } else if (cannayomilen > 0) {
      newyomilen = cannayomilen;
    }

    if (newyomilen > 0) {
      nbun = jl_fi_nobi_conv(cx->wnnid, bun_no, newyomilen, cx->max_bun,
			     0, WNN_DAI);
    } else {
      nbun = cx->max_bun;
    }

    if (nbun > 0) {
      ckoho = ww_after_conversion(cx, nbun, bun_no, &len);
      
      datalen = 2 + len * 2 + 2;

      buffer_check(cbuf, 4 + datalen);
      header = (cannaheader_t *)cbuf->buf;
      sp = (ushort *)cbuf->buf;

      header->type = 0x1a;
      header->extra = 0;
      header->datalen = LSBMSB16(datalen);
      sp[2] = LSBMSB16(nbun);

      memcpy(&(sp[3]), ckoho, len * 2);
      sp[3 + len] = 0;
      
      return 1;
    }
  }

  header->datalen = LSBMSB16(2);
  header->err.e16 = LSBMSB16(-1);

  return 1;
}

int wnnwrapper_get_hinshi(int id, buffer_t *cbuf)
{
  WW_ERROR8(cbuf);
  return 1;
}

int wnnwrapper_get_lex(int id, buffer_t *cbuf)
{
  WW_ERROR16(cbuf);
  return 1;
}

int wnnwrapper_get_status(int id, buffer_t *cbuf)
{
  struct {
    int bunnum;
    int candnum;
    int maxcand;
    int diccand;
    int ylen;
    int klen;
    int tlen;
  } stat;

  short bun_no, koho_no, cx_num;
  short *sp = (short *)cbuf->buf;
  int len, koho_num;
  cannaheader_t *header = (cannaheader_t *)cbuf->buf;
  context_t *cx;

  cx_num = LSBMSB16(sp[2]);
  bun_no = LSBMSB16(sp[3]);
  koho_no = LSBMSB16(sp[4]);

  cx = ww_get_context(cx_num);

  if (cx->wnnid) {
    if (ww_get_yomi(cx, bun_no, &len) != NULL) {
      stat.ylen = LSBMSB32(len); /* カレント候補の読みがなのバイト数 */

      if ((koho_num = ww_get_cand_init(cx, bun_no)) > 0 &&
	  ww_get_cand(cx, koho_no, &len) != NULL) {
	stat.klen = LSBMSB32(len); /* カレント候補の漢字候補のバイト数 */

	stat.tlen = LSBMSB32(1); /* カレント候補の構成単語数 */

	stat.maxcand = LSBMSB32(koho_num); /* カレント文節の候補数 */

	stat.diccand = LSBMSB32(koho_num); /* FIXME: maxcand - モード指定分 */

	stat.bunnum = LSBMSB32(bun_no);
	stat.candnum = LSBMSB32(koho_no);

	buffer_check(cbuf, 33);
	header = (cannaheader_t *)cbuf->buf;
  
	header->type = 0x1d;
	header->extra = 0;
	header->datalen = LSBMSB16(29);

	cbuf->buf[4] = 0;

	memcpy(&(cbuf->buf[5]), (char *)&stat, 28);

	return 1;
      }
    }
  }

  header->datalen = LSBMSB16(1);
  header->err.e8 = -1;
  
  return 1;
}

int wnnwrapper_set_locale(int id, buffer_t *cbuf)
{
  WW_ERROR8(cbuf);
  return 1;
}

int wnnwrapper_auto_convert(int id, buffer_t *cbuf)
{
  WW_ERROR8(cbuf);
  return 1;
}



      

    



syntax highlighted by Code2HTML, v. 0.9.1