/*

  This is a module which probably no one will ever use ;) because giving
oper status to a bot is very risky. Anyway, this only implements a !kill
command. Use it by setting the oline's password (it uses the current nick's
oline):

ircop password

in the configuration file.

*/

#include "mbot.h"

#define LEVEL_KILL 9
#define IRCOP_PASS_SIZE MSG_SIZE

#define DEST s->script.dest
#define BUF s->script.buf
#define SEND_TEXT s->script.send_text

struct ircop_type {
  CNetServer *s;
  CString ircop_pass;			// ircop password
  bool ircop;				// if it is ircop
  ircop_type (CNetServer *server, c_char p) : s (server),
    ircop_pass (IRCOP_PASS_SIZE), ircop (0) {}
};
CList *ircop_list;

///////////////
// prototypes
///////////////

static void kill_cmd_kill (CNetServer *);

static ircop_type *server2ircop (CNetServer *);
static void ircop_reply (CNetServer *);
static void ircop_event (CNetServer *);
static void ircop_conf (CNetServer *, const char *);
static void ircop_stop (CModule *);
static void ircop_start (CModule *);

/////////////
// commands
/////////////

// !kill nick reason
static void
kill_cmd_kill (CNetServer *s)
{
  strsplit (CMD[3], BUF, 2);
  if (BUF[1][0] == 0)
    {
      SEND_TEXT (DEST, "usage: !kill nick reason");
      return;
    }
  if (s->nick |= BUF[1])		// doesn't kill itself
    SEND_TEXT (DEST, "%s", SCRIPT_HURT_BOT);
  else
    s->irc_kill (BUF[1], BUF[2]);
}

////////////////////
// module managing
////////////////////

// return the ircop for a given server, NULL if nonexistant
static ircop_type *
server2ircop (CNetServer *s)
{
  ircop_type *ircop;
  ircop_list->rewind ();
  while ((ircop = (ircop_type *)ircop_list->next ()) != NULL)
    if (ircop->s == s)
      return ircop;
  return NULL;
}

// look for the first server init reply, to identify as ircop
static void
ircop_reply (CNetServer *s)
{
  if (strcmp (CMD[1], INIT) == 0)
    {
      ircop_type *ircop = server2ircop (s);
      if (ircop != NULL)
        if (ircop->ircop_pass[0] && !ircop->ircop)
          {
            s->irc_oper (s->nick, ircop->ircop_pass);
            ircop->ircop = 1;
          }
    }
}

// look for the first server ping, to identify as ircop
static void
ircop_event (CNetServer *s)
{
  if (strcmp (CMD[0], "PING") == 0)
    {
      ircop_type *ircop = server2ircop (s);
      if (ircop != NULL)
        if (ircop->ircop_pass[0] && !ircop->ircop)
          {
            s->irc_oper (s->nick, ircop->ircop_pass);
            ircop->ircop = 1;
          }
    }
}

// configuration file's local parser
static void
ircop_conf (CNetServer *s, const char *bufread)
{
  char buf[3][MSG_SIZE+1];

  strsplit (bufread, buf, 2);

  if (strcasecmp (buf[0], "ircop") == 0)
    {
      if (server2ircop (s) == NULL)
        {
          ircop_type *ircop = new ircop_type (s, buf[1]);
          if (ircop == NULL)
            s->bot->conf_error ("error initializing ircop");
          ircop_list->add ((void *)ircop);
          s->script.events.add ((void *)ircop_event);
          s->script.replies.add ((void *)ircop_reply);
          s->script.bind_cmd (kill_cmd_kill, LEVEL_KILL, "!kill");
        } 
      else
        s->bot->conf_error ("ircop already defined for this server.");
    }
}

// module termination
static void
ircop_stop (CModule *m)
{
  ircop_type *ircop;
  ircop_list->rewind ();
  while ((ircop = (ircop_type *)ircop_list->next ()) != NULL)
    {
      ircop->s->script.events.del ((void *)ircop_event);
      ircop->s->script.replies.del ((void *)ircop_reply);
      ircop->s->script.unbind_cmd ("!kill");
      delete ircop;
    }
  delete ircop_list;
}

// module initialization
static void
ircop_start (CModule *m)
{
  ircop_list = new CList ();
}

struct CModule::module_type module = {
  MODULE_VERSION,
  "ircop",
  ircop_start,
  ircop_stop,
  ircop_conf,
  NULL
};
