/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Channel
 * ----------------------------------------------------------------
 * Copyright (C) 1997-2006 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.08.2004)
 *
 */

#define CHAN_C

#define NEED_SYS_TYPES_H 1		/* Extra types */
#define NEED_SYS_PARAM_H 1		/* Some systems need this */
#define NEED_LIMITS_H 1			/* 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 "conn.h"
#include "chan.h"
#include "chan_user.h"
#include "chan_mode.h"

/* VARIABLES - JONAS (30.07.2001) */

static CHAN_HASHMEMS Chan_Hash_Map[CHAN_HASHMAPSIZE];
static CHAN_HASHMEMS Chan_Hash_Weight_Table[CHAR_MAX - CHAR_MIN + 1];

/* CHAN_ADD FUNCTION - JONAS (30.07.2001) */

struct Chan_Struct *chan_add(struct Conn_Struct *ConnS, const char *const ChanPT) {

  struct Chan_Struct *ChanS = NULL;
  struct Chan_Struct *ChanS_NEW = NULL;
  CHAN_HASHREGS Hash = 0;

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

  ChanS = chan_get(ConnS, ChanPT);
  if (ChanS != NULL) {
    aerrno = AEEXISTS;
    return(ChanS);
  }

  ChanS_NEW = malloc(sizeof(struct Chan_Struct));
  if (ChanS_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(ChanS_NEW, 0, sizeof(struct Chan_Struct));

  ChanS_NEW->Chan = strdup(ChanPT);
  if (ChanS_NEW->Chan == NULL) {
    free(ChanS_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  if (ConnS->Chan_Head == NULL) {
    ConnS->Chan_Head = ChanS_NEW;
    ConnS->Chan_Tail = ChanS_NEW;
  }
  else {
    ChanS = ConnS->Chan_Tail;
    ChanS->Next = ChanS_NEW;
    ChanS_NEW->Prev = ChanS;
    ConnS->Chan_Tail = ChanS_NEW;
  }

  Hash = chan_strhash(ChanS_NEW->Chan);

  ChanS = ConnS->Chan_Table[Hash];
  if (ChanS != NULL) { ChanS->PrevH = ChanS_NEW; }

  ChanS_NEW->NextH = ChanS;
  ConnS->Chan_Table[Hash] = ChanS_NEW;

  ConnS->NumChans++;

  aerrno = AESUCCESS;
  return(ChanS_NEW);

}

/* CHAN_REM FUNCTION - JONAS (30.07.2001) */

void chan_rem(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) {

  CHAN_HASHREGS Hash = 0;
  struct Chan_Struct *ChanH = NULL;

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

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

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

  Hash = chan_strhash(ChanS->Chan);
  for (ChanH = ConnS->Chan_Table[Hash] ; ((ChanH != NULL) && (ChanH != ChanS)) ; ChanH = ChanH->NextH);
  assert(ChanH == ChanS);

  if (ChanH->PrevH != NULL) { ChanH->PrevH->NextH = ChanH->NextH; }
  if (ChanH->NextH != NULL) { ChanH->NextH->PrevH = ChanH->PrevH; }

  if (ConnS->Chan_Table[Hash] == ChanH) { ConnS->Chan_Table[Hash] = ChanH->NextH; }

  chan_init(ConnS, ChanS);

  free(ChanS);

  ConnS->NumChans--;

}

/* CHAN_GET FUNCTION - JONAS (30.07.2001) */

struct Chan_Struct *chan_get(struct Conn_Struct *ConnS, const char *const ChanPT) {

  CHAN_HASHREGS Hash = 0;
  struct Chan_Struct *ChanS = NULL;
  struct Chan_Struct *ChanH = NULL;

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

  Hash = chan_strhash(ChanPT);
  for (ChanS = ConnS->Chan_Table[Hash] ; ((ChanS != NULL) && (strcasecmp(ChanPT, ChanS->Chan) != FALSE)) ; ChanS = ChanS->NextH);

  if (ChanS == NULL) {
    aerrno = AENOMATCH;
    return(NULL);
  }

  if (ChanS != ConnS->Chan_Table[Hash]) {
    if (ChanS->PrevH != NULL) { ChanS->PrevH->NextH = ChanS->NextH; }
    if (ChanS->NextH != NULL) { ChanS->NextH->PrevH = ChanS->PrevH; }
    ChanH = ConnS->Chan_Table[Hash];
    ChanH->PrevH = ChanS;
    ChanS->PrevH = NULL;
    ChanS->NextH = ChanH;
    ConnS->Chan_Table[Hash] = ChanS;
  }

  aerrno = AESUCCESS;
  return(ChanS);

}

/* CHAN_HASH_INIT FUNCTION - JONAS (26.07.2001) */

void chan_hash_init(void) {

  signed short int Index1 = 0;
  signed short int Index2 = 0;

  unsigned long Count1 = 0;
  unsigned long Count2 = 0;

  for (Index1 = CHAR_MIN ; Index1 <= CHAR_MAX ; Index1++) {
    Chan_Hash_Weight(Index1) = (CHAN_HASHMEMS) (CHAN_HASHSTEP * ((char) Index1));
  }

  for (Index1 = CHAR_MIN ; Index1 <= CHAR_MAX ; Index1++) {
    for (Index2 = CHAR_MIN ; Index2 < Index1 ; Index2++) {
      if (HASHEQ(Index1, Index2)) {
        Chan_Hash_Weight(Index1) = Chan_Hash_Weight(Index2);
      }
    }
  }

  for (Count1 = 0 ; Count1 < (unsigned long) CHAN_HASHMAPSIZE ; Count1++) {

    Count2 = Count1;
    Count2 *= (unsigned long) CHAN_HASHSHIFT;
    Count2 %= (unsigned long) CHAN_HASHSIZE;
    Chan_Hash_Map[Count1] = (CHAN_HASHMEMS) Count2;

  }

}

/* CHAN_STRHASH FUNCTION - JONAS (26.07.2001) */

static CHAN_HASHREGS chan_strhash(const char *ChanPT) {

  CHAN_HASHREGS Hash = Chan_Hash_Weight(*ChanPT);

  ChanPT++;

  while (*ChanPT != '\0') {
    Hash = Chan_Hash_Map[Hash] + Chan_Hash_Weight(*ChanPT);
    ChanPT++;
  }

  return(Chan_Hash_Map[Hash]);

}

/* CHAN_INIT FUNCTION - JONAS (30.06.2001) */

void chan_init(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) {

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

  chan_destroyusers(ConnS, ChanS);
  chan_destroysentmodes(ConnS, ChanS);
  chan_destroymodes(ConnS, ChanS);
  FREE(ChanS->Chan);

}

/* CHAN_DESTROY FUNCTION - JONAS (30.07.2001) */

void chan_destroy(struct Conn_Struct *ConnS) {

  assert(ConnS != NULL);

  while (ConnS->Chan_Head != NULL) { chan_rem(ConnS, ConnS->Chan_Head); }
  assert(ConnS->NumChans == 0);

}



syntax highlighted by Code2HTML, v. 0.9.1