summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/channels.cpp82
-rw-r--r--src/commands/cmd_kick.cpp6
-rw-r--r--src/modules/m_permchannels.cpp5
3 files changed, 55 insertions, 38 deletions
diff --git a/src/channels.cpp b/src/channels.cpp
index 2807249c1..2b347a69e 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -138,32 +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);
+}
+
+void Channel::CheckDestroy()
+{
+ if (!userlist.empty())
+ return;
+
+ ModResult res;
+ FIRST_MOD_RESULT(OnChannelPreDelete, res, (this));
+ if (res == MOD_RES_DENY)
+ return;
- if (a != userlist.end())
+ chan_hash::iterator iter = ServerInstance->chanlist->find(this->name);
+ /* kill the record */
+ if (iter != ServerInstance->chanlist->end())
{
- a->second->cull();
- delete a->second;
- userlist.erase(a);
+ FOREACH_MOD(I_OnChannelDelete, OnChannelDelete(this));
+ ServerInstance->chanlist->erase(iter);
}
- 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);
- }
+ ClearInvites();
+ ServerInstance->GlobalCulls.AddItem(this);
+}
- ClearInvites();
- ServerInstance->GlobalCulls.AddItem(this);
- }
+void Channel::DelUser(const UserMembIter& membiter)
+{
+ 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)
@@ -481,38 +491,44 @@ 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)
{
- 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* victim, const std::string& reason)
+void Channel::KickUser(User* src, User* victim, const std::string& reason, Membership* srcmemb)
{
- Membership* memb = GetUser(victim);
+ 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;
}
+ // Do the following checks only if the KICK is done by a local user;
+ // each server enforces its own rules.
if (IS_LOCAL(src))
{
+ // Modules are allowed to explicitly allow or deny kicks done by local users
ModResult res;
FIRST_MOD_RESULT(OnUserPreKick, res, (src,memb,reason));
if (res == MOD_RES_DENY)
@@ -520,7 +536,9 @@ void Channel::KickUser(User* src, User* victim, const std::string& reason)
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++)
{
@@ -544,7 +562,7 @@ void Channel::KickUser(User* src, User* victim, const std::string& reason)
WriteAllExcept(src, false, 0, except_list, "KICK %s %s :%s", name.c_str(), victim->nick.c_str(), reason.c_str());
victim->chans.erase(this);
- this->DelUser(victim);
+ this->DelUser(victimiter);
}
void Channel::WriteChannel(User* user, const char* text, ...)
diff --git a/src/commands/cmd_kick.cpp b/src/commands/cmd_kick.cpp
index ecbdbad1e..016a14b2e 100644
--- a/src/commands/cmd_kick.cpp
+++ b/src/commands/cmd_kick.cpp
@@ -62,9 +62,11 @@ CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User
return CMD_FAILURE;
}
+ Membership* srcmemb = NULL;
if (IS_LOCAL(user))
{
- if (!c->HasUser(user))
+ srcmemb = c->GetUser(user);
+ if (!srcmemb)
{
user->WriteServ( "442 %s %s :You're not on that channel!", user->nick.c_str(), parameters[0].c_str());
return CMD_FAILURE;
@@ -86,7 +88,7 @@ CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User
reason.assign(user->nick, 0, ServerInstance->Config->Limits.MaxKick);
}
- c->KickUser(user, u, reason);
+ c->KickUser(user, u, reason, srcmemb);
return CMD_SUCCESS;
}
diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp
index 8aa888485..41477ba35 100644
--- a/src/modules/m_permchannels.cpp
+++ b/src/modules/m_permchannels.cpp
@@ -143,10 +143,7 @@ class PermChannel : public ModeHandler
if (channel->IsModeSet('P'))
{
channel->SetMode(this,false);
- if (channel->GetUserCounter() == 0)
- {
- channel->DelUser(ServerInstance->FakeClient);
- }
+ channel->CheckDestroy();
return MODEACTION_ALLOW;
}
}