X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fchannels.cpp;h=0d43bc802e129b89151ab5935b10f62aee28682f;hb=967bce73791bd3dcfe3b5f342a4d6b3a33330bd0;hp=9e9ad670aef0fc1ed77a1c90a5230058d9bc86cc;hpb=8790551dc182cd8804ee7d8ef89ccb31067cc2a4;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/channels.cpp b/src/channels.cpp index 9e9ad670a..0d43bc802 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -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", @@ -472,10 +456,9 @@ bool Channel::CheckBan(User* user, const std::string& mask) if (at == std::string::npos) return false; - char tomatch[MAXBUF]; - snprintf(tomatch, MAXBUF, "%s!%s", user->nick.c_str(), user->ident.c_str()); + const std::string nickIdent = user->nick + "!" + user->ident; std::string prefix = mask.substr(0, at); - if (InspIRCd::Match(tomatch, prefix, NULL)) + if (InspIRCd::Match(nickIdent, prefix, NULL)) { std::string suffix = mask.substr(at + 1); if (InspIRCd::Match(user->host, suffix, NULL) || @@ -508,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; + UserMembIter membiter = userlist.find(user); - Membership* memb = GetUser(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 char* reason) +void Channel::KickUser(User* src, User* victim, const std::string& reason, Membership* srcmemb) { - if (!src || !user || !reason) + 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++) { @@ -580,78 +556,48 @@ void Channel::KickUser(User *src, User *user, const char* 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); + 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, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!user || !text) - return; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteChannel(user, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteChannel(user, textbuffer); } void Channel::WriteChannel(User* user, const std::string &text) { - char tb[MAXBUF]; - - if (!user) - return; - - snprintf(tb,MAXBUF,":%s %s", user->GetFullHost().c_str(), text.c_str()); - std::string out = tb; + const std::string message = ":" + user->GetFullHost() + " " + text; for (UserMembIter i = userlist.begin(); i != userlist.end(); i++) { if (IS_LOCAL(i->first)) - i->first->Write(out); + i->first->Write(message); } } void Channel::WriteChannelWithServ(const std::string& ServName, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!text) - return; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteChannelWithServ(ServName, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteChannelWithServ(ServName, textbuffer); } void Channel::WriteChannelWithServ(const std::string& ServName, const std::string &text) { - char tb[MAXBUF]; - - snprintf(tb,MAXBUF,":%s %s", ServName.empty() ? ServerInstance->Config->ServerName.c_str() : ServName.c_str(), text.c_str()); - std::string out = tb; + const std::string message = ":" + (ServName.empty() ? ServerInstance->Config->ServerName : ServName) + " " + text; for (UserMembIter i = userlist.begin(); i != userlist.end(); i++) { if (IS_LOCAL(i->first)) - i->first->Write(out); + i->first->Write(message); } } @@ -659,44 +605,23 @@ 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, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!text) - return; - - va_start(argsPtr, text); - vsnprintf(textbuffer, MAXBUF, text, argsPtr); - va_end(argsPtr); - - this->WriteAllExceptSender(user, serversource, status, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + this->WriteAllExceptSender(user, serversource, status, textbuffer); } void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const char* text, ...) { - char textbuffer[MAXBUF]; - va_list argsPtr; - - if (!text) - return; - - int offset = snprintf(textbuffer,MAXBUF,":%s ", serversource ? ServerInstance->Config->ServerName.c_str() : user->GetFullHost().c_str()); - - va_start(argsPtr, text); - vsnprintf(textbuffer + offset, MAXBUF - offset, text, argsPtr); - va_end(argsPtr); - - this->RawWriteAllExcept(user, serversource, status, except_list, std::string(textbuffer)); + std::string textbuffer; + VAFORMAT(textbuffer, text, text); + textbuffer = ":" + (serversource ? ServerInstance->Config->ServerName : user->GetFullHost()) + " " + textbuffer; + this->RawWriteAllExcept(user, serversource, status, except_list, textbuffer); } void Channel::WriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &text) { - 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)); + const std::string message = ":" + (serversource ? ServerInstance->Config->ServerName : user->GetFullHost()) + " " + text; + this->RawWriteAllExcept(user, serversource, status, except_list, message); } void Channel::RawWriteAllExcept(User* user, bool serversource, char status, CUList &except_list, const std::string &out) @@ -728,59 +653,37 @@ 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() +const char* Channel::ChanModes(bool showkey) { - int count = 0; - for (UserMembIter i = userlist.begin(); i != userlist.end(); i++) - { - if (!i->first->quitting && !i->first->IsModeSet('i')) - count++; - } - - return count; -} - -char* Channel::ChanModes(bool showkey) -{ - static char scratch[MAXBUF]; - static char sparam[MAXBUF]; - char* offset = scratch; - std::string extparam; + static std::string scratch; + std::string sparam; - *scratch = '\0'; - *sparam = '\0'; + scratch.clear(); /* This was still iterating up to 190, Channel::modes is only 64 elements -- Om */ for(int n = 0; n < 64; n++) { if(this->modes[n]) { - *offset++ = n + 65; - extparam.clear(); + scratch.push_back(n + 65); if (n == 'k' - 65 && !showkey) { - extparam = ""; + sparam += " "; } else { - extparam = this->GetModeParameter(n + 65); - } - if (!extparam.empty()) - { - charlcat(sparam,' ',MAXBUF); - strlcat(sparam,extparam.c_str(),MAXBUF); + const std::string param = this->GetModeParameter(n + 65); + if (!param.empty()) + { + sparam += ' '; + sparam += param; + } } } } - /* Null terminate scratch */ - *offset = '\0'; - strlcat(scratch,sparam,MAXBUF); - return scratch; + scratch += sparam; + return scratch.c_str(); } /* compile a userlist of a channel into a string, each nick seperated by @@ -788,29 +691,29 @@ 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; @@ -823,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)); @@ -832,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)); + 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()); @@ -958,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))