summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-05-22 07:40:22 +0000
committerAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-05-22 07:40:22 +0000
commitd5f036017510dad134fd9c8d471135f774f1fe17 (patch)
treeee037c32da9ad223cd660af9f5ed36133a517bec
parentfae2710ba7e068edb68baf26f901af564741e5bf (diff)
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
-rw-r--r--include/account.h27
-rw-r--r--include/extern.h5
-rw-r--r--include/services.h39
-rw-r--r--include/users.h7
-rw-r--r--src/bots.cpp3
-rw-r--r--src/core/bs_bot.c1
-rw-r--r--src/core/ns_forbid.c2
-rw-r--r--src/core/ns_identify.c7
-rw-r--r--src/core/ns_logout.c8
-rw-r--r--src/core/ns_recover.c4
-rw-r--r--src/core/ns_release.c6
-rw-r--r--src/core/ns_suspend.c7
-rw-r--r--src/init.c3
-rw-r--r--src/messages.c2
-rw-r--r--src/nickalias.cpp50
-rw-r--r--src/nickserv.c215
-rw-r--r--src/protocol/bahamut.c1
-rw-r--r--src/protocol/ratbox.c1
-rw-r--r--src/protocol/unreal32.c3
-rw-r--r--src/users.c133
20 files changed, 237 insertions, 287 deletions
diff --git a/include/account.h b/include/account.h
index 25c3ff87d..004760699 100644
--- a/include/account.h
+++ b/include/account.h
@@ -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>
diff --git a/include/extern.h b/include/extern.h
index 4194338e9..f3b295bb8 100644
--- a/include/extern.h
+++ b/include/extern.h
@@ -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);
diff --git a/include/services.h b/include/services.h
index 2807c49c8..1eb644c52 100644
--- a/include/services.h
+++ b/include/services.h
@@ -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
diff --git a/include/users.h b/include/users.h
index 0d701f839..ff7c74622 100644
--- a/include/users.h
+++ b/include/users.h
@@ -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
diff --git a/src/bots.cpp b/src/bots.cpp
index e9b72f3e8..316f7c23a 100644
--- a/src/bots.cpp
+++ b/src/bots.cpp
@@ -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()
diff --git a/src/core/bs_bot.c b/src/core/bs_bot.c
index 9c7ce4854..09463a77b 100644
--- a/src/core/bs_bot.c
+++ b/src/core/bs_bot.c
@@ -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();
}
diff --git a/src/core/ns_forbid.c b/src/core/ns_forbid.c
index 18f3bf2aa..7ddaec68a 100644
--- a/src/core/ns_forbid.c
+++ b/src/core/ns_forbid.c
@@ -65,7 +65,7 @@ class CommandNSForbid : public Command
if (curr)
{
notice_lang(Config.s_NickServ, curr, FORCENICKCHANGE_NOW);
- collide(na, 0);
+ curr->Collide(na);
}
diff --git a/src/core/ns_identify.c b/src/core/ns_identify.c
index f16b5e84c..1b829179c 100644
--- a/src/core/ns_identify.c
+++ b/src/core/ns_identify.c
@@ -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;
}
diff --git a/src/core/ns_logout.c b/src/core/ns_logout.c
index fcb14fb8e..7e16dc8f5 100644
--- a/src/core/ns_logout.c
+++ b/src/core/ns_logout.c
@@ -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);
diff --git a/src/core/ns_recover.c b/src/core/ns_recover.c
index 23b284e46..99b5e34f1 100644
--- a/src/core/ns_recover.c
+++ b/src/core/ns_recover.c
@@ -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);
diff --git a/src/core/ns_release.c b/src/core/ns_release.c
index a4169ecda..6f360e942 100644
--- a/src/core/ns_release.c
+++ b/src/core/ns_release.c
@@ -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
diff --git a/src/core/ns_suspend.c b/src/core/ns_suspend.c
index 7c3dd0ca9..2354fe66b 100644
--- a/src/core/ns_suspend.c
+++ b/src/core/ns_suspend.c
@@ -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);
+ }
}
}
diff --git a/src/init.c b/src/init.c
index cafb30ada..b551325bb 100644
--- a/src/init.c
+++ b/src/init.c
@@ -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");
+ }
}
}
}
diff --git a/src/messages.c b/src/messages.c
index 212174939..5e97dfc71 100644
--- a/src/messages.c
+++ b/src/messages.c
@@ -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
diff --git a/src/nickalias.cpp b/src/nickalias.cpp
index 12e656668..afd40ccd7 100644
--- a/src/nickalias.cpp
+++ b/src/nickalias.cpp
@@ -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);
+ }
+ }
+}
+
diff --git a/src/nickserv.c b/src/nickserv.c
index aef24eecf..c9f2e2ffb 100644
--- a/src/nickserv.c
+++ b/src/nickserv.c
@@ -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);
-}
-
-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);
+ NickAlias *na = findnick(nick);
- 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.
*/
@@ -700,86 +613,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 ***********************/
/*************************************************************************/
diff --git a/src/protocol/bahamut.c b/src/protocol/bahamut.c
index 01462708c..a813a4b6c 100644
--- a/src/protocol/bahamut.c
+++ b/src/protocol/bahamut.c
@@ -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 */
diff --git a/src/protocol/ratbox.c b/src/protocol/ratbox.c
index 116042992..f1c2f3b3b 100644
--- a/src/protocol/ratbox.c
+++ b/src/protocol/ratbox.c
@@ -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)
diff --git a/src/protocol/unreal32.c b/src/protocol/unreal32.c
index e1b673c25..d36a5db20 100644
--- a/src/protocol/unreal32.c
+++ b/src/protocol/unreal32.c
@@ -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)
diff --git a/src/users.c b/src/users.c
index c1532bc27..26e50a40d 100644
--- a/src/users.c
+++ b/src/users.c
@@ -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;