summaryrefslogtreecommitdiff
path: root/src/channels.c
diff options
context:
space:
mode:
authorAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-01-21 06:31:17 +0000
committerAdam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864>2010-01-21 06:31:17 +0000
commit0ed0fa4af62554a7281d403b6895b29e198e8186 (patch)
tree4b0509084ef8181790f19c258c3bc1f5e38b80cc /src/channels.c
parent15817208aae1c80e2b03668981ac9268d6a02dde (diff)
Rewrote how Anope stores channel status modes on users.
This allows 3rd party modules to add and track their own status mode. Additionally we now store a users status in both the UserContainer and ChannelContainer. This also fixes the ModeStacker to not send any mode strings unnecessarially and shuffles some code around so we don't have to manually remove channels from users lists everywhere. git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2775 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src/channels.c')
-rw-r--r--src/channels.c377
1 files changed, 123 insertions, 254 deletions
diff --git a/src/channels.c b/src/channels.c
index f0c6e704e..7f2467f62 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -129,10 +129,13 @@ void Channel::JoinUser(User *user)
if (debug)
alog("debug: %s joins %s", user->nick.c_str(), this->name.c_str());
+ Flags<ChannelModeName> *Status = new Flags<ChannelModeName>;
ChannelContainer *cc = new ChannelContainer(this);
+ cc->Status = Status;
user->chans.push_back(cc);
UserContainer *uc = new UserContainer(user);
+ uc->Status = Status;
this->users.push_back(uc);
if (get_ignore(user->nick.c_str()) == NULL)
@@ -188,17 +191,30 @@ void Channel::DeleteUser(User *user)
if (this->ci)
update_cs_lastseen(user, this->ci);
- CUserList::iterator it;
- for (it = this->users.begin(); (*it)->user != user && it != this->users.end(); ++it);
- if (it == this->users.end())
+ CUserList::iterator cit;
+ for (cit = this->users.begin(); (*cit)->user != user && cit != this->users.end(); ++cit);
+ if (cit == this->users.end())
{
if (debug)
- alog("debug: Channel::DelUser() tried to delete nonexistnat user %s from channel %s", user->nick.c_str(), this->name.c_str());
+ alog("debug: Channel::DeleteUser() tried to delete nonexistnat user %s from channel %s", user->nick.c_str(), this->name.c_str());
return;
}
- delete *it;
- this->users.erase(it);
+ delete (*cit)->Status;
+ delete *cit;
+ this->users.erase(cit);
+
+ UChannelList::iterator uit;
+ for (uit = user->chans.begin(); (*uit)->chan != this && uit != user->chans.end(); ++uit);
+ if (uit == user->chans.end())
+ {
+ if (debug)
+ alog("debug: Channel::DeleteUser() tried to delete nonexistant channel %s from %s's channel list", this->name.c_str(), user->nick.c_str());
+ return;
+ }
+
+ delete *uit;
+ user->chans.erase(uit);
/* Channel is persistant, it shouldn't be deleted and the service bot should stay */
if (this->HasFlag(CH_PERSIST) || (this->ci && this->ci->HasFlag(CI_PERSIST)))
@@ -221,6 +237,52 @@ void Channel::DeleteUser(User *user)
delete this;
}
+/** Check if the user is on the channel
+ * @param u The user
+ * @return A user container if found, else NULL
+ */
+UserContainer *Channel::FindUser(User *u)
+{
+ for (CUserList::iterator it = this->users.begin(); it != this->users.end(); ++it)
+ if ((*it)->user == u)
+ return *it;
+ return NULL;
+}
+
+/** Check if a user has a status on a channel
+ * @param u The user
+ * @param cms The status mode, or NULL to represent no status
+ * @return true or false
+ */
+bool Channel::HasUserStatus(User *u, ChannelModeStatus *cms)
+{
+ if (!u || (cms && cms->Type != MODE_STATUS))
+ throw CoreException("Channel::HasUserStatus got bad mode");
+
+ /* Usually its more efficient to search the users channels than the channels users */
+ ChannelContainer *cc = u->FindChannel(this);
+ if (cc)
+ {
+ if (cms)
+ return cc->Status->HasFlag(cms->Name);
+ else
+ return !cc->Status->FlagCount();
+ }
+
+ return false;
+}
+
+/** Check if a user has a status on a channel
+ * Use the overloaded function for ChannelModeStatus* to check for no status
+ * @param u The user
+ * @param Name The Mode name, eg CMODE_OP, CMODE_VOICE
+ * @return true or false
+ */
+bool Channel::HasUserStatus(User *u, ChannelModeName Name)
+{
+ return HasUserStatus(u, dynamic_cast<ChannelModeStatus *>(ModeManager::FindChannelModeByName(Name)));
+}
+
/**
* See if a channel has a mode
* @param Name The mode name
@@ -268,9 +330,13 @@ void Channel::SetModeInternal(ChannelMode *cm, const std::string &param, bool En
if (debug)
alog("debug: Setting +%c on %s for %s", cm->ModeChar, this->name.c_str(), u->nick.c_str());
- ChannelModeStatus *cms = dynamic_cast<ChannelModeStatus *>(cm);
- /* Set the new status on the user */
- chan_set_user_status(this, u, cms->Status);
+ /* Set the status on the user */
+ ChannelContainer *cc = u->FindChannel(this);
+ if (cc)
+ {
+ cc->Status->SetFlag(cm->Name);
+ }
+
/* Enforce secureops, etc */
chan_set_correct_modes(u, this, 0);
return;
@@ -399,8 +465,13 @@ void Channel::RemoveModeInternal(ChannelMode *cm, const std::string &param, bool
if (debug)
alog("debug: Setting -%c on %s for %s", cm->ModeChar, this->name.c_str(), u->nick.c_str());
- ChannelModeStatus *cms = dynamic_cast<ChannelModeStatus *>(cm);
- chan_remove_user_status(this, u, cms->Status);
+ /* Remove the status on the user */
+ ChannelContainer *cc = u->FindChannel(this);
+ if (cc)
+ {
+ cc->Status->UnsetFlag(cm->Name);
+ }
+
return;
}
/* Setting b/e/I etc */
@@ -489,13 +560,8 @@ void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const std::string &param, bo
else if (cm->Type == MODE_STATUS)
{
User *u = finduser(param);
- if (u)
- {
- if (chan_has_user_status(this, u, dynamic_cast<ChannelModeStatus *>(cm)->Status))
- {
- return;
- }
- }
+ if (u && HasUserStatus(u, dynamic_cast<ChannelModeStatus *>(cm)))
+ return;
}
ModeManager::StackerAdd(bi, this, cm, true, param);
@@ -543,13 +609,8 @@ void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const std::string &param,
else if (cm->Type == MODE_STATUS)
{
User *u = finduser(param);
- if (u)
- {
- if (!chan_has_user_status(this, u, dynamic_cast<ChannelModeStatus *>(cm)->Status))
- {
- return;
- }
- }
+ if (u && !HasUserStatus(u, dynamic_cast<ChannelModeStatus *>(cm)))
+ return;
}
ModeManager::StackerAdd(bi, this, cm, false, param);
@@ -872,16 +933,10 @@ void Channel::KickInternal(const std::string &source, const std::string &nick, c
if (debug)
alog("debug: Channel::KickInternal kicking %s from %s", user->nick.c_str(), this->name.c_str());
- UChannelList::iterator it;
- for (it = user->chans.begin(); (*it)->chan != this && it != user->chans.end(); ++it);
- if (it != user->chans.end())
+ if (user->FindChannel(this))
{
- ChannelContainer *cc = *it;
-
- FOREACH_MOD(I_OnUserKicked, OnUserKicked(cc->chan, user, source, reason));
- cc->chan->DeleteUser(user);
- delete cc;
- user->chans.erase(it);
+ FOREACH_MOD(I_OnUserKicked, OnUserKicked(this, user, source, reason));
+ this->DeleteUser(user);
}
else if (debug)
alog("debug: Channel::KickInternal got kick for user %s who isn't on channel %s ?", user->nick.c_str(), this->name.c_str());
@@ -974,96 +1029,6 @@ char *chan_get_modes(Channel * chan, int complete, int plus)
/*************************************************************************/
-/* Retrieves the status of an user on a channel */
-
-int chan_get_user_status(Channel * chan, User * user)
-{
- for (UChannelList::iterator it = user->chans.begin(); it != user->chans.end(); ++it)
- if ((*it)->chan == chan)
- return (*it)->status;
-
- return 0;
-}
-
-/*************************************************************************/
-
-/* Has the given user the given status on the given channel? :p */
-
-int chan_has_user_status(Channel * chan, User * user, int16 status)
-{
- for (UChannelList::iterator it = user->chans.begin(); it != user->chans.end(); ++it)
- {
- ChannelContainer *cc = *it;
-
- if (cc->chan == chan)
- {
- if (debug)
- alog("debug: chan_has_user_status wanted %d the user is %d", status, cc->status);
- return (cc->status & status);
- }
- }
- return 0;
-}
-
-/*************************************************************************/
-
-/* Remove the status of an user on a channel */
-
-void chan_remove_user_status(Channel * chan, User * user, int16 status)
-{
- if (debug >= 2)
- alog("debug: removing user status (%d) from %s for %s", status,
- user->nick.c_str(), chan->name.c_str());
-
- for (UChannelList::iterator it = user->chans.begin(); it != user->chans.end(); ++it)
- {
- ChannelContainer *cc = *it;
-
- if (cc->chan == chan)
- {
- cc->status &= ~status;
- break;
- }
- }
-}
-
-/*************************************************************************/
-
-/* Set the status of an user on a channel */
-
-void chan_set_user_status(Channel * chan, User * user, int16 status)
-{
- UserMode *um;
-
- if (debug >= 2)
- alog("debug: setting user status (%d) on %s for %s", status,
- user->nick.c_str(), chan->name.c_str());
-
- if (Config.HelpChannel && ((um = ModeManager::FindUserModeByName(UMODE_HELPOP))) && (status & CUS_OP)
- && (stricmp(chan->name.c_str(), Config.HelpChannel) == 0)
- && (!chan->ci || check_access(user, chan->ci, CA_AUTOOP))) {
- if (debug) {
- alog("debug: %s being given helpop for having %d status in %s",
- user->nick.c_str(), status, chan->name.c_str());
- }
-
- user->SetMode(NULL, um);
- }
-
- for (UChannelList::iterator it = user->chans.begin(); it != user->chans.end(); ++it)
- {
- ChannelContainer *cc = *it;
-
- if (cc->chan == chan)
- {
- cc->status |= status;
- break;
- }
- }
-}
-
-/*************************************************************************/
-
/* Return the Channel structure corresponding to the named channel, or NULL
* if the channel was not found. chan is assumed to be non-NULL and valid
* (i.e. pointing to a channel name of 2 or more characters). */
@@ -1178,19 +1143,6 @@ void get_channel_stats(long *nrec, long *memuse)
/*************************************************************************/
-/* Is the given nick on the given channel? */
-
-int is_on_chan(Channel * c, User * u)
-{
- for (UChannelList::iterator it = u->chans.begin(); it != u->chans.end(); ++it)
- if ((*it)->chan == c)
- return 1;
-
- return 0;
-}
-
-/*************************************************************************/
-
/* Is the given nick on the given channel?
This function supports links. */
@@ -1236,7 +1188,8 @@ void do_join(const char *source, int ac, const char **av)
ci::string buf;
while (sep.GetToken(buf))
{
- if (buf[0] == '0') {
+ if (buf[0] == '0')
+ {
for (UChannelList::iterator it = user->chans.begin(); it != user->chans.end();)
{
ChannelContainer *cc = *it++;
@@ -1245,8 +1198,6 @@ void do_join(const char *source, int ac, const char **av)
FOREACH_MOD(I_OnPrePartChannel, OnPrePartChannel(user, cc->chan));
cc->chan->DeleteUser(user);
FOREACH_MOD(I_OnPartChannel, OnPartChannel(user, findchan(channame.c_str()), channame, ""));
- delete cc;
- user->chans.erase(it);
}
user->chans.clear();
continue;
@@ -1338,14 +1289,11 @@ void do_kick(const std::string &source, int ac, const char **av)
void do_part(const char *source, int ac, const char **av)
{
- User *user;
-
- user = finduser(source);
- if (!user) {
- if (debug) {
- alog("debug: PART from nonexistent user %s: %s", source,
- merge_args(ac, av));
- }
+ User *user = finduser(source);
+ if (!user)
+ {
+ if (debug)
+ alog("debug: PART from nonexistent user %s: %s", source, merge_args(ac, av));
return;
}
@@ -1353,24 +1301,26 @@ void do_part(const char *source, int ac, const char **av)
ci::string buf;
while (sep.GetToken(buf))
{
- if (debug)
- alog("debug: %s leaves %s", source, buf.c_str());
- UChannelList::iterator it;
- for (it = user->chans.begin(); buf != (*it)->chan->name && it != user->chans.end(); ++it);
- if (it != user->chans.end())
+ Channel *c = findchan(buf.c_str());
+
+ if (!c)
{
- ChannelContainer *cc = *it;
-
- FOREACH_MOD(I_OnPrePartChannel, OnPrePartChannel(user, cc->chan));
- std::string ChannelName = cc->chan->name;
-
- cc->chan->DeleteUser(user);
+ if (debug)
+ alog("debug: Recieved PART from %s for nonexistant channel %s", user->nick.c_str(), buf.c_str());
+ }
- delete *it;
- user->chans.erase(it);
+ if (debug)
+ alog("debug: %s leaves %s", source, buf.c_str());
+ if (user->FindChannel(c))
+ {
+ FOREACH_MOD(I_OnPrePartChannel, OnPrePartChannel(user, c));
+ std::string ChannelName = c->name;
+ c->DeleteUser(user);
FOREACH_MOD(I_OnPartChannel, OnPartChannel(user, findchan(ChannelName.c_str()), ChannelName, av[1] ? av[1] : ""));
}
+ else if (debug)
+ alog("debug: Recieved PART from %s for %s, but %s isn't in %s ?", user->nick.c_str(), c->name.c_str(), user->nick.c_str(), c->name.c_str());
}
}
@@ -1535,9 +1485,6 @@ void do_topic(const char *source, int ac, const char **av)
**/
void chan_set_correct_modes(User * user, Channel * c, int give_modes)
{
- int status;
- int add_modes = 0;
- int rem_modes = 0;
ChannelInfo *ci;
ChannelMode *owner, *admin, *op, *halfop, *voice;
@@ -1553,118 +1500,40 @@ void chan_set_correct_modes(User * user, Channel * c, int give_modes)
if ((ci->HasFlag(CI_FORBIDDEN)) || (*(c->name.c_str()) == '+'))
return;
- status = chan_get_user_status(c, user);
-
if (debug)
- alog("debug: Setting correct user modes for %s on %s (current status: %d, %sgiving modes)", user->nick.c_str(), c->name.c_str(), status, (give_modes ? "" : "not "));
+ alog("debug: Setting correct user modes for %s on %s (%sgiving modes)", user->nick.c_str(), c->name.c_str(), (give_modes ? "" : "not "));
- /* Changed the second line of this if a bit, to make sure unregistered
- * users can always get modes (IE: they always have autoop enabled). Before
- * this change, you were required to have a registered nick to be able
- * to receive modes. I wonder who added that... *looks at Rob* ;) -GD
- */
- if (give_modes && (get_ignore(user->nick.c_str()) == NULL)
- && (!user->nc || !user->nc->HasFlag(NI_AUTOOP))) {
- if (owner && check_access(user, ci, CA_AUTOOWNER))
- add_modes |= CUS_OWNER;
- else if (admin && check_access(user, ci, CA_AUTOPROTECT))
- add_modes |= CUS_PROTECT;
- if (op && check_access(user, ci, CA_AUTOOP))
- add_modes |= CUS_OP;
- else if (halfop && check_access(user, ci, CA_AUTOHALFOP))
- add_modes |= CUS_HALFOP;
- else if (voice && check_access(user, ci, CA_AUTOVOICE))
- add_modes |= CUS_VOICE;
- }
-
- /* We check if every mode they have is legally acquired here, and remove
- * the modes that they're not allowed to have. But only if SECUREOPS is
- * on, because else every mode is legal. -GD
- * Unless the channel has just been created. -heinz
- * Or the user matches CA_AUTODEOP... -GD
- */
- if (((ci->HasFlag(CI_SECUREOPS)) || (c->users.size() == 1)
- || check_access(user, ci, CA_AUTODEOP))
- && !is_ulined(user->server->name)) {
- if (owner && (status & CUS_OWNER) && !IsFounder(user, ci))
- rem_modes |= CUS_OWNER;
- if (admin && (status & CUS_PROTECT)
- && !check_access(user, ci, CA_AUTOPROTECT)
- && !check_access(user, ci, CA_PROTECTME))
- rem_modes |= CUS_PROTECT;
- if (op && (status & CUS_OP) && !check_access(user, ci, CA_AUTOOP)
- && !check_access(user, ci, CA_OPDEOPME))
- rem_modes |= CUS_OP;
- if (halfop && (status & CUS_HALFOP)
- && !check_access(user, ci, CA_AUTOHALFOP)
- && !check_access(user, ci, CA_HALFOPME))
- rem_modes |= CUS_HALFOP;
- }
-
- /* No modes to add or remove, exit function -GD */
- if (!add_modes && !rem_modes)
- return;
-
- if (add_modes > 0)
+ if (give_modes && !get_ignore(user->nick.c_str()) && (!user->nc || !user->nc->HasFlag(NI_AUTOOP)))
{
- if (owner && (add_modes & CUS_OWNER) && !(status & CUS_OWNER))
+ if (owner && check_access(user, ci, CA_AUTOOWNER))
c->SetMode(NULL, CMODE_OWNER, user->nick);
- else
- add_modes &= ~CUS_OWNER;
- if (admin && (add_modes & CUS_PROTECT) && !(status & CUS_PROTECT))
+ if (admin && check_access(user, ci, CA_AUTOPROTECT))
c->SetMode(NULL, CMODE_PROTECT, user->nick);
- else
- add_modes &= ~CUS_PROTECT;
- if (op && (add_modes & CUS_OP) && !(status & CUS_OP))
+ if (op && check_access(user, ci, CA_AUTOOP))
c->SetMode(NULL, CMODE_OP, user->nick);
- else
- add_modes &= ~CUS_OP;
- if (halfop && (add_modes & CUS_HALFOP) && !(status & CUS_HALFOP))
+ if (halfop && check_access(user, ci, CA_AUTOHALFOP))
c->SetMode(NULL, CMODE_HALFOP, user->nick);
- else
- add_modes &= ~CUS_HALFOP;
- if (voice && (add_modes & CUS_VOICE) && !(status & CUS_VOICE))
+ if (voice && check_access(user, ci, CA_AUTOVOICE))
c->SetMode(NULL, CMODE_VOICE, user->nick);
- else
- add_modes &= ~CUS_VOICE;
}
- if (rem_modes > 0)
+ if ((ci->HasFlag(CI_SECUREOPS) || check_access(user, ci, CA_AUTODEOP)) && !is_ulined(user->server->name))
{
- if (owner && rem_modes & CUS_OWNER)
- {
+ if (owner && !IsFounder(user, ci))
c->RemoveMode(NULL, CMODE_OWNER, user->nick);
- }
- if (admin && rem_modes & CUS_PROTECT)
- {
+ if (admin && !check_access(user, ci, CA_AUTOPROTECT) && !check_access(user, ci, CA_PROTECTME))
c->RemoveMode(NULL, CMODE_PROTECT, user->nick);
- }
- if (op && rem_modes & CUS_OP)
- {
+ if (op && !check_access(user, ci, CA_AUTOOP) && !check_access(user, ci, CA_OPDEOPME))
c->RemoveMode(NULL, CMODE_OP, user->nick);
- }
- if (halfop && rem_modes & CUS_HALFOP)
- {
+ if (halfop && !check_access(user, ci, CA_AUTOHALFOP) && !check_access(user, ci, CA_HALFOPME))
c->RemoveMode(NULL, CMODE_HALFOP, user->nick);
- }
}
-
- /* Here, both can be empty again due to the "isn't it set already?"
- * checks above. -GD
- */
- if (!add_modes && !rem_modes)
- return;
-
- if (add_modes > 0)
- chan_set_user_status(c, user, add_modes);
- if (rem_modes > 0)
- chan_remove_user_status(c, user, rem_modes);
}
/*************************************************************************/