diff options
Diffstat (limited to 'modules/commands/cs_xop.cpp')
-rw-r--r-- | modules/commands/cs_xop.cpp | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/modules/commands/cs_xop.cpp b/modules/commands/cs_xop.cpp new file mode 100644 index 000000000..1b9348026 --- /dev/null +++ b/modules/commands/cs_xop.cpp @@ -0,0 +1,880 @@ +/* ChanServ core functions + * + * (C) 2003-2011 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +/*************************************************************************/ + +#include "module.h" + +enum XOPType +{ + XOP_QOP, + XOP_SOP, + XOP_AOP, + XOP_HOP, + XOP_VOP, + XOP_UNKNOWN +}; + +static struct XOPAccess +{ + XOPType type; + Anope::string name; + ChannelAccess access[CA_SIZE]; +} xopAccess[] = { + { XOP_QOP, "QOP", + { + CA_SIGNKICK, + CA_SET, + CA_AUTOOWNER, + CA_OWNERME, + CA_PROTECT, + CA_INFO, + CA_SIZE + } + }, + { XOP_SOP, "SOP", + { + CA_AUTOPROTECT, + CA_AKICK, + CA_BADWORDS, + CA_ASSIGN, + CA_MEMO, + CA_ACCESS_CHANGE, + CA_PROTECTME, + CA_OPDEOP, + CA_SIZE + } + }, + { XOP_AOP, "AOP", + { + CA_TOPIC, + CA_MODE, + CA_GETKEY, + CA_INVITE, + CA_UNBAN, + CA_AUTOOP, + CA_OPDEOPME, + CA_HALFOP, + CA_SAY, + CA_NOKICK, + CA_SIZE + } + }, + { XOP_HOP, "HOP", + { + CA_AUTOHALFOP, + CA_HALFOPME, + CA_KICK, + CA_BAN, + CA_FANTASIA, + CA_SIZE + } + }, + { XOP_VOP, "VOP", + { + CA_AUTOVOICE, + CA_VOICEME, + CA_ACCESS_LIST, + CA_SIZE + } + }, + { XOP_UNKNOWN, "", { } + } +}; + +class XOPChanAccess : public ChanAccess +{ + public: + XOPType type; + + XOPChanAccess(AccessProvider *p) : ChanAccess(p) + { + } + + bool Matches(User *u, NickCore *nc) + { + if (u && (Anope::Match(u->nick, this->mask) || Anope::Match(u->GetMask(), this->mask))) + return true; + else if (nc && Anope::Match(nc->display, this->mask)) + return true; + return false; + } + + bool HasPriv(ChannelAccess priv) + { + for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i) + { + XOPAccess &x = xopAccess[i]; + + if (this->type > x.type) + continue; + + for (int j = 0; x.access[j] != CA_SIZE; ++j) + if (x.access[j] == priv) + return true; + } + + return false; + } + + Anope::string Serialize() + { + for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i) + { + XOPAccess &x = xopAccess[i]; + + if (this->type == x.type) + return x.name; + } + + return ""; + } + + void Unserialize(const Anope::string &data) + { + for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i) + { + XOPAccess &x = xopAccess[i]; + + if (data == x.name) + { + this->type = x.type; + return; + } + } + + this->type = XOP_UNKNOWN; + } + + static XOPType DetermineLevel(ChanAccess *access) + { + if (access->provider->name == "access/xop") + { + XOPChanAccess *xaccess = debug_cast<XOPChanAccess *>(access); + return xaccess->type; + } + else + { + int count[XOP_UNKNOWN]; + for (int i = 0; i < XOP_UNKNOWN; ++i) + count[i] = 0; + + for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i) + { + XOPAccess &x = xopAccess[i]; + + for (int j = 0; x.access[j] != CA_SIZE; ++j) + if (access->HasPriv(x.access[j])) + ++count[x.type]; + } + + XOPType max = XOP_UNKNOWN; + int maxn = 0; + for (int i = 0; i < XOP_UNKNOWN; ++i) + if (count[i] > maxn) + { + max = static_cast<XOPType>(i); + maxn = count[i]; + } + + return max; + } + } +}; + +class XOPAccessProvider : public AccessProvider +{ + public: + XOPAccessProvider(Module *o) : AccessProvider(o, "access/xop") + { + } + + ChanAccess *Create() + { + return new XOPChanAccess(this); + } +}; + +class XOPListCallback : public NumberList +{ + CommandSource &source; + ChannelInfo *ci; + XOPType type; + Command *c; + bool SentHeader; + public: + XOPListCallback(CommandSource &_source, ChannelInfo *_ci, const Anope::string &numlist, XOPType _type, Command *_c) : NumberList(numlist, false), source(_source), ci(_ci), type(_type), c(_c), SentHeader(false) + { + } + + void HandleNumber(unsigned Number) + { + if (!Number || Number > ci->GetAccessCount()) + return; + + ChanAccess *access = ci->GetAccess(Number - 1); + + if (this->type != XOPChanAccess::DetermineLevel(access)) + return; + + if (!SentHeader) + { + SentHeader = true; + source.Reply(_("%s list for %s:\n Num Nick"), source.command.c_str(), ci->name.c_str()); + } + + DoList(source, access, Number - 1, this->type); + } + + static void DoList(CommandSource &source, ChanAccess *access, unsigned index, XOPType type) + { + source.Reply(_(" %3d %s"), index, access->mask.c_str()); + } +}; + +class XOPDelCallback : public NumberList +{ + CommandSource &source; + ChannelInfo *ci; + Command *c; + unsigned Deleted; + Anope::string Nicks; + bool override; + XOPType type; + public: + XOPDelCallback(CommandSource &_source, ChannelInfo *_ci, Command *_c, bool _override, XOPType _type, const Anope::string &numlist) : NumberList(numlist, true), source(_source), ci(_ci), c(_c), Deleted(0), override(_override), type(_type) + { + } + + ~XOPDelCallback() + { + if (!Deleted) + source.Reply(_("No matching entries on %s %s list."), ci->name.c_str(), source.command.c_str()); + else + { + Log(override ? LOG_OVERRIDE : LOG_COMMAND, source.u, c, ci) << "deleted access of users " << Nicks; + + if (Deleted == 1) + source.Reply(_("Deleted one entry from %s %s list."), ci->name.c_str(), source.command.c_str()); + else + source.Reply(_("Deleted %d entries from %s %s list."), Deleted, ci->name.c_str(), source.command.c_str()); + } + } + + void HandleNumber(unsigned Number) + { + if (!Number || Number > ci->GetAccessCount()) + return; + + ChanAccess *access = ci->GetAccess(Number - 1); + + if (this->type != XOPChanAccess::DetermineLevel(access)) + return; + + ++Deleted; + if (!Nicks.empty()) + Nicks += ", " + access->mask; + else + Nicks = access->mask; + + FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, source.u, access)); + + ci->EraseAccess(Number - 1); + } +}; + +class XOPBase : public Command +{ + private: + void DoAdd(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms, XOPType level) + { + User *u = source.u; + + Anope::string mask = params.size() > 2 ? params[2] : ""; + + if (mask.empty()) + { + this->OnSyntaxError(source, "ADD"); + return; + } + + if (readonly) + { + source.Reply(_("Sorry, channel %s list modification is temporarily disabled."), source.command.c_str()); + return; + } + + AccessGroup access = ci->AccessFor(u); + ChanAccess *highest = access.Highest(); + int u_level = (highest ? XOPChanAccess::DetermineLevel(highest) : 0); + + if (((access.HasPriv(CA_FOUNDER) || level >= u_level) || !access.HasPriv(CA_ACCESS_CHANGE)) && !u->HasPriv("chanserv/access/modify")) + { + source.Reply(ACCESS_DENIED); + return; + } + + for (unsigned i = 0; i < ci->GetAccessCount(); ++i) + { + ChanAccess *a = ci->GetAccess(i); + + if (a->mask.equals_ci(mask)) + { + if (XOPChanAccess::DetermineLevel(a) >= u_level && !u->HasPriv("chanserv/access/modify")) + { + source.Reply(ACCESS_DENIED); + return; + } + + ci->EraseAccess(i); + break; + } + } + + if (ci->GetAccessCount() >= Config->CSAccessMax) + { + source.Reply(_("Sorry, you can only have %d %s entries on a channel."), Config->CSAccessMax, source.command.c_str()); + return; + } + + if (mask.find_first_of("!*@") == Anope::string::npos && findnick(mask) == NULL) + mask += "!*@*"; + + service_reference<AccessProvider> provider("access/xop"); + if (!provider) + return; + XOPChanAccess *acc = debug_cast<XOPChanAccess *>(provider->Create()); + acc->ci = ci; + acc->mask = mask; + acc->creator = u->nick; + acc->type = level; + acc->last_seen = 0; + acc->created = Anope::CurTime; + ci->AddAccess(acc); + + bool override = level >= u_level || !access.HasPriv(CA_ACCESS_CHANGE); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, u, this, ci) << "ADD " << mask << " as level " << level; + + FOREACH_MOD(I_OnAccessAdd, OnAccessAdd(ci, u, acc)); + source.Reply(("\002%s\002 added to %s %s list."), acc->mask.c_str(), ci->name.c_str(), source.command.c_str()); + } + + void DoDel(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms, XOPType level) + { + User *u = source.u; + + const Anope::string &mask = params.size() > 2 ? params[2] : ""; + + if (mask.empty()) + { + this->OnSyntaxError(source, "DEL"); + return; + } + + if (readonly) + { + source.Reply(_("Sorry, channel %s list modification is temporarily disabled."), source.command.c_str()); + return; + } + + if (!ci->GetAccessCount()) + { + source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str()); + return; + } + + AccessGroup access = ci->AccessFor(u); + ChanAccess *highest = access.Highest(); + bool override = false; + if (!mask.equals_ci(u->Account()->display) && !access.HasPriv(CA_ACCESS_CHANGE) && (!highest || level >= XOPChanAccess::DetermineLevel(highest))) + { + if (u->HasPriv("chanserv/access/modify")) + override = true; + else + { + source.Reply(ACCESS_DENIED); + return; + } + } + + /* Special case: is it a number/list? Only do search if it isn't. */ + if (isdigit(mask[0]) && mask.find_first_not_of("1234567890,-") == Anope::string::npos) + { + XOPDelCallback list(source, ci, this, override, level, mask); + list.Process(); + } + else + { + for (unsigned i = 0; i < ci->GetAccessCount(); ++i) + { + ChanAccess *a = ci->GetAccess(i); + + if (a->mask.equals_ci(mask) && XOPChanAccess::DetermineLevel(a) == level) + { + Log(override ? LOG_OVERRIDE : LOG_COMMAND, u, this, ci) << "DEL " << a->mask; + + source.Reply(_("\002%s\002 deleted from %s %s list."), a->mask.c_str(), ci->name.c_str(), source.command.c_str()); + + FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, u, a)); + ci->EraseAccess(a); + + return; + } + } + + source.Reply(_("\002%s\002 not found on %s %s list."), mask.c_str(), ci->name.c_str(), source.command.c_str()); + } + } + + void DoList(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> ¶ms, XOPType level) + { + User *u = source.u; + + const Anope::string &nick = params.size() > 2 ? params[2] : ""; + + AccessGroup access = ci->AccessFor(u); + bool override = false; + + if (!access.HasPriv(CA_ACCESS_LIST)) + { + if (u->HasCommand("chanserv/access/list")) + override = true; + else + { + source.Reply(ACCESS_DENIED); + return; + } + } + + Log(override ? LOG_OVERRIDE : LOG_COMMAND, u, this, ci); + + if (!ci->GetAccessCount()) + { + source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str()); + return; + } + + if (!nick.empty() && nick.find_first_not_of("1234567890,-") == Anope::string::npos) + { + XOPListCallback list(source, ci, nick, level, this); + list.Process(); + } + else + { + bool SentHeader = false; + + for (unsigned i = 0, end = ci->GetAccessCount(); i < end; ++i) + { + ChanAccess *a = ci->GetAccess(i); + + if (XOPChanAccess::DetermineLevel(a) != level) + continue; + else if (!nick.empty() && !Anope::Match(a->mask, nick)) + continue; + + if (!SentHeader) + { + SentHeader = true; + source.Reply(_("%s list for %s:\n Num Nick"), source.command.c_str(), ci->name.c_str()); + } + + XOPListCallback::DoList(source, a, i + 1, level); + } + + if (!SentHeader) + source.Reply(_("No matching entries on %s %s list."), ci->name.c_str(), source.command.c_str()); + } + + return; + } + + void DoClear(CommandSource &source, ChannelInfo *ci, XOPType level) + { + User *u = source.u; + + if (readonly) + { + source.Reply(_("Sorry, channel %s list modification is temporarily disabled."), source.command.c_str()); + return; + } + + if (!ci->GetAccessCount()) + { + source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str()); + return; + } + + if (!ci->HasPriv(u, CA_FOUNDER) && !u->HasPriv("chanserv/access/modify")) + { + source.Reply(ACCESS_DENIED); + return; + } + + bool override = !ci->HasPriv(u, CA_FOUNDER); + Log(override ? LOG_OVERRIDE : LOG_COMMAND, u, this, ci) << "CLEAR level " << level; + + for (unsigned i = ci->GetAccessCount(); i > 0; --i) + { + ChanAccess *access = ci->GetAccess(i - 1); + if (XOPChanAccess::DetermineLevel(access) == level) + ci->EraseAccess(i - 1); + } + + FOREACH_MOD(I_OnAccessClear, OnAccessClear(ci, u)); + + source.Reply(_("Channel %s %s list has been cleared."), ci->name.c_str(), source.command.c_str()); + + return; + } + + protected: + void DoXop(CommandSource &source, const std::vector<Anope::string> ¶ms, XOPType level) + { + ChannelInfo *ci = cs_findchan(params[0]); + if (ci == NULL) + { + source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + return; + } + + const Anope::string &cmd = params[1]; + + if (cmd.equals_ci("ADD")) + return this->DoAdd(source, ci, params, level); + else if (cmd.equals_ci("DEL")) + return this->DoDel(source, ci, params, level); + else if (cmd.equals_ci("LIST")) + return this->DoList(source, ci, params, level); + else if (cmd.equals_ci("CLEAR")) + return this->DoClear(source, ci, level); + else + this->OnSyntaxError(source, ""); + + return; + } + public: + XOPBase(Module *modname, const Anope::string &command) : Command(modname, command, 2, 4) + { + this->SetSyntax("\037channel\037 ADD \037mask\037"); + this->SetSyntax("\037channel\037 DEL {\037mask\037 | \037entry-num\037 | \037list\037}"); + this->SetSyntax("\037channel\037 LIST [\037mask\037 | \037list\037]"); + this->SetSyntax("\037channel\037 CLEAR"); + } + + virtual ~XOPBase() + { + } + + virtual void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) = 0; + + virtual bool OnHelp(CommandSource &source, const Anope::string &subcommand) = 0; +}; + +class CommandCSQOP : public XOPBase +{ + public: + CommandCSQOP(Module *creator) : XOPBase(creator, "chanserv/qop") + { + this->SetDesc(_("Modify the list of QOP users")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + return this->DoXop(source, params, XOP_QOP); + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Maintains the \002QOP\002 (AutoOwner) \002list\002 for a channel. The QOP \n" + "list gives users the right to be auto-owner on your channel,\n" + "which gives them almost (or potentially, total) access.\n" + " \n" + "The \002QOP ADD\002 command adds the given nickname to the\n" + "QOP list.\n" + " \n" + "The \002QOP DEL\002 command removes the given nick from the\n" + "QOP list. If a list of entry numbers is given, those\n" + "entries are deleted. (See the example for LIST below.)\n" + " \n" + "The \002QOP LIST\002 command displays the QOP list. If\n" + "a wildcard mask is given, only those entries matching the\n" + "mask are displayed. If a list of entry numbers is given,\n" + "only those entries are shown; for example:\n" + " \002QOP #channel LIST 2-5,7-9\002\n" + " Lists QOP entries numbered 2 through 5 and\n" + " 7 through 9.\n" + " \n" + "The \002QOP CLEAR\002 command clears all entries of the\n" + "QOP list.\n")); + source.Reply(_(" \n" + "The \002QOP\002 commands are limited to\n" + "founders (unless SECUREOPS is off). However, any user on the\n" + "QOP list may use the \002QOP LIST\002 command.\n" + " \n")); + source.Reply(_("This command may have been disabled for your channel, and\n" + "in that case you need to use the access list. See \n" + "\002%s%s HELP ACCESS\002 for information about the access list,\n" + "and \002%s%s HELP SET XOP\002 to know how to toggle between \n" + "the access list and xOP list systems."), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str(), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str()); + return true; + } +}; + +class CommandCSAOP : public XOPBase +{ + public: + CommandCSAOP(Module *creator) : XOPBase(creator, "chanserv/aop") + { + this->SetDesc(_("Modify the list of AOP users")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + return this->DoXop(source, params, XOP_AOP); + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Maintains the \002AOP\002 (AutoOP) \002list\002 for a channel. The AOP \n" + "list gives users the right to be auto-opped on your channel,\n" + "to unban or invite themselves if needed, to have their\n" + "greet message showed on join, and so on.\n" + " \n" + "The \002AOP ADD\002 command adds the given nickname to the\n" + "AOP list.\n" + " \n" + "The \002AOP DEL\002 command removes the given nick from the\n" + "AOP list. If a list of entry numbers is given, those\n" + "entries are deleted. (See the example for LIST below.)\n" + " \n" + "The \002AOP LIST\002 command displays the AOP list. If\n" + "a wildcard mask is given, only those entries matching the\n" + "mask are displayed. If a list of entry numbers is given,\n" + "only those entries are shown; for example:\n" + " \002AOP #channel LIST 2-5,7-9\002\n" + " Lists AOP entries numbered 2 through 5 and\n" + " 7 through 9.\n" + " \n" + "The \002AOP CLEAR\002 command clears all entries of the\n" + "AOP list.\n")); + source.Reply(_(" \n" + "The \002AOP ADD\002 and \002AOP DEL\002 commands are limited to\n" + "SOPs or above, while the \002AOP CLEAR\002 command can only\n" + "be used by the channel founder. However, any user on the\n" + "AOP list may use the \002AOP LIST\002 command.\n" + " \n")); + source.Reply(_("This command may have been disabled for your channel, and\n" + "in that case you need to use the access list. See \n" + "\002%s%s HELP ACCESS\002 for information about the access list,\n" + "and \002%s%s HELP SET XOP\002 to know how to toggle between \n" + "the access list and xOP list systems."), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str(), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str()); + return true; + } +}; + +class CommandCSHOP : public XOPBase +{ + public: + CommandCSHOP(Module *creator) : XOPBase(creator, "chanserv/hop") + { + this->SetDesc(_("Maintains the HOP (HalfOP) list for a channel")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + return this->DoXop(source, params, XOP_HOP); + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Maintains the \002HOP\002 (HalfOP) \002list\002 for a channel. The HOP \n" + "list gives users the right to be auto-halfopped on your \n" + "channel.\n" + " \n" + "The \002HOP ADD\002 command adds the given nickname to the\n" + "HOP list.\n" + " \n" + "The \002HOP DEL\002 command removes the given nick from the\n" + "HOP list. If a list of entry numbers is given, those\n" + "entries are deleted. (See the example for LIST below.)\n" + " \n" + "The \002HOP LIST\002 command displays the HOP list. If\n" + "a wildcard mask is given, only those entries matching the\n" + "mask are displayed. If a list of entry numbers is given,\n" + "only those entries are shown; for example:\n" + " \002HOP #channel LIST 2-5,7-9\002\n" + " Lists HOP entries numbered 2 through 5 and\n" + " 7 through 9.\n" + " \n" + "The \002HOP CLEAR\002 command clears all entries of the\n" + "HOP list.\n")); + source.Reply(_(" \n" + "The \002HOP ADD\002, \002HOP DEL\002 and \002HOP LIST\002 commands are \n" + "limited to AOPs or above, while the \002HOP CLEAR\002 command \n" + "can only be used by the channel founder.\n" + " \n")); + source.Reply(_("This command may have been disabled for your channel, and\n" + "in that case you need to use the access list. See \n" + "\002%s%s HELP ACCESS\002 for information about the access list,\n" + "and \002%s%s HELP SET XOP\002 to know how to toggle between \n" + "the access list and xOP list systems."), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str(), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str()); + return true; + } +}; + +class CommandCSSOP : public XOPBase +{ + public: + CommandCSSOP(Module *creator) : XOPBase(creator, "chanserv/sop") + { + this->SetDesc(_("Modify the list of SOP users")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + return this->DoXop(source, params, XOP_SOP); + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Maintains the \002SOP\002 (SuperOP) \002list\002 for a channel. The SOP \n" + "list gives users all rights given by the AOP list, and adds\n" + "those needed to use the AutoKick and the BadWords lists, \n" + "to send and read channel memos, and so on.\n" + " \n" + "The \002SOP ADD\002 command adds the given nickname to the\n" + "SOP list.\n" + " \n" + "The \002SOP DEL\002 command removes the given nick from the\n" + "SOP list. If a list of entry numbers is given, those\n" + "entries are deleted. (See the example for LIST below.)\n" + " \n" + "The \002SOP LIST\002 command displays the SOP list. If\n" + "a wildcard mask is given, only those entries matching the\n" + "mask are displayed. If a list of entry numbers is given,\n" + "only those entries are shown; for example:\n" + " \002SOP #channel LIST 2-5,7-9\002\n" + " Lists AOP entries numbered 2 through 5 and\n" + " 7 through 9.\n" + " \n" + "The \002SOP CLEAR\002 command clears all entries of the\n" + "SOP list.\n")); + source.Reply(_( + " \n" + "The \002SOP ADD\002, \002SOP DEL\002 and \002SOP CLEAR\002 commands are \n" + "limited to the channel founder. However, any user on the\n" + "AOP list may use the \002SOP LIST\002 command.\n" + " \n")); + source.Reply(_("This command may have been disabled for your channel, and\n" + "in that case you need to use the access list. See \n" + "\002%s%s HELP ACCESS\002 for information about the access list,\n" + "and \002%s%s HELP SET XOP\002 to know how to toggle between \n" + "the access list and xOP list systems."), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str(), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str()); + return true; + } +}; + +class CommandCSVOP : public XOPBase +{ + public: + CommandCSVOP(Module *creator) : XOPBase(creator, "chanserv/vop") + { + this->SetDesc(_("Maintains the VOP (VOicePeople) list for a channel")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + return this->DoXop(source, params, XOP_VOP); + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("Maintains the \002VOP\002 (VOicePeople) \002list\002 for a channel. \n" + "The VOP list allows users to be auto-voiced and to voice \n" + "themselves if they aren't.\n" + " \n" + "The \002VOP ADD\002 command adds the given nickname to the\n" + "VOP list.\n" + " \n" + "The \002VOP DEL\002 command removes the given nick from the\n" + "VOP list. If a list of entry numbers is given, those\n" + "entries are deleted. (See the example for LIST below.)\n" + " \n" + "The \002VOP LIST\002 command displays the VOP list. If\n" + "a wildcard mask is given, only those entries matching the\n" + "mask are displayed. If a list of entry numbers is given,\n" + "only those entries are shown; for example:\n" + " \002VOP #channel LIST 2-5,7-9\002\n" + " Lists VOP entries numbered 2 through 5 and\n" + " 7 through 9.\n" + " \n" + "The \002VOP CLEAR\002 command clears all entries of the\n" + "VOP list.\n")); + source.Reply(_( + " \n" + "The \002VOP ADD\002, \002VOP DEL\002 and \002VOP LIST\002 commands are \n" + "limited to AOPs or above, while the \002VOP CLEAR\002 command \n" + "can only be used by the channel founder.\n" + " \n")); + source.Reply(_("This command may have been disabled for your channel, and\n" + "in that case you need to use the access list. See \n" + "\002%s%s HELP ACCESS\002 for information about the access list,\n" + "and \002%s%s HELP SET XOP\002 to know how to toggle between \n" + "the access list and xOP list systems."), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str(), + Config->UseStrictPrivMsgString.c_str(), source.owner->nick.c_str()); + return true; + } +}; + +class CSXOP : public Module +{ + XOPAccessProvider accessprovider; + CommandCSQOP commandcsqop; + CommandCSSOP commandcssop; + CommandCSAOP commandcsaop; + CommandCSHOP commandcshop; + CommandCSVOP commandcsvop; + + public: + CSXOP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), + accessprovider(this), commandcsqop(this), commandcssop(this), commandcsaop(this), commandcshop(this), commandcsvop(this) + { + this->SetAuthor("Anope"); + + ModuleManager::RegisterService(&accessprovider); + ModuleManager::RegisterService(&commandcssop); + ModuleManager::RegisterService(&commandcsaop); + ModuleManager::RegisterService(&commandcsqop); + ModuleManager::RegisterService(&commandcsvop); + ModuleManager::RegisterService(&commandcshop); + } +}; + +MODULE_INIT(CSXOP) |