Files
undernet-cservice/Sources/users.c
2015-01-25 18:26:44 -06:00

522 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* @(#)$Id: users.c,v 1.7 1998/11/21 14:58:43 seks Exp $ */
/* Undernet Channel Service (X)
* Copyright (C) 1995-2002 Robin Thellend
*
* 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
*
* The author can be contact by email at <csfeedback@robin.pfft.net>
*
* Please note that this software is unsupported and mostly
* obsolete. It was replaced by GNUworld/CMaster. See
* http://gnuworld.sourceforge.net/ for more information.
*/
#include "h.h"
int lu_hash(char *nick)
{
register int i, j;
for (i = 0, j = 0; i < strlen(nick); i++)
j += toupper((unsigned char)nick[i]);
return (j % 1000);
}
int su_hash(char *nick)
{
register int i, j;
for (i = 0, j = 0; i < strlen(nick); i++)
j += toupper((unsigned char)nick[i]);
return (j % 100);
}
aluser *ToLuser(char *nick)
{
register aluser *curr;
curr = Lusers[lu_hash(nick)];
while (curr && strcasecmp(nick, curr->nick))
curr = curr->next;
return (curr);
}
void onnick(char *source, char *newnick, char *body)
{
register aluser *user, **u;
register asuser *suser, **s;
register aserver *serv;
char username[80];
char hostname[80];
char TS[80];
char server[80];
register achannelnode *chan;
register anickchange *curr, *prec;
char buffer[512];
int i = 0;
#ifdef DEBUG
printf("NICK: %s --> %s ...\n", source, newnick);
#endif
/* a new user */
if (!ToLuser(source))
{ /* Not a user, so a server or nothing */
if (strchr(source, '.') == NULL)
{
/* Source is not a user and not a server either */
return;
}
if (!strcasecmp(newnick, mynick))
{
log("ERROR: I'm nick collided");
#ifdef DEBUG
printf("ARGH!!! I'M NICK COLLIDED!\n");
#endif
GetWord(1, body, TS);
GetWord(2, body, username);
GetWord(3, body, hostname);
if (atol(TS) <= logTS &&
strcasecmp(username, myuser) &&
strcasecmp(hostname, mysite))
{
NickInUse();
log(source);
log(newnick);
log(body);
}
else
{
onquit(source);
return; /*ignore */
}
#ifdef BACKUP
}
else if (!strcasecmp(newnick, MAIN_NICK))
{
return; /* ignore */
#endif
}
else if (ToLuser(newnick))
{
#ifdef DEBUG
printf("ARGH!!! NICK COLLISION\n");
#endif
onquit(newnick);
}
GetWord(1, body, TS);
GetWord(2, body, username);
GetWord(3, body, hostname);
GetWord(4, body, server);
#ifdef FAKE_UWORLD
if (Uworld_status == 1 && !strcasecmp(newnick, UFAKE_NICK))
{
if (atol(TS) <= UworldTS && atol(TS) != 0 &&
strcasecmp(username, UFAKE_NICK) &&
strcasecmp(hostname, UFAKE_HOST))
{
sprintf(buffer, "%s nick collided", UFAKE_NICK);
log(buffer);
Uworld_status = 0;
KillUworld("nick collision");
return; /* ignore if younger */
}
}
#endif
user = (aluser *) MALLOC(sizeof(aluser));
user->nick = (char *)MALLOC(strlen(newnick) + 1);
strcpy(user->nick, newnick);
user->username = (char *)MALLOC(strlen(username) + 1);
strcpy(user->username, username);
user->site = (char *)MALLOC(strlen(hostname) + 1);
strcpy(user->site, hostname);
if (*newnick == '+')
serv = &VirtualServer;
else
serv = ToServer(server);
user->server = serv;
user->time = atol(TS);
user->mode = 0;
user->channel = NULL;
user->valchan = NULL;
user->next = Lusers[lu_hash(newnick)];
Lusers[lu_hash(newnick)] = user;
/* add user in server's userlist
*/
suser = (asuser *) MALLOC(sizeof(asuser));
suser->N = user;
suser->next = serv->users[su_hash(newnick)];
serv->users[su_hash(newnick)] = suser;
#ifdef NICKSERV
nserv_nick(newnick, user);
#endif
}
else
{ /* nick change */
#if 0
if (!strcasecmp(source, DEFAULT_NICKNAME) &&
strcasecmp(newnick, DEFAULT_NICKNAME))
{
ChNick(DEFAULT_NICKNAME);
}
#endif
if (!strcasecmp(newnick, mynick))
{
#ifdef DEBUG
printf("ARGH!!! I'M NICK COLLIDED!\n");
#endif
GetWord(0, body, TS);
if (atol(TS + 1) <= logTS)
{
NickInUse();
log(source);
log(newnick);
log(body);
}
else
{
onquit(source);
return; /*ignore */
}
}
u = &Lusers[lu_hash(source)];
while (*u && strcasecmp(source, (*u)->nick))
u = &(*u)->next;
user = *u;
#ifdef NICKSERV
nserv_nick(newnick, user);
#endif
if (user == NULL)
quit("ERROR! onnick() can't find user", 1);
s = &user->server->users[su_hash(source)];
while (*s && strcasecmp((*s)->N->nick, user->nick))
s = &(*s)->next;
suser = *s;
/* change the nick in memory */
TTLALLOCMEM -= strlen(user->nick) + 1;
free(user->nick);
user->nick = (char *)MALLOC(strlen(newnick) + 1);
strcpy(user->nick, newnick);
/* now relocate the structure */
*u = user->next;
user->next = Lusers[lu_hash(newnick)];
Lusers[lu_hash(newnick)] = user;
*s = suser->next;
suser->next = user->server->users[su_hash(newnick)];
user->server->users[su_hash(newnick)] = suser;
/* NICK FLOOD PROTECTION */
/* 1st wipe old nick changes off */
chan = user->channel;
while (chan)
{
curr = chan->nickhist;
prec = NULL;
/* if not on channel.. ignore nick flood pro */
if (!chan->N->on)
{
chan = chan->next;
continue; /* yurk.. as bad as a goto ;) */
}
while (curr)
{
if (curr->time < (now - 15))
{
if (prec)
{
prec->next = curr->next;
TTLALLOCMEM -= sizeof(anickchange);
free(curr);
curr = prec->next;
}
else
{
chan->nickhist = curr->next;
TTLALLOCMEM -= sizeof(anickchange);
free(curr);
curr = chan->nickhist;
}
}
else
{
prec = curr;
curr = curr->next;
}
}
/* now add the new nick change to the history */
curr = (anickchange *) MALLOC(sizeof(anickchange));
strcpy(curr->nick, source);
curr->time = now; /* a lil confusing :( */
curr->next = chan->nickhist;
chan->nickhist = curr;
/* now count the nick changes in history
if there are more than allowed.. grrrr */
for (i = 0, curr = chan->nickhist; curr;
curr = curr->next, i++);
if (i == chan->N->NickFloodPro && chan->N->NickFloodPro != 0
&& chan->N->on)
{
sprintf(buffer, "%s!%s@%s", user->nick, user->username, user->site);
notice(newnick,
"### NICK FLOOD PROTECTION ACTIVATED ###");
sprintf(buffer, "%s %d", newnick,
NICK_FLOOD_SUSPEND_TIME);
suspend("", chan->N->name, buffer);
ban("", chan->N->name, newnick);
}
chan = chan->next;
}
}
}
void onquit(char *nick)
{
register aluser *user, **u;
register asuser *suser, **s;
register avalchan *valchan;
#ifdef DEBUG
printf("Detected user quit..\n");
#endif
u = &Lusers[lu_hash(nick)];
while (*u && strcasecmp(nick, (*u)->nick))
u = &(*u)->next;
user = *u;
if (user == NULL)
{
log("ERROR: onquit() can't find user!");
#ifdef HISTORY
History(NULL);
#endif
return;
}
/* remove from memory */
while ((valchan = user->valchan) != NULL)
{
#ifdef DEBUG
printf("\twas validated on %s\n", valchan->name);
#endif
valchan->reg->inuse--;
user->valchan = valchan->next;
TTLALLOCMEM -= strlen(valchan->name) + 1;
free(valchan->name);
TTLALLOCMEM -= sizeof(avalchan);
free(valchan);
}
while (user->channel != NULL)
{
#ifdef DEBUG
printf("\twas on %s\n", user->channel->N->name);
#endif
/* onpart() free's the chan structure
* we can't do chan=chan->next after the
* onpart() call. We must start from the
* beginning of the list every time
*/
onpart(nick, user->channel->N->name);
}
/* remove user from server's userlist
*/
s = &user->server->users[su_hash(user->nick)];
while (*s != NULL && strcasecmp((*s)->N->nick, user->nick))
{
s = &(*s)->next;
}
if (*s != NULL)
{
suser = *s;
*s = (*s)->next;
TTLALLOCMEM -= sizeof(asuser);
free(suser);
}
else
{
log("ERROR: onquit() user not found in server's userlist!");
}
*u = user->next;
#if 0
if (!strcasecmp(user->nick, DEFAULT_NICKNAME))
{
ChNick(DEFAULT_NICKNAME);
}
#endif
#ifdef NICKSERV
nserv_quit(user);
#endif
TTLALLOCMEM -= strlen(user->nick) + 1;
free(user->nick);
TTLALLOCMEM -= strlen(user->username) + 1;
free(user->username);
TTLALLOCMEM -= strlen(user->site) + 1;
free(user->site);
TTLALLOCMEM -= sizeof(aluser);
free(user);
}
void onkill(char *source, char *target, char *comment)
{
char buffer[200];
if (!strcasecmp(target, mynick))
{
#if 0
/* ignore kill for nick collisions because we
* already check in onnick() if we're collided.
* This kill is prolly a lost kill resulting of
* another nick collision..
*/
if (strstr(comment, "older nick overruled") ||
strstr(comment, "collided yourself"))
{
log("ERROR: Nick collision on me?");
return;
}
#endif
sprintf(buffer, ":%s SQUIT %s 0 :killed by %s\n",
SERVERNAME, SERVERNAME, source);
sendtoserv(buffer);
dumpbuff();
close(Irc.fd);
Irc.fd = -1;
if (reconnect(server))
{
try_later(server);
}
#ifdef BACKUP
}
else if (!strcasecmp(target, MAIN_NICK))
{
quit(MAIN_NICK " is back", 0);
#endif
#ifdef FAKE_UWORLD
}
else if (!strcasecmp(target, UFAKE_NICK))
{
char buffer[200];
sprintf(buffer, "%s is KILLED by %s", UFAKE_NICK, source);
log(buffer);
Uworld_status = 0;
KillUworld("Killed");
#endif
}
else
onquit(target);
}
void onwhois(char *source, char *nick)
{
register aluser *user;
register auser *usr;
register achannelnode *chan;
char buffer[512];
user = ToLuser(nick);
if (user == NULL)
{
sprintf(buffer, ":%s 401 %s %s :No such nick\n", SERVERNAME, source, nick);
sendtoserv(buffer);
}
else
{
sprintf(buffer, ":%s 311 %s %s %s %s * :\n", SERVERNAME, source, user->nick,
user->username, user->site);
sendtoserv(buffer);
chan = user->channel;
if (chan != NULL && strcmp(user->nick, "X") && strcmp(user->nick, "W"))
{
sprintf(buffer, ":%s 319 %s %s :", SERVERNAME, source, nick);
while (chan != NULL)
{
/* show a channel only if it is
* not +s or +p
*/
if (!IsSet(chan->N->name, 's', "") &&
!IsSet(chan->N->name, 'p', ""))
{
usr = ToUser(chan->N->name, nick);
if (usr->chanop)
strcat(buffer, "@");
strcat(buffer, chan->N->name);
strcat(buffer, " ");
}
chan = chan->next;
if (strlen(buffer) > 300)
{
strcat(buffer, "\n");
sendtoserv(buffer);
sprintf(buffer, ":%s 319 %s %s :",
SERVERNAME, source, nick);
}
}
strcat(buffer, "\n");
sendtoserv(buffer);
}
sprintf(buffer, ":%s 312 %s %s %s :\n", SERVERNAME, source, source, user->server->name);
sendtoserv(buffer);
if (user->mode & LFL_ISOPER)
{
sprintf(buffer, ":%s 313 %s %s :is an IRC Operator\n",
SERVERNAME, source, user->nick);
sendtoserv(buffer);
}
}
sprintf(buffer, ":%s 318 %s :End of /WHOIS list.\n", SERVERNAME, source);
sendtoserv(buffer);
}