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