/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Connection 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 (24.11.2007)
 *
 */

#define CONN_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 1		/* 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 1		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 1		/* 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 1		/* Socket functions */
#define NEED_NETDB_H 1			/* 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 "access_conf.h"
#include "conn_conf.h"

#include "conn.h"
#include "conn_io.h"
#include "conn_connection.h"
#include "conn_sendq.h"
#include "conn_ignore.h"
#include "conn_log.h"

#include "chan.h"
#include "chan_user.h"

#include "client.h"
#include "client_handle.h"
#include "client_notice.h"

/* VARIABLES - JONAS (31.07.2001) */

struct Conn_Struct *Conn_Head = NULL;
struct Conn_Struct *Conn_Tail = NULL;
unsigned long int G_Conns = 0;

extern struct Client_Struct *Client_Head;

/* CONN_ADD FUNCTION - JONAS (22.07.2001) */

struct Conn_Struct *conn_add(struct ConnConf_Struct *ConnConf) {

  struct Conn_Struct *ConnS = NULL;
  struct Conn_Struct *ConnS_NEW = NULL;

  assert(ConnConf != NULL);

  ConnS = conn_get(ConnConf->Name);
  if (ConnS != NULL) {
    aerrno = AEEXISTS;
    return(ConnS);
  }

  ConnS_NEW = malloc(sizeof(struct Conn_Struct));
  if (ConnS_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }
  memset(ConnS_NEW, 0, sizeof(struct Conn_Struct));

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

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

  ConnS_NEW->ConfFlags = ConnConf->ConfFlags;
  ConnS_NEW->MaxClients = ConnConf->MaxClients;
  ConnS_NEW->SendMaxLines = ConnConf->SendMaxLines;
  ConnS_NEW->SendLineTime = ConnConf->SendLineTime;
  ConnS_NEW->SendMaxBuffer = ConnConf->SendMaxBuffer;
  ConnS_NEW->SendBufferTime = ConnConf->SendBufferTime;

  conn_initconnection(ConnS_NEW);

  if (Conn_Head == NULL) {
    Conn_Head = ConnS_NEW;
    Conn_Tail = ConnS_NEW;
  }
  else {
    ConnS = Conn_Tail;
    ConnS->Next = ConnS_NEW;
    ConnS_NEW->Prev = ConnS;
    Conn_Tail = ConnS_NEW;
  }

  G_Conns++;

  conn_log(ConnS_NEW, HOSTNAME, "", ""); /* Init the log file */

  aerrno = AESUCCESS;
  return(ConnS_NEW);

}

/* CONN_REM FUNCTION - JONAS (01.08.2001) */

void conn_rem(struct Conn_Struct *ConnS) {

  struct Client_Struct *ClientS = NULL;

  assert(ConnS != NULL);

  if (ConnS->Prev == NULL) { Conn_Head = ConnS->Next; }
  else { ConnS->Prev->Next = ConnS->Next; }

  if (ConnS->Next == NULL) { Conn_Tail = ConnS->Prev; }
  else { ConnS->Next->Prev = ConnS->Prev; }

  for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) {
    if (ClientS->ConnS == ConnS) {
      if (!Client_IsSentError(ClientS)) { client_notice(ClientS, "You are automatically detached from connection %s: Connection removed.", ConnS->Name); }
      client_detach(ClientS);
    }
  }

  conn_destroyignores(ConnS);
  conn_initconnection(ConnS);

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

  G_Conns--;

}

/* CONN_GET - JONAS (06.10.2000) */

struct Conn_Struct *conn_get(const char *const NamePT) {

  struct Conn_Struct *ConnS = NULL;

  assert(NamePT != NULL);

  for (ConnS = Conn_Head ; ConnS != NULL ; ConnS = ConnS->Next) {
    if (strwm(NamePT, ConnS->Name) == TRUE) {
      aerrno = AESUCCESS;
      return(ConnS);
    }
  }
  aerrno = AENOMATCH;
  return(NULL);

}

/* CONN_ADDSERVER - JONAS (31.07.2001) */

struct ConnServer_Struct *conn_addserver(struct Conn_Struct *ConnS, const char *const HostPT, const unsigned long int Port, const char *const PassPT) {

  struct ConnServer_Struct *ConnServer = NULL;
  struct ConnServer_Struct *ConnServer_NEW = NULL;

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

  ConnServer = conn_getserver(ConnS, HostPT);
  if (ConnServer != NULL) {
    aerrno = AEEXISTS;
    return(ConnServer);
  }

  ConnServer_NEW = malloc(sizeof(struct ConnServer_Struct));
  if (ConnServer_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }
  memset(ConnServer_NEW, 0, sizeof(struct ConnServer_Struct));

  ConnServer_NEW->Host = strdup(HostPT);
  ConnServer_NEW->Port = Port;

  if (ConnServer_NEW->Host == NULL) {
    free(ConnServer_NEW->Host);
    free(ConnServer_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  if (ConnS->Server_Head == NULL) {
    ConnS->Server_Head = ConnServer_NEW;
    ConnS->Server_Tail = ConnServer_NEW;
  }
  else {
    ConnServer = ConnS->Server_Tail;
    ConnServer->Next = ConnServer_NEW;
    ConnServer_NEW->Prev = ConnServer;
    ConnS->Server_Tail = ConnServer_NEW;
  }

  ConnS->NumServers++;

  aerrno = AESUCCESS;
  return(ConnServer_NEW);

}

/* CONN_REMSERVER FUNCTION - JONAS (31.07.2001) */

void conn_remserver(struct Conn_Struct *ConnS, struct ConnServer_Struct *ConnServer) {

  assert(ConnS != NULL);
  assert(ConnServer != NULL);

  if (ConnServer->Prev == NULL) { ConnS->Server_Head = ConnServer->Next; }
  else { ConnServer->Prev->Next = ConnServer->Next; }

  if (ConnServer->Next == NULL) { ConnS->Server_Tail = ConnServer->Prev; }
  else { ConnServer->Next->Prev = ConnServer->Prev; }

  free(ConnServer->Host);
  free(ConnServer);

  if (ConnS->ConnServerTry == ConnServer) { ConnS->ConnServerTry = NULL; }

  ConnS->NumServers--;

}

/* CONN_GETSERVER FUNCTION - JONAS (31.07.2001) */

struct ConnServer_Struct *conn_getserver(struct Conn_Struct *ConnS, const char *const HostPT) {

  struct ConnServer_Struct *ConnServer = NULL;

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

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

}

/* CONN_REMSERVERS FUNCTION - JONAS (31.07.2001) */

void conn_destroyservers(struct Conn_Struct *ConnS) {

  while (ConnS->Server_Head != NULL) { conn_remserver(ConnS, ConnS->Server_Head); }

}

/* CONN_INITCONNECTION FUNCTION - JONAS (01.08.2001) */

void conn_initconnection(struct Conn_Struct *ConnS) {

  unsigned short int Index = 0;

  assert(ConnS != NULL);

  DEBUGPRINT(BITMASK_DEBUG_CONN, "conn_initconnection(%s)", ConnS->Name);

  FREE(ConnS->FileName);
  ConnS->ResolveFlags = 0;
  FREE(ConnS->HostName);
  FREE(ConnS->HostIPS);
  memset(&ConnS->INAddr, 0, sizeof(ConnS->INAddr));
#if IPV6_SUPPORT
  memset(&ConnS->INAddr6, 0, sizeof(ConnS->INAddr6));
#endif
  ConnS->PortH = 0;
  ConnS->PortN = 0;

  ConnS->ServerResolveFlags = 0;
  FREE(ConnS->ServerHostName);
  FREE(ConnS->ServerHostIPS);
  memset(&ConnS->ServerINAddr, 0, sizeof(ConnS->ServerINAddr));
#if IPV6_SUPPORT
  memset(&ConnS->ServerINAddr6, 0, sizeof(ConnS->ServerINAddr6));
#endif
  ConnS->ServerPortH = 0;
  ConnS->ServerPortN = 0;
  FREE(ConnS->ServerPass);

  ConnS->ConnectionFlags = 0;
  ConnS->FD = FD_NONE;
  FREE(ConnS->ServerName);
  FREE(ConnS->IRCNick);
  for (Index = 0 ; Index <= 4 ; ++Index) { FREE(ConnS->Welcome[Index]); }
  for (Index = 0 ; Index < ConnS->ISupportLines ; ++Index) { free(ConnS->ISupport_String[Index]); }
  FREE(ConnS->ISupport_String);
  ConnS->ISupportLines = 0;
  ConnS->UserModeFlags = 0;
  ConnS->ChanModeFlags = 0;
  ConnS->ChanListModeFlags = 0;
  ConnS->ChanUserModeFlags = 0;
  conn_initsendq(ConnS);
  FREE(ConnS->RecvBuffer);
  FREE(ConnS->SendBuffer);
  ConnS->NicksIndex = 0;
  chan_destroy(ConnS);

  FREE(ConnS->ISupport.Network);
  ConnS->ISupport.Networks = 0;
  ConnS->ISupport.MaxModes = IRCMAXMODES;
  ConnS->ISupport.MaxChans = IRCMAXCHANS;
  ConnS->ISupport.MaxBans = IRCCHANMAXBANS;
  ConnS->ISupport.NickLen = IRCNICKLEN;
  ConnS->ISupport.AwayMsgLen = IRCAWAYMSGLEN;
  ConnS->ISupport.TopicLen = IRCCHANTOPICLEN;
  ConnS->ISupport.KickMsgLen = IRCCHANKICKMSGLEN;


}


syntax highlighted by Code2HTML, v. 0.9.1