summaryrefslogtreecommitdiff
path: root/modules/commands/cs_mode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/commands/cs_mode.cpp')
-rw-r--r--modules/commands/cs_mode.cpp191
1 files changed, 149 insertions, 42 deletions
diff --git a/modules/commands/cs_mode.cpp b/modules/commands/cs_mode.cpp
index c33b317a2..d44e7e07b 100644
--- a/modules/commands/cs_mode.cpp
+++ b/modules/commands/cs_mode.cpp
@@ -1,6 +1,6 @@
/* ChanServ core functions
*
- * (C) 2003-2012 Anope Team
+ * (C) 2003-2013 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
@@ -15,29 +15,30 @@
class CommandCSMode : public Command
{
- bool CanSet(CommandSource &source, ChannelInfo *ci, ChannelMode *cm)
+ bool CanSet(CommandSource &source, ChannelInfo *ci, ChannelMode *cm, bool self)
{
if (!ci || !cm || cm->type != MODE_STATUS)
return false;
- const Anope::string accesses[] = { "VOICE", "HALFOP", "OPDEOP", "PROTECT", "OWNER", "" };
- const ChannelModeName modes[] = { CMODE_VOICE, CMODE_HALFOP, CMODE_OP, CMODE_PROTECT, CMODE_OWNER };
+ const Anope::string accesses[] = { "VOICE", "HALFOP", "OPDEOP", "PROTECT", "OWNER", "" },
+ accesses_self[] = { "VOICEME", "HALFOPME", "OPDEOPME", "PROTECTME", "OWNERME", "" };
+ const Anope::string modes[] = { "VOICE", "HALFOP", "OP", "PROTECT", "OWNER" };
ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
AccessGroup access = source.AccessFor(ci);
- unsigned short u_level = 0;
+ short u_level = -1;
for (int i = 0; !accesses[i].empty(); ++i)
- if (access.HasPriv(accesses[i]))
+ if (access.HasPriv(self ? accesses_self[i] : accesses[i]))
{
ChannelMode *cm2 = ModeManager::FindChannelModeByName(modes[i]);
if (cm2 == NULL || cm2->type != MODE_STATUS)
continue;
ChannelModeStatus *cms2 = anope_dynamic_static_cast<ChannelModeStatus *>(cm2);
- if (cms2->Level > u_level)
- u_level = cms2->Level;
+ if (cms2->level > u_level)
+ u_level = cms2->level;
}
- return u_level >= cms->Level;
+ return u_level >= cms->level;
}
void DoLock(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
@@ -48,12 +49,29 @@ class CommandCSMode : public Command
bool override = !source.AccessFor(ci).HasPriv("MODE");
- if (subcommand.equals_ci("ADD") && !param.empty())
+ if ((subcommand.equals_ci("ADD") || subcommand.equals_ci("SET")) && !param.empty())
{
+ /* If setting, remove the existing locks */
+ if (subcommand.equals_ci("SET"))
+ {
+ const ChannelInfo::ModeList &mlocks = ci->GetMLock();
+ for (ChannelInfo::ModeList::const_iterator it = mlocks.begin(), it_next; it != mlocks.end(); it = it_next)
+ {
+ const ModeLock *ml = it->second;
+ ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
+ it_next = it;
+ ++it_next;
+ if (cm && cm->CanSet(source.GetUser()))
+ ci->RemoveMLock(cm, ml->set, ml->param);
+ }
+ }
+
spacesepstream sep(param);
Anope::string modes;
sep.GetToken(modes);
+
+ Anope::string pos = "+", neg = "-", pos_params, neg_params;
int adding = -1;
for (size_t i = 0; i < modes.length(); ++i)
@@ -87,14 +105,32 @@ class CommandCSMode : public Command
else
{
ci->SetMLock(cm, adding, mode_param, source.GetNick());
- if (!mode_param.empty())
- mode_param = " " + mode_param;
- source.Reply(_("%c%c%s locked on %s"), adding ? '+' : '-', cm->mchar, mode_param.c_str(), ci->name.c_str());
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to lock " << (adding ? '+' : '-') << cm->mchar << mode_param;
+
+ if (adding)
+ {
+ pos += cm->mchar;
+ if (!mode_param.empty())
+ pos_params += " " + mode_param;
+ }
+ else
+ {
+ neg += cm->mchar;
+ if (!mode_param.empty())
+ neg_params += " " + mode_param;
+ }
}
}
}
+ if (pos == "+")
+ pos.clear();
+ if (neg == "-")
+ neg.clear();
+ Anope::string reply = pos + neg + pos_params + neg_params;
+
+ source.Reply(_("%s locked on %s."), ci->GetMLockAsString(true).c_str(), ci->name.c_str());
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to lock " << ci->GetMLockAsString(true);
+
if (ci->c)
ci->c->CheckModes();
}
@@ -193,10 +229,12 @@ class CommandCSMode : public Command
{
User *u = source.GetUser();
+ bool has_access = source.AccessFor(ci).HasPriv("MODE") || source.HasPriv("chanserv/set");
+
spacesepstream sep(params.size() > 3 ? params[3] : "");
Anope::string modes = params[2], param;
- bool override = !source.AccessFor(ci).HasPriv("MODE");
+ bool override = !source.AccessFor(ci).HasPriv("MODE") && source.HasPriv("chanserv/set");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to set " << params[2];
int adding = -1;
@@ -211,7 +249,7 @@ class CommandCSMode : public Command
adding = 0;
break;
case '*':
- if (adding == -1)
+ if (adding == -1 || !has_access)
break;
for (unsigned j = 0; j < ModeManager::ChannelModes.size(); ++j)
{
@@ -237,12 +275,16 @@ class CommandCSMode : public Command
switch (cm->type)
{
case MODE_REGULAR:
+ if (!has_access)
+ break;
if (adding)
ci->c->SetMode(NULL, cm);
else
ci->c->RemoveMode(NULL, cm);
break;
case MODE_PARAM:
+ if (!has_access)
+ break;
if (adding && !sep.GetToken(param))
break;
if (adding)
@@ -253,25 +295,25 @@ class CommandCSMode : public Command
case MODE_STATUS:
{
if (!sep.GetToken(param))
- break;
-
- if (!this->CanSet(source, ci, cm))
- {
- source.Reply(_("You do not have access to set mode %c."), cm->mchar);
- break;
- }
+ param = source.GetNick();
AccessGroup u_access = source.AccessFor(ci);
if (param.find_first_of("*?") != Anope::string::npos)
{
- for (CUserList::const_iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it)
+ if (!this->CanSet(source, ci, cm, false))
{
- UserContainer *uc = *it;
+ source.Reply(_("You do not have access to set mode %c."), cm->mchar);
+ break;
+ }
+
+ for (Channel::ChanUserList::const_iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it)
+ {
+ ChanUserContainer *uc = *it;
AccessGroup targ_access = ci->AccessFor(uc->user);
- if (targ_access > u_access)
+ if (uc->user->IsProtected() || targ_access > u_access)
{
source.Reply(_("You do not have the access to change %s's modes."), uc->user->nick.c_str());
continue;
@@ -295,13 +337,27 @@ class CommandCSMode : public Command
break;
}
- AccessGroup targ_access = ci->AccessFor(target);
- if (targ_access > u_access)
+ if (!this->CanSet(source, ci, cm, source.GetUser() == target))
{
- source.Reply(_("You do not have the access to change %s's modes."), target->nick.c_str());
+ source.Reply(_("You do not have access to set mode %c."), cm->mchar);
break;
}
+ if (source.GetUser() != target)
+ {
+ AccessGroup targ_access = ci->AccessFor(target);
+ if (targ_access > u_access)
+ {
+ source.Reply(_("You do not have the access to change %s's modes."), target->nick.c_str());
+ break;
+ }
+ else if (target->IsProtected())
+ {
+ source.Reply(ACCESS_DENIED);
+ break;
+ }
+ }
+
if (adding)
ci->c->SetMode(NULL, cm, target->GetUID());
else
@@ -310,6 +366,8 @@ class CommandCSMode : public Command
break;
}
case MODE_LIST:
+ if (!has_access)
+ break;
if (!sep.GetToken(param))
break;
if (adding)
@@ -331,12 +389,46 @@ class CommandCSMode : public Command
}
}
+ void DoClear(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
+ {
+ const Anope::string &param = params.size() > 2 ? params[2] : "";
+
+ if (param.empty())
+ {
+ std::vector<Anope::string> new_params;
+ new_params.push_back(params[0]);
+ new_params.push_back("SET");
+ new_params.push_back("-*");
+ this->DoSet(source, ci, new_params);
+ }
+ else if (param.equals_ci("BANS") || param.equals_ci("EXCEPTS") || param.equals_ci("INVITEOVERRIDES") || param.equals_ci("VOICES") || param.equals_ci("HALFOPS") || param.equals_ci("OPS"))
+ {
+ const Anope::string &mname = param.upper().substr(0, param.length() - 1);
+ ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
+ if (cm == NULL)
+ {
+ source.Reply(_("Your IRCD does not support %s."), mname.upper().c_str());
+ return;
+ }
+
+ std::vector<Anope::string> new_params;
+ new_params.push_back(params[0]);
+ new_params.push_back("SET");
+ new_params.push_back("-" + stringify(cm->mchar));
+ new_params.push_back("*");
+ this->DoSet(source, ci, new_params);
+ }
+ else
+ this->SendSyntax(source);
+ }
+
public:
- CommandCSMode(Module *creator) : Command(creator, "chanserv/mode", 3, 4)
+ CommandCSMode(Module *creator) : Command(creator, "chanserv/mode", 2, 4)
{
this->SetDesc(_("Control modes and mode locks on a channel"));
- this->SetSyntax(_("\037channel\037 LOCK {ADD|DEL|LIST} [\037what\037]"));
+ this->SetSyntax(_("\037channel\037 LOCK {ADD|DEL|SET|LIST} [\037what\037]"));
this->SetSyntax(_("\037channel\037 SET \037modes\037"));
+ this->SetSyntax(_("\037channel\037 CLEAR [\037what\037]"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
@@ -347,16 +439,24 @@ class CommandCSMode : public Command
if (!ci || !ci->c)
source.Reply(CHAN_X_NOT_IN_USE, params[0].c_str());
- else if (!source.AccessFor(ci).HasPriv("MODE") && !source.HasPriv("chanserv/set"))
- source.Reply(ACCESS_DENIED);
- else if (subcommand.equals_ci("LOCK"))
- this->DoLock(source, ci, params);
- else if (subcommand.equals_ci("SET"))
+ else if (subcommand.equals_ci("LOCK") && params.size() > 2)
+ {
+ if (!source.AccessFor(ci).HasPriv("MODE") && !source.HasPriv("chanserv/set"))
+ source.Reply(ACCESS_DENIED);
+ else
+ this->DoLock(source, ci, params);
+ }
+ else if (subcommand.equals_ci("SET") && params.size() > 2)
this->DoSet(source, ci, params);
+ else if (subcommand.equals_ci("CLEAR"))
+ {
+ if (!source.AccessFor(ci).HasPriv("MODE") && !source.HasPriv("chanserv/set"))
+ source.Reply(ACCESS_DENIED);
+ else
+ this->DoClear(source, ci, params);
+ }
else
this->OnSyntaxError(source, "");
-
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -366,19 +466,26 @@ class CommandCSMode : public Command
source.Reply(_("Mainly controls mode locks and mode access (which is different from channel access)\n"
"on a channel.\n"
" \n"
- "The \002MODE LOCK\002 command allows you to add, delete, and view mode locks on a channel.\n"
- "If a mode is locked on or off, services will not allow that mode to be changed.\n"
+ "The \002%s LOCK\002 command allows you to add, delete, and view mode locks on a channel.\n"
+ "If a mode is locked on or off, services will not allow that mode to be changed. The \2SET\2\n"
+ "command will clear all existing mode locks and set the new one given, while \2ADD\2 and \2DEL\2\n"
+ "modify the existing mode lock.\n"
"Example:\n"
" \002MODE #channel LOCK ADD +bmnt *!*@*aol*\002\n"
" \n"
- "The \002MODE SET\002 command allows you to set modes through services. Wildcards * and ? may\n"
+ "The \002%s SET\002 command allows you to set modes through services. Wildcards * and ? may\n"
"be given as parameters for list and status modes.\n"
"Example:\n"
" \002MODE #channel SET +v *\002\n"
" Sets voice status to all users in the channel.\n"
" \n"
" \002MODE #channel SET -b ~c:*\n"
- " Clears all extended bans that start with ~c:"));
+ " Clears all extended bans that start with ~c:\n"
+ " \n"
+ "The \002%s CLEAR\002 command is an easy way to clear modes on a channel. \037what\037 may be\n"
+ "one of bans, exempts, inviteoverrides, ops, halfops, or voices. If \037what\037 is not given then all\n"
+ "basic modes are removed."),
+ source.command.upper().c_str(), source.command.upper().c_str(), source.command.upper().c_str());
return true;
}
};