/*////////////////////////////////////////////////////////////////////////
Copyright (c) 1994-2000 Yutaka Sato and ETL,AIST,MITI
Copyright (c) 2001-2005 National Institute of Advanced Industrial Science and Technology (AIST)
AIST-Product-ID: 2000-ETL-198715-01, H14PRO-049, H15PRO-165, H18PRO-443

Permission to use this material for noncommercial and/or evaluation
purpose, copy this material for your own use, and distribute the copies
via publicly accessible on-line media, without fee, is hereby granted
provided that the above copyright notice and this permission notice
appear in all copies.
AIST MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY OF THIS
MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", WITHOUT ANY EXPRESS
OR IMPLIED WARRANTIES.
/////////////////////////////////////////////////////////////////////////
Content-Type:	program/C; charset=US-ASCII
Program:	X.c (X proxy)
Author:		Yutaka Sato <ysato@etl.go.jp>
Description:
History:
	950308	created
//////////////////////////////////////////////////////////////////////#*/
#include <stdio.h>
#include "ystring.h"
#include "vsignal.h"
#include "delegate.h"
#include "fpoll.h"
#include "proc.h"
void DBGMSG(PCStr(fmt),...);

static jmp_buf tel_env;
static void sigPIPE(int sig){
	signal(SIGPIPE,SIG_IGN);
	longjmp(tel_env,SIGPIPE);
}
static void sigTERM(int sig){
	signal(SIGTERM,SIG_IGN);
	longjmp(tel_env,SIGTERM);
}

#define Getc(fc)	fputc(fgetc(fc),ts)

static int LEND;

static int GetInt2(FILE *fc,FILE *ts)
{	int iv;

	iv = Getc(fc);
	if( LEND )
		iv = (Getc(fc) << 8) | iv;
	else	iv = (iv << 8) | Getc(fc);
	return iv;
}
static int GetInt4(FILE *fc,FILE *ts)
{	int iv;

	iv = GetInt2(fc,ts);
	if( LEND )
		iv = (GetInt2(fc,ts) << 16) | iv;
	else	iv = (iv << 16) | GetInt2(fc,ts);
	return iv;
}

static int XCS(Connection *Conn,int fcbsize,int peer,int omask)
{	CStr(buf,0x4000);
	int gotsig;
	int rcc;
	int count,total;
	FILE *fc,*ts;
	int ch,op;
int b_order;
int n,l,r;
int code[4];
int ver,rev,nan,nad;

	total = count = 0;
	if( fcbsize == 0 )
		fcbsize = 1;
	if( sizeof(buf) < fcbsize )
		fcbsize = sizeof(buf);

	if( (gotsig = setjmp(tel_env)) == 0 ){

fc = fdopen(FromC,"r");
ts = fdopen(ToS,"w");

		sigsetmask(omask);

		b_order = Getc(fc);
		DBGMSG("BYTEORDER: %x:%c\n",b_order,b_order);
		if( b_order == 'l' || b_order == 'L' ){
			Verbose("#### LITTLE ENDIEN ####\n");
			LEND = 1;
		}else	LEND = 0;
		Getc(fc); /* padding */

		ver = GetInt2(fc,ts);
		rev = GetInt2(fc,ts);
		DBGMSG("VERSION: %d.%d\n",ver,rev);
		nan = GetInt2(fc,ts);
		nad = GetInt2(fc,ts);
		GetInt2(fc,ts); /* padding */

		for(;;){
			if( ready_cc(fc) == 0 )
				fflush(ts);
			op = getc(fc);
			if( op == EOF ){
				sv1log("EOF from the client\n");
				break;
			}
			buf[0] = op;
			if( putc(op,ts) == EOF ){
				sv1log("EOF from the server\n");
				break;
			}
			n = Getc(fc);
			l = GetInt2(fc,ts);

if( op == 45 ){
	int fid,leng,i;
	CStr(name,128);

	fid = GetInt4(fc,ts);
	leng = GetInt2(fc,ts);
	GetInt2(fc,ts);

	if( sizeof(name) <= leng+1 ){
		syslog_ERROR("OpenFont so long name: %d\n",leng);
	}
	for( i = 0; i < leng; i++ ){
		if( elnumof(name)-1 <= i ){
			Getc(fc);
			continue;
		}
		setVStrElem(name,i,Getc(fc)); /**/
	}
	setVStrEnd(name,i);
	Verbose("OpenFont: %s\n",name);
	for(; i % 4 != 0; i++ )
		Getc(fc);
}else
if( op == 46 ){
	int fid;
	fid = GetInt4(fc,ts);
	Verbose("CloseFont: %d\n",fid);
}else
if( op == 74 || op == 76 || op == 77 ){
	int d,g,x,y,p,i,och;
	d = GetInt4(fc,ts);
	g = GetInt4(fc,ts);
	x = GetInt2(fc,ts);
	y = GetInt2(fc,ts);

	if( op == 77 ){
		for( i = 0; i < n; i++ ){
			/*
			och = getc(fc)<<8 | getc(fc);
			*/
			och = getc(fc) << 8;
			och = och | getc(fc);
DBGMSG("OP ImageTEXT16[%3d / %3d/%3d]: outch=%4x x=%4d, y=%4d\n",i,n,l,och,x,y);
			putc(och >> 8,ts);
			putc(och&0xFF,ts);
		}
		if( (i % 2) != 0 )
			GetInt2(fc,ts);
	}else
	if( op == 76 ){
DBGMSG("OP ImageTEXT8[%3d/%3d]: x=%4d, y=%4d\n",n,l,x,y);
		for( i = 0; i < n; i++ ){
			int nch;
			och = getc(fc);
DBGMSG("OP ImageTEXT8[%3d / %3d/%3d]: outch=%4x x=%4d, y=%4d\n",i,n,l,och,x,y);
			if( (och & 0x80) && i+1 <= n ){
				nch = getc(fc);
				if( nch & 0x80 ){
					putc('+',ts);
					putc('-',ts);
				}else{
					putc(och,ts);
					putc(nch,ts);
				}
				i++;
			}else	putc(och,ts);
		}
		for(; i % 4 != 0; i++ )
			Getc(fc);
	}else
	if( op == 74 ){
		int len,delta,j,r;
DBGMSG("OP PolyTEXT8[%3d/%3d]: x=%4d, y=%4d\n",n,l,x,y);
		r = (l-4)*4;
		for( i = 0; 1 < r; i++ ){
			len = getc(fc); r--;
DBGMSG("OP PolyTEXT8[%3d / %3d/%3d]: len=%3d x=%4d, y=%4d\n",i,n,l,len,x,y);
			if( len == 255 ){
				int fid;
				putc(len,ts);
				fid = GetInt4(fc,ts);
				r -= 4;
DBGMSG("OP PolyTEXT8:Font=[%8x]:",fid);
			}else{
				putc(len,ts);
				delta = getc(fc); r--;
				putc(delta,ts);

				for( j = 0; j < len; j++ ){
					och = getc(fc); r--;
DBGMSG("PolyTEXT8[%3d]: %2x %c\n",j,och,och);
					putc(och,ts);
				}
			}
		}
		for(; 0 < r; r-- )
			Getc(fc);
	}
}else{
DBGMSG("OP %4d / %4d / %4d\n",op,n,l);
	for( r = (l-1)*4; 0 < r; r-- )
		ch = Getc(fc);
}
			count += 1;
			total += 1;
		}
	}
	signal(SIGPIPE,SIG_IGN);
	signal(SIGTERM,SIG_IGN);
	sv1log("CS-RELAY[%d>%d]: %dBytes %dI/O buf=%d\n",
		FromC,ToS,total,count,fcbsize);

	return total;
}
static int XSC(Connection *Conn,int fsbsize,int peer,int omask)
{	CStr(buf,0x4000);
	int gotsig;
	int rcc,wcc;
	int count,total;

	total = count = 0;
	if( fsbsize == 0 )
		fsbsize = 1;
	if( sizeof(buf) < fsbsize )
		fsbsize = sizeof(buf);

	if( setjmp(tel_env) == 0 ){
		sigsetmask(omask);
		while( 0 < (rcc = read(FromS,buf,QVSSize(buf,fsbsize))) ){
			count += 1;
			total += rcc;
			if( (wcc = write(ToC,buf,rcc)) <= 0 )
				break;
		}
		if( rcc <= 0 ) sv1log("SC-EOF\n");
	}
	signal(SIGPIPE,SIG_IGN);
	signal(SIGTERM,SIG_IGN);
	sv1log("SC-RELAY[%d<%d]: %dBytes %dI/O buf=%d\n",
		ToC,FromS,total,count,fsbsize);

	Kill(peer,SIGTERM);
	return total;
}
static int bidirectional_relay(Connection *Conn,int fcbsize,int fsbsize)
{	register int ppid,cpid;
	int omask;
	int total;

	Verbose("buffer: CS=%d SC=%d\n",fcbsize,fsbsize);

	ppid = getpid();
	omask = sigblock(sigmask(SIGPIPE)|sigmask(SIGTERM));
	signal(SIGPIPE,sigPIPE);
	signal(SIGTERM,sigTERM);

	if( (cpid = Fork("bidirectional_relay")) == 0 ){
		total = XSC(Conn,fsbsize,ppid,omask);
		Finish(0);
	}else{
		total = XCS(Conn,fcbsize,cpid,omask);
Kill(cpid,SIGTERM);
		wait(0);
		sigsetmask(omask);
	}
	return total;
}

void proxyX(Connection *Conn)
{	const char *rhost;
	int rdisp;

	/*
	 *	should support MOUNT="%d X://host:port/" ?
	 */
	rhost = "ysato";
	rdisp = 0;
	set_realserver(Conn,"X",rhost,6000+rdisp);

	sv1log("#### PROXY X to %s:%d [%s://%s:%d]\n",rhost,rdisp,
		DFLT_PROTO,DFLT_HOST,DFLT_PORT);

	if( 0 <= connect_to_serv(Conn,FromC,ToC,0) ){
		bidirectional_relay(Conn,0x1000,0x1000);
	}
}
int service_X(Connection *Conn)
{	int total;

	if( isMYSELF(DFLT_HOST) ){
		proxyX(Conn);
		return -1;
	}
	if( ToS < 0 ){
		sv1log("No connection\n");
		return -1;
	}
	total = bidirectional_relay(Conn,0x1000,0x1000);
	return total;
}
