This repository has been archived on 2025-02-12. You can view files and clone it, but cannot push or open issues or pull requests.
NeoStats-NeoIRCd/modules/core/m_nick.c
2003-03-06 14:01:51 +00:00

1056 lines
28 KiB
C

/*
* NeoIRCd: NeoStats Group. Based on Hybird7
* m_nick.c: Sets a users nick.
*
* Copyright (C) 2002 by the past and present ircd coders, and others.
*
* 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
*
* $Id: m_nick.c,v 1.21 2003/03/06 14:01:48 fishwaldo Exp $
*/
#include "stdinc.h"
#include "handlers.h"
#include "client.h"
#include "hash.h"
#include "fdlist.h"
#include "irc_string.h"
#include "ircd.h"
#include "numeric.h"
#include "s_conf.h"
#include "s_stats.h"
#include "s_user.h"
#include "hash.h"
#include "whowas.h"
#include "s_serv.h"
#include "send.h"
#include "list.h"
#include "channel.h"
#include "s_log.h"
#include "resv.h"
#include "msg.h"
#include "parse.h"
#include "modules.h"
#include "common.h"
#include "packet.h"
static void mr_nick(struct Client *, struct Client *, int, char**);
static void m_nick(struct Client *, struct Client *, int, char**);
static void ms_nick(struct Client *, struct Client *, int, char**);
static void ms_client(struct Client *, struct Client *, int, char**);
static int nick_from_server(struct Client *, struct Client *, int, char **,
time_t, char *);
static int client_from_server(struct Client *, struct Client *, int, char **,
time_t, char *);
static int check_clean_nick(struct Client *, struct Client *,
char *, char *, char *);
static int check_clean_user(struct Client *, char *, char *, char *);
static int check_clean_host(struct Client *, char *, char *, char *);
static int clean_nick_name(char *);
static int clean_user_name(char *);
static int clean_host_name(char *);
static int perform_nick_collides(struct Client *, struct Client *,
struct Client *, int, char **, time_t, char *);
struct Message nick_msgtab = {
"NICK", 0, 0, 1, 0, MFLG_SLOW, 0,
{mr_nick, m_nick, ms_nick, m_nick}
};
struct Message client_msgtab = {
"CLIENT", 0, 0, 11, 0, MFLG_SLOW, 0,
{m_ignore, m_ignore, ms_client, m_ignore}
};
#ifndef STATIC_MODULES
void
_modinit(void)
{
mod_add_cmd(&nick_msgtab);
mod_add_cmd(&client_msgtab);
}
void
_moddeinit(void)
{
mod_del_cmd(&nick_msgtab);
mod_del_cmd(&client_msgtab);
}
const char *_version = "$Revision: 1.21 $";
#endif
/*
* mr_nick()
*
* parv[0] = sender prefix
* parv[1] = nickname
*/
static void
mr_nick(struct Client *client_p, struct Client *source_p,
int parc, char *parv[])
{
struct Client *target_p, *uclient_p;
char nick[NICKLEN];
char* s;
dlink_node *ptr;
if(parc < 2 || BadPtr(parv[1]))
{
sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
me.name, BadPtr(parv[0]) ? "*" : parv[0]);
return;
}
/* Terminate the nick at the first ~ */
if ((s = strchr(parv[1], '~')))
*s = '\0';
/* copy the nick and terminate it */
strlcpy(nick, parv[1], NICKLEN);
/* check the nickname is ok */
if(!clean_nick_name(nick))
{
sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
me.name, BadPtr(parv[0]) ? "*" : parv[0], parv[1]);
return;
}
/* check if the nick is resv'd */
if(find_nick_resv(nick) &&
!(IsOper(source_p) && ConfigChannel.oper_pass_resv))
{
sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
me.name, BadPtr(parv[0]) ? "*" : parv[0], nick);
return;
}
if ((target_p = find_client(nick)) == NULL)
{
if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
{
/* We don't know anyone called nick, but our hub might */
for(ptr = unknown_list.head; ptr; ptr = ptr->next)
{
uclient_p = ptr->data;
if(!strcmp(nick, uclient_p->llname))
{
/* We're already waiting for a reply about this nick
* for someone else. */
sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
return;
}
}
/* Set their llname so we can find them later */
strcpy(source_p->llname, nick);
/* Ask the hub about their requested name */
sendto_one(uplink, ":%s NBURST %s %s !%s", me.name, nick,
nick, nick);
/* wait for LLNICK */
return;
}
else
{
set_initial_nick(client_p, source_p, nick);
return;
}
}
else if(source_p == target_p)
{
strcpy(source_p->name, nick);
return;
}
else
{
sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
}
}
/*
* m_nick()
*
* parv[0] = sender prefix
* parv[1] = nickname
*/
static void
m_nick(struct Client *client_p, struct Client *source_p,
int parc, char *parv[])
{
char nick[NICKLEN];
struct Client *target_p;
/* XXX BadPtr is needed */
if(parc < 2 || BadPtr(parv[1]))
{
sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
me.name, parv[0]);
return;
}
/* mark end of grace period, to prevent nickflooding */
if(!IsFloodDone(source_p))
flood_endgrace(source_p);
/* terminate nick to NICKLEN */
strlcpy(nick, parv[1], NICKLEN);
/* check the nickname is ok */
if(!clean_nick_name(nick))
{
sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
me.name, parv[0], nick);
return;
}
if(find_nick_resv(nick) &&
!(IsOper(source_p) && ConfigChannel.oper_pass_resv))
{
sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
me.name, parv[0], nick);
return;
}
if ((target_p = find_client(nick)))
{
/* If(target_p == source_p) the client is changing nicks between
* equivalent nicknames ie: [nick] -> {nick}
*/
if(target_p == source_p)
{
/* check the nick isnt exactly the same */
if(strcmp(target_p->name, nick))
{
change_local_nick(client_p, source_p, nick);
return;
}
else
{
/* client is doing :old NICK old
* ignore it..
*/
return;
}
}
/* if the client that has the nick isnt registered yet (nick but no
* user) then drop the unregged client
*/
if(IsUnknown(target_p))
{
/* the old code had an if(MyConnect(target_p)) here.. but I cant see
* how that can happen, m_nick() is local only --fl_
*/
exit_client(NULL, target_p, &me, "Overridden");
change_local_nick(client_p, source_p, nick);
return;
}
else
{
sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name,
parv[0], nick);
return;
}
}
else
{
if(!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
{
/* The uplink might know someone by this name already. */
sendto_one(uplink, ":%s NBURST %s %s %s", me.name, nick,
nick, source_p->name);
return;
}
else
{
change_local_nick(client_p,source_p,nick);
return;
}
}
}
/*
* ms_nick()
*
* server -> server nick change
* parv[0] = sender prefix
* parv[1] = nickname
* parv[2] = TS when nick change
*
* server introducing new nick
* parv[0] = sender prefix
* parv[1] = nickname
* parv[2] = hop count
* parv[3] = TS
* parv[4] = umode
* parv[5] = username
* parv[6] = hostname
* parv[7] = vhost
* parv[8] = server
* parv[9] = svsid
* parv[10] = ircname
*/
static void
ms_nick(struct Client *client_p, struct Client *source_p,
int parc, char *parv[])
{
struct Client* target_p;
char nick[NICKLEN];
time_t newts = 0;
/* XXX BadPtr is needed */
if(parc < 2 || BadPtr(parv[1]))
{
sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
return;
}
/* parc == 3 on nickchange, parc == 11 on new nick */
if((IsClient(source_p) && (parc != 3)) || (IsServer(source_p) && (parc != 11)))
{
char tbuf[BUFSIZE] = { 0 };
int j;
for(j = 0; j < parc; j++)
{
strcat(tbuf, parv[j]);
strcat(tbuf, " ");
}
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Dropping server %s due to (invalid) command 'NICK' "
"with only %d arguments. (Buf: '%s')",
client_p->name, parc, tbuf);
ilog(L_CRIT, "Insufficient parameters (%d) for command 'NICK' from %s. Buf: %s",
parc, client_p->name, tbuf);
exit_client(client_p, client_p, client_p, "Not enough arguments to server command.");
return;
}
/* fix the length of the nick */
strlcpy(nick, parv[1], NICKLEN);
if(check_clean_nick(client_p, source_p, nick, parv[1], parv[8]))
return;
if (parc == 11)
{
if (check_clean_user(client_p, nick, parv[5], parv[8]) ||
check_clean_host(client_p, nick, parv[6], parv[8]))
return;
/* check the length of the clients gecos */
if(strlen(parv[10]) > REALLEN)
{
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL, "Long realname from server %s for %s",
parv[8], parv[1]);
parv[10][REALLEN] = '\0';
}
if (IsServer(source_p))
newts = atol(parv[3]);
}
else
{
if (!IsServer(source_p))
newts = atol(parv[2]);
}
/* if the nick doesnt exist, allow it and process like normal */
if (!(target_p = find_client(nick)))
{
nick_from_server(client_p,source_p,parc,parv,newts,nick);
return;
}
/* we're not living in the past anymore, an unknown client is local only. */
if(IsUnknown(target_p))
{
exit_client(NULL, target_p, &me, "Overridden");
nick_from_server(client_p,source_p,parc,parv,newts,nick);
return;
}
if(target_p == source_p)
{
if(strcmp(target_p->name, nick))
{
/* client changing case of nick */
nick_from_server(client_p,source_p,parc,parv,newts,nick);
return;
}
else
/* client not changing nicks at all */
return;
}
perform_nick_collides(source_p, client_p, target_p,
parc, parv, newts, nick);
}
/*
* ms_client()
*/
static void
ms_client(struct Client *client_p, struct Client *source_p,
int parc, char *parv[])
{
struct Client* target_p;
char nick[NICKLEN];
time_t newts = 0;
char *id;
char *name;
id = parv[9];
name = parv[10];
/* XXX can this happen ? */
if (BadPtr(parv[1]))
return;
/* parse the nickname */
strlcpy(nick, parv[1], NICKLEN);
/* check the nicknames, usernames and hostnames are ok */
if(check_clean_nick(client_p, source_p, nick, parv[1], parv[8]) ||
check_clean_user(client_p, nick, parv[5], parv[8]) ||
check_clean_host(client_p, nick, parv[6], parv[8]))
return;
/* check length of clients gecos */
if (strlen(name) > REALLEN)
{
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL, "Long realname from server %s for %s",
parv[0], parv[1]);
name[REALLEN] = '\0';
}
newts = atol(parv[3]);
/* if there is an ID collision, kill our client, and kill theirs.
* this may generate 401's, but it ensures that both clients always
* go, even if the other server refuses to do the right thing.
*/
if((target_p = find_id(id)))
{
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"ID collision on %s(%s <- %s)(both killed)",
target_p->name, target_p->from->name,
client_p->name);
if(ServerInfo.hub && IsCapable(client_p, CAP_LL))
add_lazylinkclient(client_p, source_p);
kill_client_ll_serv_butone(NULL, target_p, "%s (ID collision)",
me.name);
ServerStats->is_kill++;
SetKilled(target_p);
exit_client(client_p, target_p, &me, "ID Collision");
return;
}
if (!(target_p = find_client(nick)))
{
client_from_server(client_p,source_p,parc,parv,newts,nick);
return;
}
if(IsUnknown(target_p))
{
exit_client(NULL, target_p, &me, "Overridden");
client_from_server(client_p,source_p,parc,parv,newts,nick);
return;
}
perform_nick_collides(source_p, client_p, target_p,
parc, parv, newts, nick);
}
/*
* check_clean_nick()
*
* input - pointer to source
* - nickname
* - truncated nickname
* - origin of client
* output - none
* side effects - if nickname is erroneous, or a different length to
* truncated nickname, return 1
*/
static int
check_clean_nick(struct Client *client_p, struct Client *source_p,
char *nick, char *newnick, char *server)
{
/* the old code did some wacky stuff here, if the nick is invalid, kill it
* and dont bother messing at all
*/
if(!clean_nick_name(nick) || strcmp(nick, newnick))
{
ServerStats->is_kill++;
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
"Bad Nick: %s From: %s(via %s)",
nick, server, client_p->name);
sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
me.name, newnick, me.name);
/* bad nick change */
if(source_p != client_p)
{
kill_client_ll_serv_butone(client_p, source_p,
"%s (Bad Nickname)",
me.name);
SetKilled(source_p);
exit_client(client_p, source_p, &me, "Bad Nickname");
}
return (1);
}
return (0);
}
/* check_clean_user()
*
* input - pointer to client sending data
* - nickname
* - username to check
* - origin of NICK
* output - none
* side effects - if username is erroneous, return 1
*/
static int
check_clean_user(struct Client *client_p, char *nick,
char *user, char *server)
{
if(strlen(user) > USERLEN)
{
ServerStats->is_kill++;
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
"Long Username: %s Nickname: %s From: %s(via %s)",
user, nick, server, client_p->name);
sendto_one(client_p, ":%s KILL %s :%s (Bad Username)",
me.name, nick, me.name);
return (1);
}
if(!clean_user_name(user))
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
"Bad Username: %s Nickname: %s From: %s(via %s)",
user, nick, server, client_p->name);
return (0);
}
/* check_clean_host()
*
* input - pointer to client sending us data
* - nickname
* - hostname to check
* - source name
* output - none
* side effects - if hostname is erroneous, return 1
*/
static int
check_clean_host(struct Client *client_p, char *nick,
char *host, char *server)
{
if(strlen(host) > HOSTLEN)
{
ServerStats->is_kill++;
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
"Long Hostname: %s Nickname: %s From: %s(via %s)",
host, nick, server, client_p->name);
sendto_one(client_p, ":%s KILL %s :%s (Bad Hostname)",
me.name, nick, me.name);
return (1);
}
if(!clean_host_name(host))
sendto_realops_flags(FLAGS_DEBUG, L_ALL,
"Bad Hostname: %s Nickname: %s From: %s(via %s)",
host, nick, server, client_p->name);
return (0);
}
/* clean_nick_name()
*
* input - nickname
* output - none
* side effects - walks through the nickname, returning 0 if erroneous
*/
static int
clean_nick_name(char *nick)
{
assert(nick);
if(nick == NULL)
return (0);
/* nicks cant start with a digit or - or be 0 length */
/* This closer duplicates behaviour of hybrid-6 */
if (*nick == '-' || IsDigit(*nick) || *nick == '\0')
return (0);
for(; *nick; nick++)
{
if(!IsNickChar(*nick))
return (0);
}
return (1);
}
/* clean_user_name()
*
* input - username
* output - none
* side effects - walks through the username, returning 0 if erroneous
*/
static int
clean_user_name(char *user)
{
assert(user);
if(user == NULL)
return 0;
for(; *user; user++)
{
if(!IsUserChar(*user))
return 0;
}
return 1;
}
/* clean_host_name()
* input - hostname
* output - none
* side effects - walks through the hostname, returning 0 if erroneous
*/
static int
clean_host_name(char *host)
{
assert(host);
if(host == NULL)
return 0;
for(; *host; host++)
{
if(!IsHostChar(*host))
return 0;
}
return 1;
}
/*
* nick_from_server()
*/
static int
nick_from_server(struct Client *client_p, struct Client *source_p, int parc,
char *parv[], time_t newts,char *nick)
{
if(IsServer(source_p))
{
/* A server introducing a new client, change source */
source_p = make_client(client_p);
add_client_to_list(source_p);
/* We don't need to introduce leafs clients back to them! */
if (ConfigFileEntry.hub && IsCapable(client_p, CAP_LL))
add_lazylinkclient(client_p, source_p);
if(parc > 2)
source_p->hopcount = atoi(parv[2]);
if(newts)
source_p->tsinfo = newts;
else
{
newts = source_p->tsinfo = CurrentTime;
ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]);
}
/* copy the nick in place */
(void)strcpy(source_p->name, nick);
(void)add_to_client_hash_table(nick, source_p);
strncpy(source_p->vhost, parv[6], HOSTLEN+1);
if (parc > 8)
{
int flag;
char *m;
/* parse usermodes */
m = &parv[4][1];
while (*m)
{
flag = user_modes_from_c_to_bitmask[(unsigned char)*m];
if(!(source_p->umodes & FLAGS_INVISIBLE) && (flag & FLAGS_INVISIBLE))
Count.invisi++;
if(!(source_p->umodes & FLAGS_OPER) && (flag & FLAGS_OPER))
Count.oper++;
if(!(source_p->umodes & FLAGS_HIDDEN) && (flag & FLAGS_HIDDEN)) {
if (parv[7][0] != '*')
strncpy(source_p->vhost, parv[7], HOSTLEN +1);
else {
/* THIS SHOULD NEVER HAPPEN */
sendto_realops_flags(FLAGS_DEBUG|FLAGS_REMOTE, L_ALL, "Warning, Server %s sent a Invalid Vhost in nick_from_server", source_p->from->name);
strncpy(source_p->vhost, source_p->host, HOSTLEN +1);
}
}
/* we only allow Ulined Servers to set +s */
if ((flag & FLAGS_SERVICES) && (!IsUlined(find_server(parv[8])))) {
sendto_one(source_p, ":%s NOTICE %s :*** Only Ulined Services can set +S", me.name, source_p->name);
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL, "Warning, Non-Ulined Server %s tried to set %s as +S", source_p->from->name, source_p->name);
/* we don't allow them to get +S, so do a continue */
continue;
}
source_p->umodes |= flag & SEND_UMODES;
m++;
}
return do_remote_user(nick, client_p, source_p, parv[5], parv[6],
parv[8], parv[10], NULL, atol(parv[9]));
}
}
else if(source_p->name[0])
{
/* client changing their nick */
if(irccmp(parv[0], nick))
source_p->tsinfo = newts ? newts : CurrentTime;
sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
source_p->name,source_p->username,source_p->vhost,
nick);
if (source_p->user)
{
add_history(source_p,1);
sendto_server(client_p, source_p, NULL, NOCAPS, NOCAPS, NOFLAGS,
":%s NICK %s :%lu",
parv[0], nick, (unsigned long) source_p->tsinfo);
}
}
/* set the new nick name */
if(source_p->name[0])
del_from_client_hash_table(source_p->name, source_p);
strcpy(source_p->name, nick);
add_to_client_hash_table(nick, source_p);
/* remove all accepts pointing to the client */
del_all_accepts(source_p);
return 0;
}
/*
* client_from_server()
*/
static int
client_from_server(struct Client *client_p, struct Client *source_p, int parc,
char *parv[], time_t newts,char *nick)
{
char *name;
char *id;
int flag;
char *m;
id = parv[9];
name = parv[11];
source_p = make_client(client_p);
add_client_to_list(source_p);
/* We don't need to introduce leafs clients back to them! */
if (ConfigFileEntry.hub && IsCapable(client_p, CAP_LL))
add_lazylinkclient(client_p, source_p);
source_p->hopcount = atoi(parv[2]);
source_p->tsinfo = newts;
/* copy the nick in place */
(void)strcpy(source_p->name, nick);
(void)add_to_client_hash_table(nick, source_p);
add_to_id_hash_table(id, source_p);
strncpy(source_p->vhost, parv[6], HOSTLEN+1);
/* parse usermodes */
m = &parv[4][1];
while (*m)
{
flag = user_modes_from_c_to_bitmask[(unsigned char)*m];
if(flag & FLAGS_INVISIBLE)
Count.invisi++;
if(flag & FLAGS_OPER)
Count.oper++;
if(!(source_p->umodes & FLAGS_HIDDEN) && (flag & FLAGS_HIDDEN)) {
if (parv[7][0] != '*')
strncpy(source_p->vhost, parv[7], HOSTLEN +1);
else {
sendto_realops_flags(FLAGS_DEBUG|FLAGS_REMOTE, L_ALL, "Warning %s sent a Invalid Hidden Host command in client_from_server", source_p->from->name);
strncpy(source_p->vhost, source_p->host, HOSTLEN +1);
}
}
/* we only allow Ulined Servers to set +s */
if ((flag & FLAGS_SERVICES) && (!IsUlined(find_server(parv[8])))) {
sendto_one(source_p, ":%s NOTICE %s :*** Only Ulined Services can set +S", me.name, source_p->name);
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL, "Warning, Non-Ulined Server %s tried to set %s as +S", source_p->from->name, source_p->name);
/* we don't allow them to get +S, so do a continue */
continue;
}
source_p->umodes |= flag & SEND_UMODES;
m++;
}
return do_remote_user(nick, client_p, source_p, parv[5], parv[6],
parv[8], name, id, atol(parv[10]));
}
static int
perform_nick_collides(struct Client *source_p, struct Client *client_p,
struct Client *target_p, int parc, char *parv[],
time_t newts, char *nick)
{
int sameuser;
/* server introducing new nick */
if(IsServer(source_p))
{
/* if we dont have a ts, or their TS's are the same, kill both */
if(!newts || !target_p->tsinfo ||
(newts == target_p->tsinfo))
{
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick collision on %s(%s <- %s)(both killed)",
target_p->name, target_p->from->name,
client_p->name);
if(ServerInfo.hub && IsCapable(client_p,CAP_LL))
add_lazylinkclient(client_p, target_p);
kill_client_ll_serv_butone(NULL, target_p,
"%s (Nick collision (new))",
me.name);
ServerStats->is_kill++;
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
me.name, target_p->name, target_p->name);
SetKilled(target_p);
exit_client(client_p, target_p, &me, "Nick collision (new)");
return 0;
}
/* the timestamps are different */
else
{
sameuser = (target_p->user) && !irccmp(target_p->username, parv[5])
&& !irccmp(target_p->host, parv[6]);
/* if the users are the same (loaded a client on a different server)
* and the new users ts is older, or the users are different and the
* new users ts is newer, ignore the new client and let it do the kill
*/
if ((sameuser && newts < target_p->tsinfo) ||
(!sameuser && newts > target_p->tsinfo))
{
client_burst_if_needed(client_p, target_p);
return 0;
}
else
{
if(sameuser)
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick collision on %s(%s <- %s)(older killed)",
target_p->name, target_p->from->name,
client_p->name);
else
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick collision on %s(%s <- %s)(newer killed)",
target_p->name, target_p->from->name,
client_p->name);
ServerStats->is_kill++;
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
me.name, target_p->name, target_p->name);
/* if it came from a LL server, itd have been source_p,
* so we dont need to mark target_p as known
*/
kill_client_ll_serv_butone(source_p, target_p,
"%s (Nick collision (new))",
me.name);
SetKilled(target_p);
exit_client(client_p, target_p, &me, "Nick collision");
if(parc == 11)
nick_from_server(client_p,source_p,parc,parv,newts,nick);
else if(parc == 12)
client_from_server(client_p,source_p,parc,parv,newts,nick);
return 0;
}
}
}
/* its a client changing nick and causing a collide */
if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) ||
!source_p->user)
{
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick change collision from %s to %s(%s <- %s)(both killed)",
source_p->name, target_p->name, target_p->from->name,
client_p->name);
ServerStats->is_kill++;
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
me.name, target_p->name, target_p->name);
/* if we got the message from a LL, it knows about source_p */
kill_client_ll_serv_butone(NULL, source_p,
"%s (Nick change collision)",
me.name);
ServerStats->is_kill++;
/* If we got the message from a LL, ensure it gets the kill */
if(ServerInfo.hub && IsCapable(client_p,CAP_LL))
add_lazylinkclient(client_p, target_p);
kill_client_ll_serv_butone(NULL, target_p,
"%s (Nick change collision)",
me.name);
SetKilled(target_p);
exit_client(NULL, target_p, &me, "Nick collision(new)");
SetKilled(source_p);
exit_client(client_p, source_p, &me, "Nick collision(old)");
return 0;
}
else
{
sameuser = !irccmp(target_p->username, source_p->username) &&
!irccmp(target_p->host, source_p->host);
if ((sameuser && newts < target_p->tsinfo) ||
(!sameuser && newts > target_p->tsinfo))
{
if(sameuser)
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick change collision from %s to %s(%s <- %s)(older killed)",
source_p->name, target_p->name, target_p->from->name,
client_p->name);
else
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick change collision from %s to %s(%s <- %s)(newer killed)",
source_p->name, target_p->name, target_p->from->name,
client_p->name);
ServerStats->is_kill++;
/* this won't go back to the incoming link, so LL doesnt matter */
kill_client_ll_serv_butone(client_p, source_p,
"%s (Nick change collision)",
me.name);
SetKilled(source_p);
if(sameuser)
exit_client(client_p, source_p, &me, "Nick collision(old)");
else
exit_client(client_p, source_p, &me, "Nick collision(new)");
return 0;
}
else
{
if(sameuser)
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick collision on %s(%s <- %s)(older killed)",
target_p->name, target_p->from->name,
client_p->name);
else
sendto_realops_flags(FLAGS_ALL|FLAGS_REMOTE, L_ALL,
"Nick collision on %s(%s <- %s)(newer killed)",
target_p->name, target_p->from->name,
client_p->name);
kill_client_ll_serv_butone(source_p, target_p,
"%s (Nick collision)",
me.name);
ServerStats->is_kill++;
sendto_one(target_p, form_str(ERR_NICKCOLLISION),
me.name, target_p->name, target_p->name);
SetKilled(target_p);
exit_client(client_p, target_p, &me, "Nick collision");
}
}
/*
if(HasID(source_p))
client_from_server(client_p,source_p,parc,parv,newts,nick);
else
*/
/* we should only ever call nick_from_server() here, as
* this is a client changing nick, not a new client
*/
nick_from_server(client_p,source_p,parc,parv,newts,nick);
return 0;
}