TinyMAZE/
TinyMAZE/config/
TinyMAZE/doc/
TinyMAZE/run/msgs/
TinyMAZE/src/
TinyMAZE/src/db/
TinyMAZE/src/ident/
TinyMAZE/src/io/
TinyMAZE/src/prog/
TinyMAZE/src/softcode/
TinyMAZE/src/util/
#include <stdio.h>
#include <arpa/telnet.h>
#include "db.h"
#include "net.h"
#include "externs.h"

STATE state_list[] =
{
  { STATE_WAITCONNECT,     do_state_waitconnect     },
  { STATE_WAITLOGIN,       do_state_waitlogin       },
  { STATE_WAITPASS,        do_state_waitpass        },
  { STATE_CONNECTED,       NULL                     },
  { STATE_RELOADCONNECT,   NULL                     },
  { STATE_WAITINPUT,       NULL                     },
  { STATE_WAITPLAYERNAME,  do_state_waitplayername  },
  { STATE_WAITPLAYERPASS,  do_state_waitplayerpass  },
  { STATE_WAITPASSVERIFY,  do_state_waitpassverify  },
  { STATE_WAITPLAYEREMAIL, do_state_waitplayeremail },
  { -1, NULL }
};

static void do_login_screen(DDATA *d)
{
  queue_string(d, tprintf("Welcome to %s!\n", config.maze_name), 1);
  show_file(d, "msgs/welcome.txt");
  queue_string(d, tprintf("Server: %s\n", get_version()), 1);
  queue_string(d,
    "Login with your player name or type 'guest' to login as a guest.", 1);
  if(config.auto_create)
    queue_string(d,
      "Login as 'new' to create a character.\n", 1);
}

static OBJ *make_guest(DDATA *d)
{
  int i;
  OBJ *player;
  char *name = NULL;

  if(config.max_guests < 1)
  {
    queue_string(d, "Guest logins are not currently allowed. Sorry.", 1);
    return(NULL);
  }

  for(i = 1;i <= config.max_guests;i++)
  {
    name = tprintf("%s%d", config.guest_prefix, i);
    if(!(player = match_player(NULL, name)))
      break;

/* See if this guest is 'stale' */
    if(!is_connected_raw(player))
    {
      log_guest(tprintf("Destroying stale guest '%s'",
        unparse_object(player, player)));
      destroy_guest(player);
      break;
    }
  }

  if(i-1 == config.max_guests)
  {
    queue_string(d, "All guest ID's are busy; please try again later.", 1);
    return(NULL);
  }

  player = create_guest(name,
    tprintf("%c%d", *name, i), create_random_password());

  if(!player)
  {
    queue_string(d, "Error creating guest ID, please try again later.", 1);
    log_error(tprintf("Error creating guest ID. '%s' already exists.",
      name));
    return(NULL);
  }

  queue_string(d,
    tprintf("You are guest %d of %d.", i, config.max_guests), 1);

  return(player);
}

static void echo_on(DDATA *d)
{
  char echo_on_str[] = { IAC, WONT, TELOPT_ECHO, '\0' };

  queue_string(d, echo_on_str, 0);
}

static void echo_off(DDATA *d)
{
  char echo_off_str[] = { IAC, WILL, TELOPT_ECHO, '\0' };

  queue_string(d, echo_off_str, 0);
}

STATE *find_state(int state)
{
  STATE *s;

  for(s = state_list;s->num != -1;s++)
    if(s->num == state)
      break;

  return(s);
}

void set_state(DDATA *des, int state)
{
  STATE *s;

  if(!(s = find_state(state)))
  {
    log_error(tprintf("Unable to set state for descriptor %d to %d.",
      des->descriptor, state));
    return;
  }

  des->state = s;
}

int check_state(DDATA *des, int state)
{
  return((des->state->num == state));
}

int do_state_waitlogin(DDATA *d, char *str)
{
  char *login_msg = tprintf("%s Login: ", config.maze_name);

  if(!string_compare(str, "guest"))
  {
    if(!(d->player = make_guest(d)))
    {
      queue_string(d, login_msg, 0);
      return(0);
    }

    return(1);
  }

  if(!string_compare(str, "new"))
  {
    if(!config.auto_create)
    {
      queue_string(d, "Automatic player creation is disabled.", 1);
      queue_string(d, login_msg, 0);
      return(0);
    }

    queue_string(d, "Please enter desired name: ", 0);
    set_state(d, STATE_WAITPLAYERNAME);
    return(0);
  }

  if(!(d->player = match_player(NULL, str)))
  {
    queue_string(d, tprintf("Player '%s' doesn't exist.", str), 1);
    queue_string(d, login_msg, 0);
    return(0);
  }

  queue_string(d, tprintf("Password for %s: ", d->player->name), 0);
  echo_off(d);
  set_state(d, STATE_WAITPASS);
  return(0);
}

static void add_bad_login(DDATA *d)
{
  ATTR *attr = find_attr("BADLOGINS");
  char *msg = tprintf("%s@%s", d->user, d->addr);

  if(*atr_get_a(d->player, attr))
    atr_add_a(d->player, attr,
      tprintf("%s %s", atr_get_a(d->player, attr), msg));
  else
    atr_add_a(d->player, attr, msg);
}

int do_state_waitpass(DDATA *d, char *str)
{
  echo_on(d);

  if(!check_password(d->player, str))
  {
    log_io(tprintf("FAILED CONNECT '%s' on descriptor %d",
      name(d->player), d->descriptor));
    queue_string(d, "Invalid password.", 1);
    queue_string(d, tprintf("%s Login: ", config.maze_name), 0);
    set_state(d, STATE_WAITLOGIN);
    add_bad_login(d);
    d->player = NULL;
    return(0);
  }

  queue_string(d, "", 1);
  return(1);
}

int do_state_waitconnect(DDATA *d, char *str)
{
  do_login_screen(d);
  queue_string(d, tprintf("%s Login: ", config.maze_name), 0);
  set_state(d, STATE_WAITLOGIN);
  return(0);
}

int do_state_waitplayername(DDATA *d, char *str)
{
  if(!*str || !ok_player_name(NULL, strip_color(str), "") ||
    string_prefix(str, config.guest_prefix) || match_player(NULL, str))
  {
    queue_string(d,
      tprintf("Sorry, '%s' is not a valid player name.", str), 1);
    queue_string(d, "Please enter desired name: ", 0);
    return(0);
  }

  d->create_info = (struct create_info *)stack_alloc(sizeof(struct create_info), 1, 0);
  SET(d->create_info->name, str);
  d->create_info->password = NULL;

  echo_off(d);
  queue_string(d, "Please enter desired password: ", 0);
  set_state(d, STATE_WAITPLAYERPASS);
  return(0);
}

int do_state_waitplayerpass(DDATA *d, char *str)
{
  if(!ok_password(str))
  {
    queue_string(d, tprintf("Sorry, '%s' is not a valid password.", str), 1);
    queue_string(d, "Please enter desired password: ", 0);
    return(0);
  }

  SET(d->create_info->password, str);
  echo_off(d);
  queue_string(d, "Please re-enter password for verification: ", 0);
  set_state(d, STATE_WAITPASSVERIFY);
  return(0);
}

int do_state_waitpassverify(DDATA *d, char *str)
{
  if(strcmp(d->create_info->password, str))
  {
    queue_string(d, "Passwords don't match.", 1);
    queue_string(d, "Please enter desired password: ", 0);
    set_state(d, STATE_WAITPLAYERPASS);
    return(0);
  }

  SET(d->create_info->passverify, str);
  echo_on(d);
  queue_string(d, "Please enter your email address: ", 0);
  set_state(d, STATE_WAITPLAYEREMAIL);
  return(0);
}

int do_state_waitplayeremail(DDATA *d, char *str)
{
  if(!is_valid_email(str))
  {
    queue_string(d,
      tprintf("Sorry, '%s' is not a valid email address.", str), 1);
    queue_string(d, "Please enter your email address: ", 0);
    return(0);
  }

  if(!(d->player = create_player(d->create_info->name,
    d->create_info->password, CLASS_CITIZEN, player_start_obj)))
  {
    log_error(tprintf("Failure creating '%s'", d->create_info->name));
    queue_string(d, "Sorry, I couldn't create your character!", 1);
    shutdownsock(d);
    return(0);
  }

  d->player->creator = root_obj;
  atr_add(d->player, "EMAIL", str);

  stack_free(d->create_info->name);
  stack_free(d->create_info->password);
  stack_free(d->create_info->passverify);
  stack_free(d->create_info);

  queue_string(d, tprintf("\nWelcome to %s!\n", config.maze_name), 1);

  return(1);
}