/*
 * $Id: js.c,v 2.69.2.4 2000/08/04 05:37:22 kaneda Exp $
 */

/*
WNN6 CLIENT LIBRARY--SOFTWARE LICENSE TERMS AND CONDITIONS


Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993

Preamble

These Wnn6 Client Library--Software License Terms and Conditions
 (the "License Agreement") shall state the conditions under which you are
 permitted to copy, distribute or modify the software which can be used
 to create Wnn6 Client Library (the "Wnn6 Client Library").  The License
 Agreement can be freely copied and distributed verbatim, however, you
 shall NOT add, delete or change anything on the License Agreement.

OMRON Corporation and OMRON Software Co., Ltd. (collectively referred to
 as "OMRON") jointly developed the Wnn6 Software (development code name
 is FI-Wnn), based on the Wnn Software.  Starting from November, 1st, 1998,
 OMRON publishes the source code of the Wnn6 Client Library, and OMRON
 permits anyone to copy, distribute or change the Wnn6 Client Library under
 the License Agreement.

Wnn6 Client Library is based on the original version of Wnn developed by
 Kyoto University Research Institute for Mathematical Sciences (KURIMS),
 OMRON Corporation and ASTEC Inc.

Article 1.  Definition.

"Source Code" means the embodiment of the computer code, readable and
 understandable by a programmer of ordinary skills.  It includes related
 source code level system documentation, comments and procedural code.

"Object File" means a file, in substantially binary form, which is directly
 executable by a computer after linking applicable files.

"Library" means a file, composed of several Object Files, which is directly
 executable by a computer after linking applicable files.

"Software" means a set of Source Code including information on its use.

"Wnn6 Client Library" the computer program, originally supplied by OMRON,
 which can be used to create Wnn6 Client Library.

"Executable Module" means a file, created after linking Object Files or
 Library, which is directly executable by a computer.

"User" means anyone who uses the Wnn6 Client Library under the License
 Agreement.

Article 2.  Copyright

2.1  OMRON Corporation and OMRON Software Co., Ltd. jointly own the Wnn6
 Client Library, including, without limitation, its copyright.

2.2  Following words followed by the above copyright notices appear
 in all supporting documentation of software based on Wnn6 Client Library:

  This software is based on the original version of Wnn6 Client Library
  developed by OMRON Corporation and OMRON Software Co., Ltd. and also based on
  the original version of Wnn developed by Kyoto University Research Institute
  for Mathematical Sciences (KURIMS), OMRON Corporation and ASTEC Inc.

Article 3.  Grant

3.1  A User is permitted to make and distribute verbatim copies of
 the Wnn6 Client Library, including verbatim of copies of the License
 Agreement, under the License Agreement.

3.2  A User is permitted to modify the Wnn6 Client Library to create
 Software ("Modified Software") under the License Agreement.  A User
 is also permitted to make or distribute copies of Modified Software,
 including verbatim copies of the License Agreement with the following
 information.  Upon modifying the Wnn6 Client Library, a User MUST insert
 comments--stating the name of the User, the reason for the modifications,
 the date of the modifications, additional terms and conditions on the
 part of the modifications if there is any, and potential risks of using
 the Modified Software if they are known--right after the end of the
 License Agreement (or the last comment, if comments are inserted already).

3.3  A User is permitted to create Library or Executable Modules by
 modifying the Wnn6 Client Library in whole or in part under the License
 Agreement.  A User is also permitted to make or distribute copies of
 Library or Executable Modules with verbatim copies of the License
 Agreement under the License Agreement.  Upon modifying the Wnn6 Client
 Library for creating Library or Executable Modules, except for porting
 a computer, a User MUST add a text file to a package of the Wnn6 Client
 Library, providing information on the name of the User, the reason for
 the modifications, the date of the modifications, additional terms and
 conditions on the part of the modifications if there is any, and potential
 risks associated with using the modified Wnn6 Client Library, Library or
 Executable Modules if they are known.

3.4  A User is permitted to incorporate the Wnn6 Client Library in whole
 or in part into another Software, although its license terms and
 conditions may be different from the License Agreement, if such
 incorporation or use associated with the incorporation does NOT violate
 the License Agreement.

Article 4. Warranty

THE WNN6 CLIENT LIBRARY IS PROVIDED BY OMRON ON AN "AS IS" BAISIS.
  OMRON EXPRESSLY DISLCIAMS ANY AND ALL WRRANTIES, EXPRESS OR IMPLIED,
 INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY AND FITNESS
 FOR A PARTICULAR PURPOSE, IN CONNECTION WITH THE WNN6 CLIENT LIBRARY
 OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT LIBRARY.  IN NO EVENT
 SHALL OMRON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, PUNITIVE
 OR CONSEQUENTIAL DAMAGES OF ANY KIND WHATSOEVER IN CONNECTION WITH THE
 WNN6 CLIENT LIBRARY OR THE USE OR OTHER DEALING IN THE WNN6 CLIENT
LIBRARY.

***************************************************************************
Wnn6 Client Library :
(C) Copyright OMRON Corporation.       1995,1998,2000 all rights reserved.
(C) Copyright OMRON Software Co., Ltd. 1995,1998,2000 all rights reserved.

Wnn Software :
(C) Copyright Kyoto University Research Institute for Mathematical Sciences
     1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1993
(C) Copyright ASCTEC, Inc.  1987, 1988, 1989, 1990, 1991, 1992, 1993
***************************************************************************

Comments on Modifications:
*/

/*	Version 4
 */
/*
	Nihongo Henkan Library
*/
/*
	entry functions

	js_open_lang	js_close
	js_change_current_jserver
	js_connect_lang	js_disconnect
	js_isconnect

	js_param_get	js_param_set

	js_access	js_mkdir

	js_get_lang	js_set_lang


extern	Variables
	int	wnn_errorno;
*/


extern	char	*malloc();

#include <stdio.h>
#include <ctype.h>
#ifdef UX386
#include <X11/Xos.h>
#else
#include <fcntl.h>
#endif
#include <pwd.h>
#ifndef UX386
#include <sys/types.h>
#endif
#include <sys/stat.h>
#include <errno.h>
extern int errno;
#include <signal.h>
#include "jd_sock.h"
#include "commonhd.h"
#include "demcom.h"
#include "config.h"

#include "wnnerror.h"
#include "jslib.h"
#include "jllib.h"
#include "mt_jlib.h"
#include "jh.h"

#include "msg.h"
#include "serverdefs.h"

#ifdef SYSVR2
#define	bzero(adr,n)	memset((adr),0,(n))
#endif

#define JS			/* For include ../etc/bdic.c */
#include "../etc/bdic.c"
/*
 * Hideyuki Kishiba (Jul. 11, 1994)
 * New bdic function for FI-Wnn
 */
#include "../etc/fi_bdic.c"
#include "../etc/pwd.c"


char *malloc();

typedef struct _host_address {
    int address_len;
    char *address;
} host_address;

int	wnn_errorno	=0;

struct msg_cat *wnn_msg_cat = NULL;

/*	j Lib.	*/

static	int		current_sd;		/** ソケットfd	**/
static	WNN_JSERVER_ID_INT	*current_js = NULL;

/*	Packet Buffers		*/
static	unsigned char	snd_buf[S_BUF_SIZ];	/** 送信 **/
static	int	sbp=0;			/** 送信バッファーポインター **/
static	int	rbc= -1;		/** 受信バッファーポインター **/

#if defined(EAGAIN)
# if defined(EWOULDBLOCK)
# define ERRNO_CHECK(no) 	((no) == EAGAIN || (no) == EWOULDBLOCK)
# else /* defined(EWOULDBLOCK) */
# define ERRNO_CHECK(no)	((no) == EAGAIN)
# endif /* defined(EWOULDBLOCK) */
#else /* defined(EAGAIN) */
# if defined(EWOULDBLOCK)
# define ERRNO_CHECK(no)	((no) == EWOULDBLOCK)
# else /* defined(EWOULDBLOCK) */
# define ERRNO_CHECK(no)	(0)
# endif /* defined(EWOULDBLOCK) */
#endif /* defined(EAGAIN) */

static int _get_server_name(
    char *server,
    char *pserver,
    int pserver_size,
    int *portNO
);
static int writen();


/*********	V4	*****************/
/***
	jserver_dead Macro
***/

static	jmp_buf	current_jserver_dead;

#define	handler_of_jserver_dead(current_js) \
{ \
    if (current_js) { \
	if(current_js->js_dead){ \
	    js_wnn_errorno_set=WNN_JSERVER_DEAD; \
	} else \
	if(setjmp(js_current_jserver_dead)){ \
	    if (!js_wnn_errorno_eql) js_wnn_errorno_set=WNN_JSERVER_DEAD; \
	} else \
	js_wnn_errorno_set = 0; /* here initialize wnn_errorno; */    \
    } \
}

#define handler_of_jserver_dead_env(env) \
{ \
    if (env->js_id) { \
        if(env->js_id->js_dead){ \
            env_wnn_errorno_set=WNN_JSERVER_DEAD; \
        } else \
        if(setjmp(env_current_jserver_dead)){ \
            if (!env_wnn_errorno_eql) env_wnn_errorno_set=WNN_JSERVER_DEAD; \
        } else \
        env_wnn_errorno_set = 0; /* here initialize wnn_errorno; */    \
    } \
}


static void
set_current_js(server)
register WNN_JSERVER_ID *server;
{
 current_js = (WNN_JSERVER_ID_INT *)server;
 current_sd = current_js->orig.sd;
}

#undef ARGS
#define ARGS char
#define js_wnn_errorno_set wnn_errorno
#define js_wnn_errorno_eql wnn_errorno
#define env_wnn_errorno_set wnn_errorno
#define env_wnn_errorno_eql wnn_errorno
#define js_current_jserver_dead current_jserver_dead
#define env_current_jserver_dead current_jserver_dead

/**	デーモンが死んだ時のための後始末	**/
static void
demon_dead(server)
ARGS *server;
{
 current_js->orig.js_dead= -1;
 js_wnn_errorno_set = WNN_JSERVER_DEAD;
 shutdown(current_sd, 2);
 close(current_sd);
#if DEBUG
	fprintf(stderr,"jslib:JSERVER %s is Dead\n",current_js->orig.js_name);
#endif
 if(current_js->orig.js_dead_env_flg){
	longjmp(current_js->orig.js_dead_env,666);
 }
 longjmp(js_current_jserver_dead,666);
/* never reach */
}


/**
	ソケットをオープンしてcurrent_sdにソケットfdを返す
			(cdというのはコミュニケーションデバイスの名残)
**/
static int
cd_open(lang)
register char *lang;
{
#ifdef AF_UNIX
    int sd;
    struct sockaddr_un saddr;		/** ソケット **/
    char *sock_name = NULL;
    saddr.sun_family = AF_UNIX;

    /* find socket name from table by lang */
    if (lang && *lang) {
	if ((sock_name = wnn_get_unixdomain_of_serverdefs(lang)) == NULL) {
	    sock_name = UNIX_SOCKET_NAME;
	}
    } else {
	sock_name = UNIX_SOCKET_NAME;		/* Jserver */
    }
    strcpy(saddr.sun_path, sock_name);
#if ((defined AIXV3) || (defined FREEBSD) || (defined BSDOS) || (defined NETBSD))
    strcat(saddr.sun_path, "=");
#endif
	    
    if ((sd = socket(AF_UNIX,SOCK_STREAM, 0)) == ERROR) {
#if DEBUG
	xerror("jslib:Can't create socket.\n");
#endif
	return -1;
    }
    if (connect(sd,(struct sockaddr *)&saddr,strlen(saddr.sun_path)+sizeof(saddr.sun_family)) == ERROR) {
#if DEBUG
	xerror("jslib:Can't connect socket.\n");
#endif
	close(sd);
	return -1;
    }
    return sd;
#else
    return -1;
#endif
}

static intfntype
connect_timeout()
{
    SIGNAL_RETURN;
}

static int
cd_open_in_core(sa, tmout)
register struct sockaddr_in *sa;
register int tmout;
{
    int sd;
    int ret;
    int old_alarm = 0;
    intfntype (*save_alarm_proc)() = NULL;

    if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == ERROR){
#if DEBUG
	xerror("jslib:Can't create Inet socket.\n");
#endif
	return -1 ;
    }

    if (tmout > 0) {
	save_alarm_proc = signal(SIGALRM, connect_timeout);
	old_alarm = alarm(tmout);
    }
    ret = connect(sd, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
    if (tmout > 0) {
	alarm(old_alarm);
	if (save_alarm_proc)
	    signal(SIGALRM, save_alarm_proc);
	else
	    signal(SIGALRM, SIG_IGN);
    }
    if (ret == ERROR) {
#if DEBUG
	xerror("jslib:Can't connect Inet socket.\n");
#endif
	close(sd);
	return -1 ;
    }
    return sd;
}

static int
cd_open_in_by_addr(addr, addrlen, port, tmout)
char *addr;
int addrlen, port, tmout;
{
    struct sockaddr_in saddr_in;

    bzero((char *)&saddr_in,sizeof(saddr_in));
    bcopy(addr,(char *)&saddr_in.sin_addr, addrlen);
    saddr_in.sin_family = AF_INET;
    saddr_in.sin_port = port;
    return(cd_open_in_core(&saddr_in, tmout));
}

typedef struct _my_serv_struct {
    char *name;
    int port;
    struct _my_serv_struct *next;
} my_serv_struct;

static int my_getservbyname(name)
register char *name;
{
    static my_serv_struct *tbl = NULL;
    register my_serv_struct *p;
    struct servent *sp = NULL;
    register int len;

    for (p = tbl; p; p = p->next) {
	if (p->name && !strcmp(p->name, name)) return(p->port);
    }
    if (!(sp = getservbyname(name,"tcp"))) return(-1);
    len = strlen(name);
    if (!(p = (my_serv_struct *)malloc(sizeof(my_serv_struct) + len + 1)))
	return(-1);
    p->name = ((char *)p) + sizeof(my_serv_struct);
    strcpy(p->name, name);
    p->port = ntohs(sp->s_port);
    p->next = tbl;
    tbl = p;
    return(p->port);
}

static int
cd_open_in(server, lang, tmout)
register char *server;
register char *lang;
register int tmout;
{
    struct sockaddr_in saddr_in;		/** ソケット **/
    register struct hostent *hp;
    int serverNO, port_num;
    char pserver[64];
    char sserver[64];
    char *serv_name = NULL;
    unsigned long ia;
    char *inet_ntoa();

    serverNO = _get_server_name(server, pserver, sizeof(pserver), &port_num);

    if (port_num > 0) {
	/* absolute port number is specified */
	serverNO += port_num;
    } else {
	/* find service name from table by lang */
	if (lang && *lang) {
	    if ((serv_name = wnn_get_service_of_serverdefs(lang)) == NULL) {
		strncpy(sserver, SERVERNAME, sizeof(sserver) - 1);
	    } else {
		strncpy(sserver, serv_name, sizeof(sserver) - 1);
	    }
	} else {
	    strncpy(sserver, SERVERNAME, sizeof(sserver) - 1);
	}
	sserver[sizeof(sserver) - 1] = 0;

	if ((port_num = my_getservbyname(sserver)) != -1) {
	    serverNO += port_num;
	} else {
	    if (lang && *lang &&
		(port_num = wnn_get_port_num_of_serverdefs(lang)) != -1) {
		serverNO += port_num;
	    } else {
		serverNO += WNN_PORT_IN;
	    }
	}
    }
    bzero((char *)&saddr_in,sizeof(saddr_in));

    if (isascii(pserver[0]) && isdigit(pserver[0])) {
	ia = inet_addr(pserver);
	saddr_in.sin_addr.s_addr = ia;
    } else if ((hp = gethostbyname(pserver))) {
	bcopy(hp->h_addr,(char *)&saddr_in.sin_addr, hp->h_length);
    } else {
	return(-1);
    }
    saddr_in.sin_family = AF_INET;
    saddr_in.sin_port = htons(serverNO);
    return(cd_open_in_core(&saddr_in, tmout));
}

/* get server name and return serverNo */
/* and return absolute port number 1993/12/07 S.Kuwari */
static int
_get_server_name(server, pserver, pserver_size, portNO)
char *server;
char *pserver;
int pserver_size;
int *portNO;
{
    register char *p;
    register int port = 0, offset = 0;

    strncpy(pserver, server, pserver_size - 1);
    pserver[pserver_size - 1] = '\0';
    if ((p = strchr(pserver, ':'))) {
	*p = '\0';
	if (*(p+1)) offset = atoi(p+1);
    }
    if ((p = strchr(pserver, '/'))) {
	*p = '\0';
	if (*(p+1)) port = atoi(p+1);
    }
    *portNO = port;
    return(offset);
}

/*	Packet SND/RCV subroutines	*/
static void put4com();

/* サーバが指定プロトコルをサポートしているかどうかのチェック */
#define check_version(cmd) \
	(((cmd>>12) & 0xFFF) > (current_js->version & 0xFFF))

/* サーバがＦＩ関係処理をサポートしているかどうかのチェック */
#define CHECK_FI \
        ((current_js->version & 0xFFF) >= 0xF00)

/**	パケットのヘッダーを送る	**/
static void
snd_head(cmd, server)
int cmd;	/** cmd=コマンド **/
ARGS *server;
{
 sbp=0;
 if (check_version(cmd)) {
    js_wnn_errorno_set = WNN_NOT_SUPPORT_PACKET;
    longjmp(js_current_jserver_dead,666);
 }
 put4com(cmd, server);
 rbc= -1;
}

/**	パケットのヘッダーを送る	**/
static int
snd_env_head(env,cmd)
register struct wnn_env *env;
int cmd;	/** cmd=コマンド **/
{
 ARGS *args = NULL;

 snd_head(cmd, args);
 put4com(env->env_id, args);
 return 0;
}

/**	パケットのヘッダーを送る	**/
static int
snd_server_head(server,cmd)
register WNN_JSERVER_ID *server;
int cmd;	/** cmd=コマンド **/
{
 ARGS *args = NULL;

 snd_head(cmd, args);
 return 0;
}

/**	送信バッファをフラッシュする	**/
static int
snd_flush(server)
ARGS *server;
{
 if(sbp==0)return(-1);
 writen(sbp, server);
 sbp=0;
 return(0);
}

static int
writen(n, server)
int n;
ARGS *server;
{int cc,x;
 for(cc=0;cc<n;){
	errno = 0;
	x=write(current_sd, &(snd_buf[cc]), n-cc );
	if(x < 0) {
	    if (ERRNO_CHECK(errno) || errno == EINTR) {
		continue;
	    } else {
		demon_dead(server);
		return -1;
	    }
	}
	cc+=x;
 }
#if DEBUG
	fprintf(stderr,"jslib:writen=%d\n",x);
/*	dmp(snd_buf,x); */
#endif
 return(0);
}

/**	サーバへ1バイト送る	**/
static void
put1com(c, server)
int c;
ARGS *server;
{
 snd_buf[sbp++]=c;
 if(sbp>=S_BUF_SIZ){ 
	writen(S_BUF_SIZ, server);
	sbp=0;
 }
}

/**	サーバへ2バイト送る	**/
static void
put2com(c, server)
int c;
ARGS *server;
{
 put1com(c>>(8*1), server);
 put1com(c       , server);
}

/**	サーバへ4バイト送る	**/
static void
put4com(c, server)
int c;
ARGS *server;
{
 put1com(c>>(8*3), server);
 put1com(c>>(8*2), server);
 put1com(c>>(8*1), server);
 put1com(c       , server);
}

/**	サーバへ文字列を送る	**/
static void
putwscom(p, server)
register w_char *p;
ARGS *server;
{
 if(p==NULL){ put2com(0, server); return; }
 while(*p)put2com(*p++, server);
 put2com(0, server);
}

/**	サーバへ文字列を送る	**/
static void
putscom(p, server)
register char *p;
ARGS *server;
{
 if(p==NULL){ put1com(0, server); return; }
 while(*p)put1com(*p++, server);
 put1com(0, server);
}

/**	サーバから1バイト受ける	**/
static int
get1com(server)
ARGS *server;
{
 static int rbp;
 static	unsigned char	rcv_buf[R_BUF_SIZ];	/** 受信 **/

 if(rbc<=0){
    while(1) {
	errno = 0;
	rbc = read(current_sd, rcv_buf, R_BUF_SIZ);
	if(rbc <= 0) {
	    if (ERRNO_CHECK(errno)) {
		continue;
	    } else if (rbc == 0) {
		demon_dead(server);
		return -1;
	    } else {	/* cc == -1 */
		if (errno != EINTR) {
		    demon_dead(server);
		    return -1;
		}
		continue;
	    }
	}
	rbp=0;
#if DEBUG
	fprintf(stderr,"jslib:read:rbc=%d\n",rbc);
/*	dmp(rcv_buf,rbc); */
#endif
	break;
    }
 }
 rbc--;
 return rcv_buf[rbp++] & 0xFF ;
}

/**	サーバから2バイト受ける	**/
static int
get2com(server)
ARGS *server;
{register int h;
 h=get1com(server);
 return (h<<8) | get1com(server);
}

/**	サーバから4バイト受ける	**/
static int
get4com(server)
ARGS *server;
{register int h1,h2,h3;
 h1=get1com(server) << 24 ;
 h2=get1com(server) << 16 ;
 h3=get1com(server) <<  8 ;
 return h1 | h2 | h3 | get1com(server);
}

/**	サーバから文字列を受け取る	**/
static void
getscom(cp, server, buflen)
register char *cp;
ARGS *server;
register int buflen;
{
    register int i;

    for (i = 0 ; i < buflen ; i++) {
	if ((*cp++ = get1com(server)) == '\0')
	    break;
    }
    /* Buffer Overflow size? */
    if (i >= buflen) {
	/* 残りのデータを破棄する */
	while (get1com(server) != 0)
	    ;
	if (i > 0)
	    *(cp - 1) = '\0'; /* set null terminate */
    }
}

/**	サーバから文字列を受け取る	**/
static void
getwscom(wp, server, buflen)
register w_char *wp;
ARGS *server;
register int buflen; /* not bytes. "buflen" is word length. */
{
    register int i;

    for (i = 0 ; i < buflen ; i++) {
	if ((*wp++ = get2com(server)) == '\0')
	    break;
    }
    /* Buffer Overflow size? */
    if (i >= buflen) {
	/* 残りのデータを破棄する */
	while (get2com(server) != 0)
	    ;
	if (i > 0)
	    *(wp - 1) = '\0'; /* set null terminate */
    }
}



/*	Debug Subroutines	*/
#if DEBUG
void
xerror(s)char *s;
{
 fprintf(stderr,"%s\n",s);
}

void
dmp(p,c)char *p;
{
 int i,j;
 for(i=0;;i+=16){
	for(j=0;j<16;j++){
	    	if(c<=0){	fprintf(stderr,"\n"); return;}
		fprintf(stderr,"%02x ",p[i+j]&0xFF);
		c--;
	}
	fprintf(stderr,"\n");
 }
}

#endif

/*	get login name form /etc/passwd file	*/
static char*	
getlogname()
{
    extern struct passwd *getpwuid();
    struct passwd *p;

    if ((p = getpwuid(getuid())) == NULL)
	return(NULL);
    return(p->pw_name);
}

static int
send_js_open_core(server, host, user, version)
WNN_JSERVER_ID *server;
char *host, *user;
int version;
{
    int x;

    handler_of_jserver_dead(server);
    if(js_wnn_errorno_eql) return(-1);
    snd_head(JS_OPEN, server);
    put4com(version, server);		/* H.T. */
    putscom(host, server);
    putscom(user, server);
    snd_flush(server);
    if((x = get4com(server)) == -1){
	js_wnn_errorno_set=get4com(server);
	return(-1);
    }
    return(x);
}



/*:::DOC_START
 *
 *    Function Name: version_negotiation
 *    Description  : 
 *	   クライアント／サーバ間のプロトコルバージョンの調整を行う
 *    Parameter    :
 *	   server :       (InOut) サーバ情報構造体へのポインタ
 *	   host :         (In) クライアント使用ホスト名
 *	   user :         (In) クライアント使用ユーザ名
 *	   init_version : (In) クライアントのプロトコル初期バージョン番号
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
version_negotiation(server, host, user, init_version)
WNN_JSERVER_ID *server;
char *host, *user;
int init_version;
{
    int version, dummy;

    /* メジャー・バージョンチェック */
    if((init_version >> 12) != 4) return(-1);

    if (init_version > 0x4F00) {
	/* 4.F00 より大きければ 4.F00 で再トライ */
	if (send_js_open_core(server, host, user, 0x4F00) < 0) {
	    if (js_wnn_errorno_eql == WNN_BAD_VERSION) {
		/* 4.003 で再トライ */
		if (send_js_open_core(server, host, user, 0x4003) < 0)
		    return(-1);
		((WNN_JSERVER_ID_INT *)server)->version = 0x4003;
		return(0);
	    }
	    return(-1);
	}
	/* サーババージョンのチェック */
	if (js_version(server, &version, &dummy) == -1) return(-1);
	if (version > 0x4F00) {
	    /* サーババージョンで再トライ */
	    if (send_js_open_core(server, host, user, version) >= 0) {
	        ((WNN_JSERVER_ID_INT *)server)->version = version;
		return(0);
	    }
	}
	((WNN_JSERVER_ID_INT *)server)->version = 0x4F00;
    } else {
	/* 4.003 で再トライ */
	if (send_js_open_core(server, host, user, 0x4003) < 0)
	    return(-1);
	((WNN_JSERVER_ID_INT *)server)->version = 0x4003;
    }

    return(0);
} /* End of version_negotiation */



static  WNN_JSERVER_ID *
reconnect_other_host(server, user, host, tmout)
WNN_JSERVER_ID *server;
char *user, *host;
int tmout;
{
    char addr[32];
    int addrlen, i, port;
    char *new_js;
    int x;
    struct hostent *hp;

    addrlen = get4com(server);
    /* Buffer Overflow size? */
    if (addrlen > sizeof(addr)) {
	for (i = 0; i < addrlen; i++) get1com(server);
    } else {
	for (i = 0; i < addrlen; i++) addr[i] = get1com(server);
    }
    port = get4com(server);
    js_close(server);

    /* Buffer Overflow size? */
    if (addrlen > sizeof(addr)) {
	js_wnn_errorno_set = WNN_SOME_ERROR;
	return NULL;
    }
    if (!(hp = gethostbyaddr(addr, addrlen, AF_INET))) {
	js_wnn_errorno_set = WNN_NO_JSERVER;
	return NULL;
    }
    sbp=0;	/* init sndBufPointer */
    if(!(new_js=(char *)malloc(sizeof(WNN_JSERVER_ID_INT)))){
 	js_wnn_errorno_set=WNN_ALLOC_FAIL;
	return NULL;
    }
    server =(WNN_JSERVER_ID *) new_js;
    strncpy(server->js_name, hp->h_name, sizeof(server->js_name) - 1);
    server->js_name[sizeof(server->js_name) - 1] = '\0';
    server->js_dead= 0;
    server->js_dead_env_flg= 0;
    if((current_sd= cd_open_in_by_addr(addr, addrlen, port, tmout))==-1){
	js_wnn_errorno_set = WNN_NO_JSERVER;
	free((char*)server);
	current_js=NULL;
	return NULL;
    }
    server->sd= current_sd;
    ((WNN_JSERVER_ID_INT *)server)->version = JLIB_VERSION;
    ((WNN_JSERVER_ID_INT *)server)->extensions = NULL;
    if ((x = send_js_open_core(server, host, user, JLIB_VERSION)) == -1) {
	x = js_wnn_errorno_eql;
	js_wnn_errorno_set = 0;
	if ((x != WNN_BAD_VERSION) ||
	    version_negotiation(server, host, user, JLIB_VERSION)) {
	    js_close(server);		/* H.T. */
	    current_js = NULL;
	    return NULL;
	}
    } else if (x == 1) {
	/* re-connect to other server */
	return(reconnect_other_host(server, user, host, tmout));
    }
    return(server);
}

/*
 *		Lib. Functions
 *		raw lib.
 */

/***
	js
	・global
***/


/**	  jserver と接続する。jserver_id を返す。	**/
WNN_JSERVER_ID *
js_open_lang(servername, lang, tmout)
register char *servername, *lang;
register int tmout;
{char *new_js, *username;
 char host[WNN_HOSTLEN],user[WNN_ENVNAME_LEN];
 int x;
 WNN_JSERVER_ID_INT *server;

 DoOnce( &once, _InitMutexs );
 LockMutex(&msg_lock);
 if (wnn_msg_cat == NULL){
    char nlspath[64];
    strcpy(nlspath, LIBDIR);
    strcat(nlspath, "/%L/%N");
    wnn_msg_cat = msg_open("libwnn.msg", nlspath, lang, NULL);
    if(wnn_msg_cat == NULL){
	fprintf(stderr, "libwnn: Can't open message file for libwnn.a\n");
    }
 }
 UnlockMutex(&msg_lock);

 if(!(new_js=(char *)malloc(sizeof(WNN_JSERVER_ID_INT)))){
     wnn_errorno=WNN_ALLOC_FAIL;
     return NULL;
 }

 LockMutex(&open_lock);
 current_js =(WNN_JSERVER_ID_INT *) new_js;
 if (servername == NULL) {
   current_js->orig.js_name[0] = '\0';
 } else {
   strncpy(current_js->orig.js_name, servername, sizeof(current_js->orig.js_name) - 1);
   current_js->orig.js_name[sizeof(current_js->orig.js_name) - 1] = '\0';
 }
 current_js->orig.js_dead= 0;
 current_js->orig.js_dead_env_flg= 0;
 InitMutex(&(current_js_js_lock));

/*
 if(user == NULL || 0==strcmp(user,""))
*/
 username = getlogname();
 if (username) {
   strncpy(user, username, WNN_ENVNAME_LEN);
   user[WNN_ENVNAME_LEN-1] = '\0';      /* truncate by WNN_ENVNAME_LEN */
 } else {
   user[0] = '\0';
 }
 if(servername == NULL || 0==strcmp(servername,"") || 0==strcmp(servername,"unix")){
   strcpy(host,"unix");
   if((current_sd= cd_open(lang))==-1){
	UnlockMutex(&open_lock);
	wnn_errorno=WNN_SOCK_OPEN_FAIL;free((char*)current_js);current_js=NULL;
	return NULL;
   }
 }else{
   gethostname(host,WNN_HOSTLEN);
   host[WNN_HOSTLEN-1] = '\0';	/* truncate by WNN_HOSTLEN */
   if((current_sd= cd_open_in(servername, lang, tmout))==-1){
        UnlockMutex(&open_lock);
	wnn_errorno=WNN_SOCK_OPEN_FAIL;free((char*)current_js);current_js=NULL;
	return NULL;
   }
 }
 current_js->orig.sd= current_sd;
 current_js->version= JLIB_VERSION;
 current_js->extensions= NULL;
 server = current_js;
 if ((x = send_js_open_core(server, host, user, JLIB_VERSION)) == -1) {
	x = wnn_errorno;
	wnn_errorno = 0;
	if ((x != WNN_BAD_VERSION) ||
	    version_negotiation(server, host, user, JLIB_VERSION)) {
	    js_close(current_js);
	    current_js = NULL;
	    wnn_errorno = x;
	    UnlockMutex(&open_lock);
	    return NULL;
	}
 } else if (x == 1) {
	/* re-connect to other server */
	return(reconnect_other_host(server, user, host, tmout));
 }
 UnlockMutex(&open_lock);
 return (WNN_JSERVER_ID *)current_js;
}



/**	ソケットをクローズする	**/
/**	  jserver との接続を close する。	**/
int
js_close(server)
WNN_JSERVER_ID *server;
{
 register int x;
 WNN_JSERVER_ID_INT tmp_js_id;

 if(server==0) return(-1);
 tmp_js_id = *(WNN_JSERVER_ID_INT *)server;
 free((char *)server);
 current_js = &tmp_js_id;
 server = (WNN_JSERVER_ID *)current_js;
 set_current_js(server);
 LockMutex(&(current_js_js_lock));
/*	handler of jserver dead */
 handler_of_jserver_dead(server);
 if(wnn_errorno) {
     UnlockMutex(&(current_js_js_lock));
     return(-1);
 }
 snd_head(JS_CLOSE, server);
 snd_flush(server);
 x=get4com(server);
 if(x==-1)wnn_errorno=get4com(server);
 close(current_sd);
 UnlockMutex(&(current_js_js_lock));
 return x;
}


/*
	jserver との間に connection を張り、同時に jserver の内部に環
	境を作る。env_name に既に存在する環境を指定した時にはその環境を
	返し、NULL を指定した時には新しい環境を作って返す。
*/

struct wnn_env *
js_connect_lang(server, env_name, lang)
register char *env_name;
WNN_JSERVER_ID *server;
char *lang;
{
    register int e_id;
    register struct wnn_env_int *env;
    void js_set_lang();

    set_current_js(server);
    if(!(env=(struct wnn_env_int *)malloc(sizeof(struct wnn_env_int)))){
	    js_wnn_errorno_set=WNN_ALLOC_FAIL;
	    return NULL;
    }
    LockMutex(&(server_js_lock));
    handler_of_jserver_dead(server);
    if(js_wnn_errorno_eql) {
        UnlockMutex(&(server_js_lock));
        free(env);
        return(NULL);
    }
    snd_head(JS_CONNECT, server);
    putscom(env_name, server);
    snd_flush(server);
    e_id=get4com(server);
    if(e_id==-1){ js_wnn_errorno_set= get4com(server); free(env); return NULL; }
    UnlockMutex(&(server_js_lock));
    env->orig.env_id = e_id;
    env->orig.js_id  = (WNN_JSERVER_ID *)server;
    env->orig.muhenkan_mode = WNN_DIC_RDONLY;
    env->orig.bunsetsugiri_mode = WNN_DIC_RDONLY;
    env->orig.kutouten_mode = 1;
    env->orig.kakko_mode = 1;
    env->orig.kigou_mode = 1;
    strncpy(env->orig.lang, lang, sizeof(env->orig.lang) - 1);        /* set language name */
    env->orig.lang[sizeof(env->orig.lang) - 1] = 0;
    env->orig.autotune = 0;
    /* 学習情報自動セーブの確定回数初期化（デフォルト 50 回）*/
    env->orig.autosave = 50;
    return (struct wnn_env *)env;
}


/* get language value from env */
char *
js_get_lang(env)
struct wnn_env *env;
{
	return(env->lang);
}

int
js_env_exist(server,env_name)
register char *env_name;
register WNN_JSERVER_ID *server;
{
 int x;

 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_head(JS_ENV_EXIST, server);
 putscom(env_name, server);
 snd_flush(server);
 x =get4com(server);
 UnlockMutex(&(server_js_lock));
 return x;
}

int
js_env_sticky(env)
register struct wnn_env *env;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_ENV_STICKY);
 snd_flush(env->js_id);
 x = get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

int
js_env_un_sticky(env)
register struct wnn_env *env;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_ENV_UN_STICKY);
 snd_flush(env->js_id);
 x = get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**
	  env で示される環境を無くす。
**/
int
js_disconnect(env)
register struct wnn_env *env;
{register int x;
 if(env==0) return(-1);
 /* 本来は、free しなきゃあかんのだけど、リソース管理が出来ないし、
    まあ、8バイトだから、ゴミが残るけどいいだろう。
 free((char *)env);
 */
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_DISCONNECT);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){ env_wnn_errorno_set= get4com(env->js_id); }
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	サーバとコネクトしているか	**/
int
js_isconnect(env)
struct wnn_env *env;
{
    if (env && env->js_id)
        return(env->js_id->js_dead);
    return(-1);
}

/**
	  env の 環境 との通信バッファを flush する。
**/
void
js_flush(env)
struct wnn_env *env;
{
}



/*	Parameter set/get	*/
/**	変換 parameter を設定する。	**/
/**	js_param_set  	**/
int
js_param_set(env,para)
struct wnn_env *env;
register struct wnn_param *para;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_PARAM_SET);
 put4com(para->n, env->js_id);	/* Ｎ(大)文節解析のＮ */
 put4com(para->nsho, env->js_id);	/* 大文節中の小文節の最大数 */
 put4com(para->p1, env->js_id);	/* 幹語の頻度のパラメータ */
 put4com(para->p2, env->js_id);	/* 小文節長のパラメータ */
 put4com(para->p3, env->js_id);	/* 幹語長のパラメータ */
 put4com(para->p4, env->js_id);	/* 今使ったよビットのパラメータ */
 put4com(para->p5, env->js_id);	/* 辞書のパラメータ */
 put4com(para->p6, env->js_id);	/* 小文節の評価値のパラメータ */
 put4com(para->p7, env->js_id);	/* 大文節長のパラメータ */
 put4com(para->p8, env->js_id);	/* 小文節数のパラメータ */

 put4com(para->p9, env->js_id);	/* 疑似品詞 数字の頻度 */
 put4com(para->p10, env->js_id);	/* 疑似品詞 カナの頻度 *//* CWNN 英数の頻度 */
 put4com(para->p11, env->js_id);	/* 疑似品詞 英数の頻度 *//* CWNN 記号の頻度 */
 put4com(para->p12, env->js_id);	/* 疑似品詞 記号の頻度 *//* CWNN 開括弧の頻度 */
 put4com(para->p13, env->js_id);	/* 疑似品詞 閉括弧の頻度 *//* CWNN 閉括弧の頻度 */
 put4com(para->p14, env->js_id);	/* 疑似品詞 付属語の頻度 *//* BWNN No of koho */
 put4com(para->p15, env->js_id);	/* 疑似品詞 開括弧の頻度 *//* CWNN Not used */

 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){ env_wnn_errorno_set= get4com(env->js_id);
	    UnlockMutex(&(env_js_lock)); return -1; }
 UnlockMutex(&(env_js_lock));
 return 0;
}

extern int js_get_autolearning_mode_core();

#define WNN_ENV_LOCAL_MASK \
	(WNN_ENV_KUTOUTEN_MASK|WNN_ENV_KAKKO_MASK|WNN_ENV_KIGOU_MASK)

/*:::DOC_START
 *
 *    Function Name: js_set_henkan_env
 *    Description  : サーバ内の変換環境を設定する
 *    Parameter    :
 *         env :       (In) 環境へのポインタ
 *	   valuemask : (In) 有効設定値ビットマスク
 *         henv :      (In) 変換環境の構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_set_henkan_env(env,valuemask,henv)
struct wnn_env *env;
unsigned long valuemask;
register struct wnn_henkan_env *henv;
{
 register int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 if (valuemask & WNN_ENV_LOCAL_MASK){
      if (valuemask & WNN_ENV_KUTOUTEN_MASK)
	env->kutouten_mode = henv->kutouten_flag;
      if (valuemask & WNN_ENV_KAKKO_MASK)
	env->kakko_mode = henv->kakko_flag;
      if (valuemask & WNN_ENV_KIGOU_MASK)
	env->kigou_mode = henv->kigou_flag;
 }
 if (!(valuemask & ~WNN_ENV_LOCAL_MASK)) {
      UnlockMutex(&(env_js_lock));
      return 0;
 }
 snd_env_head(env,JS_SET_HENKAN_ENV);
 put4com(valuemask, env->js_id);	/* 設定ビットマスク */
 put4com(henv->last_is_first_flag, env->js_id); /* 最終使用最優先 */
 put4com(henv->complex_flag, env->js_id);       /* 複合語優先 */
 put4com(henv->okuri_learn_flag, env->js_id);   /* 送り基準学習 */
 put4com(henv->okuri_flag, env->js_id);         /* 送り基準処理 */
 put4com(henv->prefix_learn_flag, env->js_id);  /* 接頭語学習 */
 put4com(henv->prefix_flag, env->js_id);        /* 接頭語候補 */
 put4com(henv->suffix_learn_flag, env->js_id);  /* 接尾語学習 */
 put4com(henv->common_learn_flag, env->js_id);  /* 汎用語学習 */
 put4com(henv->freq_func_flag, env->js_id);     /* 頻度上昇確率関数 */
 put4com(henv->numeric_flag, env->js_id);       /* 疑似数字の初期表示方法 */
 put4com(henv->alphabet_flag, env->js_id);      /* 疑似アルファベットの初期表示方法 */
 put4com(henv->symbol_flag, env->js_id);        /* 疑似記号の初期表示方法 */
 put4com(henv->yuragi_flag, env->js_id);	/* 長音・ゆらぎ処理 */
 put4com(henv->rendaku_flag, env->js_id);	/* 連濁処理 */
 put4com(henv->bunsetsugiri_flag, env->js_id);	/* 文節切り学習モード */
 put4com(henv->muhenkan_flag, env->js_id);	/* 無変換学習モード */
 put4com(henv->fi_relation_learn_flag, env->js_id); /* ＦＩ関係学習モード */
 put4com(henv->fi_freq_func_flag, env->js_id);	/* ＦＩ関係頻度上昇確率関数 */

 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){
	env_wnn_errorno_set= get4com(env->js_id);
        UnlockMutex(&(env_js_lock));
	return -1;
 }
 if (valuemask & WNN_ENV_BUNSETSUGIRI_LEARN_MASK)
	env->bunsetsugiri_mode = henv->bunsetsugiri_flag;
 if (valuemask & WNN_ENV_MUHENKAN_LEARN_MASK)
	env->muhenkan_mode = henv->muhenkan_flag;
 UnlockMutex(&(env_js_lock));
 return 0;
} /* End of js_set_henkan_env */

/*:::DOC_START
 *
 *    Function Name: js_set_henkan_hinsi
 *    Description  : 変換に（使用／不使用）する品詞群を設定する
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *	   mode :   (In) 設定モード（0 == 絶対設定, else 相対設定）
 *	   nhinsi : (In) 設定品詞数（負 == 不使用, 正 使用）
 *         hlist :  (In) 設定品詞リストへのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_set_henkan_hinsi(env,mode,nhinsi,hlist)
struct wnn_env *env;
int mode, nhinsi, *hlist;
{
 register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_SET_HENKAN_HINSI);
 put4com(mode, env->js_id);
 put4com(nhinsi, env->js_id);
 for(x = 0; x < abs(nhinsi); x++) put4com(hlist[x], env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){ env_wnn_errorno_set= get4com(env->js_id);
            UnlockMutex(&(env_js_lock)); return -1; }
 UnlockMutex(&(env_js_lock));
 return 0;
}

/**	js_param_get  	**/
/**	env で示される環境の変換 parameter を取り出す。	**/
int
js_param_get(env,para)
struct wnn_env *env;
register struct wnn_param *para;
{
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_PARAM_GET);
 snd_flush(env->js_id);
 if(get4com(env->js_id) == -1){
     env_wnn_errorno_set= get4com(env->js_id);
     UnlockMutex(&(env_js_lock)); return -1;
 }
 para->n=get4com(env->js_id);	/* Ｎ(大)文節解析のＮ */
 para->nsho=get4com(env->js_id);	/* 大文節中の小文節の最大数 */
 para->p1=get4com(env->js_id);	/* 幹語の頻度のパラメータ */
 para->p2=get4com(env->js_id);	/* 小文節長のパラメータ */
 para->p3=get4com(env->js_id);	/* 幹語長のパラメータ */
 para->p4=get4com(env->js_id);	/* 今使ったよビットのパラメータ */
 para->p5=get4com(env->js_id);	/* 辞書のパラメータ */
 para->p6=get4com(env->js_id);	/* 小文節の評価値のパラメータ */
 para->p7=get4com(env->js_id);	/* 大文節長のパラメータ */
 para->p8=get4com(env->js_id);	/* 小文節数のパラメータ */
 para->p9=get4com(env->js_id);	/* 疑似品詞 数字の頻度 */
 para->p10=get4com(env->js_id);	/* 疑似品詞 カナの頻度 */
 para->p11=get4com(env->js_id);	/* 疑似品詞 英数の頻度 */
 para->p12=get4com(env->js_id);	/* 疑似品詞 記号の頻度 */
 para->p13=get4com(env->js_id);	/* 疑似品詞 閉括弧の頻度 */
 para->p14=get4com(env->js_id);	/* 疑似品詞 付属語の頻度 */
 para->p15=get4com(env->js_id);	/* 疑似品詞 開括弧の頻度 */
 UnlockMutex(&(env_js_lock));
 return 0;
}

/*:::DOC_START
 *
 *    Function Name: js_get_henkan_env
 *    Description  : サーバ内の変換環境を得る
 *    Parameter    :
 *         env :       (In) 環境へのポインタ
 *         henv :      (Out) 変換環境の構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_get_henkan_env(env,henv)
struct wnn_env *env;
register struct wnn_henkan_env *henv;
{
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_GET_HENKAN_ENV);
 snd_flush(env->js_id);
 if(get4com(env->js_id) == -1){
     env_wnn_errorno_set= get4com(env->js_id);
     UnlockMutex(&(env_js_lock)); return -1;
 }
 henv->last_is_first_flag=get4com(env->js_id);  /* 最終使用最優先 */
 henv->complex_flag=get4com(env->js_id);        /* 複合語優先 */
 henv->okuri_learn_flag=get4com(env->js_id);    /* 送り基準学習 */
 henv->okuri_flag=get4com(env->js_id);          /* 送り基準処理 */
 henv->prefix_learn_flag=get4com(env->js_id);   /* 接頭語学習 */
 henv->prefix_flag=get4com(env->js_id);         /* 接頭語候補 */
 henv->suffix_learn_flag=get4com(env->js_id);   /* 接尾語学習 */
 henv->common_learn_flag=get4com(env->js_id);   /* 汎用語学習 */
 henv->freq_func_flag=get4com(env->js_id);      /* 頻度上昇確率関数 */
 henv->numeric_flag=get4com(env->js_id);        /* 疑似数字の初期表示方法 */
 henv->alphabet_flag=get4com(env->js_id);       /* 疑似アルファベットの初期表示方法 */
 henv->symbol_flag=get4com(env->js_id);         /* 疑似記号の初期表示方法 */
 henv->yuragi_flag=get4com(env->js_id);		/* 長音・ゆらぎ処理 */
 henv->rendaku_flag=get4com(env->js_id);	/* 連濁処理 */
 henv->bunsetsugiri_flag=get4com(env->js_id);	/* 文節切り学習モード */
 henv->muhenkan_flag=get4com(env->js_id);	/* 無変換学習モード */
 henv->fi_relation_learn_flag=get4com(env->js_id); /* ＦＩ関係学習モード */
 henv->fi_freq_func_flag=get4com(env->js_id);	/* ＦＩ関係頻度上昇確率関数 */

 env->bunsetsugiri_mode = henv->bunsetsugiri_flag;
 env->muhenkan_mode = henv->muhenkan_flag;

 henv->kutouten_flag = env->kutouten_mode;	/* 句読点 */
 henv->kakko_flag = env->kakko_mode;		/* 括弧 */
 henv->kigou_flag = env->kigou_mode;		/* 記号 */

 UnlockMutex(&(env_js_lock));
 return 0;
} /* End of js_get_henkan_env */

/*:::DOC_START
 *
 *    Function Name: js_get_henkan_env_local
 *    Description  : 変換の環境の内，ライブラリにあるものを取る
 *                   句読点，括弧，記号
 *    Parameter    :
 *	   env :          (In) 環境へのポインタ
 *	   henv :         (In) 変換環境の構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_get_henkan_env_local(env,henv)
struct wnn_env *env;
register struct wnn_henkan_env *henv;
{
 if(env==0) return(-1);
 LockMutex(&(env_js_lock));
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 henv->kutouten_flag = env->kutouten_mode;	/* 句読点 */
 henv->kakko_flag = env->kakko_mode;		/* 括弧 */
 henv->kigou_flag = env->kigou_mode;		/* 記号 */

 UnlockMutex(&(env_js_lock));
 return 0;
}

/*:::DOC_START
 *
 *    Function Name: js_get_henkan_hinsi
 *    Description  : 変換に（使用／不使用）する品詞群を得る
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *         nhinsi : (Out) 設定品詞数（負 == 不使用, 正 使用）
 *         hlist :  (Out) 設定品詞リストへのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_get_henkan_hinsi(env,nhinsi,hlist)
struct wnn_env *env;
int *nhinsi, **hlist;
{
 int i;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_GET_HENKAN_HINSI);
 snd_flush(env->js_id);
 if(get4com(env->js_id) == -1){
     env_wnn_errorno_set= get4com(env->js_id);
     UnlockMutex(&(env_js_lock)); return -1;
 }
 *nhinsi = get4com(env->js_id);
 if(((*hlist) = (int *)malloc(abs(*nhinsi) * sizeof(int))) == NULL) {
     int dummy;
     for(i = 0; i < abs(*nhinsi); i++) dummy = get4com(env->js_id);
     env_wnn_errorno_set = WNN_ALLOC_FAIL;
     UnlockMutex(&(env_js_lock)); return -1;
 }
 for(i = 0; i < abs(*nhinsi); i++) (*hlist)[i] = get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return 0;
} /* End of js_get_henkan_hinsi */

/*
	global File Operation
*/
/**	js_mkdir	**/
int
js_mkdir(env,path)
struct wnn_env *env;
char *path;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_MKDIR);
 putscom(path, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_access	**/
int
js_access(env,path,amode)
struct wnn_env *env;
char *path;
int amode;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_ACCESS);
 put4com(amode, env->js_id);
 putscom(path, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_file_list_all	**/
static int rcv_file_list();

int
js_file_list_all(server,ret)
WNN_JSERVER_ID *server;
struct wnn_ret_buf *ret;
{
 int x;

 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_FILE_LIST_ALL);
 snd_flush(server);
 x = rcv_file_list(ret, server);
 UnlockMutex(&(server_js_lock));
 return x;
}

/**	js_file_list	**/
int
js_file_list(env,ret)
struct wnn_env *env;
struct wnn_ret_buf *ret;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_LIST);
 snd_flush(env->js_id);
 x = rcv_file_list(ret, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

static void re_alloc();

static int
rcv_file_list(ret, server)
struct wnn_ret_buf *ret;
ARGS *server;
{register int i,count;
 WNN_FILE_INFO_STRUCT	*files;
 count=get4com(server);
 re_alloc(ret,sizeof(WNN_FILE_INFO_STRUCT)*count);
 files=(WNN_FILE_INFO_STRUCT *)ret->buf;
 for(i=0;i<count;i++){
	files->fid= get4com(server);
	files->localf= get4com(server);
	files->ref_count= get4com(server);
	files->type= get4com(server);
	getscom(files->name, server, WNN_F_NAMELEN);
	files++;
 }
 return count;
}

/**	js_file_stat	**/
int
js_file_stat(env,path, s)
struct wnn_env *env;
char *path;
WNN_FILE_STAT *s;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_STAT);
 putscom(path, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 s->type = x;
 return x;
}


/**	js_file_info	**/
int
js_file_info(env,fid,file)
struct wnn_env *env;
int fid;
register WNN_FILE_INFO_STRUCT *file;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_INFO);
 put4com(fid, env->js_id);
 snd_flush(env->js_id);
 file->fid= fid;
 x=get4com(env->js_id);
 if(x==-1){
     env_wnn_errorno_set= get4com(env->js_id);
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 getscom(file->name, env->js_id, WNN_F_NAMELEN);
 file->localf= get4com(env->js_id);
 file->ref_count= get4com(env->js_id);
 file->type= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return 0;
}

/**	js_file_loaded	**/
int
js_file_loaded(server,path)
WNN_JSERVER_ID *server;
char *path;
{register int x;
 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_FILE_LOADED);
 putscom(path, server);
 snd_flush(server);
 x=get4com(server);
 UnlockMutex(&(server_js_lock));
 return x;
}

/**	js_file_loaded_local	**/
static int check_local_file();
static int file_loaded_local();

static int
js_file_loaded_local_body(server,path)
WNN_JSERVER_ID *server;
char *path;
{int x;

 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     return(-1);
 }
 if(check_local_file(path, server) == -1) return (-1);
 snd_server_head(server, JS_FILE_LOADED_LOCAL);
 x=file_loaded_local(path, server);
 return x;
}

int
js_file_loaded_local(server,path)
WNN_JSERVER_ID *server;
char *path;
{
    int x;
    set_current_js(server);
    LockMutex(&(server_js_lock));
    x = js_file_loaded_local_body(server,path);
    UnlockMutex(&(server_js_lock));
    return x;
}

static int
check_local_file(path, server)
char *path;
ARGS *server;
{
 register FILE *f;
 register int x;
 struct wnn_file_head fh;
 int is_compressed;

#ifdef WRITE_CHECK
 check_backup(path, NULL);
#endif /* WRITE_CHECK */
 f=dic_fopen(path,"r", &is_compressed);
 if(f == NULL){
     js_wnn_errorno_set = WNN_OPENF_ERR;
     return -1;
 }
 x=input_file_header(f, &fh, NULL);
 if(x==-1){
     dic_fclose(f, is_compressed);
     js_wnn_errorno_set = WNN_NOT_A_FILE;
     return -1;
 }
 if(dic_check_inode(f, &fh, path, is_compressed) == -1){
     change_file_uniq(&fh, path, NULL);
#ifdef WRITE_CHECK
     dic_fclose(f, is_compressed);
     f=dic_fopen(path,"r", &is_compressed);
     if(f == NULL){
	 js_wnn_errorno_set = WNN_OPENF_ERR;
	 return (-1);
     }
#endif /* WRITE_CHECK */
     if(dic_check_inode(f, &fh, path, is_compressed) == -1){
	 dic_fclose(f, is_compressed);
	 js_wnn_errorno_set = WNN_INODE_CHECK_ERROR;
	 return (-1);
     }
 }
 dic_fclose(f, is_compressed);
 return 0;
}


static int
file_loaded_local(path, server)
char *path;
ARGS *server;
{register int x,i;
 FILE *f;
 struct wnn_file_head fh;
 int is_compressed;

#ifdef WRITE_CHECK
 check_backup(path, NULL);
#endif /* WRITE_CHECK */
 f=dic_fopen(path,"r", &is_compressed);
 if(f == NULL){
     js_wnn_errorno_set = WNN_OPENF_ERR;
     return -1;
 }
 x=input_file_header(f, &fh, NULL);
 if(x==-1){
     dic_fclose(f, is_compressed);
     js_wnn_errorno_set = WNN_NOT_A_FILE;
     return -1;
 }
 put4com(fh.file_uniq.time, server);
 put4com(fh.file_uniq.dev, server);
 put4com(fh.file_uniq.inode, server);
 for(i=0;i<WNN_HOSTLEN;i++){
	put1com(fh.file_uniq.createhost[i], server);
 }

 snd_flush(server);
 x=get4com(server);
 dic_fclose(f, is_compressed);
 return x;
}

/**	js_hindo_file_create	**/
int
js_hindo_file_create(env,fid,fn,comment,hpasswd)
struct wnn_env *env;
int	fid;
char *fn;
w_char *comment;
char *hpasswd;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_HINDO_FILE_CREATE);
 put4com(fid, env->js_id);
 putscom(fn, env->js_id);
 putwscom(comment, env->js_id);
 putscom(hpasswd, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/*:::DOC_START
 *
 *    Function Name: js_fi_hindo_file_create
 *    Description  : サーバ側にＦＩ関係頻度ファイルを作成する
 *    Parameter    :
 *         env :     (In) 環境へのポインタ
 *	   fid :     (In) 対応ＦＩ関係辞書ファイルＩＤ
 *	   fn :      (In) ＦＩ関係頻度ファイル名
 *	   comment : (In) ＦＩ関係頻度ファイルコメント
 * 	   hpasswd : (In) ＦＩ関係頻度ファイルパスワード
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_fi_hindo_file_create(env, fid, fn, comment, hpasswd)
struct wnn_env *env;
int     fid;
char *fn;
w_char *comment;
char *hpasswd;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FI_HINDO_FILE_CREATE);
 put4com(fid, env->js_id);
 putscom(fn, env->js_id);
 putwscom(comment, env->js_id);
 putscom(hpasswd, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
} /* End of js_fi_hindo_file_create */

/*:::DOC_START
 *
 *    Function Name: js_dic_file_create
 *    Description  : サーバ側に辞書ファイルを作成する
 *    Parameter    :
 *         env :     (In) 環境へのポインタ
 *         fn :      (In) 作成辞書ファイル名
 *         type :    (In) 作成辞書ファイルタイプ
 *         comment : (In) 作成辞書ファイルコメント
 *         passwd    (In) 作成辞書ファイルパスワード
 *         hpasswd : (In) 作成辞書内頻度パスワード
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_dic_file_create(env, fn, type, comment, passwd, hpasswd)
struct wnn_env *env;
char *fn;
w_char *comment;
char *passwd, *hpasswd;
int type;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_DIC_FILE_CREATE);
 putscom(fn, env->js_id);
 putwscom(comment, env->js_id);
 putscom(passwd, env->js_id);
 putscom(hpasswd, env->js_id);
 put4com(type, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
} /* End of js_dic_file_create */


/**	js_file_discard	**/
int
js_file_discard(env,fid)
struct wnn_env *env;
int	fid;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_DISCARD);
 put4com(fid, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_file_read	**/
int
js_file_read(env,fn)
struct wnn_env *env;
char	*fn;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_READ);
 putscom(fn, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_file_write	**/
int
js_file_write(env,fid,fn)
struct wnn_env *env;
int	fid;
char	*fn;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_WRITE);
 put4com(fid, env->js_id);
 putscom(fn, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_file_receive	**/
static int xget1com();
static void xput1com();

int
js_file_receive(env,fid,fn)
struct wnn_env *env;
int	fid;
char	*fn;
{register int mode, x;
 char file_name[1024];
 char buf[1024];
 FILE *f;
 int n;
 struct wnn_file_head fh;
 int i;
#ifdef WRITE_CHECK
 char *tmp = NULL, *backup = NULL, tmp_x;
 int tmp_err = 0;
#endif /* WRITE_CHECK */
 int is_compressed;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_RECEIVE);
 put4com(fid, env->js_id);
 snd_flush(env->js_id);
/**/
 getscom(file_name, env->js_id, sizeof(file_name));
 if(fn ==NULL || strcmp(fn,"")==0){
     gethostname(buf, 1024);
     n = strlen(buf);
     buf[n] = C_LOCAL;
     buf[n+1] = 0;
     if(strncmp(buf, file_name, n + 1) == 0){
	 fn = file_name + n + 1;
     }
 }
#ifdef WRITE_CHECK
 check_backup(fn, NULL);
#endif /* WRITE_CHECK */
 if((f = dic_fopen(fn, "r", &is_compressed)) == NULL){ /* New File */
     fh.file_uniq.time = fh.file_uniq.dev = fh.file_uniq.inode = 0;
 }else{			/* Old File Exists */
     if(input_file_header(f, &fh, NULL) == -1){
	 env_wnn_errorno_set=WNN_NOT_A_FILE;
	 dic_fclose(f, is_compressed);
	 put4com(-1, env->js_id);snd_flush(env->js_id);
	 UnlockMutex(&(env_js_lock));
	 return(-1);
     }
     if( is_compressed ){
	 env_wnn_errorno_set=NOT_SUPPORTED_OPERATION;
	 dic_fclose(f, is_compressed);
	 put4com(-1, env->js_id);snd_flush(env->js_id);
	 UnlockMutex(&(env_js_lock));
	 return(-1);
     }
     dic_fclose(f, is_compressed);
 }
 put4com(0, env->js_id);                    /* Ack */
 put4com(fh.file_uniq.time, env->js_id);
 put4com(fh.file_uniq.dev, env->js_id);
 put4com(fh.file_uniq.inode, env->js_id);
 for(i=0;i<WNN_HOSTLEN;i++){
     put1com(fh.file_uniq.createhost[i], env->js_id);
 }

 snd_flush(env->js_id);

 if((mode=get4com(env->js_id))==-1){ /* check stat */
        env_wnn_errorno_set= get4com(env->js_id);
	UnlockMutex(&(env_js_lock));
        return -1;
 }else if(mode==0){
        UnlockMutex(&(env_js_lock));
        return 0; /* need not saving */
 }else if(mode == 1 || mode == 3){ /* mode == 3 means the file is a new one. */
#ifdef WRITE_CHECK
     backup = make_backup_file(fn, NULL);
     if ((tmp = make_tmp_file(fn, 0, &f, NULL)) == NULL) {
         delete_tmp_file(backup);
#else /* WRITE_CHECK */
     if((f = fopen(fn, "w+")) == NULL){ 
#endif /* WRITE_CHECK */
         env_wnn_errorno_set=WNN_FILE_WRITE_ERROR;
         put4com(-1, env->js_id);snd_flush(env->js_id);
	 UnlockMutex(&(env_js_lock));
         return(-1);
     }
 }else if(mode == 2){
#ifdef WRITE_CHECK
     backup = make_backup_file(fn, NULL);
     if ((tmp = make_tmp_file(fn, 1, &f, NULL)) == NULL) {
         delete_tmp_file(backup);
#else /* WRITE_CHECK */
     if((f = fopen(fn, "r+")) == NULL){ /* New File */
#endif /* WRITE_CHECK */
         env_wnn_errorno_set=WNN_FILE_WRITE_ERROR;
         put4com(-1, env->js_id);snd_flush(env->js_id);
	 UnlockMutex(&(env_js_lock));
         return(-1);
     }
 }
 put4com(0, env->js_id); snd_flush(env->js_id); /* ACK */
 for(;;){
        if((x=xget1com(env->js_id))== -1) break; /* EOF */
#ifdef WRITE_CHECK
        tmp_x = (char)x;
        if (fwrite(&tmp_x, sizeof(char), 1, f) == -1) tmp_err = 1;
#else /* WRITE_CHECK */
        fputc(x,f);
#endif /* WRITE_CHECK */
 }
 fclose(f);
#ifdef WRITE_CHECK
 if (tmp_err == 0) {
     move_tmp_to_org(tmp, fn, 1);
 } else {
     delete_tmp_file(tmp);
 }
 delete_tmp_file(backup);
#endif /* WRITE_CHECK */

 x=get4com(env->js_id);
 if(x==-1) env_wnn_errorno_set= get4com(env->js_id);
#ifdef WRITE_CHECK
 if (tmp_err) {
     env_wnn_errorno_set = WNN_FILE_WRITE_ERROR;
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
#endif /* WRITE_CHECK */
 UnlockMutex(&(env_js_lock));
 return x;
}

static int
xget1com(server)
ARGS *server;
{register int x;
 if((x= get1com(server)) != 0xFF) return x;
 if(get1com(server) == 0xFF) return -1; /* EOF */
 return 0xFF;
}

/**	js_file_send	**/
int
js_file_send(env,fn)
struct wnn_env *env;
char	*fn;
{register int x;
 FILE *f;
 int n;
 char buf[1024],*b;
 register int cc,i;
 int is_compressed;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 if(check_local_file(fn, env->js_id) == -1) {
     UnlockMutex(&(env_js_lock));
     return (-1);
 }
 snd_env_head(env,JS_FILE_SEND);
 x=file_loaded_local(fn, env->js_id);
 if(x!= -1){ /* file is already loaded */
     if(get4com(env->js_id) == -1) {
         env_wnn_errorno_set= get4com(env->js_id);
	 UnlockMutex(&(env_js_lock));
         return(-1);
     }
     return x;
     UnlockMutex(&(env_js_lock));
 }

 x=get4com(env->js_id);
 if(x==-1){
        env_wnn_errorno_set= get4com(env->js_id);
	UnlockMutex(&(env_js_lock));
        return -1;
 }

 gethostname(buf, 1024);
 n = strlen(buf);
 buf[n] = C_LOCAL;
 strcpy(buf + n + 1,fn);
 putscom(buf, env->js_id);

#ifdef WRITE_CHECK
 check_backup(fn, NULL);
#endif /* WRITE_CHECK */
 if((f=dic_fopen(fn,"r", &is_compressed))== NULL){
        xput1com(-1, env->js_id); /* EOF */
	UnlockMutex(&(env_js_lock));
        return -1;
 }

 /* send contents of file */
 for(;;){
        cc = fread(buf,1,1024,f);
        if(cc <= 0) break; /* EOF */
        for(b=buf,i=0;i<cc;i++){
                xput1com((int)*b++ & 0xff, env->js_id);
        }
 }
 dic_fclose(f, is_compressed);
 xput1com(-1, env->js_id); /* EOF */
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1) env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

static void
xput1com(d, server)
int d;
ARGS *server;
{
 if(d == -1){ put1com(0xFF, server); put1com(0xFF, server); return;/* EOF */}
 put1com(d, server);
 if(d == 0xFF){ put1com(0x00, server);}
}


/***	Dic. Operation for Env.	 ***/

/**	js_dic_add	**/
static int
js_dic_add_body(env,fid,hfid,rev, jnice,rw,hrw, pw1, pw2)
struct wnn_env *env;
int	fid,hfid,rev,jnice,rw,hrw;
char *pw1, *pw2;
{register int x;
 snd_env_head(env,JS_DIC_ADD);
 put4com(fid, env->js_id);
 put4com(hfid, env->js_id);
 put4com(jnice, env->js_id);
 put4com(rw, env->js_id);
 put4com(hrw, env->js_id);
 putscom(pw1, env->js_id);
 putscom(pw2, env->js_id);
 put4com(rev, env->js_id);		/* rev is to add it as reverse dict */
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 return x;
}
int
js_dic_add(env,fid,hfid,rev, jnice,rw,hrw, pw1, pw2)
struct wnn_env *env;
int	fid,hfid,rev,jnice,rw,hrw;
char *pw1, *pw2;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 x = js_dic_add_body(env,fid,hfid,rev, jnice,rw,hrw, pw1, pw2);
 UnlockMutex(&(env_js_lock));
 return x;
}

/*:::DOC_START
 *
 *    Function Name: js_fi_dic_add_body
 *    Description  : js_fi_dic_add のサブルーチン関数
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *	   fid :    (In) ＦＩ関係辞書ファイルＩＤ
 *	   hfid :   (In) ＦＩ関係頻度ファイルＩＤ
 * 	   suflag : (In) システム辞書ｏｒユーザ辞書
 * 	   rw :     (In) 辞書更新が可能ｏｒ不可能
 *	   hrw :    (In) 頻度更新が可能ｏｒ不可能
 *	   pw1 :    (In) ＦＩ関係辞書ファイルのパスワード
 *	   pw2 :    (In) ＦＩ関係頻度ファイルのパスワード
 *
 *    Return value : -1==ERROR, else 登録辞書番号
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
js_fi_dic_add_body(env, fid, hfid, suflag, rw, hrw, pw1, pw2)
struct wnn_env *env;
int     fid,hfid,suflag,rw,hrw;
char *pw1, *pw2;
{register int x;
 snd_env_head(env,JS_FI_DIC_ADD);
 put4com(fid, env->js_id);
 put4com(hfid, env->js_id);
 put4com(suflag, env->js_id);
 put4com(rw, env->js_id);
 put4com(hrw, env->js_id);
 putscom(pw1, env->js_id);
 putscom(pw2, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 return x;
} /* End of js_fi_dic_add_body */

/*:::DOC_START
 *
 *    Function Name: js_fi_dic_add
 *    Description  : 環境にＦＩ辞書を追加する
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *	   fid :    (In) ＦＩ関係辞書ファイルＩＤ
 *	   hfid :   (In) ＦＩ関係頻度ファイルＩＤ
 * 	   suflag : (In) システム辞書ｏｒユーザ辞書
 * 	   rw :     (In) 辞書更新が可能ｏｒ不可能
 *	   hrw :    (In) 頻度更新が可能ｏｒ不可能
 *	   pw1 :    (In) ＦＩ関係辞書ファイルのパスワード
 *	   pw2 :    (In) ＦＩ関係頻度ファイルのパスワード
 *
 *    Return value : -1==ERROR, else 登録辞書番号
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_fi_dic_add(env, fid, hfid, suflag, rw, hrw, pw1, pw2)
struct wnn_env *env;
int     fid,hfid,suflag,rw,hrw;
char *pw1, *pw2;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 /* call sub routine function */
 x = js_fi_dic_add_body(env, fid, hfid, suflag, rw, hrw, pw1, pw2);
 UnlockMutex(&(env_js_lock));
 return x;
} /* End of js_fi_dic_add */

/**	js_dic_delete	**/
int
js_dic_delete(env,dicno)
struct wnn_env *env;
int	dicno;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_DIC_DELETE);
 put4com(dicno, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_dic_use	**/
int
js_dic_use(env,dic_no,flag)
struct wnn_env *env;
int	dic_no,flag;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_DIC_USE);
 put4com(dic_no, env->js_id);
 put4com(flag, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_fuzokugo_set	**/
int
js_fuzokugo_set(env,fid)
struct wnn_env *env;
int	fid;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FUZOKUGO_SET);
 put4com(fid, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_fuzokugo_get	**/
int
js_fuzokugo_get(env)
struct wnn_env *env;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FUZOKUGO_GET);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

static int rcv_dic_list();
static void get_dic_info();

/*:::DOC_START
 *
 *    Function Name: js_dic_list_all
 *    Description  : 指定されたサーバの全環境に登録されているＷｎｎ辞書の
 *		     情報を返す
 *    Parameter    :
 *         server : (In) サーバへのポインタ
 *	   ret :    (Out) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_dic_list_all(server,ret)
WNN_JSERVER_ID *server;
struct wnn_ret_buf *ret;
{
 int x;

 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_DIC_LIST_ALL);
 snd_flush(server);
 x = rcv_dic_list(ret, server);
 UnlockMutex(&(server_js_lock));
 return x;
} /* End of js_dic_list_all */

/*:::DOC_START
 *
 *    Function Name: js_dic_list
 *    Description  : 指定された環境に登録されているＷｎｎ辞書の情報を返す
 *    Parameter    :
 *         env : (In) 環境へのポインタ
 *         ret : (Out) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_dic_list(env,ret)
struct wnn_env *env;
struct wnn_ret_buf *ret;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_DIC_LIST);
 snd_flush(env->js_id);
 x = rcv_dic_list(ret, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
} /* End of js_dic_list */

/*:::DOC_START
 *
 *    Function Name: js_fi_dic_list_all
 *    Description  : 指定されたサーバの全環境に登録されている辞書の内、
 *                   指定された辞書群の情報を返す
 *    Parameter    :
 *         server : (In) サーバへのポインタ
 *	   dmask :  (In) 辞書群設定マスク
 *         ret :    (Out) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_fi_dic_list_all(server, dmask, ret)
WNN_JSERVER_ID *server;
unsigned long dmask;
struct wnn_ret_buf *ret;
{
 int x;

 set_current_js(server);

 /* サーバが FI-Wnn より前のバージョンなら、従来の dic_list 命令を送る */
 if(!CHECK_FI) return(js_dic_list_all(server, ret));

 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_FI_DIC_LIST_ALL);
 put4com(dmask, server);
 snd_flush(server);
 x = rcv_dic_list(ret, server);
 UnlockMutex(&(server_js_lock));
 return x;
} /* End of js_fi_dic_list_all */

/*:::DOC_START
 *
 *    Function Name: js_fi_dic_list
 *    Description  : 指定された環境に登録されている辞書の内、
 *		     指定された辞書群の情報を返す
 *    Parameter    :
 *         env :   (In) 環境へのポインタ
 *	   dmask : (In) 辞書群設定マスク
 *         ret :   (Out) データ受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_fi_dic_list(env, dmask, ret)
struct wnn_env *env;
unsigned long dmask;
struct wnn_ret_buf *ret;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);

 /* サーバが FI-Wnn より前のバージョンなら、従来の dic_list 命令を送る */
 if(!CHECK_FI) return(js_dic_list(env, ret));

 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FI_DIC_LIST);
 put4com(dmask, env->js_id);
 snd_flush(env->js_id);
 x = rcv_dic_list(ret, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
} /* End of js_fi_dic_list */

/*:::DOC_START
 *
 *    Function Name: rcv_dic_list
 *    Description  : 辞書情報受け取り用構造体の領域を確保する
 *    Parameter    :
 *         ret :    (Out) データ受け取り用構造体へのポインタ
 *	   server : (In) サーバへのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
rcv_dic_list(ret, server)
struct wnn_ret_buf *ret;
ARGS *server;
{register int i,count;
 register WNN_DIC_INFO *dic;
 if((count=get4com(server)) == -1) {
     js_wnn_errorno_set = get4com(server);
     return(-1);
 }
 re_alloc(ret, sizeof(WNN_DIC_INFO)*(count + 1));

 dic=(WNN_DIC_INFO *)ret->buf;
 for(i=0;i<count;i++){
     get_dic_info(dic, server);
     dic++;
 }
 dic->dic_no = -1;
 return count;
} /* End of rcv_dic_list */

/*:::DOC_START
 *
 *    Function Name: get_dic_info
 *    Description  : 辞書情報をサーバから受け取る
 *    Parameter    :
 *         dic :    (Out) 辞書情報受け取り用構造体へのポインタ
 *         server : (In) サーバへのポインタ
 *
 *    Return value : -1==ERROR, else 登録辞書数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static void
get_dic_info(dic, server)
register WNN_DIC_INFO *dic;
ARGS *server;
{
	dic->dic_no =get4com(server);	/* dic_No */
	dic->body =get4com(server);	/* body fid */
	dic->hindo =get4com(server);	/* hindo fid */
	dic->rw =get4com(server);	/* r/w */
	dic->hindo_rw =get4com(server);	/* hindo r/w */
	dic->enablef =get4com(server);	/* enable/disable */
	dic->nice =get4com(server);	/* nice */
	dic->rev = get4com(server);
/* added H.T */
	getwscom(dic->comment, server, WNN_COMMENT_LEN);
	getscom(dic->fname, server, WNN_F_NAMELEN);
	getscom(dic->hfname, server, WNN_F_NAMELEN);
	getscom(dic->passwd, server, WNN_PASSWD_LEN);
	getscom(dic->hpasswd, server, WNN_PASSWD_LEN);
	dic->type = get4com(server);
	dic->gosuu = get4com(server);
	dic->localf = get4com(server);
	dic->hlocalf = get4com(server);
} /* End of get_dic_info */

/*:::DOC_START
 *
 *    Function Name: rcv_fzk_list
 *    Description  : 付属語情報受け取り用構造体の領域を確保し、
 *		     サーバから情報を受け取る
 *    Parameter    :
 *         curfzk : (Out) 現在使用ファイル識別子
 *         ret :    (Out) 付属語情報受け取り用構造体へのポインタ
 *         server : (In) サーバへのポインタ
 *
 *    Return value : -1==ERROR, else 読込み付属語数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
rcv_fzk_list(curfzk, ret, server)
int *curfzk;
WNN_FZK_INFO **ret;
ARGS *server;
{
    register int i, count;
    register WNN_FZK_INFO *fzk;

    /* 読込み付属語数・現在使用ファイル識別子を受け取る */
    if((count = get4com(server)) == -1) {
	js_wnn_errorno_set = get4com(server);
	return(-1);
    }
    *curfzk = get4com(server);

    /* 情報受け取り用構造体の領域を確保する */
    if(((*ret) = (WNN_FZK_INFO *)malloc((count + 1) *
					sizeof(WNN_FZK_INFO))) == NULL) {
	WNN_FZK_INFO dummy;
	for(i = 0; i < count; i++){
	    getwscom(dummy.comment, server, WNN_COMMENT_LEN);
	    getscom(dummy.fname, server, WNN_F_NAMELEN);
	}
	js_wnn_errorno_set = WNN_ALLOC_FAIL;
	return(-1);
    }
    fzk = (WNN_FZK_INFO *)*ret;

    /* 付属語情報を受け取る */
    for(i = 0; i < count; i++){
	getwscom(fzk->comment, server, WNN_COMMENT_LEN);
	getscom(fzk->fname, server, WNN_F_NAMELEN);
	fzk++;
    }

    fzk->fname[0] = 0;
    return count;
} /* End of rcv_fzk_list */

/*:::DOC_START
 *
 *    Function Name: js_fuzokugo_list
 *    Description  : 指定されたサーバに読み込まれている全付属語情報と
 *                   環境に現在設定されている情報の識別子を返す
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *         curfzk : (Out) 現在使用ファイル識別子
 *         ret :    (Out) 付属語情報受け取り用構造体へのポインタ
 *
 *    Return value : -1==ERROR, else 読込み付属語数
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_fuzokugo_list(env, curfzk, ret)
struct wnn_env *env;
int *curfzk;
WNN_FZK_INFO **ret;
{
    register int x;

    if(env==0) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_FUZOKUGO_LIST);
    snd_flush(env->js_id);
    x = rcv_fzk_list(curfzk, ret, env->js_id);
    UnlockMutex(&(env_js_lock));
    return x;
} /* End of js_fuzokugo_list */

/***	Dic. Operation by dic_No.	***/

/**	js_word_add		**/
int
js_word_add(env,dic_no,yomi,kanji,comment,hinshi,init_hindo)
struct wnn_env *env;
int	dic_no;
w_char	*yomi,*kanji,*comment;
int	hinshi,init_hindo;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_WORD_ADD);
 put4com(dic_no, env->js_id);
 putwscom(yomi, env->js_id);
 putwscom(kanji, env->js_id);
 putwscom(comment, env->js_id);
 put4com(hinshi, env->js_id);
 put4com(init_hindo, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_word_delete		**/
int
js_word_delete(env,dic_no,entry)
struct wnn_env *env;
int	dic_no;
int	entry;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_WORD_DELETE);
 put4com(dic_no, env->js_id);
 put4com(entry, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1)env_wnn_errorno_set= get4com(env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}


/**	js_word_search		**/
static int rcv_word_data();

int
js_word_search(env,dic_no,yomi,ret)
struct wnn_env *env;
int	dic_no;
w_char	*yomi;
struct wnn_ret_buf *ret;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_WORD_SEARCH);
 put4com(dic_no, env->js_id);
 putwscom(yomi, env->js_id);
 snd_flush(env->js_id);
 x = rcv_word_data(ret, yomi, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_word_search_by_env	**/
int
js_word_search_by_env(env,yomi,ret)
struct wnn_env *env;
w_char	*yomi;
struct wnn_ret_buf *ret;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_WORD_SEARCH_BY_ENV);
 putwscom(yomi, env->js_id);
 snd_flush(env->js_id);
 x = rcv_word_data(ret, yomi, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_word_info		**/
int
js_word_info(env,dic_no,entry,ret)
struct wnn_env *env;
int	dic_no,entry;
struct wnn_ret_buf *ret;
{register int x;
 w_char yomi[LENGTHYOMI];

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_WORD_INFO);
 put4com(dic_no, env->js_id);
 put4com(entry, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){
     env_wnn_errorno_set= get4com(env->js_id);
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 getwscom(yomi, env->js_id, sizeof(yomi) / sizeof(w_char));
 rcv_word_data(ret, yomi, env->js_id);
 UnlockMutex(&(env_js_lock));
 return(0);
}

int
js_word_comment_set(env, dic_no, entry, comment)
struct wnn_env *env;
int	dic_no,entry;
w_char *comment;
{
 register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_WORD_COMMENT_SET);
 put4com(dic_no, env->js_id);
 put4com(entry, env->js_id);
 putwscom(comment, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){
     env_wnn_errorno_set= get4com(env->js_id);
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 UnlockMutex(&(env_js_lock));
 return(0);
}    

/**	rcv for word_search		**/
static int
rcv_word_data(ret, yomi, server)
struct wnn_ret_buf *ret;
w_char *yomi;			/* Yomi is not sent from server
				 *  (at least for the time being).
				 */
ARGS *server;
{register int x, j_c,k_c, databytes, wlen;
 w_char *k;
 w_char wbuf[LENGTHKANJI];
 register struct wnn_jdata *jd;
 register int cnt, error_flag;

 j_c = get4com(server);
 k_c = get4com(server);
 databytes = sizeof(w_char)*(k_c + j_c * 3 + j_c * wnn_Strlen(yomi));
 re_alloc(ret, sizeof(struct wnn_jdata)*(j_c + 1) + databytes);
 jd=(struct wnn_jdata *)ret->buf;
 for(cnt = 0;;cnt++){
        jd->dic_no = x = get4com(server);
        if(x==-1) break;
        jd->serial  = get4com(server);
        jd->hinshi = get4com(server);
        jd->hindo = get4com(server);  jd->ima = get4com(server);
        jd->int_hindo = get4com(server); jd->int_ima = get4com(server);
        jd++;
 }
 jd++;
 k= (w_char *)jd;
 jd=(struct wnn_jdata *)ret->buf;
 error_flag = 0;
 for(;;){
        if(jd->dic_no==-1) break;

	if (!error_flag) {
	    wlen = wnn_Strlen(yomi) + 1;
	    if ((wlen * sizeof(w_char)) > databytes) {
		error_flag = 1;
	    } else {
		jd->yomi = k;           /* Copy Yomi */
		wnn_Strcpy(k, yomi);
		k+= wlen;
		databytes -= (wlen * sizeof(w_char));
	    }
	}

	getwscom(wbuf, server, sizeof(wbuf) / sizeof(w_char));
	if (!error_flag) {
	    wlen = wnn_Strlen(wbuf) + 1;
	    if ((wlen * sizeof(w_char)) > databytes) {
		error_flag = 1;
	    } else {
		jd->kanji = k;          /* Get Kanji */
		wnn_Strcpy(k, wbuf);
		k+= wlen;
		databytes -= (wlen * sizeof(w_char));
	    }
	}

	getwscom(wbuf, server, sizeof(wbuf) / sizeof(w_char));
	if (!error_flag) {
	    wlen = wnn_Strlen(wbuf) + 1;
	    if ((wlen * sizeof(w_char)) > databytes) {
		error_flag = 1;
	    } else {
		jd->com = k;            /* Get Comment */
		wnn_Strcpy(k, wbuf);
		k+= wlen;
		databytes -= (wlen * sizeof(w_char));
	    }
	}
        jd++;
 }
 return cnt;
}


/**	js_dic_info	**/
int
js_dic_info(env,dic_no,ret)
struct wnn_env *env;
int	dic_no;
register WNN_DIC_INFO *ret;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_DIC_INFO);
 put4com(dic_no, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){
     env_wnn_errorno_set = get4com(env->js_id);
     UnlockMutex(&(env_js_lock));
     return x;
 }
 get_dic_info(ret, env->js_id);
 UnlockMutex(&(env_js_lock));
 return dic_no;
}

/**	js_who		**/
int
js_who(server,ret)
WNN_JSERVER_ID *server;
struct wnn_ret_buf *ret;
{register int i,j,c;
 WNN_JWHO *w;
 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_WHO);
 snd_flush(server);

 c=get4com(server);
 if(c==-1){
     js_wnn_errorno_set= get4com(server);
     UnlockMutex(&(server_js_lock));
     return -1;
 }

 re_alloc(ret, sizeof(WNN_JWHO)*c);
 w=(WNN_JWHO *)ret->buf;
 for(i=0;i<c;i++){
        w->sd=get4com(server);
        getscom(w->user_name, server, sizeof(w->user_name));
        getscom(w->host_name, server, sizeof(w->host_name));
        for(j=0;j<WNN_MAX_ENV_OF_A_CLIENT;j++){
                (w->env)[j]=get4com(server);
        }
        w++;
 }
 UnlockMutex(&(server_js_lock));
 return(c);
}

/**	jserver 中の全ての環境に関する情報を得る。
	(ウラ技)
**/
int
js_env_list(server,ret)
WNN_JSERVER_ID *server;
struct wnn_ret_buf *ret;
{register int i,j,c;
 WNN_ENV_INFO *w;
 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_ENV_LIST);
 snd_flush(server);

 c=get4com(server);
 if(c==-1){ 
     js_wnn_errorno_set= get4com(server);
     UnlockMutex(&(server_js_lock));
     return -1;
 }

 re_alloc(ret, sizeof(WNN_ENV_INFO)*c);
 w=(WNN_ENV_INFO *)ret->buf;
 for(i=0;i<c;i++){
        w->env_id = get4com(server);
        getscom(w->env_name, server, WNN_ENVNAME_LEN);
        w->ref_count=get4com(server);
        w->fzk_fid=get4com(server);
        w->jishomax=get4com(server);
        for(j=0;j<WNN_MAX_JISHO_OF_AN_ENV;j++){
                (w->jisho)[j]= get4com(server);
        }
        for(j=0;j<WNN_MAX_FILE_OF_AN_ENV;j++){
                (w->file)[j]= get4com(server);
        }
        w++;
 }
 UnlockMutex(&(server_js_lock));
 return(c);
}

/****

****/
/*:::DOC_START
 *
 *    Function Name: js_hindo_set
 *    Description  : 指定された候補の今ビット・頻度を設定する
 *    Parameter    :
 *         env :   (In) 環境へのポインタ
 *	   dic :   (In) 候補が登録されている辞書番号
 *	   entry : (In) 候補のエントリ番号
 *	   ima :   (In) 今ビットの設定方法フラグ
 *	   hindo : (In) 頻度の設定方法フラグ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_hindo_set(env,dic,entry,ima,hindo)
struct wnn_env *env;
int dic, entry, ima,hindo;
{register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_HINDO_SET);

 put4com(dic, env->js_id);
 put4com(entry, env->js_id);
 put4com(ima, env->js_id);
 put4com(hindo, env->js_id);
 snd_flush(env->js_id);
 if((x=get4com(env->js_id))==-1){
	env_wnn_errorno_set= get4com(env->js_id);
	UnlockMutex(&(env_js_lock)); return -1;
 }
 UnlockMutex(&(env_js_lock));
 return x;
} /* End of js_hindo_set */

/*:::DOC_START
 *
 *    Function Name: js_set_fi_priority
 *    Description  : 指定ＦＩ関係データのＦＩ関係接続今ビットと
 *		     ＦＩ関係接続頻度を設定する
 *    Parameter    :
 *         env :          (In) 環境へのポインタ
 *	   fi_rel_entry : (In) 使用ＦＩ関係送信用構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_set_fi_priority(env, fi_rel_entry)
struct wnn_env *env;
struct wnn_fi_rel_buf *fi_rel_entry;
{
    register int x;

    if(env==0) return(-1);
    set_current_js(env->js_id);

    /* サーバがＦＩ学習をサポートしていない時は何もしない */
    if(!CHECK_FI) return(0);

    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_SET_FI_PRIORITY);

    put4com(fi_rel_entry->num, env->js_id);
    for(x = 0; x < fi_rel_entry->num; x++) {
	put4com(fi_rel_entry->fi_buf[x].fi_dic_no, env->js_id);
	put4com(fi_rel_entry->fi_buf[x].dic_no, env->js_id);
	put4com(fi_rel_entry->fi_buf[x].entry, env->js_id);
	put4com(fi_rel_entry->fi_buf[x].offset, env->js_id);
	put4com(fi_rel_entry->fi_buf[x].fi_hindo, env->js_id);
	put4com(fi_rel_entry->fi_buf[x].fi_ima, env->js_id);
    }
    snd_flush(env->js_id);

    if((x = get4com(env->js_id)) == -1) {
        env_wnn_errorno_set= get4com(env->js_id);
        UnlockMutex(&(env_js_lock)); return -1;
    }
    UnlockMutex(&(env_js_lock));
    return x;
} /* End of js_set_fi_priority */

/*:::DOC_START
 *
 *    Function Name: js_optimize_fi
 *    Description  : 確定された全候補の今ビット・頻度を設定し、各学習処理
 *                   （接頭語・送り基準・汎用語・接尾語・ＦＩ）を行う
 *    Parameter    :
 *         env :    (In) 環境へのポインタ
 *         nkouho : (In) 確定候補数
 *         dic :    (In) 候補が登録されている辞書番号配列へのポインタ
 *         entry    (In) 候補のエントリ番号配列へのポインタ
 *         ima :    (In) 今ビットの設定方法フラグ配列へのポインタ
 *         hindo :  (In) 頻度の設定方法フラグ配列へのポインタ
 *         kmoji :  (In) 候補文字数（付属語なし）配列へのポインタ
 *         kouho :  (In) 候補文字列（付属語あり）配列へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_optimize_fi(env,nkouho,dic,entry,ima,hindo,kmoji,kouho)
struct wnn_env *env;
int nkouho, *dic, *entry, *ima, *hindo, *kmoji;
w_char **kouho;
{
    register int x, i;

    x = 0;
    if(env==0) return(-1);
    set_current_js(env->js_id);

    /* サーバがＦＩ学習をサポートしていない時は、
       従来の頻度設定プロトコルを確定候補数回送る */
    if(!CHECK_FI) {
	for(i = 0; i < nkouho; i++) {
	    x = js_hindo_set(env, dic[i], entry[i], ima[i], hindo[i]);
	    if(x == -1) return(-1);
	}
	return(x);
    }

    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_OPTIMIZE_FI);

    put4com(nkouho, env->js_id);
    for(x = 0; x < nkouho; x++) {
	put4com(dic[x], env->js_id);
	put4com(entry[x], env->js_id);
	put4com(ima[x], env->js_id);
	put4com(hindo[x], env->js_id);
	put4com(kmoji[x], env->js_id);
	putwscom(kouho[x], env->js_id);
    }
    snd_flush(env->js_id);
    
    if((x = get4com(env->js_id)) == -1) {
        env_wnn_errorno_set= get4com(env->js_id);
        UnlockMutex(&(env_js_lock)); return -1;
    }
    UnlockMutex(&(env_js_lock));
    return x;
} /* End of js_optimize_fi */


/****
	Henkan
****/

static void
put_fzk_vec(hinsi,fzk,vec,vec1, server)
int hinsi;
w_char *fzk;
int vec;
int vec1;
ARGS *server;
{
	put4com(hinsi, server);
	putwscom(fzk, server);
	put4com(vec, server);
	put4com(vec1, server);
}

/**
	kanren
**/
static int rcv_dai(), rcv_fi_rel_data();
static void rcv_sho_x();
static void rcv_sho_kanji();

int
js_kanren(env,yomi,hinsi,fzk,vec,vec1,vec2,rb)
struct wnn_env *env;
w_char	*yomi;
int	hinsi;
w_char	*fzk;
int	vec;
int	vec1;
int	vec2;
struct wnn_ret_buf *rb;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_KANREN);
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 put4com(vec2, env->js_id);
 snd_flush(env->js_id);
 x = rcv_dai(rb, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

/*:::DOC_START
 *
 *    Function Name: js_fi_kanren
 *    Description  : 連文節ＦＩ変換を行い、結果を受け取る
 *    Parameter    :
 *         env :   (In) 環境へのポインタ
 *	   yomi:   (In) 変換読み文字列へのポインタ
 *	   hinsi   (In) 前の文節の品詞番号
 *	   fzk :   (In) 前の文節の付属語文字列へのポインタ
 *	   vec :   (In) 終端ベクトル１
 *	   vec1 :  (In) 終端ベクトル２
 *	   vec2 :  (In) 連文節変換の途中の文節の終端ベクトル
 *	   prev :  (In) 直前確定文節情報構造体へのポインタ
 *	   rb :    (Out) 変換結果代入用構造体へのポインタ
 *	   fi_rb : (Out) 使用ＦＩ関係代入用構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_fi_kanren(env,yomi,hinsi,fzk,vec,vec1,vec2,prev,rb,fi_rb)
struct wnn_env *env;
w_char  *yomi;
int     hinsi;
w_char  *fzk;
int     vec;
int     vec1;
int     vec2;
struct wnn_prev_bun *prev;
struct wnn_ret_buf *rb;
struct wnn_fi_rel_buf *fi_rb;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);

 /* サーバがＦＩ変換をサポートしていない時は、従来の連文節解析
    プロトコルを送る */
 if(!CHECK_FI) return(js_kanren(env,yomi,hinsi,fzk,vec,vec1,vec2,rb));

 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FI_KANREN);
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 put4com(vec2, env->js_id);
 /* 直前確定文節情報 */
 for(x = 0; x < WNN_PREV_BUN_SUU; x++) {
     put4com(prev[x].dic_no, env->js_id);	/* Wnn 辞書番号 */
     put4com(prev[x].entry, env->js_id);	/* エントリ番号 */
     put4com(prev[x].jirilen, env->js_id);	/* 自立語読み長 */
     put4com(prev[x].hinsi, env->js_id);	/* 品詞番号 */
     putwscom((prev[x].kouho + prev[x].real_kanjilen), env->js_id);
                                                /* 付属語文字列 */
 }
 snd_flush(env->js_id);

 /* 連文節ＦＩ変換結果を受け取る */
 x = rcv_dai(rb, env->js_id);
 /* 使用ＦＩ関係を受け取る */
 if(x != -1) {
     if(rcv_fi_rel_data(fi_rb, env->js_id) == -1) x = -1;
 }

 UnlockMutex(&(env_js_lock));
 return x;
} /* End of js_fi_kanren */

/*	rcv dai		*/
static int
rcv_dai(ret, server)
struct wnn_ret_buf *ret;
ARGS *server;
{int dai_cnt,sho_sum,kanji_sum,d_size,s_size,k_size,x;
 register int i;
 struct wnn_dai_bunsetsu *dai_list;
 register struct wnn_dai_bunsetsu *dp;
 struct wnn_sho_bunsetsu *sho_list;
 register struct wnn_sho_bunsetsu *sp;
 w_char *kanji,*kp;

 dai_cnt = get4com(server);
 if(dai_cnt == -1){     /* error dayo */
        js_wnn_errorno_set = get4com(server);
        return -1;
 }
 sho_sum = get4com(server);
 kanji_sum = get4com(server);

 d_size=sizeof(struct wnn_dai_bunsetsu)*dai_cnt;
 s_size=sizeof(struct wnn_sho_bunsetsu)*sho_sum;
 k_size=sizeof(w_char)*kanji_sum;

/* re_alloc(ret, d_size+s_size+k_size); Seems This cause Bug?? H.T.*/
 re_alloc(ret, d_size+s_size+k_size);

 dai_list = ( struct wnn_dai_bunsetsu *) ret->buf;
 sho_list = ( struct wnn_sho_bunsetsu *)((char *)ret->buf + d_size);
 kanji = (w_char *)((char *)ret->buf + d_size + s_size);

 for(dp = dai_list,i=0; i<dai_cnt; i++){
        dp -> end = get4com(server);
        dp -> start = get4com(server);
        dp -> sbncnt = get4com(server);
        dp -> hyoka = get4com(server);
        dp++;
 }

 for(dp = dai_list, sp = sho_list, i=0; i<dai_cnt; i++){
        dp -> sbn = sp;
        x = dp -> sbncnt;
        rcv_sho_x(sp,x, server);
        sp += x;
        dp++;
 }

 for(dp=dai_list, kp=kanji, i=0; i<dai_cnt; i++){
        rcv_sho_kanji(dp->sbn,dp->sbncnt,&kp,&k_size,server);
        dp++;
 }
 return dai_cnt;
}

/*	rcv sho routines	*/
static void
rcv_sho_x(sho_list,sho_cnt, server)
register struct wnn_sho_bunsetsu *sho_list;
int sho_cnt;
ARGS *server;
{register int i;
 for(i=0;i<sho_cnt;i++){
        sho_list -> end = get4com(server);
        sho_list -> start = get4com(server);
        sho_list -> jiriend = get4com(server);
        sho_list -> dic_no = get4com(server);
        sho_list -> entry = get4com(server);
        sho_list -> hindo = get4com(server);
        sho_list -> ima = get4com(server);
        sho_list -> hinsi = get4com(server);
        sho_list -> status = get4com(server);
        sho_list -> status_bkwd = get4com(server);
        sho_list ->kangovect = get4com(server);
        sho_list -> hyoka = get4com(server);
        sho_list++;
 }
}

static void
rcv_sho_kanji(sho_list,sho_cnt,kanji,kanjibytes,server)
struct wnn_sho_bunsetsu *sho_list;
int sho_cnt;
w_char **kanji;
int *kanjibytes;
ARGS *server;
{
 register w_char *k;
 register int i, bytes, error_flag, wlen;
 w_char wbuf[LENGTHKANJI];

 k = *kanji;
 bytes = *kanjibytes;
 if (bytes <= 0)
	error_flag = 1;
 else
	error_flag = 0;

 for(i=0;i<sho_cnt;i++){
        getwscom(wbuf, server, sizeof(wbuf) / sizeof(w_char));
	if (!error_flag) {
	    wlen = wnn_Strlen(wbuf) + 1;
	    if ((wlen * sizeof(w_char)) > bytes) {
		error_flag = 1;
	    } else {
		sho_list->kanji = k;
		wnn_Strcpy(k, wbuf);
		k += wlen;
		bytes -= (wlen * sizeof(w_char));
	    }
	}

        getwscom(wbuf, server, sizeof(wbuf) / sizeof(w_char));
	if (!error_flag) {
	    wlen = wnn_Strlen(wbuf) + 1;
	    if ((wlen * sizeof(w_char)) > bytes) {
		error_flag = 1;
	    } else {
		sho_list->yomi = k;
		wnn_Strcpy(k, wbuf);
		k += wlen;
		bytes -= (wlen * sizeof(w_char));
	    }
	}

        getwscom(wbuf, server, sizeof(wbuf) / sizeof(w_char));
	if (!error_flag) {
	    wlen = wnn_Strlen(wbuf) + 1;
	    if ((wlen * sizeof(w_char)) > bytes) { /* '>=' ではない */
		error_flag = 1;
	    } else {
		sho_list->fuzoku = k;
		wnn_Strcpy(k, wbuf);
		k += wlen;
		bytes -= (wlen * sizeof(w_char));
	    }
	}
        sho_list++;
 }
 *kanji = k;
 *kanjibytes = bytes;
}


static int
rcv_sho(ret, server)
struct wnn_ret_buf *ret;
ARGS *server;
{int sho_sum,kanji_sum,s_size,k_size;
 struct wnn_sho_bunsetsu *sho_list;
 w_char *kanji,*kp;

 sho_sum = get4com(server);
 if(sho_sum == -1){     /* error dayo */
        js_wnn_errorno_set = get4com(server);
        return -1;
 }
 kanji_sum = get4com(server);

 s_size=sizeof(struct wnn_sho_bunsetsu)*sho_sum;
 k_size=sizeof(w_char)*kanji_sum;

 re_alloc(ret, s_size+k_size);

 sho_list = ( struct wnn_sho_bunsetsu *)((char *)ret->buf);
 kanji = (w_char *)((char *)ret->buf + s_size);

 rcv_sho_x(sho_list,sho_sum, server);
 kp=kanji;
 rcv_sho_kanji(sho_list,sho_sum,&kp,&k_size,server);
 return sho_sum;
}

/*:::DOC_START
 *
 *    Function Name: rcv_fi_rel_data
 *    Description  : 連文節ＦＩ変換に使用したＦＩ関係情報を受け取る
 *    Parameter    :
 *         ret :    (Out) 使用ＦＩ関係受信用構造体へのポインタ
 *	   server : (In) 対象 jserver 情報構造体へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
static int
rcv_fi_rel_data(ret, server)
struct wnn_fi_rel_buf *ret;
ARGS *server;
{
    register int i, fi_num;
    struct fi_rel_data *fi_data;

    fi_num = get4com(server);	/* 使用ＦＩ関係数 */
    if(fi_num == 0) return(0);  /* 使用ＦＩ関係がなかった */

    if(ret->size < ret->num + fi_num) {
	/* 新たにＦＩ関係データ構造体配列を確保する */
	fi_data = (struct fi_rel_data *)
	    malloc((ret->num + fi_num) * sizeof(struct fi_rel_data));

	/* 既に使用していたＦＩ関係データをコピーする */
	if(fi_data) {
	    if(ret->fi_buf) {
		bcopy(ret->fi_buf, fi_data, ret->num * sizeof(struct fi_rel_data));
		free((char *)ret->fi_buf);
	    }
	}
	ret->fi_buf = fi_data;
	ret->size = ret->num + fi_num;
    }

    /* ＦＩ関係データ構造体配列が確保できたか？ */
    if(ret->fi_buf == NULL) {
	int dummy;
	for(i = 0; i < 4 * fi_num; i++) dummy = get4com(server);
	js_wnn_errorno_set = WNN_MALLOC_ERR;
	return(-1);
    }

    /* 使用ＦＩ関係データを受け取る */
    fi_data = ret->fi_buf + ret->num;
    for(i = 0; i < fi_num; i++, fi_data++) {
	fi_data->fi_dic_no = get4com(server);
	fi_data->dic_no = get4com(server);
	fi_data->entry = get4com(server);
	fi_data->offset = get4com(server);
	fi_data->fi_hindo = WNN_HINDO_NOP;
	fi_data->fi_ima = WNN_IMA_OFF;
    }
    ret->num = ret->num + fi_num;
    return(0);
} /* End of rcv_fi_rel_data */	

/**
	kantan
**/
int
js_kantan_dai(env,yomi,hinsi,fzk,vec,vec1,rb)
struct wnn_env *env;
w_char	*yomi;
int	hinsi;
w_char	*fzk;
int	vec;
int	vec1;
struct wnn_ret_buf *rb;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_KANTAN_DAI);
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 snd_flush(env->js_id);
 x = rcv_dai(rb, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}

int
js_kantan_sho(env,yomi,hinsi,fzk,vec,vec1,rb)
struct wnn_env *env;
w_char	*yomi;
int	hinsi;
w_char	*fzk;
int	vec;
int	vec1;
struct wnn_ret_buf *rb;
{int sbncnt;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_KANTAN_SHO);
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 snd_flush(env->js_id);
 
 sbncnt = rcv_sho(rb, env->js_id);
 UnlockMutex(&(env_js_lock));
 return sbncnt;
}

/**
	kanzen
**/
int
js_kanzen_dai(env,yomi,hinsi,fzk,vec,vec1,rb)
struct wnn_env *env;
w_char	*yomi;
int	hinsi;
w_char	*fzk;
int	vec;
int	vec1;
struct wnn_ret_buf *rb;
{
 int x;

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_KANZEN_DAI);
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 snd_flush(env->js_id);
 x = rcv_dai(rb, env->js_id);
 UnlockMutex(&(env_js_lock));
 return x;
}


int
js_kanzen_sho(env,yomi,hinsi,fzk,vec,vec1,rb)
struct wnn_env *env;
w_char	*yomi;
int	hinsi;
w_char	*fzk;
int	vec;
int	vec1;
struct wnn_ret_buf *rb;
{int sbncnt;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_KANZEN_SHO);
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 snd_flush(env->js_id);

 sbncnt = rcv_sho(rb, env->js_id);
 UnlockMutex(&(env_js_lock));
 return sbncnt;
}

/**	
        henkan with data
**/
int
js_henkan_with_data(env,fuku,nhinsi,hlist,henkan,yomi,hinsi,fzk,vec,vec1,vec2,rb)
struct wnn_env *env;
int fuku, nhinsi, *hlist, henkan;
w_char  *yomi;
int     hinsi;
w_char  *fzk;
int     vec;
int     vec1;
int	vec2;
struct wnn_ret_buf *rb;
{
 int x, i, loop = abs(nhinsi);

 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_HENKAN_WITH_DATA);
 put4com(fuku, env->js_id);		/* 複合語優先 */
 put4com(nhinsi, env->js_id);		/* 変換設定品詞数 */
 for(i = 0; i < loop; i++)
     put4com(hlist[i], env->js_id);	/* 変換設定品詞番号 */
 put4com(henkan, env->js_id);		/* 変換種別 */
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 put4com(vec2, env->js_id);
 snd_flush(env->js_id);

 switch(henkan) {
 case WNN_KANREN:
 case WNN_KANTAN_DAI:
 case WNN_KANZEN_DAI:
     x = rcv_dai(rb, env->js_id);
     break;
 case WNN_KANTAN_SHO:
 case WNN_KANZEN_SHO:
     x = rcv_sho(rb, env->js_id);
     break;
 default:
     x = get4com(env->js_id);
     env_wnn_errorno_set= get4com(env->js_id);
 }
 UnlockMutex(&(env_js_lock));
 return x;
}

/**	js_version		**/
int
js_version(server,serv,libv)
int *serv,*libv;
WNN_JSERVER_ID *server;
{
 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server, JS_VERSION);
 snd_flush(server);
 *libv= JLIB_VERSION;
 *serv = get4com(server);
 UnlockMutex(&(server_js_lock));
 return *serv;
}

static void
re_alloc(ret,size)
register struct wnn_ret_buf *ret;
int size;
{
 if(ret->size < size){
	if(ret->buf)
	    free((char *)ret->buf);
	ret->buf = malloc(size);
	ret->size = size;
 }
}

int
js_kill(server)
WNN_JSERVER_ID *server;
{
    int x;
    set_current_js(server);
    LockMutex(&(server_js_lock));
    handler_of_jserver_dead(server);
    if(js_wnn_errorno_eql) {
	UnlockMutex(&(server_js_lock));
	return(-1);
    }
    snd_server_head(server, JS_KILL);
    snd_flush(server);
    x = get4com(server);
    UnlockMutex(&(server_js_lock));
    return(x);
}

int
js_file_remove(server, n, pwd)
WNN_JSERVER_ID *server;
char *n, *pwd;
{
    register int x;
    set_current_js(server);
    LockMutex(&(server_js_lock));
    handler_of_jserver_dead(server);
    if(js_wnn_errorno_eql) {
	UnlockMutex(&(server_js_lock));
	return(-1);
    }
    snd_server_head(server,JS_FILE_REMOVE);
    putscom(n, server);
    putscom(pwd, server);
    snd_flush(server);
    if((x=get4com(server))==-1){
        js_wnn_errorno_set= get4com(server);
	UnlockMutex(&(server_js_lock));
	return -1;
    }
    UnlockMutex(&(server_js_lock));
    return(x);
}    

int
js_file_remove_client(server, n, pwd)
WNN_JSERVER_ID *server;
char *n, *pwd;
{
    struct wnn_file_head fh;
    register FILE *fp;
    int is_compressed;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    handler_of_jserver_dead(server);
    if(js_wnn_errorno_eql) {
	UnlockMutex(&(server_js_lock));
	return(-1);
    }
    if(js_file_loaded_local_body(server, n) != -1){
        js_wnn_errorno_set = WNN_FILE_IN_USE;
	UnlockMutex(&(server_js_lock));
        return(-1);
    }
#ifdef WRITE_CHECK
    check_backup(n, NULL);
#endif /* WRITE_CHECK */
    if((fp=dic_fopen(n,"r", &is_compressed)) == NULL){
        js_wnn_errorno_set = WNN_FILE_READ_ERROR;
	UnlockMutex(&(server_js_lock));
        return(-1);
    }
    if(input_file_header(fp, &fh, NULL) == -1){
	dic_fclose(fp, is_compressed);
	UnlockMutex(&(server_js_lock));
        return(-1);
    }
    dic_fclose(fp, is_compressed);
    if(!check_pwd(pwd, fh.file_passwd)){
        js_wnn_errorno_set = WNN_INCORRECT_PASSWD;
	UnlockMutex(&(server_js_lock));
        return(-1);
    }
    if(unlink(n) == -1){
        js_wnn_errorno_set = WNN_UNLINK;
	UnlockMutex(&(server_js_lock));
        return(-1);
    }
    UnlockMutex(&(server_js_lock));
    return(0);
}

/*:::DOC_START
 *
 *    Function Name: js_dic_file_create_client
 *    Description  : クライアント側に辞書ファイルを作成する
 *    Parameter    :
 *         env :     (In) 環境へのポインタ
 *	   fn :      (In) 作成辞書ファイル名
 *	   type :    (In) 作成辞書ファイルタイプ
 *	   com :     (In) 作成辞書ファイルコメント
 *	   passwd    (In) 作成辞書ファイルパスワード
 *         hpasswd : (In) 作成辞書内頻度パスワード
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_dic_file_create_client(env, fn, type, com, passwd, hpasswd)
struct wnn_env *env;
int type;
char *fn;
w_char *com;
char *passwd, *hpasswd;
{
    int x, js_jishonum;

    if(env==0) return(-1);
    LockMutex(&(env_js_lock));
    /*
     * Hideyuki Kishiba (Jul. 7, 1994)
     * ＦＩ関係辞書、グループ辞書、マージ辞書の作成処理を追加
     */
    if(type != WNN_REV_DICT &&
       type != CWNN_REV_DICT &&
       type != BWNN_REV_DICT &&
       type != WNN_UD_DICT &&
       type != WNN_FI_USER_DICT &&
       type != WNN_GROUP_DICT &&
       type != WNN_MERGE_DICT){
        env_wnn_errorno_set = WNN_NOT_A_UD;
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    if(type == WNN_FI_USER_DICT) { /* ＦＩ関係辞書作成関数を呼ぶ */
	int i, j;
	unsigned char njisho;
	struct wnn_file_uniq duniq[WNN_MAX_JISHO_OF_AN_ENV];
	int dprimary[WNN_MAX_JISHO_OF_AN_ENV];

	/* 接続定義辞書情報（primary index table・file uniq）の受け取り */
	set_current_js(env->js_id);
	handler_of_jserver_dead_env(env);
	if(env_wnn_errorno_eql) {
	    UnlockMutex(&(env_js_lock));
	    return(-1);
	}
	snd_env_head(env, JS_DIC_FILE_CREATE_CLIENT);
	snd_flush(env->js_id);
	x = get4com(env->js_id);
	if(x == -1) {
	    env_wnn_errorno_set = get4com(env->js_id);
	    UnlockMutex(&(env_js_lock));
	    return(-1);
	}
	js_jishonum = get1com(env->js_id); /* 接続定義辞書数 */
	if (js_jishonum > WNN_MAX_JISHO_OF_AN_ENV)
	    njisho = WNN_MAX_JISHO_OF_AN_ENV;
	else
	    njisho = js_jishonum;
	for(i = 0; i < njisho; i++) {
	    /* 接続定義辞書 file uniq */
	    duniq[i].time = get4com(env->js_id);
	    duniq[i].dev = get4com(env->js_id);
	    duniq[i].inode = get4com(env->js_id);
	    for(j = 0; j < WNN_HOSTLEN; j++){
		duniq[i].createhost[j] = get1com(env->js_id);
	    }
	    /* 接続定義辞書登録語彙数 */
	    dprimary[i] = get4com(env->js_id);
	}
	if (js_jishonum > WNN_MAX_JISHO_OF_AN_ENV) {
	    js_jishonum -= WNN_MAX_JISHO_OF_AN_ENV;
	    for(i = 0; i < js_jishonum; i++) {
		get4com(env->js_id);
		get4com(env->js_id);
		get4com(env->js_id);
		for(j = 0; j < WNN_HOSTLEN; j++){
		    get1com(env->js_id);
		}
		get4com(env->js_id);
	    }
	}
	x = create_null_fi_dic(fn, com, passwd, hpasswd, type, njisho, duniq, dprimary, NULL);

    } else /* Ｗｎｎ辞書作成関数を呼ぶ */
        x = create_null_dic(fn,com, passwd, hpasswd, type, NULL);

    if(x == -1){
        env_wnn_errorno_set = WNN_FILE_CREATE_ERROR;
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    UnlockMutex(&(env_js_lock));
    return(0);
} /* End of js_dic_file_create_client */


/**	js_hindo_file_create_client	**/
int
js_hindo_file_create_client(env,fid,fn,com,hpasswd)
struct wnn_env *env;
int	fid;
char *fn;
w_char *com;
char *hpasswd;
{
    register int x;
    struct wnn_file_uniq funiq;
    int serial;
    register int i;

    if(env==0) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_HINDO_FILE_CREATE_CLIENT);
    put4com(fid, env->js_id);
    snd_flush(env->js_id);
    x = get4com(env->js_id);
    if(x == -1){
        env_wnn_errorno_set = get4com(env->js_id);
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    serial = get4com(env->js_id);
    funiq.time = get4com(env->js_id);
    funiq.dev =  get4com(env->js_id);
    funiq.inode = get4com(env->js_id);
    for(i=0;i<WNN_HOSTLEN;i++){
        funiq.createhost[i]=get1com(env->js_id);
    }
    if(create_hindo_file(&funiq,fn,com,hpasswd,serial, NULL, NULL) == -1){
        env_wnn_errorno_set = WNN_FILE_CREATE_ERROR;
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    UnlockMutex(&(env_js_lock));
    return(0);
}

/*:::DOC_START
 *
 *    Function Name: js_fi_hindo_file_create_client
 *    Description  : クライアント側にＦＩ関係頻度ファイルを作成する
 *    Parameter    :
 *         env :     (In) 環境へのポインタ
 *	   fid :     (In) 対応ＦＩ関係辞書ファイルＩＤ
 *	   fn :      (In) ＦＩ関係頻度ファイル名
 *	   com :     (In) ＦＩ関係頻度ファイルコメント
 * 	   hpasswd : (In) ＦＩ関係頻度ファイルパスワード
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Hideyuki Kishiba
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_fi_hindo_file_create_client(env, fid, fn, com, hpasswd)
struct wnn_env *env;
int     fid;
char *fn;
w_char *com;
char *hpasswd;
{
    register int x;
    struct wnn_file_uniq funiq;
    unsigned char njisho;
    int *primary;
    register int i;

    if(env==0) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
        UnlockMutex(&(env_js_lock));
        return(-1);
    }
    snd_env_head(env,JS_FI_HINDO_FILE_CREATE_CLIENT);
    put4com(fid, env->js_id);
    snd_flush(env->js_id);
    x = get4com(env->js_id);
    if(x == -1){
        env_wnn_errorno_set = get4com(env->js_id);
        UnlockMutex(&(env_js_lock));
        return(-1);
    }
    funiq.time = get4com(env->js_id);
    funiq.dev =  get4com(env->js_id);
    funiq.inode = get4com(env->js_id);
    for(i=0;i<WNN_HOSTLEN;i++){
        funiq.createhost[i]=get1com(env->js_id);
    }
    njisho = get1com(env->js_id);
    if((primary = (int *)malloc(njisho * sizeof(int))) == NULL) {
	env_wnn_errorno_set = WNN_MALLOC_ERR;
        UnlockMutex(&(env_js_lock));
        return(-1);
    }
    for(i = 0; i < njisho; i++)
        primary[i] = get4com(env->js_id);
    if(create_fi_hindo_file(&funiq,fn,com,hpasswd,njisho,primary,NULL) == -1){
	free(primary);
        env_wnn_errorno_set = WNN_FILE_CREATE_ERROR;
        UnlockMutex(&(env_js_lock));
        return(-1);
    }
    free(primary);
    UnlockMutex(&(env_js_lock));
    return(0);
} /* End of js_fi_hindo_file_create_client */

int
js_file_comment_set(env, fid, comment)
struct wnn_env *env;
int fid;
w_char *comment;
{
 register int x;
 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 snd_env_head(env,JS_FILE_COMMENT_SET);
 put4com(fid, env->js_id);
 putwscom(comment, env->js_id);
 snd_flush(env->js_id);
 x=get4com(env->js_id);
 if(x==-1){
     env_wnn_errorno_set= get4com(env->js_id);
     UnlockMutex(&(env_js_lock));
     return(-1);
 }
 UnlockMutex(&(env_js_lock));
 return(0);
}
    
/* 
 * Hinsi Primitives
 */

int
js_hinsi_name(server, no, rb)
WNN_JSERVER_ID *server;
int no;
struct wnn_ret_buf *rb;
{
    register int size;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    handler_of_jserver_dead(server);
    if(js_wnn_errorno_eql) {
	UnlockMutex(&(server_js_lock));
	return(-1);
    }
    snd_server_head(server,JS_HINSI_NAME);
    put4com(no, server);
    snd_flush(server);
    if((size = get4com(server)) == -1){
        js_wnn_errorno_set = get4com(server);
	UnlockMutex(&(server_js_lock));
	return(-1);
    }
    re_alloc(rb,sizeof(w_char)*(size + 1));
    getwscom((w_char *)rb->buf, server, size + 1);
    UnlockMutex(&(server_js_lock));
    return(0);
}


int 
js_hinsi_number(server, name)
WNN_JSERVER_ID *server;
w_char *name;
{
    register int no;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    handler_of_jserver_dead(server);
    if(js_wnn_errorno_eql) {
	UnlockMutex(&(server_js_lock));
	return(-1);
    }
    snd_server_head(server,JS_HINSI_NUMBER);
    putwscom(name, server);
    snd_flush(server);
    if((no = get4com(server)) == -1){
        js_wnn_errorno_set = get4com(server);
	UnlockMutex(&(server_js_lock));
        return(-1);
    }
    UnlockMutex(&(server_js_lock));
    return(no);
}

int
js_hinsi_list(env, dic_no, name, rb)
struct wnn_env *env;
int dic_no;
w_char *name;
struct wnn_ret_buf *rb;
{
    int wtotal;
    int count;
    register w_char *s;
    register w_char **r;
    register int k, wlen, error_flag;
    w_char wbuf[LENGTHKANJI];

    if(env==0) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_HINSI_LIST);
    put4com(dic_no, env->js_id);
    putwscom(name, env->js_id);
    snd_flush(env->js_id);
    if((count = get4com(env->js_id)) == -1){
        env_wnn_errorno_set = get4com(env->js_id);
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    wtotal = get4com(env->js_id);
    wtotal += 1;
    re_alloc(rb,sizeof(w_char)*(wtotal) + count * sizeof(w_char *) );
    r = (w_char **)rb->buf;
    s = (w_char *)((w_char **)rb->buf + count);
    error_flag = 0;
    for(k = 0 ; k < count ; k++){
        getwscom(wbuf, env->js_id, sizeof(wbuf) / sizeof(w_char));
	if (!error_flag) {
	    wlen = wnn_Strlen(wbuf) + 1;
	    if (wlen > wtotal) {
		error_flag = 1;
	    } else {
		*r++ = s;
		wnn_Strcpy(s, wbuf);
		s += wlen;
		wtotal -= wlen;
	    }
	}
    }
    UnlockMutex(&(env_js_lock));
    return(count);
}

int 
js_hinsi_dicts(env, no,  rb)
struct wnn_env *env;
int no;
struct wnn_ret_buf *rb;
{
    register int k, count;
    int *p;

    if(env==0) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_HINSI_DICTS);
    put4com(no, env->js_id);
    snd_flush(env->js_id);
    if((count = get4com(env->js_id)) == -1){
	env_wnn_errorno_set = get4com(env->js_id);
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    re_alloc(rb,sizeof(int) * (count + 1));
    p = (int *)rb->buf;

    for(k = 0 ; k < count ; k++){
        *p++ = get4com(env->js_id);
    }
    UnlockMutex(&(env_js_lock));
    return(count);
}


char *wnn_dic_types[] = {"","固定","登録","逆引","正規","固定","FIシス","FIユーザ","FI頻度","グループ","マージ"};

char *cwnn_dic_types[] = {"","耕協","鞠村","憧咄","屎号"};
char *bwnn_dic_types[] = {"","耕協","鞠村","永侏","屎号"};

char *kwnn_dic_types[] = {"","壱舛","去系","蝕遂","舛鋭"};
			/*    由鑷   竒巵   羹齎   閨豫 */


/* New primitives  9/8 */

int
js_file_password_set(env, fid, which, old, new)
struct wnn_env *env;
int fid;
int which;			/* 1 for dic, 2 for hindo 3(0) for both*/
char *old, *new;
{
    register int x;
    if(env==0) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_FILE_PASSWORD_SET);
    put4com(fid, env->js_id);
    put4com(which, env->js_id);
    putscom(old, env->js_id);
    putscom(new, env->js_id);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if(x==-1){
        env_wnn_errorno_set= get4com(env->js_id);
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    UnlockMutex(&(env_js_lock));
    return(0);
}

int
js_hinsi_table_set(env, dic_no, hinsi_table)
struct wnn_env *env;
int dic_no;
w_char *hinsi_table;
{
    int x;
    if(env==0) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_HINSI_TABLE_SET);
    put4com(dic_no, env->js_id);
    putwscom(hinsi_table, env->js_id);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if(x==-1){
        env_wnn_errorno_set= get4com(env->js_id);
	UnlockMutex(&(env_js_lock));
        return(-1);
    }
    UnlockMutex(&(env_js_lock));
    return(0);
}

/* Start of packets in 4004 */
int
js_open_extension(server, ext_name)
WNN_JSERVER_ID *server;
char *ext_name;
{
    register wnn_extension_set *p;

    if (!ext_name || !*ext_name) {
	js_wnn_errorno_set = WNN_NOT_SUPPORT_EXTENSION;
	return(-1);
    }
    for (p = ((WNN_JSERVER_ID_INT *)server)->extensions;
	 p && p->id && p->name; p++) {
	if (!strcmp(p->name, ext_name)) {
	    return(p->id);
	}
    }
    js_wnn_errorno_set = WNN_NOT_SUPPORT_EXTENSION;
    return(0);
}

int
js_get_extension(server, ret)
WNN_JSERVER_ID *server;
char ***ret;
{
    register wnn_extension_set *p;
    register char *s, **l;
    int total = 0, num = 0;

    if (!((WNN_JSERVER_ID_INT *)server)->extensions) {
	js_wnn_errorno_set = WNN_NOT_SUPPORT_PACKET;
	return(-1);
    }
    for (p = ((WNN_JSERVER_ID_INT *)server)->extensions;
	 p && p->id && p->name; p++) {
	total += strlen(p->name) + 1;
	num++;
    }
    if (num == 0) return(0);
    if (!(l = (char **)(s = malloc((sizeof(char *) * num) + total)))) {
	js_wnn_errorno_set = WNN_MALLOC_ERR;
	return(-1);
    }
    *ret = l;
    s += sizeof(char *) * num;
    for (p = ((WNN_JSERVER_ID_INT *)server)->extensions;
	 p && p->id && p->name; p++) {
	*l++ = s;
	strcpy(s, p->name);
	s += strlen(s) + 1;
    }
    return(num);
}


static int
access_host_core(server, ha, enable, ule)
WNN_JSERVER_ID *server;
host_address *ha;
int enable, ule;
{
    register int x;
    register char *p;

    handler_of_jserver_dead(server);
    if (js_wnn_errorno_eql) return(-1);
    if (enable) {
	snd_server_head(server, JS_ACCESS_ADD_HOST);
	put4com(ule, server);
    } else {
	snd_server_head(server, JS_ACCESS_REMOVE_HOST);
    }
    put4com(ha->address_len, server);
    p = ha->address;
    for (x = 0; x < ha->address_len; x++) put1com(*p++, server);
    snd_flush(server);
    x=get4com(server);
    if(x==-1){
	js_wnn_errorno_set= get4com(server);
	return(-1);
    }
    return(x);
}

static int
access_host(server, host, enable, ule)
WNN_JSERVER_ID *server;
char *host;
int enable, ule;
{
    struct hostent *hp;
    struct in_addr addr;
    host_address ha;
    char **l;
    int x;

    if ((addr.s_addr = inet_addr(host)) != -1) {
	ha.address = (char *)&addr.s_addr;
	ha.address_len = sizeof(addr.s_addr);
	x = access_host_core(server, &ha, enable, ule);
	return(x);
    } else if ((hp = gethostbyname(host)) && hp->h_addrtype == AF_INET) {
	ha.address_len = sizeof(addr.s_addr);
	for (l = hp->h_addr_list; *l; l++) {
	    ha.address = *l;
	    if ((x = access_host_core(server, &ha, enable, ule)) == -1) {
		return(-1);
	    }
	}
	return(0);
    } else {
	js_wnn_errorno_set = WNN_ACCESS_NO_HOST;
	return(-1);
    }
}

int
js_access_add_host(server, host, ule)
WNN_JSERVER_ID *server;
char *host;
int ule;
{
    int x;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    x = access_host(server, host, 1, ule);
    UnlockMutex(&(server_js_lock));
    return(x);
}

int
js_access_remove_host(server, host)
WNN_JSERVER_ID *server;
char *host;
{
    int x;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    x = access_host(server, host, 0, 0);
    UnlockMutex(&(server_js_lock));
    return(x);
}

static int
access_user_core(server, ha, user, enable)
WNN_JSERVER_ID *server;
host_address *ha;
char *user;
int enable;
{
    register int x;
    register char *p;

    handler_of_jserver_dead(server);
    if (js_wnn_errorno_eql) return(-1);
    if (enable) {
	snd_server_head(server, JS_ACCESS_ADD_USER);
    } else {
	snd_server_head(server, JS_ACCESS_REMOVE_USER);
    }
    put4com(ha->address_len, server);
    p = ha->address;
    for (x = 0; x < ha->address_len; x++) put1com(*p++, server);
    putscom(user, server);
    snd_flush(server);
    x=get4com(server);
    if(x==-1){
	js_wnn_errorno_set= get4com(server);
	return(-1);
    }
    return(x);
}

static int
access_user(server, host, user, enable)
WNN_JSERVER_ID *server;
char *host, *user;
int enable;
{
    struct hostent *hp;
    struct in_addr addr;
    host_address ha;
    char **l;
    int x;

    if (!host || !*host) {
	ha.address = NULL;
	ha.address_len = 0;
	x = access_user_core(server, &ha, user, enable);
	return(x);
    } else if ((addr.s_addr = inet_addr(host)) != -1) {
	ha.address = (char *)&addr.s_addr;
	ha.address_len = sizeof(addr.s_addr);
	x = access_user_core(server, &ha, user, enable);
	return(x);
    } else if ((hp = gethostbyname(host)) && hp->h_addrtype == AF_INET) {
	ha.address_len = sizeof(addr.s_addr);
	for (l = hp->h_addr_list; *l; l++) {
	    ha.address = *l;
	    if ((x = access_user_core(server, &ha, user, enable)) == -1) {
		return(-1);
	    }
	}
	return(0);
    } else {
	js_wnn_errorno_set = WNN_ACCESS_NO_USER;
	return(-1);
    }
}

int
js_access_add_user(server, host, user)
WNN_JSERVER_ID *server;
char *host, *user;
{
    int x;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    x = access_user(server, host, user, 1);
    UnlockMutex(&(server_js_lock));
    return(x);
}

int
js_access_remove_user(server, host, user)
WNN_JSERVER_ID *server;
char *host, *user;
{
    int x;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    x = access_user(server, host, user, 0);
    UnlockMutex(&(server_js_lock));
    return(x);
}

static int
access_control(server, enable)
WNN_JSERVER_ID *server;
int enable;
{
    int x;

    handler_of_jserver_dead(server);
    if (js_wnn_errorno_eql) return(-1);
    if (enable) {
	snd_server_head(server, JS_ACCESS_ENABLE);
    } else {
	snd_server_head(server, JS_ACCESS_DISABLE);
    }
    snd_flush(server);
    x=get4com(server);
    if(x==-1){
	js_wnn_errorno_set= get4com(server);
	return(-1);
    }
    return(x);
}

int
js_access_enable(server)
WNN_JSERVER_ID *server;
{
    int x;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    x = access_control(server, 1);
    UnlockMutex(&(server_js_lock));
    return(x);
}

int
js_access_disable(server)
WNN_JSERVER_ID *server;
{
    int x;

    set_current_js(server);
    LockMutex(&(server_js_lock));
    x = access_control(server, 0);
    UnlockMutex(&(server_js_lock));
    return(x);
}

static int
get_host_name_len(host_p)
host_address *host_p;
{
    char *p;
    register struct hostent *hp;
    int user_len = 0;
    char address[32];
    char *inet_ntoa();

    if ((p = strchr(host_p->address, ':'))) {
	user_len = strlen(p);
    }

    bcopy((char *)host_p->address, address, host_p->address_len);
    if ((hp = gethostbyaddr (address, host_p->address_len, AF_INET))) {
	return(strlen(hp->h_name) + user_len);
    }
    if (!(p = inet_ntoa(*((struct in_addr *)(address))))) return(0);
    return(strlen(p) + user_len);
}

static int
get_host_name(host_p, host)
host_address *host_p;
char *host;
{
    char *p, *user;
    register struct hostent *hp;
    int user_len = 0;
    char address[32];
    char *inet_ntoa();

    if ((user = strchr(host_p->address, ':'))) {
	user_len = strlen(user);
    }

    bcopy((char *)host_p->address, address, host_p->address_len);
    if ((hp = gethostbyaddr (address, host_p->address_len, AF_INET))) {
	strcpy(host, hp->h_name);
	if (user) strcat(host, user);
	return(strlen(host));
    }
    if (!(p = inet_ntoa(*((struct in_addr *)(address))))) return(0);
    strcpy(host, p);
    if (user) strcat(host, user);
    return(strlen(host));
}

char **
js_access_get_info(server, enable, ret_num)
WNN_JSERVER_ID *server;
int *enable;
int *ret_num;
{
    int i, j, host_num, except_num, total_num, bytes, total, error_flag;
    register char *p, **out, *save, **out_save;
    host_address *host_p;
    char dummy[1024];

    *ret_num = -1;
    set_current_js(server);
    LockMutex(&(server_js_lock));
    handler_of_jserver_dead(server);
    if (js_wnn_errorno_eql) {
	UnlockMutex(&(server_js_lock));
	return(NULL);
    }
    snd_server_head(server, JS_ACCESS_GET_INFO);
    snd_flush(server);
    *enable = get4com(server);
    if(*enable == -1){
	js_wnn_errorno_set= get4com(server);
	UnlockMutex(&(server_js_lock));
	return((char **)NULL);
    }
    bytes = get4com(server);
    host_num = get4com(server);
    except_num = get4com(server);
    total_num = host_num + except_num;
    if (total_num == 0) {
	*ret_num = 0;
	UnlockMutex(&(server_js_lock));
	return((char **)NULL);
    }
    if (!(save = p = malloc((sizeof(host_address) * total_num) + bytes))) {
	for (i = 0; i < bytes; i++) get1com(server);
	js_wnn_errorno_set = WNN_MALLOC_ERR;
	return((char **)NULL);
    }
    host_p = (host_address *)p;
    p +=  sizeof(host_address) * total_num;
    error_flag = 0;
    for (i = 0; i < host_num; i++, host_p++) {
	host_p->address_len = get4com(server);
	if ((host_p->address_len >= bytes) || (bytes <= 0) || error_flag) {
	    error_flag = 1;
	    for (j = 0; j < host_p->address_len; j++) get1com(server);
	    if (get4com(server))
		getscom(dummy, server, sizeof(dummy));
	} else {
	    for (j = 0; j < host_p->address_len; j++) p[j] = get1com(server);
	    host_p->address = p;
	    p += host_p->address_len;
	    bytes -= host_p->address_len;
	    if (get4com(server)) {
		*p++ = ':';
		bytes--;
		getscom(p, server, bytes);
		if (bytes > 0) {
		    p += strlen(p) + 1;
		    bytes -= strlen(p) + 1;
		}
	    } else {
		*p++ = '\0';
		bytes--;
	    }
	}
    }
    for (i = 0; i < except_num; i++, host_p++) {
	if ((bytes <= 0) || error_flag) {
	    error_flag = 1;
	    getscom(dummy, server, sizeof(dummy));
	} else {
	    host_p->address = p;
	    *p++ = '@';
	    bytes--;
	    getscom(p, server, bytes);
	    if (bytes > 0) {
		p += strlen(p) + 1;
		bytes -= strlen(p) + 1;
		host_p->address_len = strlen(host_p->address);
	    }
	}
    }
    if (error_flag) {
	free((char *)save);
	js_wnn_errorno_set = WNN_SOME_ERROR;
	UnlockMutex(&(server_js_lock));
	return((char **)NULL);
    }
    for (host_p = (host_address *)save, total = 0, i = 0;
	 i < total_num; i++, host_p++) {
	if (host_p->address_len > 0 && host_p->address[0] == '@')
	    total += strlen(host_p->address);	/* exceptional user name */
	else
	    total += get_host_name_len(host_p);
    }
    if (!(p = malloc((sizeof(char *) * total_num) + total + total_num))) {
	free((char *)save);
	js_wnn_errorno_set = WNN_MALLOC_ERR;
	UnlockMutex(&(server_js_lock));
	return((char **)NULL);
    }
    out = out_save = (char **)p;
    p += (sizeof(char *) * total_num);
    for (host_p = (host_address *)save, i = 0; i < total_num; i++, host_p++) {
	*out++ = p;
	if (host_p->address_len > 0 && host_p->address[0] == '@') {
	    strcpy(p, host_p->address)	/* exceptional user name */;
	    p += strlen(host_p->address) + 1;
	} else
	    p += get_host_name(host_p, p) + 1;
    }
    free((char *)save);
    *ret_num = total_num;
    UnlockMutex(&(server_js_lock));
    return(out_save);
}

/*:::DOC_START
 *
 *    Function Name: js_is_loaded_temporary_dic
 *    Description  : 
 *	   テンポラリ辞書が環境にあるかどうかを調べる
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *
 *    Return value : 1==EXIST, 0==NO EXIST, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_is_loaded_temporary_dic(env)
struct wnn_env *env;
{
    register int x = 0;

    if(!env) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_IS_LOADED_TEMPORARY_DIC);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if (x == -1) {
        wnn_errorno = get4com(env->js_id);
    }
    UnlockMutex(&(env_js_lock));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: js_temporary_dic_delete
 *    Description  : 
 *	   テンポラリ辞書を環境に追加する
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_temporary_dic_add(env, rev)
struct wnn_env *env;
int rev;
{
    register int x = 0;

    if(!env) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_TEMPORARY_DIC_ADD);
    put4com(rev, env->js_id);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if (x == -1) wnn_errorno = get4com(env->js_id);
    UnlockMutex(&(env_js_lock));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: js_temporary_dic_delete
 *    Description  : 
 *	   テンポラリ辞書を環境から削除する
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_temporary_dic_delete(env)
struct wnn_env *env;
{
    register int x;

    if(!env) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_TEMPORARY_DIC_DELETE);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if (x == -1) wnn_errorno = get4com(env->js_id);
    UnlockMutex(&(env_js_lock));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: js_temporary_word_add
 *    Description  : 
 *	   テンポラリ辞書に単語を登録する。
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *	   yomi :     (In) 読み
 *	   kanji :    (In) 漢字
 *	   comment :  (In) コメント
 *	   hinsi :    (In) 品詞
 *	   init_hindo :(In) 初期頻度
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_temporary_word_add(env, yomi, kanji, comment, hinshi, init_hindo)
struct wnn_env *env;
w_char	*yomi,*kanji,*comment;
int	hinshi,init_hindo;
{
    register int x;

    if(!env) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_TEMPORARY_WORD_ADD);
    putwscom(yomi, env->js_id);
    putwscom(kanji, env->js_id);
    putwscom(comment, env->js_id);
    put4com(hinshi, env->js_id);
    put4com(init_hindo, env->js_id);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if (x == -1) wnn_errorno = get4com(env->js_id);
    UnlockMutex(&(env_js_lock));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: js_autolearning_word_add
 *    Description  : 
 *	   自動登録の単語を登録する。
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *	   type :     (In) 学習するタイプ(カタカナ/文節切り)
 *	   yomi :     (In) 読み
 *	   kanji :    (In) 漢字
 *	   comment :  (In) コメント
 *	   hinsi :    (In) 品詞
 *	   init_hindo :(In) 初期頻度
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_autolearning_word_add(env, type, yomi, kanji, comment, hinshi, init_hindo)
struct wnn_env *env;
w_char	*yomi,*kanji,*comment;
int	type, hinshi,init_hindo;
{
    register int x;

    if(!env) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_AUTOLEARNING_WORD_ADD);
    put4com(type, env->js_id);
    putwscom(yomi, env->js_id);
    putwscom(kanji, env->js_id);
    putwscom(comment, env->js_id);
    put4com(hinshi, env->js_id);
    put4com(init_hindo, env->js_id);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if (x == -1) wnn_errorno = get4com(env->js_id);
    UnlockMutex(&(env_js_lock));
    return x;
}

/*:::DOC_START
 *
 *    Function Name: js_set_autolearning_dic
 *    Description  : 
 *	   自動登録用の辞書を登録する
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *	   type :     (In) 辞書のタイプ(カタカナ/文節切り)
 *	   dic_no :   (In) 辞書番号
 *
 *    Return value : 0==SUCCESS, -1==ERROR
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_set_autolearning_dic(env, type, dic_no)
register struct wnn_env *env;
register int type, dic_no;
{
    int x;

    if(!env) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_SET_AUTOLEARNING_DIC);
    put4com(type, env->js_id);
    put4com(dic_no, env->js_id);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if (x == -1) wnn_errorno = get4com(env->js_id);
    UnlockMutex(&(env_js_lock));
    return(x);
}

/*:::DOC_START
 *
 *    Function Name: js_get_autolearning_dic
 *    Description  : 
 *	   自動登録用の辞書を調べる
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *	   type :     (In) 辞書のタイプ(カタカナ/文節切り)
 *
 *    Return value : -1==ERROR, ELSE==辞書の番号
 *
 *    Author      :  Seiji KUWARI
 *
 *    Revision history:
 *
 *:::DOC_END
 */
int
js_get_autolearning_dic(env, type)
register struct wnn_env *env;
register int type;
{
    register int x;

    if(!env) return(-1);
    set_current_js(env->js_id);
    LockMutex(&(env_js_lock));
    handler_of_jserver_dead_env(env);
    if(env_wnn_errorno_eql) {
	UnlockMutex(&(env_js_lock));
	return(-1);
    }
    snd_env_head(env,JS_GET_AUTOLEARNING_DIC);
    put4com(type, env->js_id);
    snd_flush(env->js_id);
    x=get4com(env->js_id);
    if (x == -1) {
	UnlockMutex(&(env_js_lock));
	wnn_errorno = get4com(env->js_id);
	return -1;
    }
    x=get4com(env->js_id);
    UnlockMutex(&(env_js_lock));
    return(x);
}


/* For wnnoffline */
#ifdef WNNOFFLINE
int
js_lock(server)
WNN_JSERVER_ID *server;
{
 int x;

 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_LOCK);
 snd_flush(server);
 if((x=get4com(server)) == -1) {
     js_wnn_errorno_set = get4com(server);
 }
 UnlockMutex(&(server_js_lock));
 return x;
}

int
js_unlock(server)
WNN_JSERVER_ID *server;
{
 int x;

 set_current_js(server);
 LockMutex(&(server_js_lock));
 handler_of_jserver_dead(server);
 if(js_wnn_errorno_eql) {
     UnlockMutex(&(server_js_lock));
     return(-1);
 }
 snd_server_head(server,JS_UNLOCK);
 snd_flush(server);
 if((x=get4com(server)) == -1) {
     js_wnn_errorno_set = get4com(server);
 }
 UnlockMutex(&(server_js_lock));
 return x;
}
#endif /* WNNOFFLINE */


/*:::DOC_START
 *
 *    Function Name:
 *	   rcv_dai_sim, rcv_sho_x_sim, rcv_sho_kanji_sim, rcv_sho_sim
 *    Description  : 
 *	   emulate rcv_dai etc. for local test
 *    Parameter    : same as emulated (omitted)
 *
 *    Return value : same as emulated (omitted)
 *
 *    Author      :  fujimori
 *
 *    Revision history:
 *         20-Dec-94: initial release
 *
 *:::DOC_END
 */



/*:::DOC_START
 *
 *    Function Name: js_ikeiji_with_data
 *    Description  : 
 *	   変換用各種データ（複合語変換、変換品詞リスト）を
 *	   指定して、異形字 変換処理を行なう
 *    Parameter    :
 *	   env :      (In) 環境へのポインタ
 *	   fuku :     (In) 複合語変換
 *	   nhinsi :     (In) 品詞の数
 *	   hlist :     (In) 品詞リスト
 *	   henkan :     (In) 変換のタイプ
 *	   yomi :     (In) 検索のキー
 *	   hinsi :     (In) 検索結果の品詞
 *	   fzk :     (In) 付属語の情報
 *	   vec :     (In) 接続の情報
 *	   vec1 :     (In) 接続の情報 1
 *	   vec2 :     (In) 接続の情報 2
 *	   cur_bun :     (In) 文節の情報
 *	   yomi_orig :     (In) 読み
 *	   rb :     (Out) 検索の結果
 *
 *    Return value : 大文節の数
 *
 *    Author      :  fujimori
 *
 *    Revision history:
 *         20-Dec-94: initial release
 *
 *:::DOC_END
 */
int
js_ikeiji_with_data(env,fuku,nhinsi,hlist,henkan,yomi,hinsi,fzk,vec,vec1,vec2,
cur_bun, yomi_orig,
rb)
struct wnn_env *env;
int fuku, nhinsi, *hlist, henkan;
w_char  *yomi;
int     hinsi;
w_char  *fzk;
int     vec;
int     vec1;
int	vec2;
WNN_BUN *cur_bun;
w_char  *yomi_orig;
struct wnn_ret_buf *rb;
{
 int x;
 int i, loop = abs(nhinsi);

 int for_ret_status;
 int for_ret_status_bkwd;

 for_ret_status = (cur_bun->dai_top)? WNN_NOT_CONNECT : WNN_CONNECT;
		 /* where are WNN_SENTOU and WNN_GIJI gone to ? */
 for_ret_status_bkwd = (cur_bun->dai_end)? WNN_NOT_CONNECT_BK : WNN_CONNECT_BK;


 if(env==0) return(-1);
 set_current_js(env->js_id);
 LockMutex(&(env_js_lock));
 handler_of_jserver_dead_env(env);
 if(env_wnn_errorno_eql) {
     UnlockMutex(&(env_js_lock));
     return(-1);
 }


 snd_env_head(env,JS_HENKAN_IKEIJI);
 put4com(fuku, env->js_id);		/* 複合語優先 */
 put4com(nhinsi, env->js_id);		/* 変換設定品詞数 */
 for(i = 0; i < loop; i++)
     put4com(hlist[i], env->js_id);	/* 変換設定品詞番号 */
 put4com(henkan, env->js_id);		/* 変換種別 */
 putwscom(yomi, env->js_id);
 put_fzk_vec(hinsi,fzk,vec,vec1, env->js_id);
 put4com(vec2, env->js_id);
/* need fugokugo-len, hinsi, etc */
 put4com( (int) (cur_bun->yomilen - cur_bun->jirilen), env->js_id);
 put4com(cur_bun->hinsi, env->js_id);

/* more */
 put4com( cur_bun->hyoka, env->js_id);
			/* for ret_sho_hyoka in jserver */
 put4com( cur_bun->daihyoka, env->js_id);
		 /* for ret_hyoka in jserver */
 put4com( for_ret_status /* (wnn_sho_bunsetsu*)->status */ , env->js_id);
		 /* for ret_status in jserver */
 put4com( for_ret_status_bkwd /* (wnn_sho_bunsetsu*)->status_bkwd */ , env->js_id);
		 /* for int ret_status_bkwd in jserver */
 put4com( cur_bun->kangovect, env->js_id);
		 /* for ret_kangovect in jserver */
 /* 変換読み文字列をサーバから受け取る ために サーバ に渡す */
 putwscom(yomi_orig, env->js_id);
		 /* for ret_yomi_orig[i] in jserver */
 put4com( cur_bun->jirilen, env->js_id);
		 /* for ret_jirilen_orig in jserver */
 put4com( cur_bun->yomilen, env->js_id);
		 /* for ret_yomilen_orig in jserver */
 put4com( cur_bun->kanjilen, env->js_id);
		 /* for ret_kanjilen_orig in jserver */
 put4com( cur_bun->real_kanjilen, env->js_id);
		 /* for ret_real_kanjilen_orig in jserver */

 snd_flush(env->js_id);

 switch(henkan) {
 case WNN_IKEIJI_DAI:
     x = rcv_dai(rb, env->js_id);
     break;
 default:
     x = get4com(env->js_id);
     env_wnn_errorno_set= get4com(env->js_id);
 }
 UnlockMutex(&(env_js_lock));
 return x;
}
/* end of js_ikeiji_with_data */


