886 lines
19 KiB
C
886 lines
19 KiB
C
/* NeoStats - IRC Statistical Services
|
|
** Copyright (c) 1999-2004 Adam Rutter, Justin Hammond
|
|
** http://www.neostats.net/
|
|
**
|
|
** Portions Copyright (c) 2000-2001 ^Enigma^
|
|
**
|
|
** Portions Copyright (c) 1999 Johnathan George net@lite.net
|
|
**
|
|
** 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
** USA
|
|
**
|
|
** NeoStats CVS Identification
|
|
** $Id$
|
|
*/
|
|
|
|
#include "stats.h"
|
|
#include "ircd.h"
|
|
#include "hash.h"
|
|
#include "dl.h"
|
|
#include "log.h"
|
|
#include "users.h"
|
|
#include "chans.h"
|
|
#include "exclude.h"
|
|
#ifdef SQLSRV
|
|
#include "sqlsrv/rta.h"
|
|
#endif
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
hash_t *uh;
|
|
|
|
static User *new_user (const char *nick);
|
|
|
|
static char quitreason[BUFSIZE];
|
|
|
|
static User *
|
|
new_user (const char *nick)
|
|
{
|
|
User *u;
|
|
hnode_t *un;
|
|
|
|
SET_SEGV_LOCATION();
|
|
u = smalloc (sizeof (User));
|
|
bzero(u, sizeof(User));
|
|
if (!nick) {
|
|
nlog (LOG_CRITICAL, LOG_CORE, "new_user: trying to add user with NULL nickname");
|
|
return NULL;
|
|
} else {
|
|
strlcpy (u->nick, nick, MAXNICK);
|
|
}
|
|
un = hnode_create (u);
|
|
if (hash_isfull (uh)) {
|
|
nlog (LOG_CRITICAL, LOG_CORE, "new_user: user hash is full");
|
|
return NULL;
|
|
} else {
|
|
hash_insert (uh, un, u->nick);
|
|
}
|
|
return (u);
|
|
}
|
|
#ifndef GOTNICKIP
|
|
static void
|
|
lookupnickip(char *data, adns_answer *a) {
|
|
User *u;
|
|
char **av;
|
|
int ac = 0;
|
|
|
|
u = finduser((char *)data);
|
|
if (a && a->nrrs > 0 && u && a->status == adns_s_ok) {
|
|
u->ipaddr.s_addr = a->rrs.addr->addr.inet.sin_addr.s_addr;
|
|
AddStringToList (&av, u->nick, &ac);
|
|
ModuleEvent (EVENT_GOTNICKIP, av, ac);
|
|
}
|
|
}
|
|
#endif
|
|
void
|
|
AddUser (const char *nick, const char *user, const char *host, const char *realname, const char *server, const char*ip, const char* TS, const char* numeric)
|
|
{
|
|
unsigned long ipaddress = 0;
|
|
unsigned long time;
|
|
char **av;
|
|
int ac = 0;
|
|
User *u;
|
|
int i;
|
|
#ifndef GOTNICKIP
|
|
struct in_addr *ipad;
|
|
int res;
|
|
#endif
|
|
|
|
SET_SEGV_LOCATION();
|
|
u = finduser (nick);
|
|
if (u) {
|
|
nlog (LOG_WARNING, LOG_CORE, "AddUser: trying to add a user that already exists %s", nick);
|
|
return;
|
|
}
|
|
|
|
if(ip) {
|
|
ipaddress = strtoul (ip, NULL, 10);
|
|
} else {
|
|
#ifndef GOTNICKIP
|
|
if (me.want_nickip == 1) {
|
|
/* first, if the u->host is a ip address, just convert it */
|
|
ipad = malloc(sizeof(struct in_addr));
|
|
res = inet_aton(host, ipad);
|
|
if (res > 0) {
|
|
/* its valid */
|
|
ipaddress = htonl(ipad->s_addr);
|
|
free(ipad);
|
|
} else {
|
|
/* kick of a dns reverse lookup for this host */
|
|
dns_lookup((char *)host, adns_r_addr, lookupnickip, (void *)nick);
|
|
ipaddress = 0;
|
|
}
|
|
} else {
|
|
ipaddress = 0;
|
|
}
|
|
#endif
|
|
}
|
|
if(TS) {
|
|
time = strtoul (TS, NULL, 10);
|
|
} else {
|
|
time = me.now;
|
|
}
|
|
nlog (LOG_DEBUG2, LOG_CORE, "AddUser: %s (%s@%s) %s (%d) -> %s at %lu", nick, user, host, realname, (int)htonl (ipaddress), server, (unsigned long)time);
|
|
|
|
u = new_user (nick);
|
|
if (!u) {
|
|
return;
|
|
}
|
|
strlcpy (u->hostname, host, MAXHOST);
|
|
strlcpy (u->vhost, host, MAXHOST);
|
|
strlcpy (u->username, user, MAXUSER);
|
|
strlcpy (u->realname, realname, MAXREALNAME);
|
|
u->server = findserver (server);
|
|
u->t_flood = me.now;
|
|
u->flood = 0;
|
|
u->is_away = 0;
|
|
u->Umode = 0;
|
|
u->flags = 0;
|
|
#ifdef GOTUSERSMODES
|
|
u->Smode = 0;
|
|
#endif
|
|
u->chans = list_create (MAXJOINCHANS);
|
|
u->modes[0]= '\0';
|
|
u->ipaddr.s_addr = htonl (ipaddress);
|
|
u->TS = time;
|
|
|
|
/* make sure the module pointers are all null */
|
|
for (i = 0; i < NUM_MODULES; i++) {
|
|
u->moddata[i] = NULL;
|
|
}
|
|
|
|
if (!ircstrcasecmp(server, me.name)) {
|
|
u->flags |= NS_FLAGS_ME;
|
|
}
|
|
|
|
/* check if the user is excluded */
|
|
ns_do_exclude_user(u);
|
|
|
|
#ifdef BASE64NICKNAME
|
|
if(numeric) {
|
|
setnickbase64 (u->nick, numeric);
|
|
}
|
|
#endif
|
|
|
|
AddStringToList (&av, u->nick, &ac);
|
|
ModuleEvent (EVENT_SIGNON, av, ac);
|
|
if (me.want_nickip == 1 && ipaddress != 0) {
|
|
/* only fire this event if we have the nickip and some module wants it */
|
|
ModuleEvent (EVENT_GOTNICKIP, av, ac);
|
|
}
|
|
free (av);
|
|
}
|
|
|
|
void
|
|
UserPart (list_t * list, lnode_t * node, void *v)
|
|
{
|
|
part_chan ((User *)v, lnode_get (node), quitreason[0] != 0 ? quitreason : NULL);
|
|
}
|
|
|
|
void
|
|
DelUser (const char *nick, int killflag, const char *reason)
|
|
{
|
|
char killnick[MAXNICK];
|
|
int botflag = 0;
|
|
User *u;
|
|
hnode_t *un;
|
|
char **av;
|
|
int ac = 0;
|
|
|
|
SET_SEGV_LOCATION();
|
|
nlog (LOG_DEBUG2, LOG_CORE, "doDelUser: %s", nick);
|
|
|
|
u = finduser(nick);
|
|
if(!u) {
|
|
nlog (LOG_WARNING, LOG_CORE, "doDelUser: %s failed!", nick);
|
|
return;
|
|
}
|
|
|
|
un = hash_lookup (uh, u->nick);
|
|
if (!un) {
|
|
nlog (LOG_WARNING, LOG_CORE, "doDelUser: %s failed!", nick);
|
|
return;
|
|
}
|
|
u = hnode_get (un);
|
|
|
|
bzero(quitreason, BUFSIZE);
|
|
if(reason) {
|
|
strlcpy(quitreason, reason, BUFSIZE);
|
|
strip_mirc_codes(quitreason);
|
|
}
|
|
list_process (u->chans, u, UserPart);
|
|
|
|
/* run the event to delete a user */
|
|
AddStringToList (&av, u->nick, &ac);
|
|
if(reason) {
|
|
AddStringToList (&av, (char*)quitreason, &ac);
|
|
}
|
|
if (killflag == 0) {
|
|
ModuleEvent (EVENT_SIGNOFF, av, ac);
|
|
} else if (killflag == 1) {
|
|
ModuleEvent (EVENT_KILL, av, ac);
|
|
}
|
|
free (av);
|
|
|
|
/* if its one of our bots, remove it from the modlist */
|
|
if (findbot (u->nick)) {
|
|
if (killflag == 1) {
|
|
nlog (LOG_NOTICE, LOG_CORE, "doDelUser: deleting bot %s as it was killed", u->nick);
|
|
strlcpy(killnick,u->nick,MAXNICK);
|
|
botflag = 1;
|
|
}
|
|
del_mod_user (u->nick);
|
|
}
|
|
|
|
hash_delete (uh, un);
|
|
hnode_destroy (un);
|
|
list_destroy (u->chans);
|
|
free (u);
|
|
if(botflag) {
|
|
ac = 0;
|
|
AddStringToList (&av, killnick, &ac);
|
|
ModuleEvent (EVENT_BOTKILL, av, ac);
|
|
free (av);
|
|
}
|
|
}
|
|
|
|
void
|
|
UserAway (const char *nick, const char *awaymsg)
|
|
{
|
|
char **av;
|
|
int ac = 0;
|
|
User *u;
|
|
|
|
u = finduser (nick);
|
|
if (u) {
|
|
if (awaymsg) {
|
|
strlcpy(u->awaymsg, awaymsg, MAXHOST);
|
|
} else {
|
|
u->awaymsg[0] = 0;
|
|
}
|
|
AddStringToList (&av, u->nick, &ac);
|
|
if ((u->is_away == 1) && (!awaymsg)) {
|
|
u->is_away = 0;
|
|
ModuleEvent (EVENT_AWAY, av, ac);
|
|
free (av);
|
|
} else if ((u->is_away == 0) && (awaymsg)) {
|
|
u->is_away = 1;
|
|
AddStringToList (&av, (char *) awaymsg, &ac);
|
|
ModuleEvent (EVENT_AWAY, av, ac);
|
|
free (av);
|
|
}
|
|
} else {
|
|
nlog (LOG_WARNING, LOG_CORE, "UserAway: unable to find user %s for away", nick);
|
|
}
|
|
}
|
|
|
|
int
|
|
UserNick (const char * oldnick, const char *newnick, const char * ts)
|
|
{
|
|
char uoldnick[MAXNICK];
|
|
hnode_t *un;
|
|
lnode_t *cm;
|
|
char **av;
|
|
int ac = 0;
|
|
User * u;
|
|
time_t time;
|
|
|
|
SET_SEGV_LOCATION();
|
|
u = finduser (oldnick);
|
|
if (!u) {
|
|
nlog (LOG_WARNING, LOG_CORE, "UserNick: can't find user %s", oldnick);
|
|
return NS_FAILURE;
|
|
}
|
|
strlcpy(uoldnick, u->nick, MAXNICK);
|
|
|
|
if(ts) {
|
|
time = atoi (ts);
|
|
} else {
|
|
time = me.now;
|
|
}
|
|
|
|
nlog (LOG_DEBUG2, LOG_CORE, "UserNick: %s -> %s", u->nick, newnick);
|
|
un = hash_lookup (uh, u->nick);
|
|
if (!un) {
|
|
nlog (LOG_WARNING, LOG_CORE, "UserNick: %s -> %s failed!", u->nick, newnick);
|
|
return NS_FAILURE;
|
|
}
|
|
cm = list_first (u->chans);
|
|
while (cm) {
|
|
ChanNickChange (findchan (lnode_get (cm)), (char *) newnick, u->nick);
|
|
cm = list_next (u->chans, cm);
|
|
}
|
|
SET_SEGV_LOCATION();
|
|
hash_delete (uh, un);
|
|
strlcpy (u->nick, newnick, MAXNICK);
|
|
if(ts) {
|
|
u->TS = time;
|
|
}
|
|
hash_insert (uh, un, u->nick);
|
|
AddStringToList (&av, (char*)uoldnick, &ac);
|
|
AddStringToList (&av, u->nick, &ac);
|
|
if(ts) {
|
|
AddStringToList (&av, (char*)ts, &ac);
|
|
}
|
|
ModuleEvent (EVENT_NICKCHANGE, av, ac);
|
|
free (av);
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
#ifdef BASE64NICKNAME
|
|
User *
|
|
finduserbase64 (const char *num)
|
|
{
|
|
User *u;
|
|
hnode_t *un;
|
|
hscan_t us;
|
|
|
|
hash_scan_begin (&us, uh);
|
|
while ((un = hash_scan_next (&us)) != NULL) {
|
|
u = hnode_get (un);
|
|
if(strncmp(u->nick64, num, BASE64NICKSIZE) == 0) {
|
|
nlog (LOG_DEBUG1, LOG_CORE, "finduserbase64: %s -> %s", num, u->nick);
|
|
return u;
|
|
}
|
|
}
|
|
nlog (LOG_DEBUG3, LOG_CORE, "finduserbase64: %s not found", num);
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
User *
|
|
finduser (const char *nick)
|
|
{
|
|
User *u;
|
|
hnode_t *un;
|
|
|
|
un = hash_lookup (uh, nick);
|
|
if (un != NULL) {
|
|
u = hnode_get (un);
|
|
return u;
|
|
}
|
|
nlog (LOG_DEBUG3, LOG_CORE, "finduser: %s not found", nick);
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef SQLSRV
|
|
|
|
/* @brief Returns the users server in text form that they are connected too
|
|
*/
|
|
|
|
void *display_server(void *tbl, char *col, char *sql, void *row) {
|
|
User *data = row;
|
|
return data->server->name;
|
|
}
|
|
|
|
void *display_umode(void *tbl, char *col, char *sql, void *row) {
|
|
User *data = row;
|
|
return UmodeMaskToString(data->Umode);
|
|
}
|
|
|
|
void *display_vhost(void *tbl, char *col, char *sql, void *row) {
|
|
User *u = row;
|
|
#ifdef UMODE_HIDE
|
|
/* Do we have a hidden host? */
|
|
if(u->Umode & UMODE_HIDE) {
|
|
return u->vhost;
|
|
}
|
|
return "*";
|
|
#else
|
|
return u->hostname;
|
|
#endif
|
|
}
|
|
|
|
#ifdef GOTUSERSMODES
|
|
void *display_smode(void *tbl, char *col, char *sql, void *row) {
|
|
User *data = row;
|
|
return SmodeMaskToString(data->Smode);
|
|
}
|
|
#endif
|
|
|
|
static char userschannellist[MAXCHANLIST];
|
|
|
|
void *display_chans(void *tbl, char *col, char *sql, void *row) {
|
|
User *data = row;
|
|
lnode_t *cn;
|
|
userschannellist[0] = '\0';
|
|
cn = list_first(data->chans);
|
|
while (cn != NULL) {
|
|
strlcat(userschannellist, lnode_get(cn), MAXCHANLIST);
|
|
strlcat(userschannellist, " ", MAXCHANLIST);
|
|
cn = list_next(data->chans, cn);
|
|
}
|
|
return userschannellist;
|
|
}
|
|
|
|
COLDEF neo_userscols[] = {
|
|
{
|
|
"users",
|
|
"nick",
|
|
RTA_STR,
|
|
MAXNICK,
|
|
offsetof(struct User, nick),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"The nickname of the user"
|
|
},
|
|
{
|
|
"users",
|
|
"hostname",
|
|
RTA_STR,
|
|
MAXHOST,
|
|
offsetof(struct User, hostname),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"The real Hostname of the user"
|
|
},
|
|
{
|
|
"users",
|
|
"ident",
|
|
RTA_STR,
|
|
MAXUSER,
|
|
offsetof(struct User, username),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"The ident portion of the users connection"
|
|
},
|
|
{
|
|
"users",
|
|
"realname",
|
|
RTA_STR,
|
|
MAXREALNAME,
|
|
offsetof(struct User, realname),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"The users realname/info message"
|
|
},
|
|
{
|
|
"users",
|
|
"vhost",
|
|
RTA_STR,
|
|
MAXHOST,
|
|
offsetof(struct User, vhost),
|
|
RTA_READONLY,
|
|
display_vhost,
|
|
NULL,
|
|
"The users Vhost, if the IRCd supports VHOSTS"
|
|
},
|
|
{
|
|
"users",
|
|
"away",
|
|
RTA_INT,
|
|
sizeof(int),
|
|
offsetof(struct User, is_away),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"Boolean variable indiciating if the user is away"
|
|
},
|
|
{
|
|
"users",
|
|
"modes",
|
|
RTA_STR,
|
|
64, /* as defined in ircd.c */
|
|
offsetof(struct User, Umode),
|
|
RTA_READONLY,
|
|
display_umode,
|
|
NULL,
|
|
"the users umodes. Does not include SMODES."
|
|
},
|
|
#ifdef GOTUSERSMODES
|
|
{
|
|
"users",
|
|
"smodes",
|
|
RTA_STR,
|
|
64,
|
|
offsetof(struct User, Smode),
|
|
RTA_READONLY,
|
|
display_smode,
|
|
NULL,
|
|
"the users Smodes, if the IRCd supports it. Does not include UMODES."
|
|
},
|
|
#endif
|
|
{
|
|
"users",
|
|
"connected",
|
|
RTA_INT,
|
|
sizeof(int),
|
|
offsetof(struct User, TS),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"When the User Connected"
|
|
},
|
|
{
|
|
"users",
|
|
"flags",
|
|
RTA_INT,
|
|
sizeof(int),
|
|
offsetof(struct User, flags),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"Flags for this user"
|
|
},
|
|
{
|
|
"users",
|
|
"server",
|
|
RTA_STR,
|
|
MAXHOST,
|
|
offsetof(struct User, server),
|
|
RTA_READONLY,
|
|
display_server,
|
|
NULL,
|
|
"the users server"
|
|
},
|
|
{
|
|
"users",
|
|
"channels",
|
|
RTA_STR,
|
|
MAXCHANLIST,
|
|
offsetof(struct User, chans),
|
|
RTA_READONLY,
|
|
display_chans,
|
|
NULL,
|
|
"the users channels."
|
|
},
|
|
{
|
|
"users",
|
|
"awaymsg",
|
|
RTA_STR,
|
|
MAXHOST,
|
|
offsetof(struct User, awaymsg),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"the users away message."
|
|
},
|
|
{
|
|
"users",
|
|
"swhois",
|
|
RTA_STR,
|
|
MAXHOST,
|
|
offsetof(struct User, swhois),
|
|
RTA_READONLY,
|
|
NULL,
|
|
NULL,
|
|
"the users swhois."
|
|
},
|
|
|
|
};
|
|
|
|
TBLDEF neo_users = {
|
|
"users",
|
|
NULL, /* for now */
|
|
sizeof(struct User),
|
|
0,
|
|
TBL_HASH,
|
|
neo_userscols,
|
|
sizeof(neo_userscols) / sizeof(COLDEF),
|
|
"",
|
|
"The list of users connected to the IRC network"
|
|
};
|
|
#endif /* SQLSRV */
|
|
|
|
|
|
|
|
int
|
|
init_user_hash ()
|
|
{
|
|
uh = hash_create (U_TABLE_SIZE, 0, 0);
|
|
if(!uh)
|
|
return NS_FAILURE;
|
|
|
|
#ifdef SQLSRV
|
|
/* add the server hash to the sql library */
|
|
neo_users.address = uh;
|
|
rta_add_table(&neo_users);
|
|
#endif
|
|
|
|
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
dumpuser (User* u)
|
|
{
|
|
lnode_t *cm;
|
|
int i = 0;
|
|
|
|
#ifdef BASE64NICKNAME
|
|
debugtochannel("User: %s!%s@%s (%s)", u->nick, u->username, u->hostname, u->nick64);
|
|
#else
|
|
debugtochannel("User: %s!%s@%s", u->nick, u->username, u->hostname);
|
|
#endif
|
|
debugtochannel("IP: %s", inet_ntoa(u->ipaddr));
|
|
debugtochannel("Vhost: %s", u->vhost);
|
|
#ifdef GOTUSERSMODES
|
|
debugtochannel("Flags: 0x%lx Modes: %s (0x%lx) Smodes: %lx", u->flags, UmodeMaskToString(u->Umode), u->Umode, u->Smode);
|
|
#else
|
|
debugtochannel("Flags: 0x%lx Modes: %s (0x%lx)", u->flags, UmodeMaskToString(u->Umode), u->Umode);
|
|
#endif
|
|
if(u->is_away) {
|
|
debugtochannel("Away: %s ", u->awaymsg);
|
|
}
|
|
|
|
cm = list_first (u->chans);
|
|
while (cm) {
|
|
if(i==0) {
|
|
debugtochannel("Channels: %s", (char *) lnode_get (cm));
|
|
} else {
|
|
debugtochannel(" %s", (char *) lnode_get (cm));
|
|
}
|
|
cm = list_next (u->chans, cm);
|
|
i++;
|
|
}
|
|
debugtochannel("========================================");
|
|
}
|
|
|
|
void
|
|
UserDump (const char *nick)
|
|
{
|
|
User *u;
|
|
hnode_t *un;
|
|
hscan_t us;
|
|
SET_SEGV_LOCATION();
|
|
debugtochannel("================USERDUMP================");
|
|
if (!nick) {
|
|
hash_scan_begin (&us, uh);
|
|
while ((un = hash_scan_next (&us)) != NULL) {
|
|
u = hnode_get (un);
|
|
dumpuser (u);
|
|
}
|
|
} else {
|
|
un = hash_lookup (uh, nick);
|
|
if (un) {
|
|
u = hnode_get (un);
|
|
dumpuser (u);
|
|
} else {
|
|
debugtochannel("UserDump: can't find user %s", nick);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Do dl lookups in advance to speed up UserLevel processing
|
|
*
|
|
*/
|
|
#ifdef EXTAUTH
|
|
int (*getauth) (User *, int curlvl);
|
|
int InitExtAuth(void)
|
|
{
|
|
int i;
|
|
i = get_dl_handle ("extauth");
|
|
if (i > 0) {
|
|
getauth = ns_dlsym ((int *) i, "__do_auth");
|
|
return NS_SUCCESS;
|
|
}
|
|
return NS_FAILURE;
|
|
}
|
|
#endif
|
|
|
|
int UmodeAuth(User * u)
|
|
{
|
|
int i, tmplvl = 0;
|
|
/* Note, tables have been reordered highest to lowest so the
|
|
* first hit will give the highest level for a given umode
|
|
* combination so we can just set it without checking against
|
|
* the current level
|
|
* we can also quit on the first occurrence of 0
|
|
* should be a lot faster!
|
|
*/
|
|
for (i = 0; i < ircd_umodecount; i++) {
|
|
if(user_umodes[i].level == 0)
|
|
break;
|
|
if (u->Umode & user_umodes[i].umode) {
|
|
tmplvl = user_umodes[i].level;
|
|
break;
|
|
}
|
|
}
|
|
nlog (LOG_DEBUG1, LOG_CORE, "UmodeAuth: umode level for %s is %d", u->nick, tmplvl);
|
|
|
|
/* I hate SMODEs damn it */
|
|
#ifdef GOTUSERSMODES
|
|
/* hey, smode can equal 0 as well you know */
|
|
/* see umode comments above */
|
|
for (i = 0; i < ircd_smodecount; i++) {
|
|
if(user_smodes[i].level == 0)
|
|
break;
|
|
if (u->Smode & user_smodes[i].umode) {
|
|
/* only if the smode level is higher than standard, do we alter tmplvl */
|
|
if (user_smodes[i].level > tmplvl)
|
|
tmplvl = user_smodes[i].level;
|
|
break;
|
|
}
|
|
}
|
|
nlog (LOG_DEBUG1, LOG_CORE, "UmodeAuth: smode level for %s is %d", u->nick, tmplvl);
|
|
#endif
|
|
return tmplvl;
|
|
}
|
|
|
|
int
|
|
UserLevel (User * u)
|
|
{
|
|
int i = 0;
|
|
int tmplvl = 0;
|
|
tmplvl = UmodeAuth(u);
|
|
|
|
#ifdef EXTAUTH
|
|
if (getauth)
|
|
i = (*getauth) (u, tmplvl);
|
|
/* if tmplvl is greater than 1000, then extauth is authoritive */
|
|
if (i > tmplvl)
|
|
tmplvl = i;
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#ifdef CODERHACK
|
|
/* this is only cause I dun have the right O lines on some of my "Beta" Networks, so I need to hack this in :) */
|
|
if (!ircstrcasecmp (u->nick, "FISH"))
|
|
tmplvl = NS_ULEVEL_ROOT;
|
|
if (!ircstrcasecmp (u->nick, "SHMAD"))
|
|
tmplvl = NS_ULEVEL_ROOT;
|
|
#endif
|
|
#endif
|
|
|
|
nlog (LOG_DEBUG1, LOG_CORE, "UserLevel for %s is %d (%d)", u->nick, tmplvl, i);
|
|
return tmplvl;
|
|
}
|
|
|
|
void
|
|
SetUserVhost(const char* nick, const char* vhost)
|
|
{
|
|
User *u;
|
|
u = finduser (nick);
|
|
nlog(LOG_DEBUG1, LOG_CORE, "Vhost %s", vhost);
|
|
if (u) {
|
|
strlcpy (u->vhost, vhost, MAXHOST);
|
|
/* these are precautions */
|
|
/* damn Unreal. /sethost on IRC doesn't send +xt, but /umode +x sends +x */
|
|
/* so, we will never be 100% sure about +t */
|
|
#ifdef UMODE_HIDE
|
|
u->Umode |= UMODE_HIDE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* I don't know why, but I spent like 3 hours trying to make this function work and
|
|
I finally got it... what a waste of time... gah, oh well... basically, it sets both the User Flags, and also the User Levels..
|
|
if a user is losing modes (ie -o) then its a real pain in the butt, but tough... */
|
|
void
|
|
UserMode (const char *nick, const char *modes)
|
|
{
|
|
User *u;
|
|
char **av;
|
|
int ac = 0;
|
|
long oldmode;
|
|
|
|
SET_SEGV_LOCATION();
|
|
nlog (LOG_DEBUG1, LOG_CORE, "UserMode: user %s modes %s", nick, modes);
|
|
u = finduser (nick);
|
|
if (!u) {
|
|
nlog (LOG_WARNING, LOG_CORE, "UserMode: mode change for unknown user %s %s", nick, modes);
|
|
return;
|
|
}
|
|
nlog (LOG_DEBUG1, LOG_CORE, "Modes: %s", modes);
|
|
strlcpy (u->modes, modes, MODESIZE);
|
|
AddStringToList (&av, u->nick, &ac);
|
|
AddStringToList (&av, (char *) modes, &ac);
|
|
ModuleEvent (EVENT_UMODE, av, ac);
|
|
free (av);
|
|
oldmode = u->Umode;
|
|
u->Umode = UmodeStringToMask(modes, u->Umode);
|
|
/* This needs to track +x and +t really but
|
|
* should be enough for Trystan to work on the SQL stuff
|
|
*/
|
|
#ifdef UMODE_HIDE
|
|
/* Do we have a hidden host any more? */
|
|
if((oldmode & UMODE_HIDE) && (!(u->Umode & UMODE_HIDE))) {
|
|
strlcpy(u->vhost, u->hostname, MAXHOST);
|
|
}
|
|
#endif
|
|
nlog (LOG_DEBUG1, LOG_CORE, "UserMode: modes for %s is now %p", u->nick, (int *)u->Umode);
|
|
}
|
|
|
|
#ifdef GOTUSERSMODES
|
|
void
|
|
UserSMode (const char *nick, const char *modes)
|
|
{
|
|
User *u;
|
|
char **av;
|
|
int ac = 0;
|
|
|
|
SET_SEGV_LOCATION();
|
|
nlog (LOG_DEBUG1, LOG_CORE, "UserSMode: user %s modes %s", nick, modes);
|
|
u = finduser (nick);
|
|
if (!u) {
|
|
nlog (LOG_WARNING, LOG_CORE, "UserSMode: smode change for unknown user %s %s", nick, modes);
|
|
return;
|
|
}
|
|
nlog (LOG_DEBUG1, LOG_CORE, "Smodes: %s", modes);
|
|
AddStringToList (&av, u->nick, &ac);
|
|
AddStringToList (&av, (char *) modes, &ac);
|
|
ModuleEvent (EVENT_SMODE, av, ac);
|
|
free (av);
|
|
u->Smode = SmodeStringToMask(modes, u->Smode);
|
|
nlog (LOG_DEBUG1, LOG_CORE, "UserSMode: smode for %s is now %p", u->nick, (int *)u->Smode);
|
|
}
|
|
#endif
|
|
|
|
void SetUserServicesTS(const char* nick, const char* ts)
|
|
{
|
|
User* u;
|
|
u = finduser(nick);
|
|
if(u) {
|
|
u->servicesstamp = strtoul(ts, NULL, 10);
|
|
}
|
|
}
|
|
|
|
/* @brief Free up all the user structs and free memory. Called when we close down
|
|
*
|
|
*/
|
|
|
|
|
|
void
|
|
FreeUsers ()
|
|
{
|
|
User *u;
|
|
hnode_t *un;
|
|
hscan_t hs;
|
|
|
|
SET_SEGV_LOCATION();
|
|
|
|
|
|
hash_scan_begin(&hs, uh);
|
|
while ((un = hash_scan_next(&hs)) != NULL) {
|
|
u = hnode_get (un);
|
|
list_process (u->chans, u, UserPart);
|
|
|
|
/* something is wrong if its our bots */
|
|
if (findbot (u->nick)) {
|
|
nlog (LOG_NOTICE, LOG_CORE, "Ehhh. FreeUsers called while we still have bots online. Baaad User: %s", u->nick);
|
|
}
|
|
hash_scan_delete (uh, un);
|
|
hnode_destroy (un);
|
|
list_destroy (u->chans);
|
|
free (u);
|
|
}
|
|
hash_destroy(uh);
|
|
hash_destroy(ch);
|
|
}
|