]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/channels.cpp
Fix sending the wrong numerics on join when a topic is empty.
[user/henk/code/inspircd.git] / src / channels.cpp
index c265171b5ce85c6ced4e78d30a440a3ed4f8eb28..6802e3d7dd7d049468dbe0ce6f52ad2a3171df20 100644 (file)
 
 Channel::Channel(const std::string &cname, time_t ts)
 {
-       chan_hash::iterator findchan = ServerInstance->chanlist->find(cname);
-       if (findchan != ServerInstance->chanlist->end())
+       if (!ServerInstance->chanlist->insert(std::make_pair(cname, this)).second)
                throw CoreException("Cannot create duplicate channel " + cname);
 
-       (*(ServerInstance->chanlist))[cname.c_str()] = this;
-       this->name.assign(cname, 0, ServerInstance->Config->Limits.ChanMax);
+       this->name = cname;
        this->age = ts ? ts : ServerInstance->Time();
 
        maxbans = topicset = 0;
@@ -118,16 +116,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();
 
@@ -212,10 +202,18 @@ void Channel::SetDefaultModes()
                if (mode)
                {
                        if (mode->GetNumParams(true))
+                       {
                                list.GetToken(parameter);
+                               // If the parameter begins with a ':' then it's invalid
+                               if (parameter.c_str()[0] == ':')
+                                       continue;
+                       }
                        else
                                parameter.clear();
 
+                       if ((mode->GetNumParams(true)) && (parameter.empty()))
+                               continue;
+
                        mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, parameter, true);
                }
        }
@@ -231,7 +229,6 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char
        if (!user || !cn || user->registered != REG_ALL)
                return NULL;
 
-       char cname[MAXBUF];
        std::string privs;
        Channel *Ptr;
 
@@ -264,7 +261,8 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char
                }
        }
 
-       strlcpy(cname, cn, ServerInstance->Config->Limits.ChanMax);
+       std::string cname;
+       cname.assign(std::string(cn), 0, ServerInstance->Config->Limits.ChanMax);
        Ptr = ServerInstance->FindChan(cname);
        bool created_by_local = false;
 
@@ -287,7 +285,7 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char
                if (IS_LOCAL(user) && override == false)
                {
                        ModResult MOD_RESULT;
-                       FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname, privs, key ? key : ""));
+                       FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, NULL, cname.c_str(), privs, key ? key : ""));
                        if (MOD_RESULT == MOD_RES_DENY)
                                return NULL;
                }
@@ -307,7 +305,7 @@ Channel* Channel::JoinUser(User *user, const char* cn, bool override, const char
                if (IS_LOCAL(user) && override == false)
                {
                        ModResult MOD_RESULT;
-                       FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, Ptr, cname, privs, key ? key : ""));
+                       FIRST_MOD_RESULT(OnUserPreJoin, MOD_RESULT, (user, Ptr, cname.c_str(), privs, key ? key : ""));
                        if (MOD_RESULT == MOD_RES_DENY)
                        {
                                return NULL;
@@ -414,7 +412,7 @@ Channel* Channel::ForceChan(Channel* Ptr, User* user, const std::string &privs,
 
        if (IS_LOCAL(user))
        {
-               if (Ptr->topicset)
+               if (!Ptr->topic.empty())
                {
                        user->WriteNumeric(RPL_TOPIC, "%s %s :%s", user->nick.c_str(), Ptr->name.c_str(), Ptr->topic.c_str());
                        user->WriteNumeric(RPL_TOPICTIME, "%s %s %s %lu", user->nick.c_str(), Ptr->name.c_str(), Ptr->setby.c_str(), (unsigned long)Ptr->topicset);
@@ -449,7 +447,7 @@ bool Channel::CheckBan(User* user, const std::string& mask)
                return (result == MOD_RES_DENY);
 
        // extbans were handled above, if this is one it obviously didn't match
-       if (mask[1] == ':')
+       if ((mask.length() <= 2) || (mask[1] == ':'))
                return false;
 
        std::string::size_type at = mask.find('@');
@@ -675,7 +673,6 @@ void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList
        char tb[MAXBUF];
 
        snprintf(tb,MAXBUF,":%s %s", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str(), text.c_str());
-       std::string out = tb;
 
        this->RawWriteAllExcept(user, serversource, status, except_list, std::string(tb));
 }
@@ -718,7 +715,7 @@ int Channel::CountInvisible()
        int count = 0;
        for (UserMembIter i = userlist.begin(); i != userlist.end(); i++)
        {
-               if (!(i->first->IsModeSet('i')))
+               if (!i->first->quitting && !i->first->IsModeSet('i'))
                        count++;
        }
 
@@ -769,31 +766,39 @@ 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"))
+       bool has_privs = user->HasPrivPermission("channels/auspex");
+
+       if (this->IsModeSet('s') && !this->HasUser(user) && !has_privs)
        {
                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++)
+       const size_t maxlen = MAXBUF - 10 - ServerInstance->Config->ServerName.size();
+       std::string prefixlist;
+       std::string nick;
+       for (UserMembIter i = userlist.begin(); i != userlist.end(); ++i)
        {
-               if ((!has_user) && (i->first->IsModeSet('i')))
+               if (i->first->quitting)
+                       continue;
+               if ((!has_user) && (i->first->IsModeSet('i')) && (!has_privs))
                {
                        /*
                         * user is +i, and source not on the channel, does not show
@@ -802,8 +807,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));
 
@@ -811,32 +816,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 > maxlen)
                {
                        /* list overflowed into multiple numerics */
-                       user->WriteNumeric(RPL_NAMREPLY, std::string(list));
+                       user->WriteNumeric(RPL_NAMREPLY, 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;
-
-                       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());
@@ -1013,7 +1011,8 @@ Invitation* Invitation::Find(Channel* c, LocalUser* u, bool check_expired)
                if ((check_expired) && (inv->expiry != 0) && (inv->expiry <= ServerInstance->Time()))
                {
                        /* Expired invite, remove it. */
-                       ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, ServerInstance->TimeString(inv->expiry).c_str());
+                       std::string expiration = ServerInstance->TimeString(inv->expiry);
+                       ServerInstance->Logs->Log("INVITATION", DEBUG, "Invitation::Find ecountered expired entry: %p expired %s", (void*) inv, expiration.c_str());
                        i = locallist.erase(i);
                        inv->cull();
                        delete inv;