/**********************************************************************
 
	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	"memory_debug.h"
#include	"task.h"
#include	"proxy.h"
#include	"lock_level.h"


SEM	proxy_lock;

PROXY_INFO proxyinfo;

void
init_proxy()
{
	proxy_lock = new_lock(LL_PROXY);
	proxyinfo.proxy_type = PT_NO_PROXY;
}


void
_free_server_list(SERVER_LIST * sl)
{
SERVER_LIST * sl2;
	for ( ; sl ; ) {
		sl2 = sl->next;
		d_f_ree(sl->name);
		d_f_ree(sl);
		sl = sl2;
	}
}

void
free_server_list(SERVER_LIST * sl)
{
	_free_server_list(sl);
}

void
_set_proxy(char type,char * server,int port)
{
	switch ( type ) {
	case PT_HTTP_PROXY:
		if ( proxyinfo.proxy_server )
			d_f_ree(proxyinfo.proxy_server);
		proxyinfo.proxy_server = copy_str(server);
		proxyinfo.proxy_port = port;
		proxyinfo.proxy_type = type;
		break;
	case PT_NO_PROXY:
		if ( proxyinfo.proxy_server )
			d_f_ree(proxyinfo.proxy_server);
		proxyinfo.proxy_server = 0;
		proxyinfo.proxy_port = 0;
		proxyinfo.proxy_type = type;
		_free_server_list(proxyinfo.da_servers);
		proxyinfo.da_servers = 0;
		break;
	default:
		er_panic("_set_proxy");
	}
}

SERVER_LIST *
_search_server_list(SERVER_LIST * sl,char * server)
{
	for ( ; sl ; sl = sl->next )
		if ( strcmp(sl->name,server) == 0 )
			return sl;
	return 0;
}

void
_set_direct_access(char type,char * server)
{
SERVER_LIST * sl;

	if ( type != PT_NO_PROXY && type != PT_XLoHTTP )
		er_panic("_set_direct_access");
	sl = _search_server_list(proxyinfo.da_servers,server);
	if ( sl ) {
		sl->type = type;
		return;
	}
	sl = d_alloc(sizeof(*sl));
	sl->name = copy_str(server);
	sl->type = type;

	sl->next = proxyinfo.da_servers;
	proxyinfo.da_servers = sl;
}

char * type_chr[9] = {
0,
"NoProxy",
"XLoHTTP",
0,
"HTTPProxy",
0,0,0,
"NativeProxy"
};

XL_SEXP *
_get_serverlist(SERVER_LIST * sl)
{
XL_SEXP * ret;
	ret = 0;
	for ( ; sl ; sl = sl->next ) {
		ret = cons(
			List(n_get_symbol("server"),
				n_get_string(type_chr[sl->type]),
				n_get_string(sl->name),
				-1),
			ret);
	}
	return ret;
}

XL_SEXP *
_get_proxyinfo()
{
void gc_gb_sexp();
XL_SEXP * ret;
	gc_push(0,0,"get_proxyinfo");
	switch ( proxyinfo.proxy_type ) {
	case PT_NO_PROXY:
		ret = List(n_get_symbol("proxyinfo"),
			n_get_string(type_chr[proxyinfo.proxy_type]),
			-1);
		break;
	case PT_HTTP_PROXY:
		ret = append(List(n_get_symbol("proxyinfo"),
			n_get_string(type_chr[proxyinfo.proxy_type]),
			n_get_string(proxyinfo.proxy_server),
			get_integer(proxyinfo.proxy_port,0),
			-1),
		 	_get_serverlist(proxyinfo.da_servers));
		break;
	default:
		er_panic("get_proxyinfo");
	}
	gc_pop(ret,gc_gb_sexp);
	return ret;
}


void
_check_proxy(PROXY_INFO * info,char * server)
{
SERVER_LIST * sl;
char * buf;
unsigned int ip;
	buf = d_alloc(1000);
	get_localhostname(buf);
	if ( strcmp(server,"localhost") == 0 ||
			strcmp(server,"127.0.0.1") == 0 ||
			strcmp(server,buf) == 0 )
		goto no_proxy;
	ip = get_localhostip();
	sprintf(buf,"%i.%i.%i.%i",
		(ip>>24)&0x0ff,
		(ip>>16)&0x0ff,
		(ip>>8)&0x0ff,
		(ip)&0x0ff);
	if ( strcmp(server,buf) == 0 )
		goto no_proxy;
	d_f_ree(buf);

	sl = _search_server_list(proxyinfo.da_servers,server);
	if ( sl ) {
		info->proxy_type = sl->type;
		info->proxy_server = 0;
		info->proxy_port = 0;
		info->da_servers = 0;
	}
	else {
		*info = proxyinfo;
		info->da_servers = 0;
	}
	return;
no_proxy:
	d_f_ree(buf);
	info->proxy_type = PT_NO_PROXY;
	info->proxy_server = 0;
	info->proxy_port = 0;
	info->da_servers = 0;
	return;
}

void
set_proxy(char type,char * server,int port)
{

	lock_task(proxy_lock);
	_set_proxy(type,server,port);
	unlock_task(proxy_lock,"set_proxy");
}

void
set_direct_access(char type,char * server)
{

	lock_task(proxy_lock);
	_set_direct_access(type,server);
	unlock_task(proxy_lock,"set_direct_access");
}

XL_SEXP *
get_proxyinfo()
{
XL_SEXP * ret;
	lock_task(proxy_lock);
	ret = _get_proxyinfo();
	unlock_task(proxy_lock,"get_proxyinfo");
	return ret;
}

void
check_proxy(PROXY_INFO * info,char * server)
{
	lock_task(proxy_lock);
	_check_proxy(info,server);
	unlock_task(proxy_lock,"check_proxy");
}

