/*
 *	SKK server support
 *
 *	by A.ITO	3 Jul, 1992
 */
#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#include "skklib.h"

#ifdef USE_SERVER

#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#ifdef PF_INET6
# define HAVE_GETADDRINFO
#endif

#define SKK_PORT_NUMBER	1178
#define SKK_SERVICENAME	"skkserv"

#ifdef BCOPY
#define bincopy(a,b,n)	bcopy(a,b,n)
#define fillzero(a,n)	bzero(a,n)
#else
#define bincopy(a,b,n)	memcpy(b,a,n)
#define fillzero(a,n)	memset(a,0,n)
#endif

int skkservsock = -1;
FILE *rserv,*wserv;
char *SKKServerHost = NULL;

char *getenv();

openSKKserv()
{
	int sock;
	int i;
	unsigned short port;
#ifdef HAVE_GETADDRINFO
	struct addrinfo aihint, *ai0, *ai;
	int error;
#else
	struct sockaddr_in hostaddr;
	struct hostent *entry;
	struct servent *serv;
	struct protoent *proto;
#endif
	char *hostname;
#ifdef SKK_CONF		/* use skk.conf */
	FILE *conffp;
	char line[128];
	char hostbuf[128];
	char servbuf[128];
	char *confhost = NULL;
	char *confport = SKK_SERVICENAME;

	if ((conffp = fopen(SKK_CONF, "r")) != NULL) {
		char *p, *data;

		while (fgets(line, sizeof line, conffp) != NULL) {
			if ((p = strchr(line, '#')) != NULL)
				*p = '\0';
			if ((p = strtok(line, ": \t\n")) == NULL)
				continue;
			if ((data = strtok((char *) NULL, " \t\n")) == NULL)
				continue;
			if (!strcmp(p, "skkserv_host")) {
				strcpy(hostbuf, data);
				confhost = hostbuf;
			} else if (!strcmp(p, "skkserv_port")) {
				strcpy(servbuf, data);
				confport = servbuf;
			}
		}
	}
# undef SKK_SERVICENAME
# define SKK_SERVICENAME confport
#endif

	if (SKKServerHost)
		hostname = SKKServerHost;
	else if ((hostname = getenv("SKKSERVER")) == NULL) {
#ifdef SKK_CONF
		if ((hostname = confhost) == NULL)
#endif
#ifdef SKK_SERVER_HOST
		hostname = SKK_SERVER_HOST;
#else
		return -1;
#endif
	}

#ifdef HAVE_GETADDRINFO
	fillzero((char*)&aihint, sizeof aihint);
	aihint.ai_family = PF_UNSPEC;
	aihint.ai_socktype = SOCK_STREAM;
	aihint.ai_flags = AI_CANONNAME;
	error = getaddrinfo(hostname, SKK_SERVICENAME, &aihint, &ai0);
	if (error) {
		printf("%s: %s\r\n", gai_strerror(error), hostname);
		return -1;
	}

	sock = -1;
	for (ai = ai0; ai; ai = ai->ai_next) {
		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (sock >= 0 &&
		    connect(sock, ai->ai_addr, ai->ai_addrlen) == 0)
			break;
		close(sock);
		sock = -1;
	}
	if (sock < 0) {
		perror(hostname);
		return -1;
	}
#else
	serv = getservbyname(SKK_SERVICENAME,"tcp");
	fillzero((char*)&hostaddr,sizeof(struct sockaddr_in));
	if ((proto = getprotobyname("tcp")) == NULL) {
		return -1;
	}

	if ((sock = socket(AF_INET,SOCK_STREAM,proto->p_proto)) < 0) {
		return -1;
	}

	if ((hostaddr.sin_addr.s_addr = inet_addr(hostname)) == INADDR_NONE) {
		if ((entry = gethostbyname(hostname)) == NULL) {
			return -1;
		}
		bincopy(entry->h_addr, &hostaddr.sin_addr, entry->h_length);
	}
        hostaddr.sin_family = AF_INET;
	hostaddr.sin_port =
		serv ? serv->s_port :
#ifdef SKK_CONF
		(i = atoi(confport)) > 0 ? htons(i) :
#endif
		htons(SKK_PORT_NUMBER);
	if (connect(sock,(struct sockaddr *)&hostaddr,sizeof(struct sockaddr_in)) < 0) {
		return -1;
	}
#endif
	printf("SKKSERVER=%s\r\n",hostname);
	skkservsock = sock;
	rserv = fdopen(sock,"r");
	wserv = fdopen(sock,"w");
	return 0;
}

CandList
getCandFromServer(s)
char *s;
{
	char r;
	CandList res;

	fprintf(wserv,"1%s \n",s);
	fflush(wserv);
	read(skkservsock,&r,1);
	if (r == '1') {  /* succeeded */
		res = getCandList(rserv,NULL,isConjugate(s,strlen(s)));
		return res;
	}
	else
		while (read(skkservsock,&r,1) > 0 && r != '\n');
	return NULL;
}

closeSKKserv()
{
	if (skkservsock >= 0) {
		fprintf(wserv,"0\n");
		fflush(wserv);
	}
}

#endif
