+ ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
+ }
+}
+
+unsigned int User::GetMaxChans()
+{
+ return this->MaxChans;
+}
+
+
+/*
+ * 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::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++)
+ {
+ 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++)
+ {
+ ConnectClass* c = *i;
+
+ if (((match(this->GetIPString(),c->GetHost().c_str(),true)) || (match(this->host,c->GetHost().c_str()))))
+ {
+ if (c->GetPort())
+ {
+ if (this->GetPort() == c->GetPort() && !c->GetDisabled())
+ {
+ found = c;
+ }
+ else
+ continue;
+ }
+ else
+ {
+ if (!c->GetDisabled())
+ found = c;
+ }
+ }
+ }
+ }
+
+ /* 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->Logs->Log("USERS", DEBUG, "OOPS: Connect class limit (%lu) 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->Logs->Log("USERS", DEBUG, "Untying user from connect class -- refcount: %lu", this->MyClass->RefCount);
+ }
+
+ this->MyClass = found;
+ this->MyClass->RefCount++;
+ ServerInstance->Logs->Log("USERS", DEBUG, "User tied to new class -- connect refcount now: %lu", 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()
+{
+ std::vector<Channel*> to_delete;
+
+ // firstly decrement the count on each channel
+ for (UCListIter f = this->chans.begin(); f != this->chans.end(); f++)
+ {
+ f->first->RemoveAllPrefixes(this);
+ if (f->first->DelUser(this) == 0)
+ {
+ /* No users left in here, mark it for deletion */
+ try
+ {
+ to_delete.push_back(f->first);
+ }
+ catch (...)
+ {
+ ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::PurgeEmptyChannels to_delete.push_back()");
+ }
+ }
+ }
+
+ for (std::vector<Channel*>::iterator n = to_delete.begin(); n != to_delete.end(); n++)
+ {
+ Channel* thischan = *n;
+ chan_hash::iterator i2 = ServerInstance->chanlist->find(thischan->name);
+ if (i2 != ServerInstance->chanlist->end())
+ {
+ FOREACH_MOD(I_OnChannelDelete,OnChannelDelete(i2->second));
+ delete i2->second;
+ ServerInstance->chanlist->erase(i2);
+ this->chans.erase(*n);
+ }
+ }
+
+ this->UnOper();
+}
+
+void User::ShowMOTD()
+{
+ if (!ServerInstance->Config->MOTD.size())
+ {
+ this->WriteNumeric(422, "%s :Message of the day file is missing.",this->nick);
+ return;
+ }
+ this->WriteNumeric(375, "%s :%s message of the day", this->nick, ServerInstance->Config->ServerName);
+
+ for (file_cache::iterator i = ServerInstance->Config->MOTD.begin(); i != ServerInstance->Config->MOTD.end(); i++)
+ this->WriteNumeric(372, "%s :- %s",this->nick,i->c_str());
+
+ this->WriteNumeric(376, "%s :End of message of the day.", this->nick);
+}
+
+void User::ShowRULES()
+{
+ if (!ServerInstance->Config->RULES.size())
+ {
+ this->WriteNumeric(434, "%s :RULES File is missing",this->nick);
+ return;
+ }
+
+ this->WriteNumeric(308, "%s :- %s Server Rules -",this->nick,ServerInstance->Config->ServerName);
+
+ for (file_cache::iterator i = ServerInstance->Config->RULES.begin(); i != ServerInstance->Config->RULES.end(); i++)
+ this->WriteNumeric(232, "%s :- %s",this->nick,i->c_str());
+
+ this->WriteNumeric(309, "%s :End of RULES command.",this->nick);
+}
+
+void User::HandleEvent(EventType et, int errornum)
+{
+ if (this->quitting) // drop everything, user is due to be quit
+ return;
+
+ /* WARNING: May delete this user! */
+ int thisfd = this->GetFd();
+
+ try
+ {
+ switch (et)
+ {
+ case EVENT_READ:
+ ServerInstance->ProcessUser(this);
+ break;
+ case EVENT_WRITE:
+ this->FlushWriteBuf();
+ break;
+ case EVENT_ERROR:
+ /** This should be safe, but dont DARE do anything after it -- Brain */
+ this->SetWriteError(errornum ? strerror(errornum) : "EOF from client");
+ break;
+ }
+ }
+ catch (...)
+ {
+ ServerInstance->Logs->Log("USERS", DEBUG,"Exception in User::HandleEvent intercepted");
+ }
+
+ /* If the user has raised an error whilst being processed, quit them now we're safe to */
+ if ((ServerInstance->SE->GetRef(thisfd) == this))
+ {
+ if (!WriteError.empty())
+ {
+ User::QuitUser(ServerInstance, this, GetWriteError());
+ }