/*
* ----------------------------------------------------------------
* Night Light IRC Proxy - Channel User
* ----------------------------------------------------------------
* 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 (03.12.2007)
*
*/
#define CHAN_USER_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"
#include "autoop_conf.h"
/* VARIABLES - JONAS (30.07.2000) */
static CHANUSER_HASHMEMS ChanUser_Hash_Map[CHANUSER_HASHMAPSIZE];
static CHANUSER_HASHMEMS ChanUser_Hash_Weight_Table[CHAR_MAX - CHAR_MIN + 1];
extern struct AutoOPConf_Struct *AutoOPConf_Head;
extern struct Conn_Struct *Conn_Head;
/* CHAN_ADDUSER FUNCTION - JONAS (26.07.2001) */
struct ChanUser_Struct *chan_adduser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const NickPT, const char *const UserPT, const char *const HostPT, const char *const NUHPT) {
struct ChanUser_Struct *ChanUser = NULL;
struct ChanUser_Struct *ChanUser_NEW = NULL;
CHANUSER_HASHREGS Hash = 0;
assert(ConnS != NULL);
assert(ChanS != NULL);
assert(NickPT != NULL);
assert(UserPT != NULL);
assert(HostPT != NULL);
assert(NUHPT != NULL);
ChanUser = chan_getuser(ConnS, ChanS, NickPT);
if (ChanUser != NULL) {
aerrno = AEEXISTS;
return(ChanUser);
}
ChanUser_NEW = malloc(sizeof(struct ChanUser_Struct));
if (ChanUser_NEW == NULL) {
aerrno = AEMALLOC;
return(NULL);
}
memset(ChanUser_NEW, 0, sizeof(struct ChanUser_Struct));
chan_inituser(ConnS, ChanS, ChanUser_NEW);
ChanUser_NEW->Nick = strdup(NickPT);
ChanUser_NEW->User = strdup(UserPT);
ChanUser_NEW->Host = strdup(HostPT);
ChanUser_NEW->NUH = strdup(NUHPT);
ChanUser_NEW->Time = NOW;
if ((ChanUser_NEW->Nick == NULL) || (ChanUser_NEW->User == NULL) || (ChanUser_NEW->Host == NULL) || (ChanUser_NEW->NUH == NULL)) {
free(ChanUser_NEW->Nick);
free(ChanUser_NEW->User);
free(ChanUser_NEW->Host);
free(ChanUser_NEW);
aerrno = AEMALLOC;
return(NULL);
}
if (ChanS->User_Head == NULL) {
ChanS->User_Head = ChanUser_NEW;
ChanS->User_Tail = ChanUser_NEW;
}
else {
ChanUser = ChanS->User_Tail;
ChanUser->Next = ChanUser_NEW;
ChanUser_NEW->Prev = ChanUser;
ChanS->User_Tail = ChanUser_NEW;
}
Hash = chanuser_strhash(ChanUser_NEW->Nick);
ChanUser = ChanS->User_Table[Hash];
if (ChanUser != NULL) { ChanUser->PrevH = ChanUser_NEW; }
ChanUser_NEW->NextH = ChanUser;
ChanS->User_Table[Hash] = ChanUser_NEW;
ChanS->Users++;
aerrno = AESUCCESS;
return(ChanUser_NEW);
}
/* CHAN_CHANGEUSER FUNCTION - JONAS (26.07.2001) */
signed short int chan_changeuser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser, const char *const NickPT) {
struct ChanUser_Struct *ChanUserH = NULL;
CHANUSER_HASHREGS Hash = 0;
CHANUSER_HASHREGS NewHash = 0;
assert(ConnS != NULL);
assert(ChanS != NULL);
assert(ChanUser != NULL);
assert(NickPT != NULL);
Hash = chanuser_strhash(ChanUser->Nick);
NewHash = chanuser_strhash(NickPT);
for (ChanUserH = ChanS->User_Table[Hash] ; ((ChanUserH != NULL) && (ChanUserH != ChanUser)) ; ChanUserH = ChanUserH->NextH);
assert(ChanUserH == ChanUser);
if (ChanUserH->PrevH != NULL) { ChanUserH->PrevH->NextH = ChanUserH->NextH; }
if (ChanUserH->NextH != NULL) { ChanUserH->NextH->PrevH = ChanUserH->PrevH; }
if (ChanS->User_Table[Hash] == ChanUserH) { ChanS->User_Table[Hash] = ChanUserH->NextH; }
ChanUserH = ChanS->User_Table[NewHash];
if (ChanUserH != NULL) { ChanUserH->PrevH = ChanUser; }
ChanUser->NextH = ChanUserH;
ChanS->User_Table[NewHash] = ChanUser;
ChanUser->Nick = strrealloc(ChanUser->Nick, NickPT);
if (aerrno != AESUCCESS) {
return(ERROR);
}
FAKELOOP {
unsigned long int NUHLen = strlen(NickPT) + strlen(ChanUser->User) + strlen(ChanUser->Host) + 2;
char NUH[NUHLen+1];
snprintf(NUH, NUHLen+1, "%s!%s@%s", NickPT, ChanUser->User, ChanUser->Host);
ChanUser->NUH = strrealloc(ChanUser->NUH, NUH);
if (aerrno != AESUCCESS) {
return(ERROR);
}
}
aerrno = AESUCCESS;
return(SUCCESS);
}
/* CHAN_REMUSER FUNCTION - JONAS (26.07.2001) */
void chan_remuser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) {
CHANUSER_HASHREGS Hash = 0;
struct ChanUser_Struct *ChanUserH = NULL;
assert(ConnS != NULL);
assert(ChanS != NULL);
assert(ChanUser != NULL);
if (ChanUser == ChanS->Me) ChanS->Me = NULL;
if (ChanUser->Prev == NULL) { ChanS->User_Head = ChanUser->Next; }
else { ChanUser->Prev->Next = ChanUser->Next; }
if (ChanUser->Next == NULL) { ChanS->User_Tail = ChanUser->Prev; }
else { ChanUser->Next->Prev = ChanUser->Prev; }
Hash = chanuser_strhash(ChanUser->Nick);
for (ChanUserH = ChanS->User_Table[Hash] ; ((ChanUserH != NULL) && (ChanUserH != ChanUser)) ; ChanUserH = ChanUserH->NextH);
assert(ChanUserH == ChanUser);
if (ChanUserH->PrevH != NULL) { ChanUserH->PrevH->NextH = ChanUserH->NextH; }
if (ChanUserH->NextH != NULL) { ChanUserH->NextH->PrevH = ChanUserH->PrevH; }
if (ChanS->User_Table[Hash] == ChanUserH) { ChanS->User_Table[Hash] = ChanUserH->NextH; }
chan_inituser(ConnS, ChanS, ChanUser);
free(ChanUser);
ChanS->Users--;
}
/* CHAN_GETUSER FUNCTION - JONAS (26.07.2001) */
struct ChanUser_Struct *chan_getuser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, const char *const NickPT) {
CHANUSER_HASHREGS Hash = 0;
struct ChanUser_Struct *ChanUser = NULL;
struct ChanUser_Struct *ChanUserH = NULL;
assert(ConnS != NULL);
assert(ChanS != NULL);
assert(NickPT != NULL);
Hash = chanuser_strhash(NickPT);
for (ChanUser = ChanS->User_Table[Hash] ; ((ChanUser != NULL) && (strcasecmp(NickPT, ChanUser->Nick) != FALSE)) ; ChanUser = ChanUser->NextH);
if (ChanUser == NULL) {
aerrno = AENOMATCH;
return(NULL);
}
if (ChanUser != ChanS->User_Table[Hash]) {
if (ChanUser->PrevH != NULL) { ChanUser->PrevH->NextH = ChanUser->NextH; }
if (ChanUser->NextH != NULL) { ChanUser->NextH->PrevH = ChanUser->PrevH; }
ChanUserH = ChanS->User_Table[Hash];
ChanUserH->PrevH = ChanUser;
ChanUser->PrevH = NULL;
ChanUser->NextH = ChanUserH;
ChanS->User_Table[Hash] = ChanUser;
}
aerrno = AESUCCESS;
return(ChanUser);
}
/* CHANUSER_HASH_INIT FUNCTION - JONAS (26.07.2001) */
void chanuser_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++) {
ChanUser_Hash_Weight(Index1) = (CHANUSER_HASHMEMS) (CHANUSER_HASHSTEP * ((char) Index1));
}
for (Index1 = CHAR_MIN ; Index1 <= CHAR_MAX ; Index1++) {
for (Index2 = CHAR_MIN ; Index2 < Index1 ; Index2++) {
if (HASHEQ(Index1, Index2)) {
ChanUser_Hash_Weight(Index1) = ChanUser_Hash_Weight(Index2);
}
}
}
for (Count1 = 0 ; Count1 < (unsigned long) CHANUSER_HASHMAPSIZE ; Count1++) {
Count2 = Count1;
Count2 *= (unsigned long) CHANUSER_HASHSHIFT;
Count2 %= (unsigned long) CHANUSER_HASHSIZE;
ChanUser_Hash_Map[Count1] = (CHANUSER_HASHMEMS) Count2;
}
}
/* CHANUSER_STRHASH FUNCTION - JONAS (26.07.2001) */
static CHANUSER_HASHREGS chanuser_strhash(const char *NickPT) {
CHANUSER_HASHREGS Hash = ChanUser_Hash_Weight(*NickPT);
NickPT++;
while (*NickPT != '\0') {
Hash = ChanUser_Hash_Map[Hash] + ChanUser_Hash_Weight(*NickPT);
NickPT++;
}
return(ChanUser_Hash_Map[Hash]);
}
/* CHAN_INITUSER FUNCTION - JONAS (05.07.2000) */
void chan_inituser(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) {
assert(ConnS != NULL);
assert(ChanS != NULL);
assert(ChanUser != NULL);
FREE(ChanUser->Nick);
FREE(ChanUser->User);
FREE(ChanUser->Host);
FREE(ChanUser->NUH);
}
/* CHAN_DESTROYUSERS FUNCTION - JONAS (30.07.2001) */
void chan_destroyusers(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS) {
assert(ConnS != NULL);
assert(ChanS != NULL);
while (ChanS->User_Head != NULL) { chan_remuser(ConnS, ChanS, ChanS->User_Head); }
assert(ChanS->Users == 0);
}
/* CHANUSER_AUTOOPCHECK FUNCTION - JONAS (27.12.2007) */
void chanuser_autoopcheck(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) {
struct AutoOPConf_Struct *AutoOPConf = NULL;
struct AutoOPConfChan_Struct *AutoOPConfChan = NULL;
for (AutoOPConf = AutoOPConf_Head ; AutoOPConf != NULL ; AutoOPConf = AutoOPConf->Next) {
if (strwm(AutoOPConf->NUH, ChanUser->NUH) != TRUE) { continue; }
if (strwm(AutoOPConf->Connection, ConnS->Name) != TRUE) { continue; }
for (AutoOPConfChan = AutoOPConf->Chan_Head ; AutoOPConfChan != NULL ; AutoOPConfChan = AutoOPConfChan->Next) {
if (strwm(AutoOPConfChan->Chan, ChanS->Chan) != TRUE) { continue; }
chan_op(ConnS, ChanS, ChanUser);
ChanUser_SetAutoOPCheck(ChanUser);
return;
}
}
ChanUser_SetAutoOPCheck(ChanUser);
}
/* CHAN_OP FUNCTION - JONAS (05.07.2000) */
void chan_op(struct Conn_Struct *ConnS, struct Chan_Struct *ChanS, struct ChanUser_Struct *ChanUser) {
struct Conn_Struct *P_ConnS = NULL;
struct Chan_Struct *P_ChanS = NULL;
struct ChanUser_Struct *P_ChanUser = NULL;
char Mode[IRCMODELINELEN+1] = "";
assert(ConnS != NULL);
assert(ChanS != NULL);
assert(ChanUser != NULL);
assert(ChanUser_IsOP(ChanS->Me));
assert(!ChanUser_IsOP(ChanUser));
assert(!ChanUser_IsSentOP(ChanUser));
for (P_ConnS = Conn_Head ; P_ConnS != NULL ; P_ConnS = P_ConnS->Next) {
if (!Conn_IsWelcome(P_ConnS)) { continue; }
P_ChanS = chan_get(P_ConnS, ChanS->Chan);
if (P_ChanS == NULL) { continue; }
if (!ChanUser_IsOP(P_ChanS->Me)) { continue; }
P_ChanUser = chan_getuser(P_ConnS, P_ChanS, ChanUser->Nick);
if (P_ChanUser == NULL) { continue; }
if ((strcasecmp(ChanUser->User, P_ChanUser->User) != FALSE) || (strcasecmp(ChanUser->Host, P_ChanUser->Host) != FALSE)) { continue; }
if (ChanUser_IsSentOP(P_ChanUser)) { return; }
}
DEBUGPRINT(BITMASK_DEBUG_CONN, "Connection %s is requesting OP for %s on %s.", ConnS->Name, ChanUser->Nick, ChanS->Chan);
ChanUser_SetSentOP(ChanUser);
ChanUser->SentOPTime = NOW;
snprintf(Mode, IRCMODELINELEN+1, "+o %s", ChanUser->Nick);
chan_addmode(ConnS, ChanS, Mode, CHANMODEPRIOOP, 0);
}
syntax highlighted by Code2HTML, v. 0.9.1