#include "CListUsers.h"

CListUsers::CListUsers (CNetServer *server, c_char name) : CList (),
  filename (PATH_MAX)
{
  s = server;
  filename = name;
  if (!load_users ())
    mbot_exit ();
}

CListUsers::~CListUsers (void)
{
}

// load users from file, return 0 on failure
bool
CListUsers::load_users (void)
{
  ifstream f ((char *)filename);
  if (!f)
    {
      s->write_botlog ("error opening user file %s: %s", (char *)filename, strerror (errno));
      return 0;
    }
  char *b, *u_mask = NULL, *u_pass = NULL;
  int u_level = 0, line = 0;
  char buf[LINE_SIZE+1];
  while (f.getline (buf, LINE_SIZE))
    {
      line++;
      if (buf[0] == '#')
        continue;
      b = strtok (buf, ":");
      if (b != NULL)
        {
          u_mask = b;
          b = strtok (NULL, ":");
          if (b != NULL)
            {
              u_pass = b;
              b = strtok (NULL, ":");
              if (b != NULL)
                {
                  u_level = atoi (b);
                  b = strtok (NULL, "");
                  addlist_user (u_mask, u_pass, u_level, b);
                  continue;
                }
            }
        }
      s->bot->write_botlog ("error reading %s: invalid field (line %d)",
                            (c_char)filename, line);
      return 0;
    }
  return 1;
}

// save users to user file, return 0 on failure
bool
CListUsers::save_users (void)
{
  ofstream f ((c_char)filename);
  if (!f)
    {
      s->write_botlog ("error opening user file %s: %s", (c_char)filename, strerror (errno));
      return 0;
    }
  f << "# DON'T EDIT THIS FILE MANUALLY - USE MBOT COMMANDS INSTEAD\n";
  struct user_type *u;
  rewind ();
  while ((u = (struct user_type *)next ()) != NULL)
    f << u->mask << ":" << u->pass << ":" << u->level << ":"
      << (u->msg ? (char *)u->msg : "") << endl;
  return 1;
}

// <msg> can be NULL to disable it
void
CListUsers::addlist_user (c_char mask, c_char crypt_pass, int level, c_char msg)
{
  struct user_type *u = new struct user_type (mask, crypt_pass, level, msg);
  add (u);
}

// return 0 if not found
bool
CListUsers::dellist_user (c_char mask)
{
  struct user_type *u = abs_mask2user (mask);
  if (u == NULL)
    return 0;
  delete u;
  del (u);
  return 1;
}

// add a user, return 0 on failure
bool
CListUsers::add_user (c_char mask, c_char pass, int level, c_char msg)
{
  addlist_user (mask, crypt (pass, SALT), level, msg);
  return save_users ();
}

// delete a user, return 0 on failure
bool
CListUsers::del_user (const char *mask)
{
  if (!dellist_user (mask))
    return 0;
  return save_users ();
}

// return 1 if <pass> is user <mask>'s password
bool
CListUsers::match_check_pass (const char *mask, const char *pass)
{
  struct user_type *u = match_mask2user (mask);
  if (u == NULL || u->pass != crypt (pass, u->pass))
    return 0;
  return 1;
}

// set user <mask>'s password to <pass>
void
CListUsers::match_set_pass (c_char mask, c_char pass)
{
  struct user_type *u = match_mask2user (mask);
  if (u == NULL)
    return;
  u->pass = crypt (pass, SALT);
  save_users ();
}

void
CListUsers::abs_set_pass (c_char abs_mask, c_char pass)
{
  struct user_type *u = abs_mask2user (abs_mask);
  if (u == NULL)
    return;
  u->pass = crypt (pass, SALT);
  save_users ();
}

void
CListUsers::match_set_msg (c_char mask, c_char msg)
{
  struct user_type *u = match_mask2user (mask);
  if (u == NULL)
    return;
  u->msg = msg;
  save_users ();
}

void
CListUsers::abs_set_msg (const char *abs_mask, const char *msg)
{
  struct user_type *u = abs_mask2user (abs_mask);
  if (u == NULL)
    return;
  u->msg = msg;
  save_users ();
}

void
CListUsers::abs_set_mask (const char *abs_mask, const char *new_abs_mask)
{
  struct user_type *u = abs_mask2user (abs_mask);
  if (u == NULL)
    return;
  u->mask = new_abs_mask;
  save_users ();
}

void
CListUsers::match_set_level (const char *mask, int level)
{
  struct user_type *u = match_mask2user (mask);
  if (u == NULL)
    return;
  u->level = level;
  save_users ();
}

void
CListUsers::abs_set_level (c_char abs_mask, int level)
{
  struct user_type *u = abs_mask2user (abs_mask);
  if (u == NULL)
    return;
  u->level = level;
  save_users ();
}

void
CListUsers::match_set_id (c_char mask, bool id)
{
  struct user_type *u = match_mask2user (mask);
  if (u == NULL)
    return;
  u->id = id;
  if (id)
    u->cur_mask = mask;
  else
    u->cur_mask = NULL;
}

struct CListUsers::user_type *
CListUsers::match_mask2user (c_char mask)
{
  struct user_type *u;
  rewind ();
  while ((u = (struct user_type *)next ()) != NULL)
    if (match_mask (mask, u->mask))
      return u;
  return NULL;
}

struct CListUsers::user_type *
CListUsers::abs_mask2user (c_char abs_mask)
{
  struct user_type *u;
  rewind ();
  while ((u = (struct user_type *)next ()) != NULL)
    if (u->mask |= abs_mask)
      return u;
  return NULL;
}

int
CListUsers::match_mask_level (c_char mask)
{
  struct user_type *u = match_mask2user (mask);
  if (u != NULL)
    {
      if (u->level < 0)
        return u->level;
      else
        {
          if (u->id && u->cur_mask == mask)
            return u->level;
          else
            return 1;
        }
    }
  return 0;
}

int
CListUsers::match_mask_reallevel (c_char mask)
{
  struct user_type *u = match_mask2user (mask);
  if (u != NULL)
    return u->level;
  return 0;
}

