diff options
Diffstat (limited to 'modules/commands/cs_mode.cpp')
-rw-r--r-- | modules/commands/cs_mode.cpp | 191 |
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> ¶ms) @@ -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> ¶ms) + { + const Anope::string ¶m = 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> ¶ms) 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; } }; |