/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Connection Configuration Functions
 * ----------------------------------------------------------------
 * Copyright (C) 1997-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 (27.11.2007)
 *
 */

#define CONN_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 1		/* 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 */
#define NEED_ARES 0			/* Functions needed for ares */
#define NEED_SSL 1			/* Needed for SSL support */

#include "includes.h"
#include "irc.h"

#include "conf.h"

#include "conn_conf.h"
#include "conn.h"

/* VARIABLES - JONAS (31.07.2001) */

unsigned long int ConnConfs = 0;

struct ConnConf_Struct *ConnConf_Head = NULL;
struct ConnConf_Struct *ConnConf_Tail = NULL;

extern struct Conf_Struct ConfS;
extern unsigned short int Root;

/* CONN_CONF_READ FUNCTION - JONAS (31.07.2001) */

signed long int conn_conf_read(void) {

  char File[FILELEN+1] = "";
  FILE *FilePT = NULL;

  char *TempPT = NULL;

  char Line[LINELEN+1] = "";
  char *LinePT = NULL;

  unsigned short int Count = 0;

  char *EntryPT = NULL;

  struct ConnConf_Struct *ConnConf = NULL;
  struct ConnConfServer_Struct *ConnConfServer = NULL;

  struct Conn_Struct *ConnS = NULL;

  unsigned short int NextLineIsAServer = 0;
  unsigned short int UnsignedShortInt = 0;

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

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

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

  conn_conf_destroy();

  FOREVERLOOP {

    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 (NextLineIsAServer == TRUE) {

      char *HostPT = CONN_CONF_SERVERHOST_DEFAULT;
      char *PortPT = CONN_CONF_SERVERPORT_DEFAULT;
      char *PassPT = CONN_CONF_SERVERPASS_DEFAULT;

      if (EntryPT[0] == '}') { /* End of server list */
        NextLineIsAServer = FALSE;
        continue;
      }

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

      if (EntryPT != NULL) {
        PortPT = EntryPT;
        StrMovePastToken(EntryPT, ':');
      }

      if (LinePT != NULL) {
        PassPT = LinePT;
        StrMovePastToken(EntryPT, ':');
      }

      if (ConnConf != NULL) conn_conf_addserver(ConnConf, HostPT, strtoul(PortPT, NULL, 0), PassPT);
      continue;
    }

    if (strcasecmp(EntryPT, "CONNECTION") == FALSE) {

      char *NamePT = NULL;

      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Expecting connection name for \"CONNECTION\" definition.", File, Count);
        continue;
      }
      NamePT = LinePT;
      StrMovePastToken(LinePT, ' ');
      ConnConf = conn_conf_add(NamePT);
      assert(ConnConf != NULL);
      continue;
    }
    if (EntryPT[0] == '}') { ConnConf = NULL; continue; } /* End of connection */

    if (ConnConf == NULL) {
      sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Entry \"%s\" is invalid before a \"CONNECTION <Name> {\" definition.", File, Count, EntryPT);
      continue;
    }

    if (strcasecmp(EntryPT, "NICK") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in NICK definition.", File, Count);
        continue;
      }
      ConnConf->Nick = strrealloc(ConnConf->Nick, LinePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "AWAYNICK") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in AWAYNICK definition.", File, Count);
        continue;
      }
      ConnConf->AwayNick = strrealloc(ConnConf->AwayNick, LinePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "USER") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in USER definition.", File, Count);
        continue;
      }
      ConnConf->User = strrealloc(ConnConf->User, LinePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "HOST") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in HOST definition.", File, Count);
        continue;
      }
      ConnConf->Host = strrealloc(ConnConf->Host, LinePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "SERVERS") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing \"{\" in SERVERS definition.", File, Count);
        continue;
      }
      if (LinePT[0] == '{') { NextLineIsAServer = TRUE; continue; }
      sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Invalid SERVERS definition.", File, Count);
      continue;
    }
    else if ((strcasecmp(EntryPT, "MODE") == FALSE) || (strcasecmp(EntryPT, "USERMODE") == FALSE)) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in USERMODE definition.", File, Count);
        continue;
      }
      ConnConf->Mode = strrealloc(ConnConf->Mode, LinePT);
      continue;
    }
    else if ((strcasecmp(EntryPT, "INFO") == FALSE) || (strcasecmp(EntryPT, "USERINFO") == FALSE)) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in USERINFO definition.", File, Count);
        continue;
      }
      ConnConf->Info = strrealloc(ConnConf->Info, LinePT);
      continue;
    }
    else if ((strcasecmp(EntryPT, "CHANS") == FALSE) || (strcasecmp(EntryPT, "CHANNELS") == FALSE)) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in CHANNELS definition.", File, Count);
        continue;
      }
      ConnConf->Chans = strrealloc(ConnConf->Chans, LinePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "IPV6") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for IPV6 definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_IPV6; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_IPV6; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: IPV6 definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if (strcasecmp(EntryPT, "SSL") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for SSL definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_SSL; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_SSL; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: SSL definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if (strcasecmp(EntryPT, "AUTOCONNECT") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for AUTOCONNECT definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_AUTOCONNECT; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_AUTOCONNECT; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: AUTOCONNECT definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if (strcasecmp(EntryPT, "LOGGING") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for LOGGING definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_LOGGING; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_LOGGING; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: LOGGING definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if (strcasecmp(EntryPT, "AUTOAWAY") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for AUTOAWAY definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_AUTOAWAY; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_AUTOAWAY; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: AUTOAWAY definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if (strcasecmp(EntryPT, "PUBLICAWAY") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for PUBLICAWAY definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_PUBLICAWAY; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_PUBLICAWAY; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: PUBLICAWAY definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if (strcasecmp(EntryPT, "REGAINNICK") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for REGAINNICK definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_REGAINNICK; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_REGAINNICK; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: REGAINNICK definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if ((strcasecmp(EntryPT, "MAXCLIENTS") == FALSE) || (strcasecmp(EntryPT, "MAXUSERS") == FALSE)) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing numeric for MAXUSERS definition.", File, Count);
        continue;
      }
      UnsignedShortInt = atoi(LinePT);
      ConnConf->MaxClients = UnsignedShortInt;
      continue;
    }
    else if (strcasecmp(EntryPT, "MAXSENDLINES") == FALSE) {
      char *SendMaxLinesPT = NULL;
      char *SendLineTimePT = NULL;
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: The MAXSENDLINES definition must be followed by an \"Lines:Time\" entry.", File, Count);
        continue;
      }
      SendMaxLinesPT = LinePT;
      StrMovePastToken(LinePT, ':');
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: The MAXSENDLINES definition must be followed by an \"Lines:Time\" entry.", File, Count);
        continue;
      }
      SendLineTimePT = LinePT;
      ConnConf->SendMaxLines = atoi(SendMaxLinesPT);
      ConnConf->SendLineTime = atoi(SendLineTimePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "MAXSENDBUFFER") == FALSE) {
      char *SendMaxBufferPT = NULL;
      char *SendBufferTimePT = NULL;
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: The MAXSENDBUFFER definition must be followed by an \"Buffer:Time\" entry.", File, Count);
        continue;
      }
      SendMaxBufferPT = LinePT;
      StrMovePastToken(LinePT, ':');
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: The MAXSENDBUFFER definition must be followed by an \"Buffer:Time\" entry.", File, Count);
        continue;
      }
      SendBufferTimePT = LinePT;
      ConnConf->SendMaxBuffer = atoi(SendMaxBufferPT);
      ConnConf->SendBufferTime = atoi(SendBufferTimePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "AWAYMSG") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in AWAYMSG definition.", File, Count);
        continue;
      }
      ConnConf->AwayMsg = strrealloc(ConnConf->AwayMsg, LinePT);
      continue;
    }
    else if ((strcasecmp(EntryPT, "PUBLICDETACHMSG") == FALSE) || (strcasecmp(EntryPT, "PUBLICAWAYMSG") == FALSE)) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in PUBLICDETACHMSG definition.", File, Count);
        continue;
      }
      ConnConf->PublicDetachMsg = strrealloc(ConnConf->PublicDetachMsg, LinePT);
      continue;
    }
    else if ((strcasecmp(EntryPT, "PUBLICATTACHMSG") == FALSE) || (strcasecmp(EntryPT, "PUBLICBACKMSG") == FALSE)) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in PUBLICATTACHMSG definition.", File, Count);
        continue;
      }
      ConnConf->PublicAttachMsg = strrealloc(ConnConf->PublicAttachMsg, LinePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "CHANCYCLE") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing 0 or 1 for CHANCYCLE definition.", File, Count);
        continue;
      }
      if ((strcasecmp(LinePT, "y") == FALSE) || (strcasecmp(LinePT, "yes") == FALSE) || (strcasecmp(LinePT, "1") == FALSE)) { ConnConf->ConfFlags |= CONN_CONF_BITMASK_CHANCYCLE; }
      else if ((strcasecmp(LinePT, "n") == FALSE) || (strcasecmp(LinePT, "no") == FALSE) || (strcasecmp(LinePT, "0") == FALSE)) { ConnConf->ConfFlags &= ~CONN_CONF_BITMASK_CHANCYCLE; }
      else { sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: CHANCYCLE definition must be yes/no or 1/0.", File, Count); }
      continue;
    }
    else if (strcasecmp(EntryPT, "NICKSERVNUH") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in NICKSERVNUH definition.", File, Count);
        continue;
      }
      ConnConf->NickServNUH = strrealloc(ConnConf->NickServNUH, LinePT);
      continue;
    }
    else if (strcasecmp(EntryPT, "NICKSERVPASS") == FALSE) {
      if (LinePT == NULL) {
        sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Missing data in NICKSERVPASS definition.", File, Count);
        continue;
      }
      ConnConf->NickServPass = strrealloc(ConnConf->NickServPass, LinePT);
      continue;
    }



#if 0
    sysprint(BITMASK_ERROR, "Connection configuration error, file %s line %d: Unknown entry \"%s\" for CONNECTION definition.", File, Count, EntryPT);
#endif

  }
  fclose(FilePT);

  for (ConnConf = ConnConf_Head ; ConnConf != NULL ; ConnConf = ConnConf->Next) {
    DEBUGPRINT(BITMASK_DEBUG_CONF, "Adding connection: Name: %s - Nick: %s - Away Nick: %s - User: %s - Host: %s - Mode: %s - Info: %s - Chans: %s - Max Users: %d - Send Max Lines: %d - Send Line Time: %d - Send Max Buffer: %d - Send Buffer Time: %d.", ConnConf->Name, ConnConf->Nick, ConnConf->AwayNick, ConnConf->User, ConnConf->Host, ConnConf->Mode, ConnConf->Info, ConnConf->Chans, ConnConf->MaxClients, ConnConf->SendMaxLines, ConnConf->SendLineTime, ConnConf->SendMaxBuffer, ConnConf->SendBufferTime);
    if ((ConfS.UnixPasswd == TRUE) && (Root == TRUE)) {
      sysgetuidfromuser(ConnConf->User);
      if (aerrno != AESUCCESS) {
        sysprint(BITMASK_ERROR, "Connection configuration error, connection %s: Owner of connection user \"%s\" does not exist in %s.", ConnConf->Name, ConnConf->User, PASSWD_FILE);
      }
    }
    ConnS = conn_add(ConnConf);
    assert(ConnS != NULL);
    for (ConnConfServer = ConnConf->Server_Head ; ConnConfServer != NULL ; ConnConfServer = ConnConfServer->Next) {
      DEBUGPRINT(BITMASK_DEBUG_CONF, "Adding connection %s server: Host: %s - Port: %ld -.", ConnConf->Name, ConnConfServer->Host, ConnConfServer->Port);
      conn_addserver(ConnS, ConnConfServer->Host, ConnConfServer->Port, ConnConfServer->Pass);
    }
  }

  return(ConnConfs);

}

/* CONN_CONF_ADD - JONAS (31.07.2001) */

struct ConnConf_Struct *conn_conf_add(const char *const NamePT) {

  struct ConnConf_Struct *ConnConf = NULL;
  struct ConnConf_Struct *ConnConf_NEW = NULL;

  assert(NamePT != NULL);

  ConnConf = conn_conf_get(NamePT);
  if (ConnConf != NULL) {
    aerrno = AEEXISTS;
    return(ConnConf);
  }

  ConnConf_NEW = malloc(sizeof(struct ConnConf_Struct));
  if (ConnConf_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(ConnConf_NEW, 0, sizeof(struct ConnConf_Struct));

  ConnConf_NEW->Name = strdup(NamePT);
  ConnConf_NEW->Nick = strdup(CONN_CONF_NICK_DEFAULT);
  ConnConf_NEW->AwayNick = strdup(CONN_CONF_AWAYNICK_DEFAULT);
  ConnConf_NEW->User = strdup(CONN_CONF_USER_DEFAULT);
  ConnConf_NEW->Host = strdup(CONN_CONF_HOST_DEFAULT);
  ConnConf_NEW->Mode = strdup(CONN_CONF_USERMODE_DEFAULT);
  ConnConf_NEW->Info = strdup(CONN_CONF_USERINFO_DEFAULT);
  ConnConf_NEW->Chans = strdup(CONN_CONF_CHANS_DEFAULT);
  ConnConf_NEW->AwayMsg = strdup(CONN_CONF_AWAYMSG_DEFAULT);
  ConnConf_NEW->PublicDetachMsg = strdup(CONN_CONF_PUBLICAWAYMSG_DEFAULT);
  ConnConf_NEW->PublicAttachMsg = strdup(CONN_CONF_PUBLICBACKMSG_DEFAULT);
  ConnConf_NEW->NickServNUH = strdup(CONN_CONF_NICKSERVNUH_DEFAULT);
  ConnConf_NEW->NickServPass = strdup(CONN_CONF_NICKSERVPASS_DEFAULT);

  if (
     (ConnConf_NEW->Name == NULL) ||
     (ConnConf_NEW->Nick == NULL) ||
     (ConnConf_NEW->AwayNick == NULL) ||
     (ConnConf_NEW->User == NULL) ||
     (ConnConf_NEW->Host == NULL) ||
     (ConnConf_NEW->Mode == NULL) ||
     (ConnConf_NEW->Info == NULL) ||
     (ConnConf_NEW->Chans == NULL) ||
     (ConnConf_NEW->AwayMsg == NULL) ||
     (ConnConf_NEW->PublicDetachMsg == NULL) ||
     (ConnConf_NEW->PublicAttachMsg == NULL) ||
     (ConnConf_NEW->NickServNUH == NULL) ||
     (ConnConf_NEW->NickServPass == NULL)
    ) {
    free(ConnConf_NEW->Name);
    free(ConnConf_NEW->Nick);
    free(ConnConf_NEW->AwayNick);
    free(ConnConf_NEW->User);
    free(ConnConf_NEW->Host);
    free(ConnConf_NEW->Mode);
    free(ConnConf_NEW->Info);
    free(ConnConf_NEW->Chans);
    free(ConnConf_NEW->AwayMsg);
    free(ConnConf_NEW->PublicDetachMsg);
    free(ConnConf_NEW->PublicAttachMsg);
    free(ConnConf_NEW->NickServNUH);
    free(ConnConf_NEW->NickServPass);
    free(ConnConf_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  ConnConf_NEW->MaxClients = CONN_CONF_MAXCLIENTS_DEFAULT;
  ConnConf_NEW->SendMaxLines = CONN_CONF_SENDMAXLINES_DEFAULT;
  ConnConf_NEW->SendLineTime = CONN_CONF_SENDLINETIME_DEFAULT;
  ConnConf_NEW->SendMaxBuffer = CONN_CONF_SENDMAXBUFFER_DEFAULT;
  ConnConf_NEW->SendBufferTime = CONN_CONF_SENDBUFFERTIME_DEFAULT;

  if (ConnConf_Head == NULL) {
    ConnConf_Head = ConnConf_NEW;
    ConnConf_Tail = ConnConf_NEW;
  }
  else {
    ConnConf = ConnConf_Tail;
    ConnConf->Next = ConnConf_NEW;
    ConnConf_NEW->Prev = ConnConf;
    ConnConf_Tail = ConnConf_NEW;
  }

  ConnConfs++;

  aerrno = AESUCCESS;
  return(ConnConf_NEW);

}

/* CONN_CONF_REM FUNCTION - JONAS (31.07.2001) */

void conn_conf_rem(struct ConnConf_Struct *ConnConf) {

  assert(ConnConf != NULL);

  if (ConnConf->Prev == NULL) { ConnConf_Head = ConnConf->Next; }
  else { ConnConf->Prev->Next = ConnConf->Next; }

  if (ConnConf->Next == NULL) { ConnConf_Tail = ConnConf->Prev; }
  else { ConnConf->Next->Prev = ConnConf->Prev; }

  conn_conf_remservers(ConnConf);

  free(ConnConf->Name);
  free(ConnConf->Nick);
  free(ConnConf->AwayNick);
  free(ConnConf->User);
  free(ConnConf->Host);
  free(ConnConf->Mode);
  free(ConnConf->Info);
  free(ConnConf->Chans);
  free(ConnConf->AwayMsg);
  free(ConnConf->PublicDetachMsg);
  free(ConnConf->PublicAttachMsg);
  free(ConnConf->NickServNUH);
  free(ConnConf->NickServPass);
  free(ConnConf);

  ConnConfs--;

}

/* CONN_CONF_GET FUNCTION - JONAS (31.07.2001) */

struct ConnConf_Struct *conn_conf_get(const char *const NamePT) {

  struct ConnConf_Struct *ConnConf = NULL;

  assert(NamePT != NULL);

  for (ConnConf = ConnConf_Head ; ConnConf != NULL ; ConnConf = ConnConf->Next) {
    if (strcasecmp(ConnConf->Name, NamePT) == FALSE) {
      aerrno = AESUCCESS;
      return(ConnConf);
    }
  }
  aerrno = AENOMATCH;
  return(NULL);

}

/* CONN_CONF_DESTROY FUNCTION - JONAS (31.07.2001) */

void conn_conf_destroy(void) {

  while (ConnConf_Head != NULL) { conn_conf_rem(ConnConf_Head); }

}

/* CONN_CONF_ADDSERVER - JONAS (31.07.2001) */

struct ConnConfServer_Struct *conn_conf_addserver(struct ConnConf_Struct *ConnConf, const char *const HostPT, const unsigned long int Port, const char *const PassPT) {

  struct ConnConfServer_Struct *ConnConfServer = NULL;
  struct ConnConfServer_Struct *ConnConfServer_NEW = NULL;

  assert(ConnConf != NULL);
  assert(HostPT != NULL);
  assert(PassPT != NULL);

  ConnConfServer = conn_conf_getserver(ConnConf, HostPT);
  if (ConnConfServer != NULL) {
    aerrno = AEEXISTS;
    return(ConnConfServer);
  }

  ConnConfServer_NEW = malloc(sizeof(struct ConnConfServer_Struct));
  if (ConnConfServer_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(ConnConfServer_NEW, 0, sizeof(struct ConnConfServer_Struct));

  ConnConfServer_NEW->Host = strdup(HostPT);
  ConnConfServer_NEW->Pass = strdup(PassPT);
  ConnConfServer_NEW->Port = Port;

  if ((ConnConfServer_NEW->Host == NULL) || (ConnConfServer_NEW->Pass == NULL)) {
    free(ConnConfServer_NEW->Host);
    free(ConnConfServer_NEW->Pass);
    free(ConnConfServer_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  if (ConnConf->Server_Head == NULL) {
    ConnConf->Server_Head = ConnConfServer_NEW;
    ConnConf->Server_Tail = ConnConfServer_NEW;
  }
  else {
    ConnConfServer = ConnConf->Server_Tail;
    ConnConfServer->Next = ConnConfServer_NEW;
    ConnConfServer_NEW->Prev = ConnConfServer;
    ConnConf->Server_Tail = ConnConfServer_NEW;
  }

  ConnConf->Servers++;

  aerrno = AESUCCESS;
  return(ConnConfServer_NEW);

}

/* CONN_CONF_REMSERVER FUNCTION - JONAS (31.07.2001) */

void conn_conf_remserver(struct ConnConf_Struct *ConnConf, struct ConnConfServer_Struct *ConnConfServer) {

  assert(ConnConf != NULL);
  assert(ConnConfServer != NULL);

  if (ConnConfServer->Prev == NULL) { ConnConf->Server_Head = ConnConfServer->Next; }
  else { ConnConfServer->Prev->Next = ConnConfServer->Next; }

  if (ConnConfServer->Next == NULL) { ConnConf->Server_Tail = ConnConfServer->Prev; }
  else { ConnConfServer->Next->Prev = ConnConfServer->Prev; }

  free(ConnConfServer->Pass);
  free(ConnConfServer->Host);
  free(ConnConfServer);
  ConnConf->Servers--;

}

/* CONN_CONF_GET FUNCTION - JONAS (31.07.2001) */

struct ConnConfServer_Struct *conn_conf_getserver(struct ConnConf_Struct *ConnConf, const char *const HostPT) {

  struct ConnConfServer_Struct *ConnConfServer = NULL;

  assert(ConnConf != NULL);
  assert(HostPT != NULL);

  for (ConnConfServer = ConnConf->Server_Head ; ConnConfServer != NULL ; ConnConfServer = ConnConfServer->Next) {
    if (strcasecmp(ConnConfServer->Host, HostPT) == FALSE) {
      aerrno = AESUCCESS;
      return(ConnConfServer);
    }
  }
  aerrno = AENOMATCH;
  return(NULL);

}

/* CONN_CONF_REMSERVERS FUNCTION - JONAS (31.07.2001) */

void conn_conf_remservers(struct ConnConf_Struct *ConnConf) {

  while (ConnConf->Server_Head != NULL) { conn_conf_remserver(ConnConf, ConnConf->Server_Head); }

}


syntax highlighted by Code2HTML, v. 0.9.1