/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Listen Configuration Functions
 * ----------------------------------------------------------------
 * Copyright (C) 1997-2003 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.06.2001)
 *
 */

#define LISTEN_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 "conf.h"

#include "listen_conf.h"
#include "listen.h"

/* VARIABLES - JONAS (06.10.2000) */

struct ListenConf_Struct *ListenConf_Head = NULL;
struct ListenConf_Struct *ListenConf_Tail = NULL;
unsigned long int ListenConfs = 0;

extern struct Conf_Struct ConfS;

/* LISTEN_CONF_READ FUNCTION - JONAS (01.07.2000) */

signed long int listen_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;
  char *DataPT = NULL;
  char *HostPT = NULL;
  unsigned long int Port = 0;
  unsigned short int SSL = FALSE;
  unsigned short int IPv6 = FALSE;

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

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

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

  listen_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, ' ');
    DataPT = LinePT;

    DEBUGPRINT(BITMASK_DEBUG_CONF, "Listen Host: %s Data: %s", EntryPT, DataPT);

    if (strcasecmp(EntryPT, "LISTEN") == FALSE) {
      FREE(HostPT);
      Port = 0;
      IPv6 = 0;
      SSL = 0;
      continue;
    }
    if (EntryPT[0] == '}') {
      if (HostPT == NULL) { continue; }
      listen_conf_add(HostPT, Port, IPv6, SSL);
      FREE(HostPT);
      Port = 0;
      IPv6 = 0;
      SSL = 0;
      continue;
    }

    if (DataPT == NULL) {
      sysprint(BITMASK_ERROR, "Listen configuration error, file %s line %d: Expecting more data for \"%s\" entry.", File, Count, EntryPT);
      continue;
    }

    if (strcasecmp(EntryPT, "HOST") == FALSE) { HostPT = strrealloc(HostPT, DataPT); }
    else if (strcasecmp(EntryPT, "PORT") == FALSE) { Port = strtoul(DataPT, NULL, 0); }
    else if (strcasecmp(EntryPT, "IPV6") == FALSE) {
      if ((strcasecmp(DataPT, "y") == FALSE) || (strcasecmp(DataPT, "yes") == FALSE) || (strcasecmp(DataPT, "1") == FALSE)) { IPv6 = TRUE; }
      else { IPv6 = FALSE; }
    }
    else if (strcasecmp(EntryPT, "SSL") == FALSE) {
      if ((strcasecmp(DataPT, "y") == FALSE) || (strcasecmp(DataPT, "yes") == FALSE) || (strcasecmp(DataPT, "1") == FALSE)) { SSL = TRUE; }
      else { SSL = FALSE; }
    }

  }
  fclose(FilePT);
  free(HostPT);

  return(ListenConfs);

}

/* LISTEN_CONF_ADD FUNCTION - JONAS (06.10.2000) */

struct ListenConf_Struct *listen_conf_add(const char *const HostPT, const unsigned long int Port, const unsigned short int IPv6, const unsigned short int SSL) {

  struct ListenConf_Struct *ListenConf = NULL;
  struct ListenConf_Struct *ListenConf_NEW = NULL;

  struct Listen_Struct *ListenS = NULL;

  assert(HostPT != NULL);

  DEBUGPRINT(BITMASK_DEBUG_CONF, "Adding listen address: Host: %s - Port: %ld.", HostPT, Port);

  ListenConf = listen_conf_get(HostPT, Port, IPv6, SSL);
  if (ListenConf != NULL) {
    aerrno = AEEXISTS;
    return(ListenConf);
  }

  ListenConf_NEW = malloc(sizeof(struct ListenConf_Struct));
  if (ListenConf_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(ListenConf_NEW, 0, sizeof(struct ListenConf_Struct));

  ListenConf_NEW->Host = strdup(HostPT);
  if (ListenConf_NEW->Host == NULL) {
    free(ListenConf_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }
  ListenConf_NEW->Port = Port;
  ListenConf_NEW->SSL = SSL;
  ListenConf_NEW->IPv6 = IPv6;

  if (ListenConf_Head == NULL) {
    ListenConf_Head = ListenConf_NEW;
    ListenConf_Tail = ListenConf_NEW;
  }
  else {
    ListenConf = ListenConf_Tail;
    ListenConf->Next = ListenConf_NEW;
    ListenConf_NEW->Prev = ListenConf;
    ListenConf_Tail = ListenConf_NEW;
  }

  ListenConfs++;

  ListenS = listen_add(HostPT, Port);
  assert(ListenS != NULL);
  if (SSL == TRUE) { Listen_SetSSL(ListenS); }
  if (IPv6 == TRUE) { Listen_SetIPv6(ListenS); }

#if !SSL_SUPPORT
  if (SSL == TRUE) {
    sysprint(BITMASK_ERROR, "Listen configuration error, entry %s:%ld has SSL enabled, but %s was compiled without SSL support! Ignoring entry!", HostPT, Port, PACKAGE);
  }
#endif

  aerrno = AESUCCESS;
  return(ListenConf_NEW);

}

/* LISTEN_CONF_REM - JONAS (06.10.2000) */

void listen_conf_rem(struct ListenConf_Struct *ListenConf) {

  assert(ListenConf != NULL);

  if (ListenConf->Prev == NULL) { ListenConf_Head = ListenConf->Next; }
  else { ListenConf->Prev->Next = ListenConf->Next; }

  if (ListenConf->Next == NULL) { ListenConf_Tail = ListenConf->Prev; }
  else { ListenConf->Next->Prev = ListenConf->Prev; }

  free(ListenConf->Host);
  free(ListenConf);

  ListenConfs--;

}

/* LISTEN_CONF_GET - JONAS (06.10.2000) */

struct ListenConf_Struct *listen_conf_get(const char *const HostPT, const unsigned long int Port, const unsigned short int IPv6, const unsigned short int SSL) {

  struct ListenConf_Struct *ListenConf = NULL;

  assert(HostPT != NULL);

  for (ListenConf = ListenConf_Head ; ListenConf != NULL ; ListenConf = ListenConf->Next) {
    if ((strcasecmp(ListenConf->Host, HostPT) == FALSE) && (ListenConf->Port == Port) && (ListenConf->IPv6 == IPv6) && (ListenConf->SSL == SSL)) {
      aerrno = AESUCCESS;
      return(ListenConf);
    }
  }
  aerrno = AENOMATCH;
  return(NULL);

}

/* LISTEN_CONF_DESTROY FUNCTION - JONAS (31.07.2001) */

void listen_conf_destroy(void) {

  while (ListenConf_Head != NULL) { listen_conf_rem(ListenConf_Head); }

}


syntax highlighted by Code2HTML, v. 0.9.1