/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/


#include	<fcntl.h>
#include	<errno.h>
#include	"machine/err.h"
#include	"memory_debug.h"
#include	"client.h"
#include	"server.h"
#include	"blacklist.h"
#include	"xl.h"
#include	"utils.h"
#include	"stream.h"
#include	"proxy.h"

int terminal_prompt();


int http_proxy_keep_alive_mode = XoH_F_KEEP_ALIVE;


int
_setup_i_self(XL_INTERPRETER * xli)
{
	xli->flags = XIF_TERMINAL;
	xli->inp = 0;
	xli->out = 0;
	xli->err = 0;
	xli->msg = nl_copy_str(std_cm,"internal thread");
	xli->thread_mode = TM_SELF;
	if ( xli->environment )
		xli->env = new_env(xli->env);
	return setup_xl_interpreter(xli);
}

int
_setup_i_stdio(XL_INTERPRETER * xli)
{
	xli->inp = s_open_terminal(terminal_prompt);
	xli->flags = XIF_TERMINAL;
	if ( xli->inp == 0 ) {
		d_f_ree(xli);
		return XLIE_CANNOT_OPEN_FILE;
	}
	xli->out = xli->inp;
	xli->err = xli->inp;
	xli->ps_flags |= PF_RAW_DISABLE;
	xli->msg = nl_copy_str(std_cm,"stdio");
	xli->thread_mode = TM_1;
	if ( xli->environment )
		xli->env = new_env(xli->env);
	return setup_xl_interpreter(xli);
}

int
_setup_i_file(XL_INTERPRETER * xli)
{
int ps_flags;
	ps_flags = PF_RAW_DISABLE;
	xli->thread_mode = TM_1;
	if ( l_strcmp(xli->input_file_name,l_string(std_cm,"-")) == 0 ) {
		xli->inp = s_stdin;
		xli->thread_mode = TM_2;
		xli->a_type = XLA_PIPE;
		ps_flags |= XIF_CODE_SYNC;
	}
	else if ( l_strcmp(xli->input_file_name,l_string(std_cm,"+")) == 0 ) {
		xli->inp = s_stdin;
		ps_flags = XIF_CODE_SYNC;
		xli->thread_mode = TM_2;
		xli->a_type = XLA_PIPE;
	}
	else {
		xli->inp = s_open_file(n_string(std_cm,xli->input_file_name),
				O_RDONLY);
		if ( xli->inp == 0 ) {
			d_f_ree(xli);
			return XLIE_CANNOT_OPEN_FILE;
		}
	}
	if ( xli->output_file_name ) {
		if ( l_strcmp(xli->output_file_name,
				l_string(std_cm,"-")) == 0 )
			xli->out = s_stdout;
		else	xli->out = s_open_file(n_string(std_cm,
				xli->output_file_name),
					O_RDWR|O_CREAT|O_TRUNC,
					0666);
		if ( xli->out == 0 ) {
			s_close(xli->inp);
			d_f_ree(xli);
			return XLIE_CANNOT_OPEN_FILE;
		}
	}
	if ( xli->error_file_name ) {
		if ( l_strcmp(xli->output_file_name,
				l_string(std_cm,"-")) == 0 ) {
			if ( xli->out )
				xli->err = xli->out;
			else	xli->err = s_stdout;
		}
		else	xli->err = s_open_file(n_string(std_cm,
				xli->output_file_name),
					O_RDWR|O_CREAT|O_TRUNC,
					0666);
		if ( xli->err == 0 ) {
			s_close(xli->inp);
			s_close(xli->out);
			return XLIE_CANNOT_OPEN_FILE;
		}
	}
	xli->ps_flags |= ps_flags;
	xli->msg = ll_copy_str(xli->input_file_name,1494);
	if ( xli->environment )
		xli->env = new_env(xli->env);
	return setup_xl_interpreter(xli);
}

int
_setup_i_descripter(XL_INTERPRETER * xli)
{
	xli->inp = s_open_descripter(xli->inp_desc,&s_socket_table);
	if ( xli->inp == 0 ) {
		d_f_ree(xli);
		return XLIE_CANNOT_OPEN_DESCRIPTER;
	}
	if( xli->out_desc != -1 ) {
		xli->out = s_open_descripter(xli->out_desc,&s_socket_table);
		if ( xli->out == 0 ) {
			s_close(xli->inp);
			d_f_ree(xli);
			return XLIE_CANNOT_OPEN_DESCRIPTER;
		}
	}
	else	xli->out = 0;
	if ( xli->err_desc != -1 ) {
		xli->err = s_open_descripter(xli->err_desc,&s_socket_table);
		if ( xli->err == 0 ) {
			s_close(xli->out);
			s_close(xli->inp);
			d_f_ree(xli);
			return XLIE_CANNOT_OPEN_DESCRIPTER;
		}
	}
	else	xli->err = 0;
	xli->msg = nl_copy_str(std_cm,"descripter input");
	xli->thread_mode = TM_2;
	if ( xli->environment )
		xli->env = new_env(xli->env);
	xli->connect_ip = s_get_socketip(xli->inp);
	xli->flags |= XIF_CODE_SYNC;
	return setup_xl_interpreter(xli);
}

int
_setup_i_pipe(XL_INTERPRETER * xli)
{
	xli->msg = nl_copy_str(std_cm,"pipe input");
	xli->thread_mode = TM_2;
	if ( xli->environment )
		xli->env = new_env(xli->env);
	xli->connect_ip = s_get_socketip(xli->inp);
	xli->flags |= XIF_CODE_SYNC;
	return setup_xl_interpreter(xli);
}

int
_setup_i_accept(XL_INTERPRETER * xli)
{
int open_port;
STREAM * st;
	st = init_server(&open_port,xli->port,xli->port_limit);
	if ( st == 0 ) {
		d_f_ree(xli);
		return XLIE_CANNOT_OPEN_ACCEPT;
	}
	xli->inp = st;
	xli->out = 0;
	xli->err = 0;
	xli->msg = nl_copy_str(std_cm,"network");
	xli->thread_mode = TM_2;
	return setup_xl_interpreter(xli);
}

int
___setup_i_connect(int * cerr,XL_INTERPRETER * xli,PROXY_INFO * pinfo)
{
int open_port;
STREAM * st;
SERVER_INFO si;
 int ret;

	*cerr = 0;
	xli->flags |= XIF_PERMISSION;
	switch ( xli->proxy_type ) {
	case PT_NO_PROXY:
		xli->inp = new_connection(
			cerr,
			n_string(std_cm,xli->hostname),
			xli->ip,xli->port,0,0);
		break;
	case PT_XLoHTTP:
		xli->inp = s_connect_XLoHTTP(
			cerr,
			n_string(std_cm,xli->hostname),
			xli->ip,xli->port,0,0,0,
				http_proxy_keep_alive_mode);
		break;
	case PT_HTTP_PROXY:
		xli->inp = s_connect_XLoHTTP(
			cerr,
			n_string(std_cm,xli->hostname),
			xli->ip,xli->port,
			pinfo->proxy_server,0,pinfo->proxy_port,
				http_proxy_keep_alive_mode);
		break;
	case PT_NATIVE_PROXY:
		er_panic("no support");
	}
	if ( xli->inp == 0 ) {
		d_f_ree(xli->hostname);
		d_f_ree(xli);
		return XLIE_CANNOT_OPEN_CONNECT;
	}
	xli->err = xli->out = xli->inp;
	if ( xli->input_file_name )
		xli->msg = ll_copy_str(xli->input_file_name,1495);
	else	xli->msg = nl_copy_str(std_cm,"connect");
	xli->thread_mode = TM_2;
	if ( xli->environment )
		xli->env = new_env(xli->env);
	xli->connect_ip = s_get_socketip(xli->inp);

	si.name = n_string(std_cm,xli->hostname);
	si.ip = xli->connect_ip;
	si.status = SIS_CONNECT;
	si.active_flags = SIA_NAME|SIA_IP|SIA_STATUS;
	set_serverinfo(&si,SIC_SET,SIS_ALL);
	ret = setup_xl_interpreter(xli);
	if ( ret == XLIE_CANNOT_OPEN_CONNECT )
			*cerr = ESYS_CTIMEOUT;
	else	*cerr = 0;
	return ret;
}

typedef struct setup_i_connect_cmd {
	BL_CMD			c;
	XL_INTERPRETER *	xli;
	PROXY_INFO *		pinfo;
	int			ret;
} SETUP_I_CONNECT_CMD;

int
_setup_i_connect_retry(BLACKLIST * bl)
{
int ret,id;
XL_INTERPRETER * xli;
XLISP_ENV * env;
int cerr;
PROXY_INFO pinfo;

set_t_msg(108);
	xli = new_xl_interpreter();
	xli->a_type = XLA_CONNECT;
	env = gblisp_top_env0;
	xli->env = env;
	xli->port = bl->port;
	xli->environment = 1;
	xli->hostname = nl_copy_str(std_cm,bl->name);
	check_proxy(&pinfo,bl->name);
	xli->proxy_type = pinfo.proxy_type;

	if ( pinfo.proxy_type == PT_HTTP_PROXY )
		id = ___setup_i_connect(&cerr,xli,&pinfo);
	else	id = ___setup_i_connect(&cerr,xli,0);
	if ( cerr == ESYS_CTIMEOUT )
		ret = BLS_ERROR;
	else	ret = BLS_OK;
set_t_msg(109);

	if ( id > 0 )
		close_interpreter(id);
set_t_msg(110);
	return ret;
}

int
_setup_i_connect_proc(BLACKLIST * bl,SETUP_I_CONNECT_CMD * c)
{
int ret;
int cerr;

	bl->port = c->xli->port;
	if ( bl->state[BLT_RESOLVE].state == BLS_ERROR )
		return BLS_ERROR;
	c->ret = ___setup_i_connect(&cerr,c->xli,c->pinfo);
	if ( cerr == ESYS_CTIMEOUT )
		ret = BLS_ERROR;
	else	ret = BLS_OK;
	bl->polling_initial = 0;
	return ret;
}

int
_setup_i_connect(XL_INTERPRETER * xli)
{
SETUP_I_CONNECT_CMD c;
int ret,cerr;
PROXY_INFO pinfo;


retry:

set_t_msg(115);

	c.pinfo = 0;
	switch ( xli->proxy_type ) {
	case PT_DONT_CARE:
		check_proxy(&pinfo,
			n_string(std_cm,xli->hostname));
		xli->proxy_type = pinfo.proxy_type;
		goto retry;
	case PT_HTTP_PROXY:
		c.pinfo = &pinfo;
	case PT_NO_PROXY:
	case PT_XLoHTTP:

		c.xli = xli;
		c.ret = -1;
		c.c.name = ln_copy_str(std_cm,xli->hostname);
		c.c.name_len = strlen(c.c.name)+1;
		c.c.retry = _setup_i_connect_retry;
		c.c.proc = _setup_i_connect_proc;
		c.c.type = BLT_CONNECT;

		bl_do(&c);

		d_f_ree(c.c.name);
		return c.ret;
/*
	case PT_HTTP_PROXY:
		return ___setup_i_connect(&cerr,xli,&pinfo);
*/
	case PT_NATIVE_PROXY:
	default:
		er_panic("_setup_i_connect");
	}
	return 0;
}

int
setup_i(XL_INTERPRETER * xli)
{
set_t_msg(120);
	switch ( xli->a_type ) {
	case XLA_STDIO:
		return _setup_i_stdio(xli);
	case XLA_FILE:
		return _setup_i_file(xli);
	case XLA_ACCEPT:
	case XLA_IPC:
		return _setup_i_accept(xli);
	case XLA_CONNECT:
		return _setup_i_connect(xli);
	case XLA_DESCRIPTER:
		return _setup_i_descripter(xli);
	case XLA_SELF:
		return _setup_i_self(xli);
	case XLA_PIPE:
		return _setup_i_pipe(xli);
	default:
		er_panic("setup_accept(1)");
	}
	return 0;
}
