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 <string.h>
#include <ctype.h>
#include "externs.h"
#include "config.h"

struct global_config_struct config;

struct config_types
{
  char *name;
  char **sptr;
  int *nptr;
  char *sdefault;
  int ndefault;
  bool type;   /* 0 = char *, 1 = int */
} configs[] =
{
  { "inet_port", NULL, &config.inet_port,
    NULL, 4201, 1 },
  { "root", NULL, &config.root,
    NULL, 1, 1 },
  { "connect_channel", &config.connect_channel, NULL,
    "Connections", 0, 0 },
  { "adm_connect_channel", &config.adm_connect_channel, NULL,
    "*connect", 0, 0 },
  { "maze_name", &config.maze_name, NULL,
    "TinyMAZE", 0, 0 },
  { "auto_create", NULL, &config.auto_create,
    NULL, 0, 1 },
  { "player_start", NULL, &config.player_start,
    NULL, 0, 1 },
  { "guest_start", NULL, &config.guest_start,
    NULL, 0, 1 },
  { "currency_name", &config.currency_name, NULL,
    "Credit", 0, 0 },
  { "currency_plural", &config.currency_plural, NULL,
    "Credits", 0, 0 },
  { "initial_wealth", NULL, &config.initial_wealth,
    NULL, 0, 1 },
  { "default_quota", NULL, &config.default_quota,
    NULL, 0, 1 },
  { "default_channel_quota", NULL, &config.default_channel_quota,
    NULL, 0, 1 },
  { "max_guests", NULL, &config.max_guests,
    NULL, 0, 1 },
  { "guest_prefix", &config.guest_prefix, NULL,
    "Guest", 0, 0 },
  { "guest_description", &config.guest_description, NULL,
    "Please help me if I need assistance.", 0, 0 },
  { "dump_interval", NULL, &config.dump_interval,
    NULL, 1800, 1 },
  { "dbck_interval", NULL, &config.dbck_interval,
    NULL, 600, 1 },
  { "max_output", NULL, &config.max_output,
    NULL, 16384, 1 },
  { "max_input", NULL, &config.max_input,
    NULL, 1024, 1 },
  { "max_server_io", NULL, &config.max_server_io,
    NULL, 0, 1 },
  { "max_player_io", NULL, &config.max_player_io,
    NULL, 0, 1 },
  { "max_users", NULL, &config.max_users,
    NULL, 50, 1 },
  { "max_queue", NULL, &config.max_queue,
    NULL, 100, 1 },
  { "db_name", &config.db_name, NULL,
    "db/mdb", 0, 0 },
  { "maildb_name", &config.maildb_name, NULL,
    "db/maildb", 0, 0 },
  { "connect_msg_file", &config.connect_msg_file, NULL,
    "msgs/connect.txt", 0, 0 },
  { "guest_msg_file", &config.guest_msg_file, NULL,
    "msgs/guest.txt", 0, 0 },
  { "leave_msg_file", &config.leave_msg_file, NULL,
    "msgs/leave.txt", 0, 0 },
  { "announce_cost", NULL, &config.announce_cost,
    NULL, 250, 1 },
  { "player_name_limit", NULL, &config.player_name_limit,
    NULL, 32, 1 },
  { "player_alias_limit", NULL, &config.player_alias_limit,
    NULL, 5, 1 },
  { "max_mail_age", NULL, (int *)&config.max_mail_age,
    NULL, 1800, 1 },
  { "old_mail_interval", NULL, &config.old_mail_interval,
    NULL, 1800, 1 },
  { "idle_boot_time", NULL, &config.idle_boot_time,
    NULL, 900, 1 },
  { NULL, NULL, NULL, 0 }
};

static void parse_line(char *str, char *setting, char *value)
{
  char buf[4096];
  char *b, *s, *v;

  strcpy(buf, str);
  *setting = *value = '\0';

  for(b = buf;isspace(*b);++b);  /* Whole loop */
  for(s = setting;*b && !isspace(*b);++b, ++s)
    *s = *b;
  *s = '\0';
  while(isspace(*b))
    b++;
  strcpy(value, b);
  v = value+strlen(value);
  if(v > value)
    v--;
  while(v > value && isspace(*v))
    v--;
  *(v+1) = '\0';
}

static int set_config(char *setting, char *value)
{
  struct config_types *c;

  for(c = configs;c->name;c++)
    if(!string_compare(c->name, setting))
      break;

  if(!c->name)
    return(0);

  switch(c->type)
  {
    case 0:
      stack_free(*(c->sptr));
      SET(*(c->sptr), value);
      break;
    case 1:
      *(c->nptr) = atoi(value);
      break;
    default:
      return(0);
  }

  return(1);
}

static void init_configs()
{
  struct config_types *c;

  for(c = configs;c->name;c++)
  {
    switch(c->type)
    {
      case 0:
        SET(*(c->sptr), c->sdefault);
        break;
      case 1:
        *(c->nptr) = c->ndefault;
        break;
      default:
        log_error(tprintf("GLOBAL CONFIG ERROR: Unknown type for config: %s",
          c->name));
        exit_nicely(1);
    }
  }
}

void read_global_config_file()
{
  char setting[4096], value[4096];
  char *read;
  FILE *fp;
  const char *filename = "../config/global_config";

  if(!(fp = fopen(filename, "r")))
  {
    log_error(tprintf("Couldn't open \"%s\" for reading!", filename));
    exit_nicely(1);
  }

  init_configs();

  while((read = get_next_line(fp)))
  {
    parse_line(read, setting, value);
    if(!set_config(setting, value))
      log_error(tprintf("GLOBAL CONFIG ERROR: Setting: %s, Value: %s",
        setting, value));
  }

  fclose(fp);
}

static void show_config_entry(OBJ *player, struct config_types *c)
{
  char buf[4096];

  if(c->type == 1)
    sprintf(buf, "%d", *(c->nptr));
  else
    strcpy(buf, *(c->sptr));

  notify(player, tprintf("|+B|%s|+W|: |+C|%s", c->name, buf));
}

static void write_config_file(void)
{
  FILE *fp;
  const char *filename = "../config/global_config";
  struct config_types *c;

  rename(filename, "../config/global_config.old");

  if(!(fp = fopen(filename, "w")))
  {
    log_error(tprintf("Couldn't open \"%s\" for writing!", filename));
    rename("../config/global_config.old", filename);
    return;
  }

  for(c = &configs[0];c->name;c++)
    fprintf(fp, "%s %s\n", c->name,
      (c->type == 1)?tprintf("%d", *(c->nptr)):*(c->sptr));

  fclose(fp);
}

void do_config(OBJ *player, char *arg1, char *arg2)
{
  struct config_types *c, *one = NULL;
  OBJ *o;

  if(*arg1)
  {
    for(one = &configs[0];one->name;one++)
      if(!string_compare(one->name, arg1))
        break;

    if(!one->name)
    {
      notify(player, tprintf("No such config field: %s", arg1));
      return;
    }
  }

  if(!*arg2)   /* They're not trying to modify anything */
  {
    if(!one)
    {
      for(c = &configs[0];c->name;c++)
        show_config_entry(player, c);
      return;
    }

    show_config_entry(player, one);
    return;
  }

  if(!power(player, POW_SECURITY))
  {
    notify(player, perm_denied());
    return;
  }

  if(!one)
  {
    notify(player, "Modify which config field?");
    return;
  }

  if(!strcmp(one->name, "inet_port"))
  {
    notify(player, "That config field may not be modified online.");
    return;
  }

  if(one->type == 1)
  {
    if(!isdigit(*arg2))
    {
      notify(player, tprintf("Illegal value '%s' for config field '%s'.",
        arg2, one->name));
      return;
    }

    *(one->nptr) = atoi(arg2);
  }
  else
  {
    if(!strcmp(one->name, "guest_prefix"))
    {
      for(o = player_list;o;o = o->next)
        if(Guest(o))
        {
          do_name(root_obj, tprintf("#%d", o->dbref),
            tprintf("%s%d", arg2, atoi(o->name+strlen(*(one->sptr)))));
          atr_add(o, "ALIAS", tprintf("%c%s", *arg2,
            atr_get(o, "ALIAS")+1));
        }
    }

    stack_free(*(one->sptr));
    SET(*(one->sptr), arg2);
  }

  write_config_file();

  show_config_entry(player, one);
  log_important(tprintf("Global config for '%s' has been changed to '%s' by %s",
    one->name, (one->type == 1)?tprintf("%d", *(one->nptr)):*(one->sptr),
    unparse_object(player, player)));
}

void free_global_config(void)
{
  struct config_types *c;

  for(c = &configs[0];c->name;c++)
    if(c->type == 0)
      stack_free(*(c->sptr));
}