age = ServerInstance->Time(true);
Penalty = 0;
lines_in = lastping = signon = idle_lastmsg = nping = registered = 0;
- ChannelCount = timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0;
+ ChannelCount = timeout = bytes_in = bytes_out = cmds_in = cmds_out = 0;
OverPenalty = ExemptFromPenalty = muted = exempt = haspassed = dns_done = false;
fd = -1;
recvq.clear();
res_forward = res_reverse = NULL;
Visibility = NULL;
ip = NULL;
+ MyClass = NULL;
chans.clear();
invites.clear();
memset(modes,0,sizeof(modes));
User::~User()
{
+ /* NULL for remote users :) */
+ if (this->MyClass)
+ {
+ this->MyClass->RefCount--;
+ ServerInstance->Log(DEBUG, "User destructor -- connect refcount now: %u", this->MyClass->RefCount);
+ }
+
this->InvalidateCache();
this->DecrementModes();
if (operquit)
if (a.length())
recvq.append(a);
- if (recvq.length() > (unsigned)this->recvqmax)
+ if (this->MyClass && (recvq.length() > this->MyClass->GetRecvqMax()))
{
this->SetWriteError("RecvQ exceeded");
- ServerInstance->WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
+ ServerInstance->WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->MyClass->GetRecvqMax());
return false;
}
if (*this->GetWriteError())
return;
- if (sendq.length() + data.length() > (unsigned)this->sendqmax)
+ if (this->MyClass && (sendq.length() + data.length() > this->MyClass->GetSendqMax()))
{
/*
* Fix by brain - Set the error text BEFORE calling writeopers, because
* to repeatedly add the text to the sendq!
*/
this->SetWriteError("SendQ exceeded");
- ServerInstance->WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->sendqmax);
+ ServerInstance->WriteOpers("*** User %s SendQ of %d exceeds connect class maximum of %d",this->nick,sendq.length() + data.length(),this->MyClass->GetSendqMax());
return;
}
* First class check. We do this again in FullConnect after DNS is done, and NICK/USER is recieved.
* See my note down there for why this is required. DO NOT REMOVE. :) -- w00t
*/
- ConnectClass* i = New->GetClass();
+ ConnectClass* i = New->SetClass();
if (!i)
{
}
#endif
- New->exempt = (Instance->XLines->matches_exception(New) != NULL);
+ New->exempt = (Instance->XLines->MatchesLine("E",New) != NULL);
if (!New->exempt)
{
- ZLine* r = Instance->XLines->matches_zline(ipaddr);
+ XLine* r = Instance->XLines->MatchesLine("Z",New);
+
if (r)
{
char reason[MAXBUF];
/*
* Check class restrictions
*/
-void User::CheckClass(const std::string &explicit_class)
+void User::CheckClass()
{
- ConnectClass* a = this->GetClass(explicit_class);
+ ConnectClass* a = this->MyClass;
if ((!a) || (a->GetType() == CC_DENY))
{
return;
}
- this->pingmax = a->GetPingTime();
this->nping = ServerInstance->Time() + a->GetPingTime() + ServerInstance->Config->dns_timeout;
this->timeout = ServerInstance->Time() + a->GetRegTimeout();
- this->flood = a->GetFlood();
- this->threshold = a->GetThreshold();
- this->sendqmax = a->GetSendqMax();
- this->recvqmax = a->GetRecvqMax();
this->MaxChans = a->GetMaxChans();
}
* may put the user into a totally seperate class with different restrictions! so we *must* check again.
* Don't remove this! -- w00t
*/
- this->CheckClass();
+ this->SetClass();
/* Check the password, if one is required by the user's connect class.
* This CANNOT be in CheckClass(), because that is called prior to PASS as well!
*/
- if ((!this->GetClass()->GetPass().empty()) && (!this->haspassed))
+ if (this->MyClass && !this->MyClass->GetPass().empty() && !this->haspassed)
{
User::QuitUser(ServerInstance, this, "Invalid password");
return;
}
-
+
if (!this->exempt)
{
- GLine* r = ServerInstance->XLines->matches_gline(this);
+ XLine* r = ServerInstance->XLines->MatchesLine("G",this);
if (r)
{
return;
}
- KLine* n = ServerInstance->XLines->matches_kline(this);
+ XLine* n = ServerInstance->XLines->MatchesLine("K",this);
if (n)
{
return false;
}
- if (ServerInstance->XLines->matches_qline(newnick))
+ if (ServerInstance->XLines->MatchesLine("Q",newnick))
{
ServerInstance->stats->statsCollisions++;
return false;
return this->MaxChans;
}
-/* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
+
+/*
+ * Sets a user's connection class.
+ * If the class name is provided, it will be used. Otherwise, the class will be guessed using host/ip/ident/etc.
* NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
* then their ip will be taken as 'priority' anyway, so for example,
* <connect allow="127.0.0.1"> will match joe!bloggs@localhost
*/
-ConnectClass* User::GetClass(const std::string &explicit_name)
+ConnectClass* User::SetClass(const std::string &explicit_name)
{
+ ConnectClass *found = NULL;
+
+ if (!IS_LOCAL(this))
+ return NULL;
+
if (!explicit_name.empty())
{
for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
{
- if (explicit_name == i->GetName())
- return &(*i);
+ ConnectClass* c = *i;
+
+ if (explicit_name == c->GetName() && !c->GetDisabled())
+ {
+ found = c;
+ }
}
}
else
{
for (ClassVector::iterator i = ServerInstance->Config->Classes.begin(); i != ServerInstance->Config->Classes.end(); i++)
{
- if (((match(this->GetIPString(),i->GetHost().c_str(),true)) || (match(this->host,i->GetHost().c_str()))))
+ ConnectClass* c = *i;
+
+ if (((match(this->GetIPString(),c->GetHost().c_str(),true)) || (match(this->host,c->GetHost().c_str()))))
{
- if (i->GetPort())
+ if (c->GetPort())
{
- if (this->GetPort() == i->GetPort())
- return &(*i);
+ if (this->GetPort() == c->GetPort() && !c->GetDisabled())
+ {
+ found = c;
+ }
else
continue;
}
else
- return &(*i);
+ {
+ if (!c->GetDisabled())
+ found = c;
+ }
}
}
}
- return NULL;
+
+ /* ensure we don't fuck things up refcount wise, only remove them from a class if we find a new one :P */
+ if (found)
+ {
+ /* deny change if change will take class over the limit */
+ if (found->limit && (found->RefCount + 1 >= found->limit))
+ {
+ ServerInstance->Log(DEBUG, "OOPS: Connect class limit (%u) hit, denying", found->limit);
+ return this->MyClass;
+ }
+
+ /* should always be valid, but just in case .. */
+ if (this->MyClass)
+ {
+ if (found == this->MyClass) // no point changing this shit :P
+ return this->MyClass;
+ this->MyClass->RefCount--;
+ ServerInstance->Log(DEBUG, "Untying user from connect class -- refcount: %u", this->MyClass->RefCount);
+ }
+
+ this->MyClass = found;
+ this->MyClass->RefCount++;
+ ServerInstance->Log(DEBUG, "User tied to new class -- connect refcount now: %u", this->MyClass->RefCount);
+ }
+
+ return this->MyClass;
+}
+
+/* looks up a users password for their connection class (<ALLOW>/<DENY> tags)
+ * NOTE: If the <ALLOW> or <DENY> tag specifies an ip, and this user resolves,
+ * then their ip will be taken as 'priority' anyway, so for example,
+ * <connect allow="127.0.0.1"> will match joe!bloggs@localhost
+ */
+ConnectClass* User::GetClass()
+{
+ return this->MyClass;
}
void User::PurgeEmptyChannels()