/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Auto-OP Configuration Functions
 * ----------------------------------------------------------------
 * Copyright (C) 2007 Jonas Kvinge <jonas@night-light.net>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Last modified by:
 * Jonas Kvinge (25.11.2007)
 *
 */

#define AUTOOP_CONF_C

#define NEED_SYS_TYPES_H 1		/* Extra types */
#define NEED_SYS_PARAM_H 1		/* Some systems need this */
#define NEED_LIMITS_H 0			/* Kernel limits */
#define NEED_STDARG_H 1			/* va_list, etc */
#define NEED_ERRNO_H 1			/* errno */
#define NEED_CTYPE_H 1			/* isdigit(), etc */
#define NEED_NETINET_IN_H 0		/* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 0		/* inet_ntoa(), inet_aton(), etc */
#define NEED_STDIO_H 1			/* Standard C UNIX functions */
#define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
#define NEED_TIME_H 1			/* time(), etc */
#define NEED_SYSCTL_H 0			/* sysctl(), etc */
#define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
#define NEED_SYS_UIO_H 0		/* iovec, etc */
#define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
#define NEED_SYS_IOCTL_H 0		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 0		/* Solaris need this for ioctl(), etc */
#define NEED_UNISTD_H 1			/* Unix standard functions */
#define NEED_STRING_H 1			/* C string functions */
#define NEED_SIGNAL_H 0			/* Signal functions */
#define NEED_SYS_SOCKET_H 0		/* Socket functions */
#define NEED_NETDB_H 0			/* Network database functions */
#define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */

#include "includes.h"

#include "conf.h"
#include "autoop_conf.h"

/* VARIABLES - JONAS (31.07.2001) */

unsigned long int AutoOPConfs = 0;

struct AutoOPConf_Struct *AutoOPConf_Head = NULL;
struct AutoOPConf_Struct *AutoOPConf_Tail = NULL;

extern struct Conf_Struct ConfS;

/* AUTOOP_CONF_READ FUNCTION - JONAS (31.07.2001) */

signed long int autoop_conf_read(void) {

  char File[FILELEN+1] = "";
  FILE *FilePT = NULL;
  unsigned short int Count = 0;
  struct AutoOPConf_Struct *AutoOPConf = NULL;

  DEBUGPRINT(BITMASK_DEBUG_CONF, "Reading AutoOP configuration file.");

  if (ConfS.AutoOPConfFile[0] != '/') {
    strncat(File, ConfS.DataPath, FILELEN);
    if (ConfS.DataPath[strlen(ConfS.DataPath)] != '/') { strncat(File, "/", (FILELEN - strlen(File))); }
  }
  strncat(File, ConfS.AutoOPConfFile, (FILELEN - strlen(File)));

  FilePT = fopen(File, "r");
  if (FilePT == NULL) {
    sysprint(BITMASK_ERROR, "Unable to open AutoOP configuration file %s: [%d] %s", File, errno, strerror(errno));
    return(ERROR);
  }

  autoop_conf_destroy();

  FOREVERLOOP {

    char Line[LINELEN+1] = "";
    char *LinePT = NULL;
    char *TempPT = NULL;
    char *EntryPT = NULL;
    char *NUHPT = NULL;
    char *ConnectionPT = NULL;
    char *ChansPT = NULL;
    char *ChanPT = NULL;

    memset(&Line, 0, LINELEN+1);
    TempPT = fgets(Line, LINELEN, FilePT);
    if (TempPT == NULL) { break; }
    ++Count;
    LinePT = Line;

    while ((TempPT = strchr(LinePT, '\r')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(LinePT, '\n')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(LinePT, '\t')) != NULL) { *TempPT = ' '; }

    while ((LinePT[0] == ' ') || (LinePT[0] == '\t')) { ++LinePT; }
    if ((LinePT[0] == '#') || (LinePT[0] == ';') || (LinePT[0] == '\0')) { continue; }

    EntryPT = LinePT;
    StrMovePastToken(LinePT, ':');

    if (strcasecmp(EntryPT, "AUTOOP") != FALSE) { continue; }

    if (LinePT == NULL) {
      sysprint(BITMASK_ERROR, "AutoOP configuration error in file %s line %d: Expecting more data.", File, Count);
      continue;
    }

    NUHPT = LinePT;
    StrMovePastToken(LinePT, ':');

    if (LinePT == NULL) {
      sysprint(BITMASK_ERROR, "AutoOP configuration error in file %s line %d: Expecting more data.", File, Count);
      continue;
    }
    ConnectionPT = LinePT;
    StrMovePastToken(LinePT, ':');

    if (LinePT == NULL) {
      sysprint(BITMASK_ERROR, "AutoOP configuration error in file %s line %d: Expecting more data.", File, Count);
      continue;
    }
    ChansPT = LinePT;

    AutoOPConf = autoop_conf_add(NUHPT, ConnectionPT);
    if (AutoOPConf == NULL) { continue; }

    while (ChansPT != NULL) {
      ChanPT = ChansPT;
      StrMovePastToken(ChansPT, ',');
      autoop_conf_addchan(AutoOPConf, ChanPT);
    }

  }

  fclose(FilePT);

  return(AutoOPConfs);

}

/* AUTOOP_CONF_ADD - JONAS (31.07.2001) */

struct AutoOPConf_Struct *autoop_conf_add(const char *const NUHPT, const char *const ConnectionPT) {

  struct AutoOPConf_Struct *AutoOPConf = NULL;
  struct AutoOPConf_Struct *AutoOPConf_NEW = NULL;

  assert(NUHPT != NULL);
  assert(ConnectionPT != NULL);

  DEBUGPRINT(BITMASK_DEBUG_CONF, "AutoOP configuration: NUH: %s Connection: %s", NUHPT, ConnectionPT);

  AutoOPConf_NEW = malloc(sizeof(struct AutoOPConf_Struct));
  if (AutoOPConf_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(AutoOPConf_NEW, 0, sizeof(struct AutoOPConf_Struct));

  AutoOPConf_NEW->NUH = strdup(NUHPT);
  AutoOPConf_NEW->Connection = strdup(ConnectionPT);

  if ((AutoOPConf_NEW->NUH == NULL) || (AutoOPConf_NEW->Connection == NULL)) {
    free(AutoOPConf_NEW->NUH);
    free(AutoOPConf_NEW->Connection);
    free(AutoOPConf_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  if (AutoOPConf_Head == NULL) {
    AutoOPConf_Head = AutoOPConf_NEW;
    AutoOPConf_Tail = AutoOPConf_NEW;
  }
  else {
    AutoOPConf = AutoOPConf_Tail;
    AutoOPConf->Next = AutoOPConf_NEW;
    AutoOPConf_NEW->Prev = AutoOPConf;
    AutoOPConf_Tail = AutoOPConf_NEW;
  }

  AutoOPConf++;

  aerrno = AESUCCESS;
  return(AutoOPConf_NEW);

}

/* AUTOOP_CONF_REM FUNCTION - JONAS (31.07.2001) */

void autoop_conf_rem(struct AutoOPConf_Struct *AutoOPConf) {

  assert(AutoOPConf != NULL);

  if (AutoOPConf->Prev == NULL) { AutoOPConf_Head = AutoOPConf->Next; }
  else { AutoOPConf->Prev->Next = AutoOPConf->Next; }

  if (AutoOPConf->Next == NULL) { AutoOPConf_Tail = AutoOPConf->Prev; }
  else { AutoOPConf->Next->Prev = AutoOPConf->Prev; }

  while (AutoOPConf->Chan_Head != NULL) { autoop_conf_remchan(AutoOPConf, AutoOPConf->Chan_Head); }

  free(AutoOPConf->NUH);
  free(AutoOPConf->Connection);

  free(AutoOPConf);

  AutoOPConf--;

}

/* AUTOOP_CONF_ADDCHAN - JONAS (31.07.2001) */

struct AutoOPConfChan_Struct *autoop_conf_addchan(struct AutoOPConf_Struct *AutoOPConf, const char *const ChanPT) {

  struct AutoOPConfChan_Struct *AutoOPConfChan = NULL;
  struct AutoOPConfChan_Struct *AutoOPConfChan_NEW = NULL;

  assert(AutoOPConf != NULL);
  assert(ChanPT != NULL);

  DEBUGPRINT(BITMASK_DEBUG_CONF, "AutoOP configuration: NUH: %s Connection: %s Chan: %s", AutoOPConf->NUH, AutoOPConf->Connection, ChanPT);

  AutoOPConfChan_NEW = malloc(sizeof(struct AutoOPConfChan_Struct));
  if (AutoOPConfChan_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(AutoOPConfChan_NEW, 0, sizeof(struct AutoOPConfChan_Struct));

  AutoOPConfChan_NEW->Chan = strdup(ChanPT);

  if (AutoOPConfChan_NEW->Chan == NULL) {
    free(AutoOPConfChan_NEW->Chan);
    free(AutoOPConfChan_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  if (AutoOPConf->Chan_Head == NULL) {
    AutoOPConf->Chan_Head = AutoOPConfChan_NEW;
    AutoOPConf->Chan_Tail = AutoOPConfChan_NEW;
  }
  else {
    AutoOPConfChan = AutoOPConf->Chan_Tail;
    AutoOPConfChan->Next = AutoOPConfChan_NEW;
    AutoOPConfChan_NEW->Prev = AutoOPConfChan;
    AutoOPConf->Chan_Tail = AutoOPConfChan_NEW;
  }

  AutoOPConf->Chans++;

  aerrno = AESUCCESS;
  return(AutoOPConfChan_NEW);

}

/* AUTOOP_CONF_REMCHAN FUNCTION - JONAS (31.07.2001) */

void autoop_conf_remchan(struct AutoOPConf_Struct *AutoOPConf, struct AutoOPConfChan_Struct *AutoOPConfChan) {

  assert(AutoOPConf != NULL);
  assert(AutoOPConfChan != NULL);

  if (AutoOPConfChan->Prev == NULL) { AutoOPConf->Chan_Head = AutoOPConfChan->Next; }
  else { AutoOPConfChan->Prev->Next = AutoOPConfChan->Next; }

  if (AutoOPConfChan->Next == NULL) { AutoOPConf->Chan_Tail = AutoOPConfChan->Prev; }
  else { AutoOPConfChan->Next->Prev = AutoOPConfChan->Prev; }

  free(AutoOPConfChan->Chan);
  free(AutoOPConfChan);

  AutoOPConf->Chans--;

}

/* AUTOOP_CONF_DESTROY FUNCTION - JONAS (31.07.2001) */

void autoop_conf_destroy(void) {

  while (AutoOPConf_Head != NULL) { autoop_conf_rem(AutoOPConf_Head); }

}


syntax highlighted by Code2HTML, v. 0.9.1