cs_xop.cpp

Go to the documentation of this file.
00001 /* ChanServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 
00016 enum XOPType
00017 {
00018         XOP_QOP,
00019         XOP_SOP,
00020         XOP_AOP,
00021         XOP_HOP,
00022         XOP_VOP,
00023         XOP_UNKNOWN
00024 };
00025 
00026 static struct XOPAccess
00027 {
00028         XOPType type;
00029         Anope::string name;
00030         Anope::string access[10];
00031 } xopAccess[] = {
00032         { XOP_QOP, "QOP",
00033                 {
00034                         "SIGNKICK",
00035                         "SET",
00036                         "MODE",
00037                         "AUTOOWNER",
00038                         "OWNERME",
00039                         "PROTECT",
00040                         "INFO",
00041                         "ASSIGN",
00042                         ""
00043                 }
00044         },
00045         { XOP_SOP, "SOP",
00046                 {
00047                         "AUTOPROTECT",
00048                         "AKICK",
00049                         "BADWORDS",
00050                         "MEMO",
00051                         "ACCESS_CHANGE",
00052                         "PROTECTME",
00053                         "OPDEOP",
00054                         ""
00055                 }
00056         },
00057         { XOP_AOP, "AOP",
00058                 {
00059                         "TOPIC",
00060                         "GETKEY",
00061                         "INVITE",
00062                         "AUTOOP",
00063                         "OPDEOPME",
00064                         "HALFOP",
00065                         "SAY",
00066                         "GREET",
00067                         ""
00068                 }
00069         },
00070         { XOP_HOP, "HOP",
00071                 {
00072                         "AUTOHALFOP",
00073                         "HALFOPME",
00074                         "VOICE",
00075                         "KICK",
00076                         "BAN",
00077                         "UNBAN",
00078                         ""
00079                 }
00080         },
00081         { XOP_VOP, "VOP",
00082                 {
00083                         "AUTOVOICE",
00084                         "VOICEME",
00085                         "ACCESS_LIST",
00086                         "FANTASIA",
00087                         "NOKICK",
00088                         ""
00089                 }
00090         },
00091         { XOP_UNKNOWN, "", { }
00092         }
00093 };
00094 
00095 class XOPChanAccess : public ChanAccess
00096 {
00097  public:
00098         XOPType type;
00099 
00100         XOPChanAccess(AccessProvider *p) : ChanAccess(p)
00101         {
00102         }
00103 
00104         bool HasPriv(const Anope::string &priv) const anope_override
00105         {
00106                 for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i)
00107                 {
00108                         XOPAccess &x = xopAccess[i];
00109 
00110                         if (this->type > x.type)
00111                                 continue;
00112 
00113                         for (int j = 0; !x.access[j].empty(); ++j)
00114                                 if (x.access[j] == priv)
00115                                         return true;
00116                 }
00117 
00118                 return false;
00119         }
00120 
00121         Anope::string AccessSerialize() const
00122         {
00123                 for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i)
00124                 {
00125                         XOPAccess &x = xopAccess[i];
00126 
00127                         if (this->type == x.type)
00128                                 return x.name;
00129                 }
00130 
00131                 return "";
00132         }
00133 
00134         void AccessUnserialize(const Anope::string &data) anope_override
00135         {
00136                 for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i)
00137                 {
00138                         XOPAccess &x = xopAccess[i];
00139 
00140                         if (data == x.name)
00141                         {
00142                                 this->type = x.type;
00143                                 return;
00144                         }
00145                 }
00146 
00147                 this->type = XOP_UNKNOWN;
00148         }
00149 
00150         static XOPType DetermineLevel(const ChanAccess *access)
00151         {
00152                 if (access->provider->name == "access/xop")
00153                 {
00154                         const XOPChanAccess *xaccess = anope_dynamic_static_cast<const XOPChanAccess *>(access);
00155                         return xaccess->type;
00156                 }
00157                 else
00158                 {
00159                         int count[XOP_UNKNOWN];
00160                         for (int i = 0; i < XOP_UNKNOWN; ++i)
00161                                 count[i] = 0;
00162 
00163                         for (int i = 0; xopAccess[i].type != XOP_UNKNOWN; ++i)
00164                         {
00165                                 XOPAccess &x = xopAccess[i];
00166 
00167                                 for (int j = 0; !x.access[j].empty(); ++j)
00168                                         if (access->HasPriv(x.access[j]))
00169                                                 ++count[x.type];
00170                         }
00171 
00172                         XOPType max = XOP_UNKNOWN;
00173                         int maxn = 0;
00174                         for (int i = 0; i < XOP_UNKNOWN; ++i)
00175                                 if (count[i] > maxn)
00176                                 {
00177                                         max = static_cast<XOPType>(i);
00178                                         maxn = count[i];
00179                                 }
00180 
00181                         return max;
00182                 }
00183         }
00184 };
00185 
00186 class XOPAccessProvider : public AccessProvider
00187 {
00188  public:
00189         XOPAccessProvider(Module *o) : AccessProvider(o, "access/xop")
00190         {
00191         }
00192 
00193         ChanAccess *Create() anope_override
00194         {
00195                 return new XOPChanAccess(this);
00196         }
00197 };
00198 
00199 class XOPBase : public Command
00200 {
00201  private:
00202         void DoAdd(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params, XOPType level)
00203         {
00204 
00205                 Anope::string mask = params.size() > 2 ? params[2] : "";
00206 
00207                 if (mask.empty())
00208                 {
00209                         this->OnSyntaxError(source, "ADD");
00210                         return;
00211                 }
00212 
00213                 if (Anope::ReadOnly)
00214                 {
00215                         source.Reply(_("Sorry, channel %s list modification is temporarily disabled."), source.command.c_str());
00216                         return;
00217                 }
00218 
00219                 XOPChanAccess tmp_access(NULL);
00220                 tmp_access.ci = ci;
00221                 tmp_access.type = level;
00222 
00223                 AccessGroup access = source.AccessFor(ci);
00224                 const ChanAccess *highest = access.Highest();
00225                 bool override = false;
00226 
00227                 if ((!access.founder && !access.HasPriv("ACCESS_CHANGE")) || ((!highest || *highest <= tmp_access) && !access.founder))
00228                 {
00229                         if (source.HasPriv("chanserv/access/modify"))
00230                                 override = true;
00231                         else
00232                         {
00233                                 source.Reply(ACCESS_DENIED);
00234                                 return;
00235                         }
00236                 }
00237 
00238                 if (mask.find_first_of("!*@") == Anope::string::npos && !NickAlias::Find(mask))
00239                 {
00240                         User *targ = User::Find(mask, true);
00241                         if (targ != NULL)
00242                                 mask = "*!*@" + targ->GetDisplayedHost();
00243                         else
00244                         {
00245                                 source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
00246                                 return;
00247                         }
00248                 }
00249 
00250                 for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
00251                 {
00252                         const ChanAccess *a = ci->GetAccess(i);
00253 
00254                         if (a->mask.equals_ci(mask))
00255                         {
00256                                 if ((!highest || *a >= *highest) && !access.founder && !source.HasPriv("chanserv/access/modify"))
00257                                 {
00258                                         source.Reply(ACCESS_DENIED);
00259                                         return;
00260                                 }
00261 
00262                                 ci->EraseAccess(i);
00263                                 break;
00264                         }
00265                 }
00266 
00267                 if (ci->GetAccessCount() >= Config->CSAccessMax)
00268                 {
00269                         source.Reply(_("Sorry, you can only have %d %s entries on a channel."), Config->CSAccessMax, source.command.c_str());
00270                         return;
00271                 }
00272 
00273                 ServiceReference<AccessProvider> provider("AccessProvider", "access/xop");
00274                 if (!provider)
00275                         return;
00276                 XOPChanAccess *acc = anope_dynamic_static_cast<XOPChanAccess *>(provider->Create());
00277                 acc->ci = ci;
00278                 acc->mask = mask;
00279                 acc->creator = source.GetNick();
00280                 acc->type = level;
00281                 acc->last_seen = 0;
00282                 acc->created = Anope::CurTime;
00283                 ci->AddAccess(acc);
00284 
00285                 Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to add " << mask;
00286 
00287                 FOREACH_MOD(I_OnAccessAdd, OnAccessAdd(ci, source, acc));
00288                 source.Reply(_("\002%s\002 added to %s %s list."), acc->mask.c_str(), ci->name.c_str(), source.command.c_str());
00289         }
00290 
00291         void DoDel(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params, XOPType level)
00292         {
00293                 NickCore *nc = source.nc;
00294                 Anope::string mask = params.size() > 2 ? params[2] : "";
00295 
00296                 if (mask.empty())
00297                 {
00298                         this->OnSyntaxError(source, "DEL");
00299                         return;
00300                 }
00301 
00302                 if (Anope::ReadOnly)
00303                 {
00304                         source.Reply(_("Sorry, channel %s list modification is temporarily disabled."), source.command.c_str());
00305                         return;
00306                 }
00307 
00308                 if (!ci->GetAccessCount())
00309                 {
00310                         source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str());
00311                         return;
00312                 }
00313 
00314                 XOPChanAccess tmp_access(NULL);
00315                 tmp_access.ci = ci;
00316                 tmp_access.type = level;
00317 
00318                 AccessGroup access = source.AccessFor(ci);
00319                 const ChanAccess *highest = access.Highest();
00320                 bool override = false;
00321 
00322                 if (!isdigit(mask[0]) && mask.find_first_of("!*@") == Anope::string::npos && !NickAlias::Find(mask))
00323                 {
00324                         User *targ = User::Find(mask, true);
00325                         if (targ != NULL)
00326                                 mask = "*!*@" + targ->GetDisplayedHost();
00327                         else
00328                         {
00329                                 source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
00330                                 return;
00331                         }
00332                 }
00333 
00334                 if ((!mask.equals_ci(nc->display) && !access.HasPriv("ACCESS_CHANGE") && !access.founder) || ((!highest || tmp_access >= *highest) && !access.founder))
00335                 {
00336                         if (source.HasPriv("chanserv/access/modify"))
00337                                 override = true;
00338                         else
00339                         {
00340                                 source.Reply(ACCESS_DENIED);
00341                                 return;
00342                         }
00343                 }
00344 
00345                 /* Special case: is it a number/list?  Only do search if it isn't. */
00346                 if (isdigit(mask[0]) && mask.find_first_not_of("1234567890,-") == Anope::string::npos)
00347                 {
00348                         class XOPDelCallback : public NumberList
00349                         {
00350                                 CommandSource &source;
00351                                 ChannelInfo *ci;
00352                                 Command *c;
00353                                 unsigned deleted;
00354                                 Anope::string nicks;
00355                                 bool override;
00356                                 XOPType type;
00357                          public:
00358                                 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)
00359                                 {
00360                                 }
00361 
00362                                 ~XOPDelCallback()
00363                                 {
00364                                         if (!deleted)
00365                                                  source.Reply(_("No matching entries on %s %s list."), ci->name.c_str(), source.command.c_str());
00366                                         else
00367                                         {
00368                                                 Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "to delete " << nicks;
00369 
00370                                                 if (deleted == 1)
00371                                                         source.Reply(_("Deleted one entry from %s %s list."), ci->name.c_str(), source.command.c_str());
00372                                                 else
00373                                                         source.Reply(_("Deleted %d entries from %s %s list."), deleted, ci->name.c_str(), source.command.c_str());
00374                                         }
00375                                 }
00376 
00377                                 void HandleNumber(unsigned number) anope_override
00378                                 {
00379                                         if (!number || number > ci->GetAccessCount())
00380                                                 return;
00381 
00382                                         ChanAccess *caccess = ci->GetAccess(number - 1);
00383 
00384                                         if (this->type != XOPChanAccess::DetermineLevel(caccess))
00385                                                 return;
00386 
00387                                         ++deleted;
00388                                         if (!nicks.empty())
00389                                                 nicks += ", " + caccess->mask;
00390                                         else
00391                                                 nicks = caccess->mask;
00392 
00393                                         FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, source, caccess));
00394 
00395                                         ci->EraseAccess(number - 1);
00396                                 }
00397                         }
00398                         delcallback(source, ci, this, override, level, mask);
00399                         delcallback.Process();
00400                 }
00401                 else
00402                 {
00403                         for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
00404                         {
00405                                 ChanAccess *a = ci->GetAccess(i);
00406 
00407                                 if (a->mask.equals_ci(mask) && XOPChanAccess::DetermineLevel(a) == level)
00408                                 {
00409                                         Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to delete " << a->mask;
00410 
00411                                         source.Reply(_("\002%s\002 deleted from %s %s list."), a->mask.c_str(), ci->name.c_str(), source.command.c_str());
00412 
00413                                         FOREACH_MOD(I_OnAccessDel, OnAccessDel(ci, source, a));
00414                                         delete a;
00415 
00416                                         return;
00417                                 }
00418                         }
00419                         
00420                         source.Reply(_("\002%s\002 not found on %s %s list."), mask.c_str(), ci->name.c_str(), source.command.c_str());
00421                 }
00422         }
00423 
00424         void DoList(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params, XOPType level)
00425         {
00426 
00427                 const Anope::string &nick = params.size() > 2 ? params[2] : "";
00428 
00429                 AccessGroup access = source.AccessFor(ci);
00430 
00431                 if (!access.HasPriv("ACCESS_LIST") && !source.HasCommand("chanserv/access/list"))
00432                 {
00433                         source.Reply(ACCESS_DENIED);
00434                         return;
00435                 }
00436 
00437                 if (!ci->GetAccessCount())
00438                 {
00439                         source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str());
00440                         return;
00441                 }
00442 
00443                 ListFormatter list;
00444                 list.AddColumn("Number").AddColumn("Mask");
00445 
00446                 if (!nick.empty() && nick.find_first_not_of("1234567890,-") == Anope::string::npos)
00447                 {
00448                         class XOPListCallback : public NumberList
00449                         {
00450                                 ListFormatter &list;
00451                                 ChannelInfo *ci;
00452                                 XOPType type;
00453                          public:
00454                                 XOPListCallback(ListFormatter &_list, ChannelInfo *_ci, const Anope::string &numlist, XOPType _type) : NumberList(numlist, false), list(_list), ci(_ci), type(_type)
00455                                 {
00456                                 }
00457 
00458                                 void HandleNumber(unsigned Number) anope_override
00459                                 {
00460                                         if (!Number || Number > ci->GetAccessCount())
00461                                                 return;
00462 
00463                                         const ChanAccess *a = ci->GetAccess(Number - 1);
00464 
00465                                         if (this->type != XOPChanAccess::DetermineLevel(a))
00466                                                 return;
00467 
00468                                         ListFormatter::ListEntry entry;
00469                                         entry["Number"] = stringify(Number);
00470                                         entry["Mask"] = a->mask;
00471                                         this->list.AddEntry(entry);
00472                                 }
00473                         } nl_list(list, ci, nick, level);
00474                         nl_list.Process();
00475                 }
00476                 else
00477                 {
00478                         for (unsigned i = 0, end = ci->GetAccessCount(); i < end; ++i)
00479                         {
00480                                 const ChanAccess *a = ci->GetAccess(i);
00481 
00482                                 if (XOPChanAccess::DetermineLevel(a) != level)
00483                                         continue;
00484                                 else if (!nick.empty() && !Anope::Match(a->mask, nick))
00485                                         continue;
00486 
00487                                 ListFormatter::ListEntry entry;
00488                                 entry["Number"] = stringify(i + 1);
00489                                 entry["Mask"] = a->mask;
00490                                 list.AddEntry(entry);
00491                         }
00492                 }
00493 
00494                 if (list.IsEmpty())
00495                         source.Reply(_("No matching entries on %s access list."), ci->name.c_str());
00496                 else
00497                 {
00498                         std::vector<Anope::string> replies;
00499                         list.Process(replies);
00500 
00501                         source.Reply(_("%s list for %s"), source.command.c_str(), ci->name.c_str());
00502                         for (unsigned i = 0; i < replies.size(); ++i)
00503                                 source.Reply(replies[i]);
00504                 }
00505         }
00506 
00507         void DoClear(CommandSource &source, ChannelInfo *ci, XOPType level)
00508         {
00509 
00510                 if (Anope::ReadOnly)
00511                 {
00512                         source.Reply(_("Sorry, channel %s list modification is temporarily disabled."), source.command.c_str());
00513                         return;
00514                 }
00515 
00516                 if (!ci->GetAccessCount())
00517                 {
00518                         source.Reply(_("%s %s list is empty."), ci->name.c_str(), source.command.c_str());
00519                         return;
00520                 }
00521 
00522                 if (!source.AccessFor(ci).HasPriv("FOUNDER") && !source.HasPriv("chanserv/access/modify"))
00523                 {
00524                         source.Reply(ACCESS_DENIED);
00525                         return;
00526                 }
00527 
00528                 bool override = !source.AccessFor(ci).HasPriv("FOUNDER");
00529                 Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to clear the access list";
00530 
00531                 for (unsigned i = ci->GetAccessCount(); i > 0; --i)
00532                 {
00533                         const ChanAccess *access = ci->GetAccess(i - 1);
00534                         if (XOPChanAccess::DetermineLevel(access) == level)
00535                                 ci->EraseAccess(i - 1);
00536                 }
00537 
00538                 FOREACH_MOD(I_OnAccessClear, OnAccessClear(ci, source));
00539 
00540                 source.Reply(_("Channel %s %s list has been cleared."), ci->name.c_str(), source.command.c_str());
00541 
00542                 return;
00543         }
00544 
00545  protected:
00546         void DoXop(CommandSource &source, const std::vector<Anope::string> &params, XOPType level)
00547         {
00548                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00549                 if (ci == NULL)
00550                 {
00551                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00552                         return;
00553                 }
00554 
00555                 const Anope::string &cmd = params[1];
00556 
00557                 if (cmd.equals_ci("ADD"))
00558                         return this->DoAdd(source, ci, params, level);
00559                 else if (cmd.equals_ci("DEL"))
00560                         return this->DoDel(source, ci, params, level);
00561                 else if (cmd.equals_ci("LIST"))
00562                         return this->DoList(source, ci, params, level);
00563                 else if (cmd.equals_ci("CLEAR"))
00564                         return this->DoClear(source, ci, level);
00565                 else
00566                         this->OnSyntaxError(source, "");
00567 
00568                 return;
00569         }
00570  public:
00571         XOPBase(Module *modname, const Anope::string &command) : Command(modname, command, 2, 4)
00572         {
00573                 this->SetSyntax("\037channel\037 ADD \037mask\037");
00574                 this->SetSyntax("\037channel\037 DEL {\037mask\037 | \037entry-num\037 | \037list\037}");
00575                 this->SetSyntax("\037channel\037 LIST [\037mask\037 | \037list\037]");
00576                 this->SetSyntax("\037channel\037 CLEAR");
00577         }
00578 
00579         virtual ~XOPBase()
00580         {
00581         }
00582 
00583         virtual void Execute(CommandSource &source, const std::vector<Anope::string> &params) = 0;
00584 
00585         virtual bool OnHelp(CommandSource &source, const Anope::string &subcommand) = 0;
00586 };
00587 
00588 class CommandCSQOP : public XOPBase
00589 {
00590  public:
00591         CommandCSQOP(Module *creator) : XOPBase(creator, "chanserv/qop")
00592         {
00593                 this->SetDesc(_("Modify the list of QOP users"));
00594         }
00595 
00596         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00597         {
00598                 return this->DoXop(source, params, XOP_QOP);
00599         }
00600 
00601         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00602         {
00603                 this->SendSyntax(source);
00604                 source.Reply(" ");
00605                 source.Reply(_("Maintains the \002QOP\002 (AutoOwner) \002list\002 for a channel. The QOP\n"
00606                                 "list gives users the right to be auto-owner on your channel,\n"
00607                                 "which gives them almost (or potentially, total) access.\n"
00608                                 " \n"
00609                                 "The \002QOP ADD\002 command adds the given nickname to the\n"
00610                                 "QOP list.\n"
00611                                 " \n"
00612                                 "The \002QOP DEL\002 command removes the given nick from the\n"
00613                                 "QOP list. If a list of entry numbers is given, those\n"
00614                                 "entries are deleted. (See the example for LIST below.)\n"
00615                                 " \n"
00616                                 "The \002QOP LIST\002 command displays the QOP list. If\n"
00617                                 "a wildcard mask is given, only those entries matching the\n"
00618                                 "mask are displayed. If a list of entry numbers is given,\n"
00619                                 "only those entries are shown; for example:\n"
00620                                 "   \002QOP #channel LIST 2-5,7-9\002\n"
00621                                 "      Lists QOP entries numbered 2 through 5 and\n"
00622                                 "      7 through 9.\n"
00623                                 "      \n"
00624                                 "The \002QOP CLEAR\002 command clears all entries of the\n"
00625                                 "QOP list."));
00626                 source.Reply(_(" \n"
00627                                 "The \002QOP\002 commands are limited to founders\n"
00628                                 "(unless SECUREOPS is off). However, any user on the\n"
00629                                 "VOP list or above may use the \002QOP LIST\002 command.\n"
00630                                 " \n"));
00631                 source.Reply(_("Alternative methods of modifying channel access lists are\n"
00632                                 "available. See \002%s%s HELP ACCESS\002 for information\n"
00633                                 "about the access list, and \002%s%s HELP FLAGS\002 for\n"
00634                                 "information about the flags based system."),
00635                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(),
00636                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00637                 return true;
00638         }
00639 };
00640 
00641 class CommandCSAOP : public XOPBase
00642 {
00643  public:
00644         CommandCSAOP(Module *creator) : XOPBase(creator, "chanserv/aop")
00645         {
00646                 this->SetDesc(_("Modify the list of AOP users"));
00647         }
00648 
00649         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00650         {
00651                 return this->DoXop(source, params, XOP_AOP);
00652         }
00653 
00654         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00655         {
00656                 this->SendSyntax(source);
00657                 source.Reply(" ");
00658                 source.Reply(_("Maintains the \002AOP\002 (AutoOP) \002list\002 for a channel. The AOP\n"
00659                                 "list gives users the right to be auto-opped on your channel,\n"
00660                                 "to unban or invite themselves if needed, to have their\n"
00661                                 "greet message showed on join, and so on.\n"
00662                                 " \n"
00663                                 "The \002AOP ADD\002 command adds the given nickname to the\n"
00664                                 "AOP list.\n"
00665                                 " \n"
00666                                 "The \002AOP DEL\002 command removes the given nick from the\n"
00667                                 "AOP list. If a list of entry numbers is given, those\n"
00668                                 "entries are deleted. (See the example for LIST below.)\n"
00669                                 " \n"
00670                                 "The \002AOP LIST\002 command displays the AOP list. If\n"
00671                                 "a wildcard mask is given, only those entries matching the\n"
00672                                 "mask are displayed. If a list of entry numbers is given,\n"
00673                                 "only those entries are shown; for example:\n"
00674                                 "   \002AOP #channel LIST 2-5,7-9\002\n"
00675                                 "      Lists AOP entries numbered 2 through 5 and\n"
00676                                 "      7 through 9.\n"
00677                                 "      \n"
00678                                 "The \002AOP CLEAR\002 command clears all entries of the\n"
00679                                 "AOP list."));
00680                 source.Reply(_(" \n"
00681                                 "The \002AOP ADD\002 and \002AOP DEL\002 commands are limited to\n"
00682                                 "SOPs or above, while the \002AOP CLEAR\002 command can only\n"
00683                                 "be used by the channel founder. However, any user on the\n"
00684                                 "VOP list or above may use the \002AOP LIST\002 command.\n"
00685                                 " \n"));
00686                 source.Reply(_("Alternative methods of modifying channel access lists are\n"
00687                                 "available. See \002%s%s HELP ACCESS\002 for information\n"
00688                                 "about the access list, and \002%s%s HELP FLAGS\002 for\n"
00689                                 "information about the flags based system."),
00690                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(), 
00691                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00692                 return true;
00693         }
00694 };
00695 
00696 class CommandCSHOP : public XOPBase
00697 {
00698  public:
00699         CommandCSHOP(Module *creator) : XOPBase(creator, "chanserv/hop")
00700         {
00701                 this->SetDesc(_("Maintains the HOP (HalfOP) list for a channel"));
00702         }
00703 
00704         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00705         {
00706                 return this->DoXop(source, params, XOP_HOP);
00707         }
00708 
00709         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00710         {
00711                 this->SendSyntax(source);
00712                 source.Reply(" ");
00713                 source.Reply(_("Maintains the \002HOP\002 (HalfOP) \002list\002 for a channel. The HOP\n"
00714                                 "list gives users the right to be auto-halfopped on your\n"
00715                                 "channel.\n"
00716                                 " \n"
00717                                 "The \002HOP ADD\002 command adds the given nickname to the\n"
00718                                 "HOP list.\n"
00719                                 " \n"
00720                                 "The \002HOP DEL\002 command removes the given nick from the\n"
00721                                 "HOP list. If a list of entry numbers is given, those\n"
00722                                 "entries are deleted. (See the example for LIST below.)\n"
00723                                 " \n"
00724                                 "The \002HOP LIST\002 command displays the HOP list. If\n"
00725                                 "a wildcard mask is given, only those entries matching the\n"
00726                                 "mask are displayed. If a list of entry numbers is given,\n"
00727                                 "only those entries are shown; for example:\n"
00728                                 "   \002HOP #channel LIST 2-5,7-9\002\n"
00729                                 "      Lists HOP entries numbered 2 through 5 and\n"
00730                                 "      7 through 9.\n"
00731                                 "      \n"
00732                                 "The \002HOP CLEAR\002 command clears all entries of the\n"
00733                                 "HOP list."));
00734                 source.Reply(_(" \n"
00735                                 "The \002HOP ADD\002 and \002HOP DEL\002 commands are limited\n"
00736                                 "to SOPs or above, while \002HOP LIST\002 is available to VOPs\n"
00737                                 "and above. The \002HOP CLEAR\002 command can only be used by the\n"
00738                                 "channel founder.\n"
00739                                 " \n"));
00740                 source.Reply(_("Alternative methods of modifying channel access lists are\n"
00741                                 "available. See \002%s%s HELP ACCESS\002 for information\n"
00742                                 "about the access list, and \002%s%s HELP FLAGS\002 for\n"
00743                                 "information about the flags based system."),
00744                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(),
00745                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00746                 return true;
00747         }
00748 };
00749 
00750 class CommandCSSOP : public XOPBase
00751 {
00752  public:
00753         CommandCSSOP(Module *creator) : XOPBase(creator, "chanserv/sop")
00754         {
00755                 this->SetDesc(_("Modify the list of SOP users"));
00756         }
00757 
00758         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00759         {
00760                 return this->DoXop(source, params, XOP_SOP);
00761         }
00762 
00763         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00764         {
00765                 this->SendSyntax(source);
00766                 source.Reply(" ");
00767                 source.Reply(_("Maintains the \002SOP\002 (SuperOP) \002list\002 for a channel. The SOP\n"
00768                                 "list gives users all rights given by the AOP list, and adds\n"
00769                                 "those needed to use the AutoKick and the BadWords lists,\n"
00770                                 "to send and read channel memos, and so on.\n"
00771                                 " \n"
00772                                 "The \002SOP ADD\002 command adds the given nickname to the\n"
00773                                 "SOP list.\n"
00774                                 " \n"
00775                                 "The \002SOP DEL\002 command removes the given nick from the\n"
00776                                 "SOP list. If a list of entry numbers is given, those\n"
00777                                 "entries are deleted. (See the example for LIST below.)\n"
00778                                 " \n"
00779                                 "The \002SOP LIST\002 command displays the SOP list. If\n"
00780                                 "a wildcard mask is given, only those entries matching the\n"
00781                                 "mask are displayed. If a list of entry numbers is given,\n"
00782                                 "only those entries are shown; for example:\n"
00783                                 "   \002SOP #channel LIST 2-5,7-9\002\n"
00784                                 "      Lists SOP entries numbered 2 through 5 and\n"
00785                                 "      7 through 9.\n"
00786                                 "      \n"
00787                                 "The \002SOP CLEAR\002 command clears all entries of the\n"
00788                                 "SOP list."));
00789                 source.Reply(_(" \n"
00790                                 "The \002SOP ADD\002, \002SOP DEL\002 and \002SOP CLEAR\002 commands are\n"
00791                                 "limited to the channel founder. However, any user on the\n"
00792                                 "VOP list or above may use the \002SOP LIST\002 command.\n"
00793                                 " \n"));
00794                 source.Reply(_("Alternative methods of modifying channel access lists are\n"
00795                                 "available. See \002%s%s HELP ACCESS\002 for information\n"
00796                                 "about the access list, and \002%s%s HELP FLAGS\002 for\n"
00797                                 "information about the flags based system."),
00798                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(),
00799                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00800                 return true;
00801         }
00802 };
00803 
00804 class CommandCSVOP : public XOPBase
00805 {
00806  public:
00807         CommandCSVOP(Module *creator) : XOPBase(creator, "chanserv/vop")
00808         {
00809                 this->SetDesc(_("Maintains the VOP (VOicePeople) list for a channel"));
00810         }
00811 
00812         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00813         {
00814                 return this->DoXop(source, params, XOP_VOP);
00815         }
00816 
00817         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00818         {
00819                 this->SendSyntax(source);
00820                 source.Reply(" ");
00821                 source.Reply(_("Maintains the \002VOP\002 (VOicePeople) \002list\002 for a channel.\n"
00822                                 "The VOP list allows users to be auto-voiced and to voice\n"
00823                                 "themselves if they aren't.\n"
00824                                 " \n"
00825                                 "The \002VOP ADD\002 command adds the given nickname to the\n"
00826                                 "VOP list.\n"
00827                                 " \n"
00828                                 "The \002VOP DEL\002 command removes the given nick from the\n"
00829                                 "VOP list. If a list of entry numbers is given, those\n"
00830                                 "entries are deleted. (See the example for LIST below.)\n"
00831                                 " \n"
00832                                 "The \002VOP LIST\002 command displays the VOP list. If\n"
00833                                 "a wildcard mask is given, only those entries matching the\n"
00834                                 "mask are displayed. If a list of entry numbers is given,\n"
00835                                 "only those entries are shown; for example:\n"
00836                                 "   \002VOP #channel LIST 2-5,7-9\002\n"
00837                                 "      Lists VOP entries numbered 2 through 5 and\n"
00838                                 "      7 through 9.\n"
00839                                 "      \n"
00840                                 "The \002VOP CLEAR\002 command clears all entries of the\n"
00841                                 "VOP list."));
00842                 source.Reply(_(" \n"
00843                                 "The \002VOP ADD\002 and \002VOP DEL\002 commands are limited\n"
00844                                 "to SOPs or above, while \002VOP LIST\002 is available to VOPs\n"
00845                                 "and above. The \002VOP CLEAR\002 command can only be used by the\n"
00846                                 "channel founder.\n"
00847                                 " \n"));
00848                 source.Reply(_("Alternative methods of modifying channel access lists are\n"
00849                                 "available. See \002%s%s HELP ACCESS\002 for information\n"
00850                                 "about the access list, and \002%s%s HELP FLAGS\002 for\n"
00851                                 "information about the flags based system."),
00852                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(),
00853                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00854                 return true;
00855         }
00856 };
00857 
00858 class CSXOP : public Module
00859 {
00860         XOPAccessProvider accessprovider;
00861         CommandCSQOP commandcsqop;
00862         CommandCSSOP commandcssop;
00863         CommandCSAOP commandcsaop;
00864         CommandCSHOP commandcshop;
00865         CommandCSVOP commandcsvop;
00866 
00867  public:
00868         CSXOP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00869                 accessprovider(this), commandcsqop(this), commandcssop(this), commandcsaop(this), commandcshop(this), commandcsvop(this)
00870         {
00871                 this->SetAuthor("Anope");
00872                 this->SetPermanent(true);
00873         }
00874 };
00875 
00876 MODULE_INIT(CSXOP)