]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/channels.cpp
Simplify stringjoiner: take 1 parameter, join from begin() to end() and use space...
[user/henk/code/inspircd.git] / src / channels.cpp
index 1c8e9e8568940b0f499f946455c5faebcfa1e1fa..0d43bc802e129b89151ab5935b10f62aee28682f 100644 (file)
@@ -94,8 +94,6 @@ std::string Channel::GetModeParameter(ModeHandler* mode)
 
 int Channel::SetTopic(User *u, std::string &ntopic, bool forceset)
 {
-       if (!u)
-               u = ServerInstance->FakeClient;
        if (IS_LOCAL(u) && !forceset)
        {
                ModResult res;
@@ -119,17 +117,8 @@ int Channel::SetTopic(User *u, std::string &ntopic, bool forceset)
        }
 
        this->topic.assign(ntopic, 0, ServerInstance->Config->Limits.MaxTopic);
-       if (u)
-       {
-               this->setby.assign(ServerInstance->Config->FullHostInTopic ? u->GetFullHost() : u->nick, 0, 128);
-               this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
-       }
-       else
-       {
-               this->setby.assign(ServerInstance->Config->ServerName);
-               this->WriteChannelWithServ(ServerInstance->Config->ServerName, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
-       }
-
+       this->setby.assign(ServerInstance->Config->FullHostInTopic ? u->GetFullHost() : u->nick, 0, 128);
+       this->WriteChannel(u, "TOPIC %s :%s", this->name.c_str(), this->topic.c_str());
        this->topicset = ServerInstance->Time();
 
        FOREACH_MOD(I_OnPostTopicChange,OnPostTopicChange(u, this, this->topic));
@@ -137,11 +126,6 @@ int Channel::SetTopic(User *u, std::string &ntopic, bool forceset)
        return CMD_SUCCESS;
 }
 
-long Channel::GetUserCounter()
-{
-       return userlist.size();
-}
-
 Membership* Channel::AddUser(User* user)
 {
        Membership*& memb = userlist[user];
@@ -154,37 +138,42 @@ Membership* Channel::AddUser(User* user)
 
 void Channel::DelUser(User* user)
 {
-       UserMembIter a = userlist.find(user);
+       UserMembIter it = userlist.find(user);
+       if (it != userlist.end())
+               DelUser(it);
+}
 
-       if (a != userlist.end())
-       {
-               a->second->cull();
-               delete a->second;
-               userlist.erase(a);
-       }
+void Channel::CheckDestroy()
+{
+       if (!userlist.empty())
+               return;
 
-       if (userlist.empty())
-       {
-               ModResult res;
-               FIRST_MOD_RESULT(OnChannelPreDelete, res, (this));
-               if (res == MOD_RES_DENY)
-                       return;
-               chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
-               /* kill the record */
-               if (iter != ServerInstance->chanlist->end())
-               {
-                       FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
-                       ServerInstance->chanlist->erase(iter);
-               }
+       ModResult res;
+       FIRST_MOD_RESULT(OnChannelPreDelete, res, (this));
+       if (res == MOD_RES_DENY)
+               return;
 
-               ClearInvites();
-               ServerInstance->GlobalCulls.AddItem(this);
+       chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
+       /* kill the record */
+       if (iter != ServerInstance->chanlist->end())
+       {
+               FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
+               ServerInstance->chanlist->erase(iter);
        }
+
+       ClearInvites();
+       ServerInstance->GlobalCulls.AddItem(this);
 }
 
-bool Channel::HasUser(User* user)
+void Channel::DelUser(const UserMembIter& membiter)
 {
-       return (userlist.find(user) != userlist.end());
+       Membership* memb = membiter->second;
+       memb->cull();
+       delete memb;
+       userlist.erase(membiter);
+
+       // If this channel became empty then it should be removed
+       CheckDestroy();
 }
 
 Membership* Channel::GetUser(User* user)
@@ -195,11 +184,6 @@ Membership* Channel::GetUser(User* user)
        return i->second;
 }
 
-const UserMembList* Channel::GetUsers()
-{
-       return &userlist;
-}
-
 void Channel::SetDefaultModes()
 {
        ServerInstance->Logs->Log("CHANNELS", LOG_DEBUG, "SetDefaultModes %s",
@@ -507,61 +491,54 @@ ModResult Channel::GetExtBanStatus(User *user, char type)
 }
 
 /* Channel::PartUser
- * remove a channel from a users record, and return the number of users left.
- * Therefore, if this function returns 0 the caller should delete the Channel.
+ * Remove a channel from a users record, remove the reference to the Membership object
+ * from the channel and destroy it.
  */
 void Channel::PartUser(User *user, std::string &reason)
 {
-       if (!user)
-               return;
-
-       Membership* memb = GetUser(user);
+       UserMembIter membiter = userlist.find(user);
 
-       if (memb)
+       if (membiter != userlist.end())
        {
+               Membership* memb = membiter->second;
                CUList except_list;
                FOREACH_MOD(I_OnUserPart,OnUserPart(memb, reason, except_list));
 
                WriteAllExcept(user, false, 0, except_list, "PART %s%s%s", this->name.c_str(), reason.empty() ? "" : " :", reason.c_str());
 
+               // Remove this channel from the user's chanlist
                user->chans.erase(this);
-               this->RemoveAllPrefixes(user);
+               // Remove the Membership from this channel's userlist and destroy it
+               this->DelUser(membiter);
        }
-
-       this->DelUser(user);
 }
 
-void Channel::KickUser(User *src, User *user, const std::string& reason)
+void Channel::KickUser(User* src, User* victim, const std::string& reason, Membership* srcmemb)
 {
-       if (!src || !user)
+       UserMembIter victimiter = userlist.find(victim);
+       Membership* memb = ((victimiter != userlist.end()) ? victimiter->second : NULL);
+
+       if (!memb)
+       {
+               src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel",src->nick.c_str(), victim->nick.c_str(), this->name.c_str());
                return;
+       }
 
-       Membership* memb = GetUser(user);
+       // Do the following checks only if the KICK is done by a local user;
+       // each server enforces its own rules.
        if (IS_LOCAL(src))
        {
-               if (!memb)
-               {
-                       src->WriteNumeric(ERR_USERNOTINCHANNEL, "%s %s %s :They are not on that channel",src->nick.c_str(), user->nick.c_str(), this->name.c_str());
-                       return;
-               }
-               if ((ServerInstance->ULine(user->server)) && (!ServerInstance->ULine(src->server)))
-               {
-                       src->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only a u-line may kick a u-line from a channel.",src->nick.c_str(), this->name.c_str());
-                       return;
-               }
-
+               // Modules are allowed to explicitly allow or deny kicks done by local users
                ModResult res;
-               if (ServerInstance->ULine(src->server))
-                       res = MOD_RES_ALLOW;
-               else
-                       FIRST_MOD_RESULT(OnUserPreKick, res, (src,memb,reason));
-
+               FIRST_MOD_RESULT(OnUserPreKick, res, (src,memb,reason));
                if (res == MOD_RES_DENY)
                        return;
 
                if (res == MOD_RES_PASSTHRU)
                {
-                       unsigned int them = this->GetPrefixValue(src);
+                       if (!srcmemb)
+                               srcmemb = GetUser(src);
+                       unsigned int them = srcmemb ? srcmemb->getRank() : 0;
                        unsigned int req = HALFOP_VALUE;
                        for (std::string::size_type i = 0; i < memb->modes.length(); i++)
                        {
@@ -579,25 +556,17 @@ void Channel::KickUser(User *src, User *user, const std::string& reason)
                }
        }
 
-       if (memb)
-       {
-               CUList except_list;
-               FOREACH_MOD(I_OnUserKick,OnUserKick(src, memb, reason, except_list));
-
-               WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), user->nick.c_str(), reason.c_str());
+       CUList except_list;
+       FOREACH_MOD(I_OnUserKick,OnUserKick(src, memb, reason, except_list));
 
-               user->chans.erase(this);
-               this->RemoveAllPrefixes(user);
-       }
+       WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), victim->nick.c_str(), reason.c_str());
 
-       this->DelUser(user);
+       victim->chans.erase(this);
+       this->DelUser(victimiter);
 }
 
 void Channel::WriteChannel(User* user, const char* text, ...)
 {
-       if (!user || !text)
-               return;
-
        std::string textbuffer;
        VAFORMAT(textbuffer, text, text);
        this->WriteChannel(user, textbuffer);
@@ -605,9 +574,6 @@ void Channel::WriteChannel(User* user, const char* text, ...)
 
 void Channel::WriteChannel(User* user, const std::string &text)
 {
-       if (!user)
-               return;
-
        const std::string message = ":" + user->GetFullHost() + " " + text;
 
        for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
@@ -619,9 +585,6 @@ void Channel::WriteChannel(User* user, const std::string &text)
 
 void Channel::WriteChannelWithServ(const std::string& ServName, const char* text, ...)
 {
-       if (!text)
-               return;
-
        std::string textbuffer;
        VAFORMAT(textbuffer, text, text);
        this->WriteChannelWithServ(ServName, textbuffer);
@@ -642,9 +605,6 @@ void Channel::WriteChannelWithServ(const std::string& ServName, const std::strin
  * for the sender (for privmsg etc) */
 void Channel::WriteAllExceptSender(User* user, bool serversource, char status, const char* text, ...)
 {
-       if (!text)
-               return;
-
        std::string textbuffer;
        VAFORMAT(textbuffer, text, text);
        this->WriteAllExceptSender(user, serversource, status, textbuffer);
@@ -652,9 +612,6 @@ void Channel::WriteAllExceptSender(User* user, bool serversource, char status, c
 
 void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const char* text, ...)
 {
-       if (!text)
-               return;
-
        std::string textbuffer;
        VAFORMAT(textbuffer, text, text);
        textbuffer = ":" + (serversource ? ServerInstance->Config->ServerName : user->GetFullHost()) + " " + textbuffer;
@@ -696,22 +653,6 @@ void Channel::WriteAllExceptSender(User* user, bool serversource, char status, c
        this->WriteAllExcept(user, serversource, status, except_list, std::string(text));
 }
 
-/*
- * return a count of the users on a specific channel accounting for
- * invisible users who won't increase the count. e.g. for /LIST
- */
-int Channel::CountInvisible()
-{
-       int count = 0;
-       for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
-       {
-               if (!i->first->quitting && !i->first->IsModeSet('i'))
-                       count++;
-       }
-
-       return count;
-}
-
 const char* Channel::ChanModes(bool showkey)
 {
        static std::string scratch;
@@ -750,29 +691,29 @@ const char* Channel::ChanModes(bool showkey)
  */
 void Channel::UserList(User *user)
 {
-       char list[MAXBUF];
-       size_t dlen, curlen;
-
-       if (!IS_LOCAL(user))
-               return;
-
        if (this->IsModeSet('s') && !this->HasUser(user) && !user->HasPrivPermission("channels/auspex"))
        {
                user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), this->name.c_str());
                return;
        }
 
-       dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=',  this->name.c_str());
+       std::string list = user->nick;
+       list.push_back(' ');
+       list.push_back(this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=');
+       list.push_back(' ');
+       list.append(this->name).append(" :");
+       std::string::size_type pos = list.size();
 
-       int numusers = 0;
-       char* ptr = list + dlen;
+       bool has_one = false;
 
        /* Improvement by Brain - this doesnt change in value, so why was it inside
         * the loop?
         */
        bool has_user = this->HasUser(user);
 
-       for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
+       std::string prefixlist;
+       std::string nick;
+       for (UserMembIter i = userlist.begin(); i != userlist.end(); ++i)
        {
                if (i->first->quitting)
                        continue;
@@ -785,8 +726,8 @@ void Channel::UserList(User *user)
                        continue;
                }
 
-               std::string prefixlist = this->GetPrefixChar(i->first);
-               std::string nick = i->first->nick;
+               prefixlist = this->GetPrefixChar(i->first);
+               nick = i->first->nick;
 
                FOREACH_MOD(I_OnNamesListItem, OnNamesListItem(user, i->second, prefixlist, nick));
 
@@ -794,32 +735,25 @@ void Channel::UserList(User *user)
                if (nick.empty())
                        continue;
 
-               size_t ptrlen = 0;
-
-               if (curlen + prefixlist.length() + nick.length() + 1 > 480)
+               if (list.size() + prefixlist.length() + nick.length() + 1 > 480)
                {
                        /* list overflowed into multiple numerics */
-                       user->WriteNumeric(RPL_NAMREPLY, std::string(list));
-
-                       /* reset our lengths */
-                       dlen = curlen = snprintf(list,MAXBUF,"%s %c %s :", user->nick.c_str(), this->IsModeSet('s') ? '@' : this->IsModeSet('p') ? '*' : '=', this->name.c_str());
-                       ptr = list + dlen;
+                       user->WriteNumeric(RPL_NAMREPLY, list);
 
-                       numusers = 0;
+                       // Erase all nicks, keep the constant part
+                       list.erase(pos);
+                       has_one = false;
                }
 
-               ptrlen = snprintf(ptr, MAXBUF, "%s%s ", prefixlist.c_str(), nick.c_str());
-
-               curlen += ptrlen;
-               ptr += ptrlen;
+               list.append(prefixlist).append(nick).push_back(' ');
 
-               numusers++;
+               has_one = true;
        }
 
        /* if whats left in the list isnt empty, send it */
-       if (numusers)
+       if (has_one)
        {
-               user->WriteNumeric(RPL_NAMREPLY, std::string(list));
+               user->WriteNumeric(RPL_NAMREPLY, list);
        }
 
        user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str());
@@ -920,15 +854,6 @@ bool Channel::SetPrefix(User* user, char prefix, bool adding)
        return adding;
 }
 
-void Channel::RemoveAllPrefixes(User* user)
-{
-       UserMembIter m = userlist.find(user);
-       if (m != userlist.end())
-       {
-               m->second->modes.clear();
-       }
-}
-
 void Invitation::Create(Channel* c, LocalUser* u, time_t timeout)
 {
        if ((timeout != 0) && (ServerInstance->Time() >= timeout))