mirror of
https://github.com/anope/anope.git
synced 2026-07-07 04:03:12 +02:00
Rewrote the nick colliding/releaseing/canceling system, fixes many many bugs on IRCds without svsnick and/or svshold
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2975 5417fbe8-f217-4b02-8779-1006273d7864
This commit is contained in:
+22
-5
@@ -11,11 +11,16 @@ enum NickNameFlag
|
||||
NS_FORBIDDEN,
|
||||
/* Nick never expires */
|
||||
NS_NO_EXPIRE,
|
||||
/* Nick is being held after a kill */
|
||||
NS_KILL_HELD,
|
||||
/* SVSNICK has been sent but nick has not yet changed.
|
||||
* An enforcer will be introduced when it does change. */
|
||||
NS_GUESTED,
|
||||
/* This nick is being held after a kill by an enforcer client
|
||||
* or is being SVSHeld. Used by ns_release to determin if something
|
||||
* should be allowed to be released
|
||||
*/
|
||||
NS_HELD,
|
||||
/* We are taking over this nick, either by SVSNICK or KILL.
|
||||
* We are waiting for the confirmation of either of these actions to
|
||||
* proceed. This is checked in NickAlias::OnCancel
|
||||
*/
|
||||
NS_COLLIDED,
|
||||
|
||||
NS_END
|
||||
};
|
||||
@@ -106,6 +111,18 @@ class CoreExport NickAlias : public Extensible, public Flags<NickNameFlag>
|
||||
time_t last_seen; /* When it was seen online for the last time */
|
||||
NickCore *nc; /* I'm an alias of this */
|
||||
HostInfo hostinfo;
|
||||
|
||||
/** Release a nick
|
||||
* See the comment in users.cpp
|
||||
*/
|
||||
void Release();
|
||||
|
||||
/** This function is called when a user on this nick either disconnects or changes nick.
|
||||
* Note that the user isnt necessarially identified to this nick
|
||||
* See the comment in users.cpp
|
||||
* @param u The user
|
||||
*/
|
||||
void OnCancel(User *u);
|
||||
};
|
||||
|
||||
class CoreExport NickCore : public Extensible, public Flags<NickCoreFlag>
|
||||
|
||||
@@ -371,23 +371,18 @@ E NickAlias *nalists[1024];
|
||||
E NickCore *nclists[1024];
|
||||
E NickRequest *nrlists[1024];
|
||||
E NickRequest *findrequestnick(const char *nick);
|
||||
E unsigned int guestnum;
|
||||
E void insert_requestnick(NickRequest * nr);
|
||||
E void alpha_insert_alias(NickAlias * na);
|
||||
E void insert_core(NickCore * nc);
|
||||
E void get_aliases_stats(long *nrec, long *memuse);
|
||||
E void get_core_stats(long *nrec, long *memuse);
|
||||
E void collide(NickAlias * na, int from_timeout);
|
||||
E void del_ns_timeout(NickAlias * na, int type);
|
||||
E void change_core_display(NickCore * nc);
|
||||
E void change_core_display(NickCore * nc, const char *newdisplay);
|
||||
E void release(NickAlias * na, int from_timeout);
|
||||
E int do_setmodes(User * u);
|
||||
|
||||
E void ns_init();
|
||||
E void nickserv(User * u, char *buf);
|
||||
E int validate_user(User * u);
|
||||
E void cancel_user(User * u);
|
||||
E void expire_nicks();
|
||||
E void expire_requests();
|
||||
E NickAlias *findnick(const char *nick);
|
||||
|
||||
+13
-26
@@ -1159,65 +1159,52 @@ class CoreExport Anope
|
||||
*/
|
||||
class NickServCollide : public Timer
|
||||
{
|
||||
public:
|
||||
/* NickAlias of the nick who were kicking off */
|
||||
NickAlias *na;
|
||||
/* Return for the std::map::insert */
|
||||
std::pair<std::map<NickAlias *, NickServCollide *>::iterator, bool> it;
|
||||
/* The nick */
|
||||
std::string nick;
|
||||
|
||||
public:
|
||||
/** Default constructor
|
||||
* @param nickalias The nick alias were kicking off
|
||||
* @param _nick The nick were colliding
|
||||
* @param delay How long to delay before kicking the user off the nick
|
||||
*/
|
||||
NickServCollide(NickAlias *nickalias, time_t delay);
|
||||
NickServCollide(const std::string &_nick, time_t delay);
|
||||
|
||||
/** Default destructor
|
||||
*/
|
||||
~NickServCollide();
|
||||
virtual ~NickServCollide();
|
||||
|
||||
/** Called when the delay is up
|
||||
* @param t The current time
|
||||
*/
|
||||
void Tick(time_t t);
|
||||
|
||||
/** Clear all timers for a nick
|
||||
* @param na The nick to remove the timers for
|
||||
*/
|
||||
static void ClearTimers(NickAlias *na);
|
||||
};
|
||||
|
||||
/** Timers for releasing nicks to be available for use
|
||||
*/
|
||||
class NickServRelease : public Timer
|
||||
{
|
||||
public:
|
||||
/* The nick */
|
||||
NickAlias *na;
|
||||
std::string nick;
|
||||
|
||||
public:
|
||||
/* The uid of the services enforcer client (used for TS6 ircds) */
|
||||
std::string uid;
|
||||
/* Return for std::map::insert */
|
||||
std::pair<std::map<NickAlias *, NickServRelease *>::iterator, bool> it;
|
||||
|
||||
/** Default constructor
|
||||
* @param nickalias The nick
|
||||
* @param _nick The nick
|
||||
* @param _uid the uid of the enforcer, if any
|
||||
* @param delay The delay before the nick is released
|
||||
*/
|
||||
NickServRelease(NickAlias *nickalias, time_t delay);
|
||||
NickServRelease(const std::string &_nick, const std::string &_uid, time_t delay);
|
||||
|
||||
/** Default destructor
|
||||
*/
|
||||
~NickServRelease();
|
||||
virtual ~NickServRelease();
|
||||
|
||||
/** Called when the delay is up
|
||||
* @param t The current time
|
||||
*/
|
||||
void Tick(time_t t);
|
||||
|
||||
/** Clear all timers for a nick
|
||||
* @param na The nick to remove the timers for
|
||||
* @param dorelase true to actually call release(), false to just remove the timers
|
||||
*/
|
||||
static void ClearTimers(NickAlias *na, bool dorelease = false);
|
||||
};
|
||||
|
||||
/** A timer used to keep the BotServ bot/ChanServ in the channel
|
||||
|
||||
@@ -130,6 +130,7 @@ class CoreExport User : public Extensible
|
||||
/** Get the full mask ( nick!ident@realhost ) of a user
|
||||
*/
|
||||
const std::string GetMask();
|
||||
|
||||
/** Updates the realname of the user record.
|
||||
*/
|
||||
void SetRealname(const std::string &realname);
|
||||
@@ -143,6 +144,12 @@ class CoreExport User : public Extensible
|
||||
virtual void SendMessage(const std::string &source, const char *fmt, ...);
|
||||
virtual void SendMessage(const std::string &source, const std::string &msg);
|
||||
|
||||
/** Collide a nick
|
||||
* See the comment in users.cpp
|
||||
* @param na The nick
|
||||
*/
|
||||
void Collide(NickAlias *na);
|
||||
|
||||
/** Check if the user should become identified because
|
||||
* their svid matches the one stored in their nickcore
|
||||
* @param svid Services id
|
||||
|
||||
@@ -64,7 +64,10 @@ BotInfo::BotInfo(const std::string &nnick, const std::string &nuser, const std::
|
||||
|
||||
// If we're synchronised with the uplink already, call introduce_user() for this bot.
|
||||
if (serv_uplink && serv_uplink->sync == SSYNC_DONE)
|
||||
{
|
||||
ircdproto->SendClientIntroduction(this->nick, this->user, this->host, this->real, ircd->pseudoclient_mode, this->uid);
|
||||
ircdproto->SendSQLine(this->nick, "Reserved for services");
|
||||
}
|
||||
}
|
||||
|
||||
BotInfo::~BotInfo()
|
||||
|
||||
@@ -274,6 +274,7 @@ class CommandBSBot : public Command
|
||||
bi->uid = ts6_uid_retrieve();
|
||||
}
|
||||
ircdproto->SendClientIntroduction(bi->nick, bi->user, bi->host, bi->real, ircd->pseudoclient_mode, bi->uid);
|
||||
ircdproto->SendSQLine(bi->nick, "Reserved for services");
|
||||
bi->RejoinAll();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class CommandNSForbid : public Command
|
||||
if (curr)
|
||||
{
|
||||
notice_lang(Config.s_NickServ, curr, FORCENICKCHANGE_NOW);
|
||||
collide(na, 0);
|
||||
curr->Collide(na);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#define TO_COLLIDE 0 /* Collide the user with this nick */
|
||||
#define TO_RELEASE 1 /* Release a collided nick */
|
||||
|
||||
class CommandNSIdentify : public Command
|
||||
{
|
||||
public:
|
||||
@@ -94,10 +91,6 @@ class CommandNSIdentify : public Command
|
||||
|
||||
if (u->IsIdentified())
|
||||
check_memos(u);
|
||||
|
||||
/* Clear any timers */
|
||||
if (na->nc->HasFlag(NI_KILLPROTECT))
|
||||
del_ns_timeout(na, TO_COLLIDE);
|
||||
}
|
||||
return MOD_CONT;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#define TO_COLLIDE 0 /* Collide the user with this nick */
|
||||
#define TO_RELEASE 1 /* Release a collided nick */
|
||||
|
||||
class CommandNSLogout : public Command
|
||||
{
|
||||
public:
|
||||
@@ -44,7 +41,6 @@ class CommandNSLogout : public Command
|
||||
|
||||
if (nick && !param.empty() && param == "REVALIDATE")
|
||||
{
|
||||
cancel_user(u2);
|
||||
validate_user(u2);
|
||||
}
|
||||
|
||||
@@ -57,10 +53,6 @@ class CommandNSLogout : public Command
|
||||
else
|
||||
notice_lang(Config.s_NickServ, u, NICK_LOGOUT_SUCCEEDED);
|
||||
|
||||
/* Clear any timers again */
|
||||
if (na && u->Account()->HasFlag(NI_KILLPROTECT))
|
||||
del_ns_timeout(na, TO_COLLIDE);
|
||||
|
||||
ircdproto->SendAccountLogout(u2, u2->Account());
|
||||
ircdproto->SendUnregisteredNick(u2);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class CommandNSRecover : public Command
|
||||
char relstr[192];
|
||||
|
||||
notice_lang(Config.s_NickServ, u2, FORCENICKCHANGE_NOW);
|
||||
collide(na, 0);
|
||||
u2->Collide(na);
|
||||
|
||||
/* Convert Config.NSReleaseTimeout seconds to string format */
|
||||
duration(na->nc, relstr, sizeof(relstr), Config.NSReleaseTimeout);
|
||||
@@ -74,7 +74,7 @@ class CommandNSRecover : public Command
|
||||
char relstr[192];
|
||||
|
||||
notice_lang(Config.s_NickServ, u2, FORCENICKCHANGE_NOW);
|
||||
collide(na, 0);
|
||||
u2->Collide(na);
|
||||
|
||||
/* Convert Config.NSReleaseTimeout seconds to string format */
|
||||
duration(na->nc, relstr, sizeof(relstr), Config.NSReleaseTimeout);
|
||||
|
||||
@@ -35,14 +35,14 @@ class CommandNSRelease : public Command
|
||||
notice_lang(Config.s_NickServ, u, NICK_X_FORBIDDEN, na->nick);
|
||||
else if (na->nc->HasFlag(NI_SUSPENDED))
|
||||
notice_lang(Config.s_NickServ, u, NICK_X_SUSPENDED, na->nick);
|
||||
else if (!(na->HasFlag(NS_KILL_HELD)))
|
||||
else if (!(na->HasFlag(NS_HELD)))
|
||||
notice_lang(Config.s_NickServ, u, NICK_RELEASE_NOT_HELD, nick);
|
||||
else if (!pass.empty())
|
||||
{
|
||||
int res = enc_check_password(pass, na->nc->pass);
|
||||
if (res == 1)
|
||||
{
|
||||
release(na, 0);
|
||||
na->Release();
|
||||
notice_lang(Config.s_NickServ, u, NICK_RELEASED);
|
||||
}
|
||||
else
|
||||
@@ -60,7 +60,7 @@ class CommandNSRelease : public Command
|
||||
{
|
||||
if (u->Account() == na->nc || (!(na->nc->HasFlag(NI_SECURE)) && is_on_access(u, na->nc)))
|
||||
{
|
||||
release(na, 0);
|
||||
na->Release();
|
||||
notice_lang(Config.s_NickServ, u, NICK_RELEASED);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -70,11 +70,12 @@ class CommandNSSuspend : public Command
|
||||
if (na2->last_quit)
|
||||
delete [] na2->last_quit;
|
||||
na2->last_quit = sstrdup(reason);
|
||||
/* removes nicktracking */
|
||||
|
||||
if ((u2 = finduser(na2->nick)))
|
||||
{
|
||||
u2->Logout();
|
||||
/* force guestnick */
|
||||
collide(na2, 0);
|
||||
u2->Collide(na2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,10 @@ void introduce_user(const std::string &user)
|
||||
{
|
||||
ci::string ci_bi_nick(bi->nick.c_str());
|
||||
if (user.empty() || ci_bi_nick == user)
|
||||
{
|
||||
ircdproto->SendClientIntroduction(bi->nick, bi->user, bi->host, bi->real, ircd->pseudoclient_mode, bi->uid);
|
||||
ircdproto->SendSQLine(bi->nick, "Reserved for services");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -300,7 +300,7 @@ int m_whois(const char *source, const char *who)
|
||||
ircdproto->SendNumeric(Config.ServerName, 317, source, "%s %ld %ld :seconds idle, signon time", bi->nick.c_str(), time(NULL) - bi->lastmsg, start_time);
|
||||
ircdproto->SendNumeric(Config.ServerName, 318, source, "%s :End of /WHOIS list.", who);
|
||||
}
|
||||
else if (!ircd->svshold && (na = findnick(who)) && na->HasFlag(NS_KILL_HELD))
|
||||
else if (!ircd->svshold && (na = findnick(who)) && na->HasFlag(NS_HELD))
|
||||
{
|
||||
/* We have a nick enforcer client here that we need to respond to.
|
||||
* We can't just say it doesn't exist here, even tho it does for
|
||||
|
||||
+46
-4
@@ -80,10 +80,6 @@ NickAlias::~NickAlias()
|
||||
{
|
||||
User *u = NULL;
|
||||
|
||||
/* First thing to do: remove any timeout belonging to the nick we're deleting */
|
||||
NickServCollide::ClearTimers(this);
|
||||
NickServRelease::ClearTimers(this, true);
|
||||
|
||||
FOREACH_MOD(I_OnDelNick, OnDelNick(this));
|
||||
|
||||
/* Second thing to do: look for an user using the alias
|
||||
@@ -130,3 +126,49 @@ NickAlias::~NickAlias()
|
||||
delete [] this->last_quit;
|
||||
}
|
||||
|
||||
/** Release a nick from being held. This can be called from the core (ns_release)
|
||||
* or from a timer used when forcing clients off of nicks. Note that if this is called
|
||||
* from a timer, ircd->svshold is NEVER true
|
||||
*/
|
||||
void NickAlias::Release()
|
||||
{
|
||||
if (this->HasFlag(NS_HELD))
|
||||
{
|
||||
if (ircd->svshold)
|
||||
{
|
||||
ircdproto->SendSVSHoldDel(this->nick);
|
||||
}
|
||||
else
|
||||
{
|
||||
ircdproto->SendQuit(this->nick, NULL);
|
||||
}
|
||||
|
||||
this->UnsetFlag(NS_HELD);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when a user gets off this nick
|
||||
* See the comment in users.cpp for User::Collide()
|
||||
* @param u The user
|
||||
*/
|
||||
void NickAlias::OnCancel(User *)
|
||||
{
|
||||
if (this->HasFlag(NS_COLLIDED))
|
||||
{
|
||||
this->SetFlag(NS_HELD);
|
||||
this->UnsetFlag(NS_COLLIDED);
|
||||
|
||||
if (ircd->svshold)
|
||||
{
|
||||
ircdproto->SendSVSHold(this->nick);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string uid = (ircd->ts6 ? ts6_uid_retrieve() : "");
|
||||
|
||||
ircdproto->SendClientIntroduction(this->nick, Config.NSEnforcerUser, Config.NSEnforcerHost, "Services Enforcer", "+", uid);
|
||||
new NickServRelease(this->nick, uid, Config.NSReleaseTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-191
@@ -24,106 +24,60 @@ NickAlias *nalists[1024];
|
||||
NickCore *nclists[1024];
|
||||
NickRequest *nrlists[1024];
|
||||
|
||||
unsigned int guestnum; /* Current guest number */
|
||||
static std::map<std::string, NickServCollide *> NickServCollides;
|
||||
static std::map<std::string, NickServRelease *> NickServReleases;
|
||||
|
||||
#define TO_COLLIDE 0 /* Collide the user with this nick */
|
||||
#define TO_RELEASE 1 /* Release a collided nick */
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static std::map<NickAlias *, NickServCollide *> NickServCollides;
|
||||
static std::map<NickAlias *, NickServRelease *> NickServReleases;
|
||||
|
||||
NickServCollide::NickServCollide(NickAlias *nickalias, time_t delay) : Timer(delay), na(nickalias)
|
||||
NickServCollide::NickServCollide(const std::string &_nick, time_t delay) : Timer(delay), nick(_nick)
|
||||
{
|
||||
/* Erase the current collide and use the new one */
|
||||
std::map<NickAlias *, NickServCollide *>::iterator nit = NickServCollides.find(nickalias);
|
||||
std::map<std::string, NickServCollide *>::iterator nit = NickServCollides.find(nick);
|
||||
if (nit != NickServCollides.end())
|
||||
{
|
||||
delete nit->second;
|
||||
}
|
||||
|
||||
it = NickServCollides.insert(std::make_pair(nickalias, this));
|
||||
NickServCollides.insert(std::make_pair(nick, this));
|
||||
}
|
||||
|
||||
NickServCollide::~NickServCollide()
|
||||
{
|
||||
if (it.second)
|
||||
{
|
||||
NickServCollides.erase(it.first);
|
||||
}
|
||||
NickServCollides.erase(nick);
|
||||
}
|
||||
|
||||
void NickServCollide::Tick(time_t ctime)
|
||||
{
|
||||
/* If they identified or don't exist anymore, don't kill them. */
|
||||
User *u = finduser(na->nick);
|
||||
if (!u || u->Account() == na->nc || u->my_signon > this->GetSetTime())
|
||||
User *u = finduser(nick);
|
||||
NickAlias *na = findnick(nick);
|
||||
if (!u || !na || u->Account() == na->nc || u->my_signon > this->GetSetTime())
|
||||
return;
|
||||
|
||||
/* The RELEASE timeout will always add to the beginning of the
|
||||
* list, so we won't see it. Which is fine because it can't be
|
||||
* triggered yet anyway. */
|
||||
collide(na, 1);
|
||||
|
||||
u->Collide(na);
|
||||
}
|
||||
|
||||
void NickServCollide::ClearTimers(NickAlias *na)
|
||||
{
|
||||
std::map<NickAlias *, NickServCollide *>::iterator i = NickServCollides.find(na);
|
||||
|
||||
if (i != NickServCollides.end())
|
||||
{
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
|
||||
NickServRelease::NickServRelease(NickAlias *nickalias, time_t delay) : Timer(delay), na(nickalias)
|
||||
NickServRelease::NickServRelease(const std::string &_nick, const std::string &_uid, time_t delay) : Timer(delay), nick(_nick), uid(_uid)
|
||||
{
|
||||
/* Erase the current release timer and use the new one */
|
||||
std::map<NickAlias *, NickServRelease *>::iterator nit = NickServReleases.find(nickalias);
|
||||
std::map<std::string, NickServRelease *>::iterator nit = NickServReleases.find(nick);
|
||||
if (nit != NickServReleases.end())
|
||||
{
|
||||
delete nit->second;
|
||||
}
|
||||
|
||||
it = NickServReleases.insert(std::make_pair(nickalias, this));
|
||||
NickServReleases.insert(std::make_pair(nick, this));
|
||||
}
|
||||
|
||||
NickServRelease::~NickServRelease()
|
||||
{
|
||||
if (it.second)
|
||||
{
|
||||
NickServReleases.erase(it.first);
|
||||
}
|
||||
NickServReleases.erase(nick);
|
||||
}
|
||||
|
||||
void NickServRelease::Tick(time_t ctime)
|
||||
{
|
||||
if (ircd->svshold)
|
||||
{
|
||||
ircdproto->SendSVSHoldDel(na->nick);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ircd->ts6 && !uid.empty())
|
||||
ircdproto->SendQuit(uid.c_str(), NULL);
|
||||
else
|
||||
ircdproto->SendQuit(na->nick, NULL);
|
||||
}
|
||||
na->UnsetFlag(NS_KILL_HELD);
|
||||
}
|
||||
NickAlias *na = findnick(nick);
|
||||
|
||||
void NickServRelease::ClearTimers(NickAlias *na, bool dorelease)
|
||||
{
|
||||
std::map<NickAlias *, NickServRelease *>::iterator i = NickServReleases.find(na);
|
||||
|
||||
if (i != NickServReleases.end())
|
||||
{
|
||||
if (dorelease)
|
||||
release(na, 1);
|
||||
|
||||
delete i->second;
|
||||
}
|
||||
if (na)
|
||||
na->Release();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -217,9 +171,6 @@ void get_core_stats(long *nrec, long *memuse)
|
||||
void ns_init()
|
||||
{
|
||||
moduleAddNickServCmds();
|
||||
guestnum = time(NULL);
|
||||
while (guestnum > 9999999)
|
||||
guestnum -= 10000000;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
@@ -265,11 +216,11 @@ int validate_user(User * u)
|
||||
{
|
||||
NickAlias *na;
|
||||
NickRequest *nr;
|
||||
NickServCollide *t;
|
||||
|
||||
if ((nr = findrequestnick(u->nick.c_str())))
|
||||
{
|
||||
notice_lang(Config.s_NickServ, u, NICK_IS_PREREG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(na = findnick(u->nick)))
|
||||
@@ -278,14 +229,14 @@ int validate_user(User * u)
|
||||
if (na->HasFlag(NS_FORBIDDEN))
|
||||
{
|
||||
notice_lang(Config.s_NickServ, u, NICK_MAY_NOT_BE_USED);
|
||||
collide(na, 0);
|
||||
u->Collide(na);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (na->nc->HasFlag(NI_SUSPENDED))
|
||||
{
|
||||
notice_lang(Config.s_NickServ, u, NICK_X_SUSPENDED, u->nick.c_str());
|
||||
collide(na, 0);
|
||||
u->Collide(na);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -315,17 +266,17 @@ int validate_user(User * u)
|
||||
if (na->nc->HasFlag(NI_KILL_IMMED))
|
||||
{
|
||||
notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_NOW);
|
||||
collide(na, 0);
|
||||
u->Collide(na);
|
||||
}
|
||||
else if (na->nc->HasFlag(NI_KILL_QUICK))
|
||||
{
|
||||
notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_IN_20_SECONDS);
|
||||
t = new NickServCollide(na, 20);
|
||||
new NickServCollide(na->nick, 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_IN_1_MINUTE);
|
||||
t = new NickServCollide(na, 60);
|
||||
new NickServCollide(na->nick, 60);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,44 +285,6 @@ int validate_user(User * u)
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Cancel validation flags for a nick (i.e. when the user with that nick
|
||||
* signs off or changes nicks). Also cancels any impending collide. */
|
||||
|
||||
void cancel_user(User * u)
|
||||
{
|
||||
NickAlias *na = findnick(u->nick);
|
||||
NickServRelease *t;
|
||||
std::string uid;
|
||||
|
||||
if (na)
|
||||
{
|
||||
if (na->HasFlag(NS_GUESTED))
|
||||
{
|
||||
if (ircd->svshold)
|
||||
{
|
||||
ircdproto->SendSVSHold(na->nick);
|
||||
}
|
||||
else if (ircd->svsnick)
|
||||
{
|
||||
uid = ts6_uid_retrieve();
|
||||
ircdproto->SendClientIntroduction(u->nick, Config.NSEnforcerUser, Config.NSEnforcerHost, "Services Enforcer", "+", uid);
|
||||
t = new NickServRelease(na, Config.NSReleaseTimeout);
|
||||
t->uid = uid;
|
||||
}
|
||||
else
|
||||
{
|
||||
ircdproto->SendSVSKill(findbot(Config.s_NickServ), u, "Please do not use a registered nickname without identifying");
|
||||
}
|
||||
na->SetFlag(NS_KILL_HELD);
|
||||
na->UnsetFlag(NS_GUESTED);
|
||||
}
|
||||
|
||||
NickServCollide::ClearTimers(na);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Remove all nicks which have expired. Also update last-seen time for all
|
||||
* nicks.
|
||||
*/
|
||||
@@ -699,86 +612,6 @@ void change_core_display(NickCore * nc)
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Collide a nick.
|
||||
*
|
||||
* When connected to a network using DALnet servers, version 4.4.15 and above,
|
||||
* Services is now able to force a nick change instead of killing the user.
|
||||
* The new nick takes the form "Guest######". If a nick change is forced, we
|
||||
* do not introduce the enforcer nick until the user's nick actually changes.
|
||||
* This is watched for and done in cancel_user(). -TheShadow
|
||||
*/
|
||||
|
||||
void collide(NickAlias * na, int from_timeout)
|
||||
{
|
||||
if (!from_timeout)
|
||||
NickServCollide::ClearTimers(na);
|
||||
|
||||
/* Old system was unsure since there can be more than one collide
|
||||
* per second. So let use another safer method.
|
||||
* --lara
|
||||
*/
|
||||
/* So you should check the length of Config.NSGUestNickPrefix, eh Lara?
|
||||
* --Certus
|
||||
*/
|
||||
|
||||
if (ircd->svsnick)
|
||||
{
|
||||
User *u = finduser(na->nick);
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
std::string guestnick;
|
||||
/* We need to make sure the guestnick is free -- heinz */
|
||||
do
|
||||
{
|
||||
char randbuf[17];
|
||||
snprintf(randbuf, sizeof(randbuf), "%d", getrandom16());
|
||||
guestnick = Config.NSGuestNickPrefix;
|
||||
guestnick += randbuf;
|
||||
}
|
||||
while (finduser(guestnick.c_str()));
|
||||
notice_lang(Config.s_NickServ, finduser(na->nick), FORCENICKCHANGE_CHANGING, guestnick.c_str());
|
||||
ircdproto->SendForceNickChange(u, guestnick.c_str(), time(NULL));
|
||||
na->SetFlag(NS_GUESTED);
|
||||
}
|
||||
else
|
||||
{
|
||||
kill_user(Config.s_NickServ, na->nick, "Services nickname-enforcer kill");
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Release hold on a nick. */
|
||||
|
||||
void release(NickAlias * na, int from_timeout)
|
||||
{
|
||||
if (!from_timeout)
|
||||
NickServRelease::ClearTimers(na);
|
||||
|
||||
if (ircd->svshold)
|
||||
{
|
||||
ircdproto->SendSVSHoldDel(na->nick);
|
||||
}
|
||||
else
|
||||
{
|
||||
ircdproto->SendQuit(na->nick, NULL);
|
||||
}
|
||||
na->UnsetFlag(NS_KILL_HELD);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
void del_ns_timeout(NickAlias * na, int type)
|
||||
{
|
||||
if (type == TO_COLLIDE)
|
||||
NickServCollide::ClearTimers(na);
|
||||
else if (type == TO_RELEASE)
|
||||
NickServRelease::ClearTimers(na);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/*********************** NickServ command routines ***********************/
|
||||
/*************************************************************************/
|
||||
|
||||
@@ -261,7 +261,6 @@ class BahamutIRCdProto : public IRCDProto
|
||||
{
|
||||
EnforceQlinedNick(nick, Config.s_BotServ);
|
||||
send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick.c_str(), static_cast<long>(time(NULL)), modes, user.c_str(), host.c_str(), Config.ServerName, real.c_str());
|
||||
SendSQLine(nick, "Reserved for services");
|
||||
}
|
||||
|
||||
/* SVSMODE +d */
|
||||
|
||||
@@ -209,7 +209,6 @@ class RatboxProto : public IRCDTS6Proto
|
||||
{
|
||||
EnforceQlinedNick(nick, NULL);
|
||||
send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0 %s :%s", nick.c_str(), static_cast<long>(time(NULL)), modes, user.c_str(), host.c_str(), uid.c_str(), real.c_str());
|
||||
SendSQLine(nick, "Reserved for services");
|
||||
}
|
||||
|
||||
void SendPartInternal(BotInfo *bi, const char *chan, const char *buf)
|
||||
|
||||
@@ -197,9 +197,8 @@ class UnrealIRCdProto : public IRCDProto
|
||||
|
||||
void SendClientIntroduction(const std::string &nick, const std::string &user, const std::string &host, const std::string &real, const char *modes, const std::string &uid)
|
||||
{
|
||||
EnforceQlinedNick(nick, Config.s_BotServ);
|
||||
EnforceQlinedNick(nick, Config.ServerName);
|
||||
send_cmd(NULL, "& %s 1 %ld %s %s %s 0 %s %s%s :%s", nick.c_str(), static_cast<long>(time(NULL)), user.c_str(), host.c_str(), Config.ServerName, modes, host.c_str(), myIrcd->nickip ? " *" : " ", real.c_str());
|
||||
SendSQLine(nick, "Reserved for services");
|
||||
}
|
||||
|
||||
void SendKickInternal(BotInfo *source, Channel *chan, User *user, const char *buf)
|
||||
|
||||
+106
-27
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "services.h"
|
||||
#include "modules.h"
|
||||
#include "language.h"
|
||||
|
||||
#define HASH(nick) (((nick)[0]&31)<<5 | ((nick)[1]&31))
|
||||
User *userlist[1024];
|
||||
@@ -223,13 +224,11 @@ void User::SetRealname(const std::string &srealname)
|
||||
|
||||
User::~User()
|
||||
{
|
||||
char *srealname;
|
||||
|
||||
Alog(LOG_DEBUG_2) << "User::~User() called";
|
||||
|
||||
if (Config.LogUsers)
|
||||
{
|
||||
srealname = normalizeBuffer(this->realname);
|
||||
const char *srealname = normalizeBuffer(this->realname);
|
||||
|
||||
Alog() << "LOGUSERS: " << this->GetMask() << (ircd->vhost ? " => " : " ")
|
||||
<< (ircd->vhost ? this->GetDisplayedHost() : "")
|
||||
@@ -244,6 +243,22 @@ User::~User()
|
||||
|
||||
if (is_oper(this))
|
||||
opcnt--;
|
||||
|
||||
while (!this->chans.empty())
|
||||
{
|
||||
this->chans.front()->chan->DeleteUser(this);
|
||||
}
|
||||
|
||||
if (this->prev)
|
||||
this->prev->next = this->next;
|
||||
else
|
||||
userlist[HASH(this->nick)] = this->next;
|
||||
if (this->next)
|
||||
this->next->prev = this->prev;
|
||||
|
||||
NickAlias *na = findnick(this->nick);
|
||||
if (na)
|
||||
na->OnCancel(this);
|
||||
|
||||
Alog(LOG_DEBUG_2) << "User::~User(): free user data";
|
||||
|
||||
@@ -257,26 +272,6 @@ User::~User()
|
||||
if (this->hostip)
|
||||
delete [] this->hostip;
|
||||
|
||||
Alog(LOG_DEBUG_2) << "User::~User(): remove from channels";
|
||||
|
||||
while (!this->chans.empty())
|
||||
{
|
||||
this->chans.front()->chan->DeleteUser(this);
|
||||
}
|
||||
|
||||
/* Cancel pending nickname enforcers, etc */
|
||||
cancel_user(this);
|
||||
|
||||
Alog(LOG_DEBUG_2) << "User::~User(): delete from list";
|
||||
|
||||
if (this->prev)
|
||||
this->prev->next = this->next;
|
||||
else
|
||||
userlist[HASH(this->nick)] = this->next;
|
||||
|
||||
if (this->next)
|
||||
this->next->prev = this->prev;
|
||||
|
||||
Alog(LOG_DEBUG_2) << "User::~User() done";
|
||||
}
|
||||
|
||||
@@ -315,6 +310,88 @@ void User::SendMessage(const std::string &source, const std::string &msg)
|
||||
}
|
||||
}
|
||||
|
||||
/** Collides a nick.
|
||||
*
|
||||
* First, it marks the nick (if the user is on a registered nick, we don't use it without but it could be)
|
||||
* as COLLIDED, this is checked in NickAlias::OnCancel.
|
||||
*
|
||||
* Then it does one of two things.
|
||||
*
|
||||
* 1. This will force change the users nick to the guest nick. This gets processed by the IRCd and comes
|
||||
* back to call do_nick. do_nick changes the nick of the use to the new one, then calls NickAlias::OnCancel
|
||||
* with the users old nick's nickalias (if there is one).
|
||||
*
|
||||
* 2. Calls kill_user, which will either delete the user immediatly or kill them, wait for the QUIT,
|
||||
* then delete the user then. Users destructor then calls NickAlias::OnCancel
|
||||
*
|
||||
* NickAlias::OnCancel checks for NS_COLLIDED, it then does one of two things.
|
||||
*
|
||||
* 1. If supported, we send a SVSHold for the user. We are done here, the IRCds expires this at the time we give it.
|
||||
*
|
||||
* 2. We create a new client with SendClientIntroduction(). Note that is it important that this is called either after the
|
||||
* user has been removed from our internal list of user or after the users nick has been updated completely internally.
|
||||
* This is beacuse SendClientIntroduction will destroy any users we think are currently on the nickname (which causes a
|
||||
* lot of problems, eg, deleting the user which recalls OnCancel), whether they really are or not. We then create a
|
||||
* release timer for this new client that waits and later on sends a QUIT for the client. Release timers are never used
|
||||
* for SVSHolds. Ever.
|
||||
*
|
||||
*
|
||||
* Note that now for the timers we only store the users name, not the NickAlias* pointer. We never remove timers when
|
||||
* a user changes nick or a nick is deleted, the timers must assume that either of these may have happend.
|
||||
*
|
||||
* Storing NickAlias* pointers caused quite a problem, some of which are:
|
||||
*
|
||||
* Having a valid timer alive that calls User::Collide would either:
|
||||
*
|
||||
* 1. Kill the user, causing users destructor to cancel all timers for the nick (as it should, it has no way of knowing
|
||||
* if we are in a timer or not) which would delete the currently active timer while it was running, causing TimerManager
|
||||
* to explode.
|
||||
*
|
||||
* 2. Force a user off of their nick, this would call NickAlias::Cancel before updating the user internally (to cancel the
|
||||
* current nicks timers, granted we could have easially saved this and called it after) which could possibly try to
|
||||
* introduce an enforcer nick. We would then check to see if the nick is already in use (it is, internally) and send
|
||||
* a kill for that nick. That may in turn delete the user immediatly, calling users destructor, which would attempt to
|
||||
* delete the timer, causing TimerManager to explode.
|
||||
*
|
||||
* Additionally, if we marked the timer as "in use" so that calling the ClearTimer function wouldn't delete them, users
|
||||
* destructor would then call NickAlias::OnCancel, which would (at this point, it was unsetting GUESTED after introducing
|
||||
* the new client) introduce the same new client again, without actually deleting the originial user, causing an infinite
|
||||
* loop.
|
||||
*
|
||||
* This is why we remove NS_GUESTED first in NickAlias::OnCancel before introducing a new client, although this should
|
||||
* not happen anymore. If I must emphasize this again, users need to be GONE from the internal list before calling
|
||||
* NickAlias::OnCancel. NickAlias::OnCancel intentionally reffers to this->nick, not the user passed to it. They *can*
|
||||
* (but not always) be different, depending if the user changed nicks or disconnected.
|
||||
*
|
||||
*
|
||||
* Adam
|
||||
*/
|
||||
void User::Collide(NickAlias *na)
|
||||
{
|
||||
if (na)
|
||||
na->SetFlag(NS_COLLIDED);
|
||||
|
||||
if (ircd->svsnick)
|
||||
{
|
||||
std::string guestnick;
|
||||
|
||||
do
|
||||
{
|
||||
char randbuf[17];
|
||||
snprintf(randbuf, sizeof(randbuf), "%d", getrandom16());
|
||||
guestnick = std::string(Config.NSGuestNickPrefix) + std::string(randbuf);
|
||||
}
|
||||
while (finduser(guestnick.c_str()));
|
||||
|
||||
notice_lang(Config.s_NickServ, this, FORCENICKCHANGE_CHANGING, guestnick.c_str());
|
||||
ircdproto->SendForceNickChange(this, guestnick.c_str(), time(NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
kill_user(Config.s_NickServ, this->nick, "Services nickname-enforcer kill");
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if the user should become identified because
|
||||
* their svid matches the one stored in their nickcore
|
||||
* @param svid Services id
|
||||
@@ -749,7 +826,6 @@ User *do_nick(const char *source, const char *nick, const char *username, const
|
||||
NickAlias *old_na; /* Old nick rec */
|
||||
int nc_changed = 1; /* Did nick core change? */
|
||||
char *logrealname;
|
||||
std::string oldnick; /* stores the old nick of the user, so we can pass it to OnUserNickChange */
|
||||
|
||||
if (!*source) {
|
||||
char ipbuf[16];
|
||||
@@ -875,16 +951,19 @@ User *do_nick(const char *source, const char *nick, const char *username, const
|
||||
user->my_signon = time(NULL);
|
||||
|
||||
old_na = findnick(user->nick);
|
||||
if (old_na) {
|
||||
if (old_na)
|
||||
{
|
||||
if (user->IsRecognized())
|
||||
old_na->last_seen = time(NULL);
|
||||
cancel_user(user);
|
||||
}
|
||||
|
||||
oldnick = user->nick;
|
||||
std::string oldnick = user->nick;
|
||||
user->SetNewNick(nick);
|
||||
FOREACH_MOD(I_OnUserNickChange, OnUserNickChange(user, oldnick.c_str()));
|
||||
|
||||
if (old_na)
|
||||
old_na->OnCancel(user);
|
||||
|
||||
if ((old_na ? old_na->nc : NULL) == user->Account())
|
||||
nc_changed = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user