/**********************************************************************
 
	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	<stdlib.h>
#include	"memory_debug.h"
#include	"utils.h"
#include	"xlerror.h"
#include	"xl.h"
#include	"xl_server.h"
#include	"lock_level.h"

XL_SEXP * xl_SetAgent();
extern SEM sem_xli_lex_lock;
SEM SetAgent_lock;

void
init_SetAgent(XLISP_ENV * env)
{
	SetAgent_lock = new_lock(LL_SETAGENT);
	set_env(env,l_string(std_cm,"SetAgent"),
		get_func_prim(xl_SetAgent,FO_APPLICATIVE,0,3,3));
	set_lock_function(l_string(std_cm,"SetAgent"));
}

XL_SEXP *
SetAgent_launch(XL_FILE * file,int line,L_CHAR * arg,int old_flag)
{
XL_INTERPRETER * xli;
STREAM * _st[3];
char cf[3];
char * _arg;
char ** argv;
char * str;
char * ptr, * p;
int cnt,i;
int pid;
char * ret_str_c;

	_arg = copy_str(n_string(std_cm,arg));
	xli = get_my_xli();
	if ( xli->inp == xli->out ) {
		_st[0] = xli->inp;
		_st[1] = 0;
		cf[0] = 1;
		cf[1] = 0;
	}
	else {
		_st[0] = xli->inp;
		_st[1] = xli->out;
		_st[2] = 0;
		cf[0] = 1;
		cf[1] = 1;
		cf[2] = 0;
	}
	for ( ptr = _arg ; ; ptr ++ ) {
		switch ( *ptr ) {
		case ' ':
		case '\t':
			*ptr = 0;
			continue;
		case 0:
			break;
		default:
			continue;
		}
		break;
	}
	cnt = 0;
	for ( p = _arg ; p != ptr && *p == 0 ; p ++ );
	if ( p == ptr ) {
		d_f_ree(_arg);
		goto param_error;
	}
	cnt ++;
	str = p;
	for ( ; ; ) {
		for ( ; *p ; p ++ );
		for ( ; p != ptr && *p == 0 ; p ++ );
		if ( p == ptr )
			break;
		cnt ++;
	}
	argv = d_alloc(sizeof(char*)*(cnt+1),177);
	p = str;
	i = 0;
	for ( ; ; ) {
		argv[i++] = p;
		for ( ; *p ; p ++ );
		for ( ; p != ptr && *p == 0 ; p ++ );
		if ( p == ptr )
			break;
	}
	argv[i] = 0;
	ret_str_c = d_alloc(100,178);


	if ( (xli->flags&XIF_ASYNC) == 0 ) {
		if ( old_flag ) {
			sprintf(ret_str_c,
				"<Result>%i ()</Result>\014\n",line);
			lock_task(sem_xli_lex_lock);
			if ( xli->mode != XIM_RUN ) {
				unlock_task(sem_xli_lex_lock,
					"SetAgent_launch");
				d_f_ree(_arg);
				d_f_ree(argv);
				return 0;
			}
			s_printf(xli->out,"\016");
			s_flush(xli->out);
			sleep_task((int)&xli->out,sem_xli_lex_lock);
			if ( xli->out == 0 ) {
				d_f_ree(_arg);
				d_f_ree(argv);
				return 0;
			}
		}
		else {
			sprintf(ret_str_c,
				"\014<Result>%i ()</Result>\n",line);
		}
	}
	else {
		sprintf(ret_str_c,"<Result>%i ()</Result>\n",line);
	}

	lock_task(SetAgent_lock);
	pid = launch_proc(str,argv,_st,cf,0,ret_str_c);
	unlock_task(SetAgent_lock,"SetAgent");
	d_f_ree(_arg);
	d_f_ree(argv);
	d_f_ree(ret_str_c);
	if ( pid < 0 )
		return get_error(
			file,
			line,
			XLE_PROTO_LAUNCH,
			l_string(std_cm,"SetAgent"),
			List(n_get_string("cannot lounch"),
				get_integer(pid,0),
				-1));
	if ( xli->out == xli->inp ) {
		xli->inp = 0;
		xli->out = 0;
	}
	else 	xli->inp = 0;
	return get_integer(pid,0);
type_missmatch:
	return get_error(
		file,
		line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"Launch"),
		n_get_string("type missmatch"));
param_error:
	return get_error(
		file,
		line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"Launch"),
		n_get_string("parameter error"));
}




XL_SEXP *
check_user(
	XLISP_ENV * env,
	XL_SEXP * s,
	L_CHAR * group,
	L_CHAR * agent,
	L_CHAR * ltype,
	int old_flag)
{
XL_INTERPRETER * xli;
XL_SEXP * ret;
XL_SEXP * s_user;
L_CHAR * user,* passwd;
P_MODE * pp;

	xli = get_my_xli();
	if ( xli->pl_accept == 0 )
		goto permission_error;
	for ( pp = xli->pl_accept->mode ; pp ; pp = pp->next )
		if ( l_strcmp(pp->name,ltype) == 0 )
			goto ok;
	goto permission_error;
ok:
	if ( old_flag == 0 )
		out_lock_function(XIF_LOCK_F);
	ret = eval(env,remote_query(xli->id,env,0,
		List(	get_symbol(l_string(std_cm,"GetUserInfo")),
			get_string(group),
			get_string(agent),
			get_string(ltype),
			n_get_string("user"),
			-1)));
	switch ( get_type(ret) ) {
	case XLT_ERROR:
		return ret;
	case XLT_STRING:
		s_user = ret;
		user = ret->string.data;
		break;
	default:
		goto type_missmatch;
	}
	if ( old_flag == 0 )
		out_lock_function(XIF_LOCK_F);
	ret = eval(env,remote_query(xli->id,env,0,
		List(	get_symbol(l_string(std_cm,"GetUserInfo")),
			get_string(group),
			get_string(agent),
			get_string(ltype),
			n_get_string("passwd"),
			-1)));
	switch ( get_type(ret) ) {
	case XLT_ERROR:
		return ret;
	case XLT_STRING:
		passwd = ret->string.data;
		break;
	default:
		goto type_missmatch;
	}
	if ( check_account(group,ltype,user,passwd) < 0 )
		goto permission_error;
	return s_user;
type_missmatch:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"SetAgent"),
		n_get_string("type missmatch result of GetUserInfo"));
permission_error:
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_PERMISSION_DENIED,
		l_string(std_cm,"SetAgent"),
		n_get_string("permission denied"));
}

void gc_gb_sexp();

void
log_output(XL_INTERPRETER * xli,L_CHAR * client,XL_SEXP * agent)
{
	if ( client == 0 ) {
		log_printf(LOG_MESSAGE,
			"%i.%i.%i.%i success to launch the agent (%s)",
			(xli->connect_ip>>24)&0x0ff,
			(xli->connect_ip>>16)&0x0ff,
			(xli->connect_ip>>8)&0x0ff,
			xli->connect_ip&0x0ff,
			n_string(std_cm,agent->string.data));
	}
	else {
		log_printf(LOG_MESSAGE,
		"%i.%i.%i.%i (%s) success to launch the agent (%s)",
			(xli->connect_ip>>24)&0x0ff,
			(xli->connect_ip>>16)&0x0ff,
			(xli->connect_ip>>8)&0x0ff,
			xli->connect_ip&0x0ff,
			n_string(std_cm,client),
			n_string(std_cm,agent->string.data));
	}
}


XL_SEXP *
xl_SetAgent(XLISP_ENV * env,XL_SEXP * s,
	XLISP_ENV * aa,
	XL_SYM_FIELD * sf)
{
XL_SEXP * agent, * type, * ret;
AGENT * a;
XL_INTERPRETER * xli;
L_CHAR * e_agent,* e_type;
L_CHAR * client;
int old_flag;

	client = get_sf_attribute(sf,l_string(std_cm,"client"));

	agent = get_el(s,1);
	type = get_el(s,2);
	switch ( get_type(agent) ) {
	case XLT_ERROR:
		out_lock_function(0);
		return agent;
	case XLT_STRING:
		break;
	default:
		goto type_missmatch;
	}
	switch ( get_type(type) ) {
	case XLT_ERROR:
		out_lock_function(0);
		return type;
	case XLT_STRING:
		break;
	default:
		goto type_missmatch;
	}

	if ( client &&
		l_strcmp(client,
			l_string(std_cm,"COSMOS/ver.02.03.06"))
			< 0 ) {
		out_lock_function(0);
		old_flag = 1;
	}
	else	old_flag = 0;


	a = search_agent(agent->string.data,type->string.data);
	if ( a == 0 ) {

		e_agent = agent->string.data;
		e_type = type->string.data;
		goto no_agent;
	}
	if ( a->flags & AF_PASSWD ) {

		ret = check_user(
			env,s,
			a->group,
			agent->string.data,
			type->string.data,
			old_flag);
		if ( get_type(ret) == XLT_ERROR ) {
			if ( old_flag == 0 )
				out_lock_function(0);
			return ret;
		}
	}
	else ret = n_get_string("");


	if ( a->flags & AF_DIRCHECK ) {
	L_CHAR * pp;
		pp = agent->string.data;
	dir_st:
		switch ( *pp++ ) {
		case 0:
			goto dir_ok;
		case '.':
			goto dir_err;
		default:
			goto name1;
		}
	name1:
		switch ( *pp++ ) {
		case 0:
			goto dir_ok;
		case '/':
			goto dir_st;
		default:
			goto name1;
		}
	dir_err:
		if ( old_flag == 0 )
			out_lock_function(0);
		return get_error(
			s->h.file,
			s->h.line,
			XLE_PROTO_PERMISSION_DENIED,
			l_string(std_cm,"SetAgent"),
			n_get_string("invalid agent directory"));
	dir_ok:
		{}
	}
	if ( a->func ) {


		if ( a->env )
			ret = eval(a->env,
				List(	a->func,
					get_string(a->group),
					agent,
					type,
					ret,
					-1));
		else	ret = eval(env,
				List(	a->func,
					get_string(a->group),
					agent,
					type,
					ret,
					-1));
		switch ( get_type(ret) ) {
		case XLT_ERROR:
			if ( old_flag == 0 )
				out_lock_function(0);
			return ret;
		case XLT_STRING:
			break;
		default:
			goto type_missmatch_in_system;
		}
		xli = get_my_xli();


		log_output(xli,client,agent);


		ret = SetAgent_launch(
			s->h.file,s->h.line,
			ret->string.data,
			old_flag);

		if ( old_flag == 0 )
			out_lock_function(0);
		return ret;
	}
	else {


		xli = get_my_xli();
		log_output(xli,client,agent);
		if ( old_flag == 0 )
			out_lock_function(0);
		if ( a->env ) {
			xli->env = a->env;
			return n_get_string("ok");
		}
		else	return n_get_string("ok");
	}
type_missmatch:
	if ( old_flag == 0 )
		out_lock_function(0);
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"SetAgent"),
		0);
type_missmatch_in_system:
	if ( old_flag == 0 )
		out_lock_function(0);
	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"SetAgent Launch function"),
		0);
no_agent:
	if ( old_flag == 0 )
		out_lock_function(0);
	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_UNDEF_DATABASE,
		l_string(std_cm,"SetAgent"),
		List(n_get_string("undefined agent"),
			get_string(e_agent),
			get_string(e_type),
			-1));
}

