+ if (this->ServerInstance->Config->CycleHosts)
+ this->WriteCommonExcept("%s","QUIT :Changing ident");
+
+ strlcpy(this->ident, newident, IDENTMAX+1);
+
+ this->InvalidateCache();
+
+ if (this->ServerInstance->Config->CycleHosts)
+ {
+ for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
+ {
+ i->first->WriteAllExceptSender(this, false, 0, "JOIN %s", i->first->name);
+ std::string n = this->ServerInstance->Modes->ModeString(this, i->first);
+ if (n.length() > 0)
+ i->first->WriteAllExceptSender(this, true, 0, "MODE %s +%s", i->first->name, n.c_str());
+ }
+ }
+
+ return true;
+}
+
+void User::SendAll(const char* command, const char* text, ...)
+{
+ char textbuffer[MAXBUF];
+ char formatbuffer[MAXBUF];
+ va_list argsPtr;
+
+ va_start(argsPtr, text);
+ vsnprintf(textbuffer, MAXBUF, text, argsPtr);
+ va_end(argsPtr);
+
+ snprintf(formatbuffer,MAXBUF,":%s %s $* :%s", this->GetFullHost(), command, textbuffer);
+ std::string fmt = formatbuffer;
+
+ for (std::vector<User*>::const_iterator i = ServerInstance->Users->local_users.begin(); i != ServerInstance->Users->local_users.end(); i++)
+ {
+ (*i)->Write(fmt);
+ }
+}
+
+
+std::string User::ChannelList(User* source)
+{
+ std::string list;
+
+ for (UCListIter i = this->chans.begin(); i != this->chans.end(); i++)
+ {
+ /* If the target is the same as the sender, let them see all their channels.
+ * If the channel is NOT private/secret OR the user shares a common channel
+ * If the user is an oper, and the <options:operspywhois> option is set.
+ */
+ if ((source == this) || (IS_OPER(source) && ServerInstance->Config->OperSpyWhois) || (((!i->first->IsModeSet('p')) && (!i->first->IsModeSet('s'))) || (i->first->HasUser(source))))
+ {
+ list.append(i->first->GetPrefixChar(this)).append(i->first->name).append(" ");
+ }
+ }
+
+ return list;
+}
+
+void User::SplitChanList(User* dest, const std::string &cl)
+{
+ std::string line;
+ std::ostringstream prefix;
+ std::string::size_type start, pos, length;
+
+ prefix << this->nick << " " << dest->nick << " :";
+ line = prefix.str();
+ int namelen = strlen(ServerInstance->Config->ServerName) + 6;
+
+ for (start = 0; (pos = cl.find(' ', start)) != std::string::npos; start = pos+1)
+ {
+ length = (pos == std::string::npos) ? cl.length() : pos;
+
+ if (line.length() + namelen + length - start > 510)
+ {
+ ServerInstance->SendWhoisLine(this, dest, 319, "%s", line.c_str());
+ line = prefix.str();
+ }
+
+ if(pos == std::string::npos)
+ {
+ line.append(cl.substr(start, length - start));
+ break;
+ }
+ else
+ {
+ line.append(cl.substr(start, length - start + 1));
+ }
+ }
+
+ if (line.length())
+ {
+ 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());
+ }
+ }
+}
+
+void User::SetOperQuit(const std::string &oquit)
+{
+ operquitmsg = oquit;
+}
+
+const char* User::GetOperQuit()
+{
+ return operquitmsg.c_str();
+}
+
+void User::IncreasePenalty(int increase)
+{
+ this->Penalty += increase;
+}
+
+void User::DecreasePenalty(int decrease)
+{
+ this->Penalty -= decrease;
+}
+
+VisData::VisData()
+{
+}
+
+VisData::~VisData()
+{
+}
+
+bool VisData::VisibleTo(User* user)
+{