return ret;
}
-User::User(const std::string& uid, Server* srv, int type)
+User::User(const std::string& uid, Server* srv, UserType type)
: age(ServerInstance->Time())
, signon(0)
, uuid(uid)
user->nick.c_str(), (unsigned long)recvq.length(), user->MyClass->GetRecvqMax());
return;
}
+
unsigned long sendqmax = ULONG_MAX;
if (!user->HasPrivPermission("users/flood/increased-buffers"))
sendqmax = user->MyClass->GetSendqSoftMax();
+
unsigned long penaltymax = ULONG_MAX;
if (!user->HasPrivPermission("users/flood/no-fakelag"))
penaltymax = user->MyClass->GetPenaltyThreshold() * 1000;
+ // The maximum size of an IRC message minus the terminating CR+LF.
+ const size_t maxmessage = ServerInstance->Config->Limits.MaxLine - 2;
+ std::string line;
+ line.reserve(maxmessage);
+
+ bool eol_found;
+ std::string::size_type qpos;
+
while (user->CommandFloodPenalty < penaltymax && getSendQSize() < sendqmax)
{
- std::string line;
- line.reserve(ServerInstance->Config->Limits.MaxLine);
- std::string::size_type qpos = 0;
- while (qpos < recvq.length())
+ qpos = 0;
+ eol_found = false;
+
+ const size_t qlen = recvq.length();
+ while (qpos < qlen)
{
char c = recvq[qpos++];
switch (c)
{
- case '\0':
- c = ' ';
- break;
- case '\r':
- continue;
- case '\n':
- goto eol_found;
+ case '\0':
+ c = ' ';
+ break;
+ case '\r':
+ continue;
+ case '\n':
+ eol_found = true;
+ break;
}
- if (line.length() < ServerInstance->Config->Limits.MaxLine - 2)
+
+ if (eol_found)
+ break;
+
+ if (line.length() < maxmessage)
line.push_back(c);
}
- // if we got here, the recvq ran out before we found a newline
- return;
-eol_found:
+
+ // if we return here, we haven't found a newline and make no modifications to recvq
+ // so we can wait for more data
+ if (!eol_found)
+ return;
+
// just found a newline. Terminate the string, and pull it out of recvq
recvq.erase(0, qpos);
ServerInstance->Parser.ProcessBuffer(line, user);
if (user->quitting)
return;
+
+ // clear() does not reclaim memory associated with the string, so our .reserve() call is safe
+ line.clear();
}
+
if (user->CommandFloodPenalty >= penaltymax && !user->MyClass->fakelag)
ServerInstance->Users->QuitUser(user, "Excess Flood");
}
WriteData(data);
}
+void UserIOHandler::OnSetEndPoint(const irc::sockets::sockaddrs& server, const irc::sockets::sockaddrs& client)
+{
+ memcpy(&user->server_sa, &server, sizeof(irc::sockets::sockaddrs));
+ user->SetClientIP(client);
+}
+
void UserIOHandler::OnError(BufferedSocketError)
{
ServerInstance->Users->QuitUser(user, getError());
if (!quitting)
ServerInstance->Users->QuitUser(this, "Culled without QuitUser");
- if (client_sa.sa.sa_family != AF_UNSPEC)
+ if (client_sa.family() != AF_UNSPEC)
ServerInstance->Users->RemoveCloneCounts(this);
return Extensible::cull();
nick.c_str(), ident.c_str(), GetRealHost().c_str(), oper->name.c_str(), opername.c_str());
this->WriteNumeric(RPL_YOUAREOPER, InspIRCd::Format("You are now %s %s", strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str()));
- ServerInstance->Logs->Log("OPER", LOG_DEFAULT, "%s opered as type: %s", GetFullRealHost().c_str(), oper->name.c_str());
ServerInstance->Users->all_opers.push_back(this);
// Expand permissions from config for faster lookup
ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER);
this->SetMode(opermh, false);
+ FOREACH_MOD(OnPostDeoper, (this));
}
/*
}
if (this->registered == REG_ALL)
- this->WriteCommon("NICK %s",newnick.c_str());
- std::string oldnick = nick;
+ this->WriteCommon("NICK %s", newnick.c_str());
+ const std::string oldnick = nick;
nick = newnick;
InvalidateCache();
int LocalUser::GetServerPort()
{
- switch (this->server_sa.sa.sa_family)
- {
- case AF_INET6:
- return htons(this->server_sa.in6.sin6_port);
- case AF_INET:
- return htons(this->server_sa.in4.sin_port);
- }
- return 0;
+ return this->server_sa.port();
}
const std::string& User::GetIPString()
irc::sockets::cidr_mask User::GetCIDRMask()
{
- int range = 0;
- switch (client_sa.sa.sa_family)
+ unsigned char range = 0;
+ switch (client_sa.family())
{
case AF_INET6:
range = ServerInstance->Config->c_ipv6_range;
if (!SocketEngine::BoundsCheckFd(&eh))
return;
- if (text.length() > ServerInstance->Config->Limits.MaxLine - 2)
+ // The maximum size of an IRC message minus the terminating CR+LF.
+ const size_t maxmessage = ServerInstance->Config->Limits.MaxLine - 2;
+ if (text.length() > maxmessage)
{
- // this should happen rarely or never. Crop the string at 512 and try again.
- std::string try_again(text, 0, ServerInstance->Config->Limits.MaxLine - 2);
+ // This should happen rarely or never. Crop the string at MaxLine and try again.
+ std::string try_again(text, 0, maxmessage);
Write(try_again);
return;
}
eh.AddWriteBuf(text);
eh.AddWriteBuf(wide_newline);
- ServerInstance->stats.Sent += text.length() + 2;
- this->bytes_out += text.length() + 2;
+ const size_t bytessent = text.length() + 2;
+ ServerInstance->stats.Sent += bytessent;
+ this->bytes_out += bytessent;
this->cmds_out++;
}
void User::ChangeRealHost(const std::string& host, bool resetdisplay)
{
- if (displayhost == host)
+ // If the real host is the new host and we are not resetting the
+ // display host then we have nothing to do.
+ const bool changehost = (realhost != host);
+ if (!changehost && !resetdisplay)
return;
+ // If the displayhost is not set and we are not resetting it then
+ // we need to copy it to the displayhost field.
if (displayhost.empty() && !resetdisplay)
displayhost = realhost;
+ // If the displayhost is the new host or we are resetting it then
+ // we clear its contents to save memory.
else if (displayhost == host || resetdisplay)
displayhost.clear();
+ // If we are just resetting the display host then we don't need to
+ // do anything else.
+ if (!changehost)
+ return;
+
realhost = host;
this->InvalidateCache();
}
const std::string& FakeUser::GetFullHost()
{
- if (!ServerInstance->Config->HideWhoisServer.empty())
- return ServerInstance->Config->HideWhoisServer;
+ if (!ServerInstance->Config->HideServer.empty())
+ return ServerInstance->Config->HideServer;
return server->GetName();
}
const std::string& FakeUser::GetFullRealHost()
{
- if (!ServerInstance->Config->HideWhoisServer.empty())
- return ServerInstance->Config->HideWhoisServer;
+ if (!ServerInstance->Config->HideServer.empty())
+ return ServerInstance->Config->HideServer;
return server->GetName();
}
Update(&parent);
name = "unnamed";
type = t;
- config = tag;
+ host = mask;
+
+ // Connect classes can inherit from each other but this is problematic for modules which can't use
+ // ConnectClass::Update so we build a hybrid tag containing all of the values set on this class as
+ // well as the parent class.
+ ConfigItems* items = NULL;
+ config = ConfigTag::create(tag->tag, tag->src_name, tag->src_line, items);
+
+ const ConfigItems& parentkeys = parent.config->getItems();
+ for (ConfigItems::const_iterator piter = parentkeys.begin(); piter != parentkeys.end(); ++piter)
+ {
+ // The class name and parent name are not inherited
+ if (stdalgo::string::equalsci(piter->first, "name") || stdalgo::string::equalsci(piter->first, "parent"))
+ continue;
+
+ // Store the item in the config tag. If this item also
+ // exists in the child it will be overwritten.
+ (*items)[piter->first] = piter->second;
+ }
+
+ const ConfigItems& childkeys = tag->getItems();
+ for (ConfigItems::const_iterator citer = childkeys.begin(); citer != childkeys.end(); ++citer)
+ {
+ // This will overwrite the parent value if present.
+ (*items)[citer->first] = citer->second;
+ }
}
void ConnectClass::Update(const ConnectClass* src)