#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "global.h"
#include "field.h"

struct dom_t {
  char *name;
  struct dom_t *next;
};

struct conf_t {
  char *name;
  void (*func)(char *);
};

struct conf_t names[] = {
  { "AllowPassword", allowpassword_set },
  { "AllowDomain", add_domain },
  { "Verify", verify_set },
  { "Redirect", redirect_set },
  { "Password", password_set },
  { "PasswordLen", password_len_set },
  { "AdminEmail", adminemail_set },
  { "RegisterUser", registeruser_set },
  { "Subject", subject_set },
  { "DB_Host", db_host_set },
  { "DB_Name", use_db_set },
  { "DB_User", db_user_set },
  { "DB_Password", db_password_set },
  { "DB_Fields", db_fields_set },
  { "Advertise", advertise_set },
  { "BadHosts", badhosts_set },
  { NULL, NULL }
};

FILE *cstream = NULL;
struct dom_t *domlist = NULL, *domtail = NULL;
struct field_t *fields = NULL, *fields_tail = NULL;
char verify = 1, *redirect = NULL, *password = NULL,
     *adminemail = NULL, *registeruser = NULL, *subject = NULL,
     allowpassword = 0, *db_name = NULL, *db_user = NULL,
     *db_password = NULL, *db_host = NULL, advertise = 1,
     *badhosts = NULL;
int password_len = 8;

int config_open(char *conf)
{
  cstream = fopen(conf, "r");
  if (cstream == NULL)
     return 0;

  init_domains();
  init_fields();

  read_config();

  if (fields->next == NULL) {
     free(fields);
     fields = NULL;
  }

  return 1;  
}

void read_config(void)
{
  char b[255];
  
  while(1) {
    memset((char *)b, 0, 255);
    fgets(b, 255, cstream);

    if (feof(cstream))
       break;
    
    parse_config(b);
  }

  fclose(cstream);
}

void parse_config(char *b)
{
  char *p = NULL, *h = NULL, *d = NULL, *pp = NULL;

  if (*b == '#')
     return;

  while((*b == ' ') || (*b == '\t'))
    b++;

  if ((*b == '\n') || (*b == '\r'))
     return;

  for (p = b;;) {
      if (*p == ' ') {
         if (h == NULL) {
            h = b;
            *p++ = '\0';            
         }

         else if (d) {
            for (pp = (p + 1); *pp; pp++) {
                if ((*pp != ' ') && (*pp != '\t') &&
                    (*pp != '\n') && (*pp != '\r'))
                   break;

                else if ((*pp == '\n') || (*pp == '\r')) {
                   *p = '\0';
                   break;
                }
            }

            if (!(*p)) {
               p++;
               break;   
            }

            p++;
         }
      }

      else if ((*p == '\n') || (*p == '\r')) {
         *p = '\0';
         break;
      }

      else {
         if ((h) && (!d))
            d = p;

         p++;
      }
  }

  if ((h) && (d))
     conf_lookup(h, d);
}

void conf_lookup(char *name, char *data)
{
  char i = 0;

  for (i = 0; names[i].name; i++) {
      if (!(strcasecmp(names[i].name, name))) {
         names[i].func(data);
         return;
      }
  }
}

void init_domains(void)
{
  domlist = (struct dom_t *)malloc(sizeof(struct dom_t));
  if (domlist == NULL)
     tfatal();

  domlist->next = NULL;
  domtail = domlist;
}

void add_domain(char *dom)
{
  struct dom_t *d = NULL;

  d = (struct dom_t *)malloc(sizeof(struct dom_t));
  if (d == NULL)
     tfatal();

  d->name = mstrdup(dom);
  d->next = NULL;
  domtail->next = d;
  domtail = d; 
}

int is_domain(char *dom)
{
  struct dom_t *d = NULL;

  for (d = domlist; d->next; d = d->next) {
      if (!(strcasecmp(d->next->name, dom)))
         return 1;
  }

  return 0;
}

void show_html_domains(void)
{
  char *dom = NULL;
  struct dom_t *d = NULL;

  dom = cgi_is_var("dom");

  printf("<SELECT NAME=\"dom\">\n");

  for (d = domlist; d->next; d = d->next) {
      printf("<OPTION VALUE=\"%s\"", d->next->name);
      
      if ((dom) && (!(strcasecmp(d->next->name, dom))))
         printf(" SELECTED");
    
      else if (d == domlist) {
         if (dom == NULL)
            printf(" SELECTED");         
      }

      printf(">%s\n", d->next->name);
  }

  printf("</SELECT>");
}

void allowpassword_set(char *data)
{
  allowpassword = 0;

  if (!(strcasecmp(data, "ON")))
     allowpassword = 1;    
}

void verify_set(char *data)
{
  verify = 0;

  if (!(strcasecmp(data, "ON")))
     verify = 1;    
}

void redirect_set(char *data)
{
  if (redirect)
     free(redirect);

  redirect = mstrdup(data);
}

void password_set(char *data)
{
  if (password)
     free(password);
  
  password = mstrdup(data);
}

void password_len_set(char *data)
{
  password_len = atoi(data);
  
  if (password_len < 1)
     password_len = 8;
}

void adminemail_set(char *data)
{
  if (adminemail)
     free(adminemail);

  adminemail = mstrdup(data);

  global_par("CA", adminemail);
}

void registeruser_set(char *data)
{
  if (registeruser)
     free(registeruser);

  registeruser = mstrdup(data);

  global_par("CR", registeruser);
}

void subject_set(char *data)
{
  if (subject)
     free(subject);

  subject = mstrdup(data);

  global_par("CS", subject);
}

void db_host_set(char *data)
{
  if (db_host)
     free(db_host);

  db_host = mstrdup(data);
}

void use_db_set(char *data)
{
  if (db_name)
     free(db_name);

  db_name = mstrdup(data);
}

void db_user_set(char *data)
{
  if (db_user)
     free(db_user);

  db_user = mstrdup(data);
}

void db_password_set(char *data)
{
  if (db_password)
     free(db_password);

  db_password = mstrdup(data);
}

void db_fields_set(char *data)
{
  /*
     DATA: <field>[,<field>[,<etc>]]
  */
  
  char *h = NULL, *t = NULL, n = 0, **fields = NULL, i = 0,
       *tname = NULL;

  for (t = h = data; *h; h++) {
      if (*h == ' ')
         break;
  }

  /*
     No table name.
  */
  if (!(*h))
     return;

  tname = t;

  *h++ = '\0';

  /*
     Determine number of fields
     h is current data
     t stores current pointer
  */

  for (t = h; (*h) && (n < 50); h++) {
      if (*h == ',')
         n++;      
  }

  n++;

  /*
     No fields?
  */
  if (n < 1) {
     printf("No fields?\n");
     return;
  }

  fields = (char **)malloc(sizeof(char *) * (n + 1));
  if (fields == NULL)
     tfatal();  

  /*
     t stores current pointer
  */
  for (i = 0, h = t;;) {      
      if ((*h == ',') || (!(*h))) { 
         if (*h == ',')
            *h = '\0';

         else if (!(*h))
            h = NULL;

         fields[i] = mstrdup(t);
     
         i++;

         if (h == NULL)
            break;

         h++;
         t = h;
      }
      
      else
         h++;
  }

  fields[i] = NULL;

  /*
     tname = table
     fields = array of fields
  */

  add_fields(tname, fields);  
}

void init_fields(void)
{
  fields = (struct field_t *)malloc(sizeof(struct field_t));
  if (fields == NULL)
     tfatal();
  
  fields->next = NULL;
  fields_tail = fields;
}

void add_fields(char *tname, char **fields)
{
  struct field_t *f = NULL;

  f = (struct field_t *)malloc(sizeof(struct field_t));
  if (f == NULL)
     tfatal();

  f->tname = mstrdup(tname);
  f->fields = fields;

  f->next = NULL;

  fields_tail->next = f;
  fields_tail = f;
}

void advertise_set(char *data)
{
  advertise = 1;

  if (!(strcasecmp(data, "off")))
     advertise = 0;
}

void badhosts_set(char *data)
{
  if (badhosts)
     free(badhosts);

  badhosts = mstrdup(data);
}


syntax highlighted by Code2HTML, v. 0.9.1