// ScriptCommands.C  -*- C++ -*-
// Copyright (c) 1998 Etienne BERNARD
// Copyright (C) 2002 Clinton Ebadi

// 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.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef USESCRIPTS

#include "Utils.H"
#include "Server.H"
#include "ServerList.H"
#include "ScriptCommands.H"
#include "Interp.H"
#include <libguile.h>

#define VERIFY_STRING(par) if (!SCM_STRINGP((par))) \
                             return scm_long2num(-17)

#define VERIFY_NUMBER(par) if (!SCM_NUMBERP((par))) \
                             return scm_long2num(-17)

SCM
ScriptCommands::Action(SCM channel, SCM message)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(message);
  Message m = Commands::Action(Interp::bot, Utils::scm2String(channel),
                               Utils::scm2String(message));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::AddUser(SCM who, SCM maskChannel, SCM level, 
			SCM prot, SCM aop, SCM expire, SCM password)
{
  // It segfaults when not online, but otherwise appears to work
  VERIFY_STRING (who);
  VERIFY_STRING (maskChannel);
  VERIFY_NUMBER (level);

  String wwho = Utils::scm2String (who);
  String mask = Utils::scm2String (maskChannel);
  String passwd; 
  std::time_t eexpire;

  if (SCM_UNBNDP (password))
    passwd = "";
  else
    {
      VERIFY_STRING (password);
      passwd = Utils::scm2String (password);
    }
  if (SCM_UNBNDP (expire))
    eexpire = -1;
  else
    {
      VERIFY_STRING (expire);
      eexpire = Utils::strToTime (Utils::scm2String (expire));
      if (!eexpire) eexpire = -1;
    }

  int protect = scm_num2int (prot, SCM_ARG1, "ScriptCommands::AddUser");
  bool aaop = SCM_NFALSEP (aop);
  int llevel = scm_num2int (level, SCM_ARG1, 
				  "ScriptCommands::AddUser");

  Message m = Commands::AddUser (Interp::bot, wwho, mask, llevel, 
				 protect, aaop, eexpire, passwd);

  return scm_long2num(m.getCode ());
}

SCM
ScriptCommands::AddServer(SCM servername, SCM port)
{
  int p = 6667;
  if (SCM_NUMBERP(port))
    p = scm_num2long(port, SCM_ARG1, "ScriptCommands::AddServer");
  Message m = Commands::AddServer(Interp::bot,
                                  Utils::scm2String(servername),
                                  p);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::AddShit(SCM mask, SCM maskChannel, SCM level, 
			SCM expiration, SCM reason)
{
  // This appears to work...not much testing though
  VERIFY_STRING (mask);
  VERIFY_STRING (maskChannel);
  VERIFY_NUMBER (level);
  String mmask = Utils::scm2String (mask);
  String mmaskChannel = Utils::scm2String (maskChannel);
  int llevel = scm_num2int (level, SCM_ARG1, "ScriptCommands::AddShit");
  std::time_t expire;
  String rreason;

  if (SCM_UNBNDP (expiration))
    expire = -1;
  else
    {
      VERIFY_STRING (expiration);
      expire = Utils::strToTime (Utils::scm2String (expiration));
      if (!expire) expire = -1;
    }
  if (SCM_UNBNDP (reason))
    rreason = "You're on my shitlist, lamer";
  else
    {
      VERIFY_STRING (reason);
      rreason = Utils::scm2String (reason);
    }
  Message m = Commands::AddShit (Interp::bot, mmask, mmaskChannel,
				 llevel, expire, rreason);

  return scm_long2num(m.getCode ());
}

SCM
ScriptCommands::Ban(SCM channel, SCM who)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  Message m = Commands::Ban(Interp::bot, Utils::scm2String(channel),
                            Utils::scm2String(who));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Cycle(SCM channel)
{
  VERIFY_STRING(channel);
  Message m = Commands::Cycle(Interp::bot, Utils::scm2String(channel));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Deban(SCM channel, SCM who)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  Message m = Commands::Deban(Interp::bot, Utils::scm2String(channel),
                              Utils::scm2String(who));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::DelServer(SCM number)
{
  VERIFY_NUMBER(number);
  Message m = Commands::DelServer(Interp::bot, 
				  scm_num2long(number, SCM_ARG1, 
					       "ScriptCommands::DelServer"));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::DelUser(SCM who, SCM maskChannel)
{
  VERIFY_STRING(who);
  VERIFY_STRING(maskChannel);
  Message m = Commands::DelUser(Interp::bot, Utils::scm2String(who),
                                Utils::scm2String(maskChannel));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::DelShit(SCM who, SCM maskChannel)
{
  VERIFY_STRING(who);
  VERIFY_STRING(maskChannel);
  Message m = Commands::DelShit(Interp::bot, Utils::scm2String(who),
                                Utils::scm2String(maskChannel));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Deop(SCM channel, SCM who)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  Message m = Commands::Deop(Interp::bot, Utils::scm2String(channel),
                             Utils::scm2String(who));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Die(SCM reason)
{
  String r = "Leaving";
  if (SCM_STRINGP(reason))
    r = Utils::scm2String(reason);
  Message m = Commands::Die(Interp::bot, r);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Do(SCM command)
{
  VERIFY_STRING(command);
  Message m = Commands::Do(Interp::bot, Utils::scm2String(command));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Invite(SCM channel, SCM who)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  Message m = Commands::Invite(Interp::bot, Utils::scm2String(channel),
                               Utils::scm2String(who));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Join(SCM channel, SCM key)
{
  VERIFY_STRING(channel);
  String k = "";
  if (SCM_STRINGP(key))
    k = Utils::scm2String(key);
  Message m = Commands::Join(Interp::bot, Utils::scm2String(channel),
                             k);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Keep(SCM channel, SCM modes)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(modes);
  Message m = Commands::Keep(Interp::bot, Utils::scm2String(channel),
                             Utils::scm2String(modes));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Kick(SCM channel, SCM who, SCM reason)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);

  String r = "";
  if (SCM_STRINGP(reason))
    r = Utils::scm2String(reason);

  Message m = Commands::Kick(Interp::bot, Utils::scm2String(channel),
                             Utils::scm2String(who), r);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::KickBan(SCM channel, SCM who, SCM reason)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  String r = "";
  if (SCM_STRINGP(reason))
    r = Utils::scm2String(reason);
  Message m = Commands::KickBan(Interp::bot, Utils::scm2String(channel),
                                Utils::scm2String(who), r);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Lock(SCM channel)
{
  VERIFY_STRING(channel);
  Message m = Commands::Lock(Interp::bot, Utils::scm2String(channel));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::LogPort(void)
{
  return Interp::bot->botInterp->logPort;
}

SCM
ScriptCommands::Mode(SCM channel, SCM mode)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(mode);
  Message m = Commands::Mode(Interp::bot, Utils::scm2String(channel),
                             Utils::scm2String(mode));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Msg(SCM nick, SCM message)
{
  VERIFY_STRING(nick);
  VERIFY_STRING(message);
  Message m = Commands::Msg(Interp::bot, Utils::scm2String(nick),
                            Utils::scm2String(message));
  return scm_long2num(m.getCode());

}

SCM
ScriptCommands::NextServer(void)
{
  Message m = Commands::NextServer(Interp::bot);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Nick(SCM nick)
{
  VERIFY_STRING(nick);
  Message m = Commands::Nick(Interp::bot, Utils::scm2String(nick));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Op(SCM channel, SCM who)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  Message m = Commands::Op(Interp::bot, Utils::scm2String(channel),
                           Utils::scm2String(who));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Part(SCM channel)
{
  VERIFY_STRING(channel);
  Message m = Commands::Part(Interp::bot, Utils::scm2String(channel));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Reconnect(void)
{
  Message m = Commands::Reconnect(Interp::bot);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Say(SCM channel, SCM message)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(message);
  Message m = Commands::Say(Interp::bot, Utils::scm2String(channel),
                            Utils::scm2String(message));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Server(SCM number)
{
  VERIFY_NUMBER(number);
  Message m = Commands::Server(Interp::bot, gh_scm2long(number));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::SetVersion(SCM version)
{
  Message m = Commands::SetVersion(Interp::bot, Utils::scm2String(version));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::TBan(SCM channel, SCM who, SCM seconds)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  VERIFY_NUMBER(seconds);
  Message m = Commands::TBan(Interp::bot, Utils::scm2String(channel),
                             Utils::scm2String(who), gh_scm2long(seconds));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::TKBan(SCM channel, SCM who, SCM seconds, SCM reason)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(who);
  VERIFY_NUMBER(seconds);
  String r = "";
  if (SCM_STRINGP(reason))
    r = Utils::scm2String(reason);
  Message m = Commands::TKBan(Interp::bot, Utils::scm2String(channel),
                              Utils::scm2String(who),
                              gh_scm2long(seconds), r);
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Topic(SCM channel, SCM topic)
{
  VERIFY_STRING(channel);
  VERIFY_STRING(topic);
  Message m = Commands::Topic(Interp::bot, Utils::scm2String(channel),
                              Utils::scm2String(topic));
  return scm_long2num(m.getCode());
}

SCM
ScriptCommands::Unlock(SCM channel)
{
  VERIFY_STRING(channel);
  Message m = Commands::Unlock(Interp::bot, Utils::scm2String(channel));
  return scm_long2num(m.getCode());
}




SCM
ScriptCommands::getNickname(void)
{
  return Utils::string2SCM(Interp::bot->nickName);
}

SCM
ScriptCommands::getServer(void)
{
  ::Server *serv = Interp::bot->serverList->currentServer();
  int serverNumber = Interp::bot->serverList->currentNumber;

  return gh_list(scm_long2num(serverNumber),
                 Utils::string2SCM(serv->getHostName()),
                 scm_long2num(serv->getPort()),
                 Utils::string2SCM(serv->getPassword()),
                 SCM_UNDEFINED);
}

SCM
ScriptCommands::getServerList(void)
{
  SCM res = gh_list(SCM_UNDEFINED);
  ::Server *s;
  int i = 0;
  std::vector<class Server *>::iterator it = Interp::bot->serverList->begin();

  for ( ; it != Interp::bot->serverList->end(); ++it) {
    s = (*it);
    res = gh_append2(res,
                     gh_list(gh_list(scm_long2num(i++),
                                     Utils::string2SCM(s->getHostName()),
                                     scm_long2num(s->getPort()),
                                     Utils::string2SCM(s->getPassword()),
                                     SCM_UNDEFINED), SCM_UNDEFINED));
  }
  return res;
}

SCM
ScriptCommands::flushQueue(void)
{
  if (!Interp::bot->serverConnection)
    return SCM_BOOL_F;
  Interp::bot->serverConnection->queue->flush();
  return SCM_BOOL_T;
}

SCM
ScriptCommands::flushPort(void)
{
  scm_flush(Interp::bot->botInterp->logPort);
  return SCM_BOOL_T;
}

SCM
ScriptCommands::random(SCM scm_max)
{
  int max = 0;
  //srand(time(NULL));
  if (SCM_NUMBERP(scm_max))
    max = gh_scm2int(scm_max);
  return scm_long2num(max ? rand() % max : 0);
}

SCM
ScriptCommands::addCommand(SCM scm_commandName, SCM scm_function,
                           SCM scm_needsChannel, SCM scm_args,
                           SCM scm_minLevel)
{
  // We check that commandName is a string
  if (!SCM_STRINGP(scm_commandName))
    return SCM_BOOL_F;

  // We check that the command does not exist
  String commandName = Utils::scm2String(scm_commandName).toUpper();
  std::list<class userFunction *>::iterator it =
    Interp::bot->userFunctions.begin();
  for ( ; it != Interp::bot->userFunctions.end(); ++it) {
    if ((*it)->name == commandName)
      return SCM_BOOL_F;
  }

  // Next we check that needsChannel is a boolean
  if (!gh_boolean_p(scm_needsChannel))
    return SCM_BOOL_F;
  bool needsChannel = (bool)gh_scm2bool(scm_needsChannel);

  // We check that minLevel is an integer and that it's
  // a valid level
  if (!SCM_NUMBERP(scm_minLevel))
    return SCM_BOOL_F;

  int minLevel = gh_scm2long(scm_minLevel);
  if (minLevel < User::NONE || minLevel > User::MASTER)
    return SCM_BOOL_F;

  // We check that "scm_function" is a Scheme procedure
  if (!gh_procedure_p(scm_function))
    return SCM_BOOL_F;

  // We check that args is an integer and is between 0 and 20 (arbitrary limit)
  if (!SCM_NUMBERP(scm_args))
    return SCM_BOOL_F;

  int args = gh_scm2long(scm_args);
  if (args < 0 || args > 20)
    return SCM_BOOL_F;

  // We add the command in the commands list
  Interp::bot->userFunctions.push_back(new userFunction(commandName, 
(void (*)(ServerConnection *, Person *, String, String))0, minLevel, needsChannel, args, scm_function));

  return SCM_BOOL_T;
}

SCM
ScriptCommands::delCommand(SCM scm_commandName)
{
  // We check that commandName is a string
  if (!SCM_STRINGP(scm_commandName))
    return SCM_BOOL_F;

  // We check that the command does exist
  String commandName = Utils::scm2String(scm_commandName).toUpper();
  std::list<class userFunction *>::iterator it =
    Interp::bot->userFunctions.begin();
  for ( ; it != Interp::bot->userFunctions.end(); ++it) {
    if ((*it)->name == commandName)
      break;
  }

  if (it == Interp::bot->userFunctions.end())
    return SCM_BOOL_F;

  // We delete the command
  Interp::bot->userFunctions.erase(it);
  delete (*it);

  return SCM_BOOL_T;
}

SCM
ScriptCommands::AddHook(SCM type, SCM regex, SCM function)
{
  return gh_bool2scm(Interp::bot->botInterp->AddHook(gh_scm2long(type),
                                                     regex, function));
}

SCM
ScriptCommands::AddTimer(SCM when, SCM function)
{
  return Interp::bot->botInterp->AddTimer(gh_scm2long(when), function);
}

SCM
ScriptCommands::DelTimer(SCM timer)
{
  return gh_bool2scm(Interp::bot->botInterp->DelTimer(timer));
}

#endif


syntax highlighted by Code2HTML, v. 0.9.1