/*
BOIL (Brunni's Own Interpreter Language)
(c) 1998 netEstate (http://www.netestate.de/, info@netestate.de),
Michael Brunnbauer & Markus Hendel, Gesellschaft fuer Netzwerkkommunikation bR
Am Bluetenanger 8, 80995 Muenchen, Germany

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
any later version.

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.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "general.h"
#include "handles.cc"
#include "boil.h"
#include "boil.tab.h"
#include "libs.h"

#ifdef WITH_RPC

#include "rpc.h"

void code_rpc_value(rpc_value* dest,type_value* src)
{
  static char empty[]="";

  dest->type=(enum rpc_data) src->type;
  switch (src->type)
    {
    case TYPE_VALUE_LONG:
      {
        dest->rpc_value_u.longval=src->val.longval;
        break;
      };
    case TYPE_VALUE_ULONG:
      {
        dest->rpc_value_u.ulongval=src->val.ulongval;
        break;
      };
    case TYPE_VALUE_DOUBLE:
      {
        dest->rpc_value_u.doubleval=src->val.doubleval;
        break;
      };
    case TYPE_VALUE_STRING:
      {
	if (defined(src->stringval))
	  {
	    dest->rpc_value_u.stringval.defined=1;
	    dest->rpc_value_u.stringval.stringval=src->stringval;
	  }
	else
	  {
	    dest->rpc_value_u.stringval.defined=0;
	    dest->rpc_value_u.stringval.stringval=empty;
	  };
        break;
      };
    case TYPE_VALUE_VOID:
      {
        break;
      };
    };

  return;
}

int decode_rpc_value(rpc_value* src,type_value* dest)
{
  dest->type=src->type;
  switch (src->type)
    {
    case TYPE_VALUE_LONG:
      {
        dest->val.longval=src->rpc_value_u.longval;
        break;
      };
    case TYPE_VALUE_ULONG:
      {
        dest->val.ulongval=src->rpc_value_u.ulongval;
        break;
      };
    case TYPE_VALUE_DOUBLE:
      {
        dest->val.doubleval=src->rpc_value_u.doubleval;
        break;
      };
    case TYPE_VALUE_STRING:
      {
	if (src->rpc_value_u.stringval.defined)
	  {
	    dest->stringval=src->rpc_value_u.stringval.stringval;
	  }
	else
	  {
	    dest->stringval=0;
	  };
        break;
      };
    case TYPE_VALUE_VOID:
      {
        break;
      };
    default:
      {
#ifdef DEBUGGING
        log(LOG_DEBUG,__FILE__,__LINE__,0,
            "decode_rpc_value: wrong type");
#endif
        return 0;
      };
    };

  return 1;
}

void code_rpc_accounting(rpc_accounting* dest,opt_a* src)
{
  for (unsigned long i=0;i!=ACCOUNTING_ANZ;i++)
    {
      dest->accounting[i].count_normal=src->accounting[i].count;
      dest->accounting[i].count_akt=src->accounting[i].count_akt;
      dest->accounting[i].count_time_sec=
        src->accounting[i].count_time.tv.tv_sec;
      dest->accounting[i].count_time_usec=
        src->accounting[i].count_time.tv.tv_usec;
    };
  return;
}

int decode_rpc_accounting(rpc_accounting* src,opt_a* dest)
{
  for (unsigned long i=0;i!=ACCOUNTING_ANZ;i++)
    {
      dest->accounting[i].count=src->accounting[i].count_normal;
      dest->accounting[i].count_akt=src->accounting[i].count_akt;
      dest->accounting[i].count_time.tv.tv_sec=
        src->accounting[i].count_time_sec;
      dest->accounting[i].count_time.tv.tv_usec=
        src->accounting[i].count_time_usec;
    };
  return 1;
}

void code_rpc_flowctrl(rpc_flowctrl* dest,flowctrl* src,opt_a* ptr_a)
{
  dest->ctrl=src->ctrl;
  code_rpc_value(&dest->returnval,&src->returnval);
  if (defined(src->error))
    {
      static rpc_error err;

      dest->error=&err;
      dest->error->error=src->error;
      dest->error->line=src->line;
    }
  else
    {
      dest->error=0;
    };

  if (ptr_a)
    {
      static rpc_accounting acc;
      dest->accounting=&acc;
      code_rpc_accounting(dest->accounting,ptr_a);
    }
  else
    {
      dest->accounting=0;
    };

  return;
}

int decode_rpc_flowctrl(rpc_flowctrl* src,flowctrl* dest,opt_a* ptr_a)
{
  dest->ctrl=src->ctrl;
  if (!decode_rpc_value(&src->returnval,&dest->returnval)) { return 0; };
  if (src->error)
    {
      dest->error=src->error->error;
      dest->line=src->error->line;
    }
  else
    {
      dest->error=0;
    };

  if (ptr_a && src->accounting)
    {
      return decode_rpc_accounting(src->accounting,ptr_a);
    };

  return 1;
}

void code_rpc_function_args(rpc_function_args* dest,
                            joined_list<type_value> *src)
{
  static rpc_value args[MAX_RPC_ARGS];

  dest->args.args_len=(*src).length();

  if ((*src).length())
    {
      dest->args.args_val=args;

      for (unsigned long i=0;i!=(*src).length() && i<MAX_RPC_ARGS;i++)
        {
          code_rpc_value(&dest->args.args_val[i],&(*src)[i]);
        };
    };
  return;
}

int decode_rpc_function_args(rpc_function_args* src,
                             joined_list<type_value> *dest)
{
  type_value dummy;

  for (unsigned long i=0;i!=src->args.args_len;i++)
    {
      if (!decode_rpc_value(&src->args.args_val[i],&dummy))
        { return 0; };
      (*dest).insert_listelem(dummy,(*dest).length());

    };
  return 1;
};

/* rpc server procedure */
rpc_flowctrl* boilrpc_call_1_svc(rpc_callargs *args, struct svc_req* rqstp)
{
  rqstp=rqstp;

  static flowctrl back;
  back.returnval.type=TYPE_VALUE_VOID;
  back.line=0;back.file=0;

  joined_list<type_value> function_args;
  type_value argument;
  type_function* function;

  static rpc_flowctrl rueck;

  /* get function */
  string funcname=args->function;
  back=getfunc(svc_run_block,svc_run_options,function,funcname);
  if (back.ctrl!=FLOW_OK)
    {
      log(LOG_WARN,__FILE__,__LINE__,ERROR_UNSPECIFIED,
	  "wrong function name: %s",(char*) args->function);
      sleep(3);
      back.error="wrong function name or password";
      code_rpc_flowctrl(&rueck,&back,0);
      return &rueck;
    };

  /* password OK ? */
  if (!defined(function->passwd) || function->passwd!=args->password)
    {
      log(LOG_WARN,__FILE__,__LINE__,ERROR_UNSPECIFIED,
          "wrong function password for %s: %s",
	  (char*) args->function,
	  (char*) args->password);
      sleep(3);
      back.ctrl=FLOW_EXIT;
      back.error="wrong function name or password";
      code_rpc_flowctrl(&rueck,&back,0);
      return &rueck;
    };

  /* decode argument list */
  if (!decode_rpc_function_args(&args->args,&function_args))
    {
      back.ctrl=FLOW_EXIT;
      back.error="error in args for "+(string) args->function;
      code_rpc_flowctrl(&rueck,&back,0);
      return &rueck;
    };

  /* call the function (preserve return value) */
  back=function->call(svc_run_block,svc_run_options,0,1,&function_args);

  /* generate flowctrl-info */
  if ((function->type==TYPE_FUNCTION_NORMAL ||
       function->type==TYPE_FUNCTION_EVAL) &&
      function->myblock->new_options.ptr_a)
    {
      code_rpc_flowctrl(&rueck,&back,
                        function->myblock->new_options.ptr_a);
    }
  else
    {
      code_rpc_flowctrl(&rueck,&back,0);
    };

  return &rueck;
}

#endif
