cs_set.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 #include "module.h"
00013 
00014 class CommandCSSet : public Command
00015 {
00016  public:
00017         CommandCSSet(Module *creator) : Command(creator, "chanserv/set", 2, 3)
00018         {
00019                 this->SetDesc(_("Set channel options and information"));
00020                 this->SetSyntax(_("\037option\037 \037channel\037 \037parameters\037"));
00021         }
00022 
00023         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00024         {
00025                 this->OnSyntaxError(source, "");
00026                 return;
00027         }
00028 
00029         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00030         {
00031                 this->SendSyntax(source);
00032                 source.Reply(" ");
00033                 source.Reply(_("Allows the channel founder to set various channel options\n"
00034                         "and other information.\n"
00035                         " \n"
00036                         "Available options:"));
00037                 Anope::string this_name = source.command;
00038                 for (CommandInfo::map::const_iterator it = source.service->commands.begin(), it_end = source.service->commands.end(); it != it_end; ++it)
00039                 {
00040                         const Anope::string &c_name = it->first;
00041                         const CommandInfo &info = it->second;
00042                         if (c_name.find_ci(this_name + " ") == 0)
00043                         {
00044                                 ServiceReference<Command> command("Command", info.name);
00045                                 if (command)
00046                                 {
00047                                         source.command = it->first;
00048                                         command->OnServHelp(source);
00049                                 }
00050                         }
00051                 }
00052                 source.Reply(_("Type \002%s%s HELP SET \037option\037\002 for more information on a\n"
00053                                 "particular option."), Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00054                 return true;
00055         }
00056 };
00057 
00058 class CommandCSSASet : public Command
00059 {
00060  public:
00061         CommandCSSASet(Module *creator) : Command(creator, "chanserv/saset", 2, 3)
00062         {
00063                 this->SetDesc(_("Forcefully set channel options and information"));
00064                 this->SetSyntax(_("\037option\037 \037channel\037 \037parameters\037"));
00065         }
00066 
00067         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00068         {
00069                 this->OnSyntaxError(source, "");
00070                 return;
00071         }
00072 
00073         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00074         {
00075                 this->SendSyntax(source);
00076                 source.Reply(" ");
00077                 source.Reply(_("Allows Services Operators to forcefully change settings\n"
00078                                 "on channels.\n"
00079                                 " \n"
00080                                 "Available options:"));
00081                 Anope::string this_name = source.command;
00082                 for (CommandInfo::map::const_iterator it = source.service->commands.begin(), it_end = source.service->commands.end(); it != it_end; ++it)
00083                 {
00084                         const Anope::string &c_name = it->first;
00085                         const CommandInfo &info = it->second;
00086                         if (c_name.find_ci(this_name + " ") == 0)
00087                         {
00088                                 ServiceReference<Command> command("Command", info.name);
00089                                 if (command)
00090                                 {
00091                                         source.command = it->first;
00092                                         command->OnServHelp(source);
00093                                 }
00094                         }
00095                 }
00096                 source.Reply(_("Type \002%s%s HELP SASET \037option\037\002 for more information on a\n"
00097                         "particular option."), Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00098                 return true;
00099         }
00100 };
00101 
00102 class CommandCSSetAutoOp : public Command
00103 {
00104  public:
00105         CommandCSSetAutoOp(Module *creator, const Anope::string &cname = "chanserv/set/autoop") : Command(creator, cname, 2, 2)
00106         {
00107                 this->SetDesc(_("Should services automatically give status to users"));
00108                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00109         }
00110 
00111         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00112         {
00113                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00114                 if (ci == NULL)
00115                 {
00116                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00117                         return;
00118                 }
00119 
00120                 EventReturn MOD_RESULT;
00121                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00122                 if (MOD_RESULT == EVENT_STOP)
00123                         return;
00124 
00125                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00126                 {
00127                         source.Reply(ACCESS_DENIED);
00128                         return;
00129                 }
00130 
00131                 if (params[1].equals_ci("ON"))
00132                 {
00133                         ci->Shrink("NOAUTOOP");
00134                         source.Reply(_("Services will now automatically give modes to users in \002%s\002."), ci->name.c_str());
00135                 }
00136                 else if (params[1].equals_ci("OFF"))
00137                 {
00138                         ci->ExtendMetadata("NOAUTOOP");
00139                         source.Reply(_("Services will no longer automatically give modes to users in \002%s\002."), ci->name.c_str());
00140                 }
00141                 else
00142                         this->OnSyntaxError(source, "AUTOOP");
00143         }
00144 
00145         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00146         {
00147                 this->SendSyntax(source);
00148                 source.Reply(" ");
00149                 source.Reply(_("Enables or disables %s's autoop feature for a\n"
00150                         "channel. When disabled, users who join the channel will\n"
00151                         "not automatically gain any status from %s."), Config->ChanServ.c_str(),
00152                         Config->ChanServ.c_str(), this->name.c_str());
00153                 return true;
00154         }
00155 };
00156 
00157 class CommandCSSetBanType : public Command
00158 {
00159  public:
00160         CommandCSSetBanType(Module *creator, const Anope::string &cname = "chanserv/set/bantype") : Command(creator, cname, 2, 2)
00161         {
00162                 this->SetDesc(_("Set how Services make bans on the channel"));
00163                 this->SetSyntax(_("\037channel\037 \037bantype\037"));
00164         }
00165 
00166         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00167         {
00168                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00169                 if (ci == NULL)
00170                 {
00171                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00172                         return;
00173                 }
00174 
00175                 EventReturn MOD_RESULT;
00176                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00177                 if (MOD_RESULT == EVENT_STOP)
00178                         return;
00179 
00180                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00181                 {
00182                         source.Reply(ACCESS_DENIED);
00183                         return;
00184                 }
00185 
00186                 try
00187                 {
00188                         int16_t new_type = convertTo<int16_t>(params[1]);
00189                         if (new_type < 0 || new_type > 3)
00190                                 throw ConvertException("Invalid range");
00191                         ci->bantype = new_type;
00192                         source.Reply(_("Ban type for channel %s is now #%d."), ci->name.c_str(), ci->bantype);
00193                 }
00194                 catch (const ConvertException &)
00195                 {
00196                         source.Reply(_("\002%s\002 is not a valid ban type."), params[1].c_str());
00197                 }
00198 
00199                 return;
00200         }
00201 
00202         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00203         {
00204                 this->SendSyntax(source);
00205                 source.Reply(" ");
00206                 source.Reply(_("Sets the ban type that will be used by services whenever\n"
00207                                 "they need to ban someone from your channel.\n"
00208                                 " \n"
00209                                 "Bantype is a number between 0 and 3 that means:\n"
00210                                 " \n"
00211                                 "0: ban in the form *!user@host\n"
00212                                 "1: ban in the form *!*user@host\n"
00213                                 "2: ban in the form *!*@host\n"
00214                                 "3: ban in the form *!*user@*.domain"), this->name.c_str());
00215                 return true;
00216         }
00217 };
00218 
00219 class CommandCSSetChanstats : public Command
00220 {
00221  public:
00222         CommandCSSetChanstats(Module *creator) : Command(creator, "chanserv/set/chanstats", 2, 2)
00223         {
00224                 this->SetDesc(_("Turn chanstat statistics on or off"));
00225                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00226         }
00227 
00228         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00229         {
00230                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00231                 if (!ci)
00232                 {
00233                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00234                         return;
00235                 }
00236 
00237                 EventReturn MOD_RESULT;
00238                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00239                 if (MOD_RESULT == EVENT_STOP)
00240                         return;
00241 
00242                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00243                 {
00244                         source.Reply(ACCESS_DENIED);
00245                         return;
00246                 }
00247 
00248                 if (params[1].equals_ci("ON"))
00249                 {
00250                         ci->ExtendMetadata("STATS");
00251                         source.Reply(_("Chanstats statistics are now enabled for this channel."));
00252                 }
00253                 else if (params[1].equals_ci("OFF"))
00254                 {
00255                         ci->Shrink("STATS");
00256                         source.Reply(_("Chanstats statistics are now disabled for this channel."));
00257                 }
00258                 else
00259                         this->OnSyntaxError(source, "");
00260                 return;
00261         }
00262 
00263         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00264         {
00265                 this->SendSyntax(source);
00266                 source.Reply(" ");
00267                 source.Reply("Turn Chanstats channel statistics ON or OFF.");
00268                 return true;
00269         }
00270 };
00271 
00272 class CommandCSSetDescription : public Command
00273 {
00274  public:
00275         CommandCSSetDescription(Module *creator, const Anope::string &cname = "chanserv/set/description") : Command(creator, cname, 1, 2)
00276         {
00277                 this->SetDesc(_("Set the channel description"));
00278                 this->SetSyntax(_("\037channel\037 [\037description\037]"));
00279         }
00280 
00281         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00282         {
00283                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00284                 if (ci == NULL)
00285                 {
00286                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00287                         return;
00288                 }
00289 
00290                 EventReturn MOD_RESULT;
00291                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00292                 if (MOD_RESULT == EVENT_STOP)
00293                         return;
00294 
00295                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00296                 {
00297                         source.Reply(ACCESS_DENIED);
00298                         return;
00299                 }
00300 
00301                 if (params.size() > 1)
00302                 {
00303                         ci->desc = params[1];
00304                         source.Reply(_("Description of %s changed to \002%s\002."), ci->name.c_str(), ci->desc.c_str());
00305                 }
00306                 else
00307                 {
00308                         ci->desc.clear();
00309                         source.Reply(_("Description of %s unset."), ci->name.c_str());
00310                 }
00311 
00312                 return;
00313         }
00314 
00315         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00316         {
00317                 this->SendSyntax(source);
00318                 source.Reply(" ");
00319                 source.Reply(_("Sets the description for the channel, which shows up with\n"
00320                                 "the \002LIST\002 and \002INFO\002 commands."), this->name.c_str());
00321                 return true;
00322         }
00323 };
00324 
00325 class CommandCSSetFounder : public Command
00326 {
00327  public:
00328         CommandCSSetFounder(Module *creator, const Anope::string &cname = "chanserv/set/founder") : Command(creator, cname, 2, 2)
00329         {
00330                 this->SetDesc(_("Set the founder of a channel"));
00331                 this->SetSyntax(_("\037channel\037 \037nick\037"));
00332         }
00333 
00334         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00335         {
00336                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00337                 if (ci == NULL)
00338                 {
00339                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00340                         return;
00341                 }
00342 
00343                 EventReturn MOD_RESULT;
00344                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00345                 if (MOD_RESULT == EVENT_STOP)
00346                         return;
00347 
00348                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00349                 {
00350                         source.Reply(ACCESS_DENIED);
00351                         return;
00352                 }
00353 
00354                 if (source.permission.empty() && (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")))
00355                 {
00356                         source.Reply(ACCESS_DENIED);
00357                         return;
00358                 }
00359 
00360                 const NickAlias *na = NickAlias::Find(params[1]);
00361                 if (!na)
00362                 {
00363                         source.Reply(NICK_X_NOT_REGISTERED, params[1].c_str());
00364                         return;
00365                 }
00366 
00367                 NickCore *nc = na->nc;
00368                 if (Config->CSMaxReg && nc->channelcount >= Config->CSMaxReg && !source.HasPriv("chanserv/no-register-limit"))
00369                 {
00370                         source.Reply(_("\002%s\002 has too many channels registered."), na->nick.c_str());
00371                         return;
00372                 }
00373 
00374                 Log(!source.permission.empty() ? LOG_ADMIN : LOG_COMMAND, source, this, ci) << "to change the founder from " << (ci->GetFounder() ? ci->GetFounder()->display : "(none)") << " to " << nc->display;
00375 
00376                 ci->SetFounder(nc);
00377 
00378                 source.Reply(_("Founder of \002%s\002 changed to \002%s\002."), ci->name.c_str(), na->nick.c_str());
00379 
00380                 return;
00381         }
00382 
00383         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00384         {
00385                 this->SendSyntax(source);
00386                 source.Reply(" ");
00387                 source.Reply(_("Changes the founder of a channel. The new nickname must\n"
00388                                 "be a registered one."), this->name.c_str());
00389                 return true;
00390         }
00391 };
00392 
00393 class CommandCSSetKeepTopic : public Command
00394 {
00395  public:
00396         CommandCSSetKeepTopic(Module *creator, const Anope::string &cname = "chanserv/set/keeptopic") : Command(creator, cname, 2, 2)
00397         {
00398                 this->SetDesc(_("Retain topic when channel is not in use"));
00399                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00400         }
00401 
00402         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00403         {
00404                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00405                 if (ci == NULL)
00406                 {
00407                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00408                         return;
00409                 }
00410 
00411                 EventReturn MOD_RESULT;
00412                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00413                 if (MOD_RESULT == EVENT_STOP)
00414                         return;
00415 
00416                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00417                 {
00418                         source.Reply(ACCESS_DENIED);
00419                         return;
00420                 }
00421 
00422                 if (params[1].equals_ci("ON"))
00423                 {
00424                         ci->ExtendMetadata("KEEPTOPIC");
00425                         source.Reply(_("Topic retention option for %s is now \002on\002."), ci->name.c_str());
00426                 }
00427                 else if (params[1].equals_ci("OFF"))
00428                 {
00429                         ci->Shrink("KEEPTOPIC");
00430                         source.Reply(_("Topic retention option for %s is now \002off\002."), ci->name.c_str());
00431                 }
00432                 else
00433                         this->OnSyntaxError(source, "KEEPTOPIC");
00434 
00435                 return;
00436         }
00437 
00438         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00439         {
00440                 this->SendSyntax(source);
00441                 source.Reply(" ");
00442                 source.Reply(_("Enables or disables the \002topic retention\002 option for a\n"
00443                                 "channel. When \002%s\002 is set, the topic for the\n"
00444                                 "channel will be remembered by %s even after the\n"
00445                                 "last user leaves the channel, and will be restored the\n"
00446                                 "next time the channel is created."), this->name.c_str(), source.service->nick.c_str());
00447                 return true;
00448         }
00449 };
00450 
00451 class CommandCSSetPeace : public Command
00452 {
00453  public:
00454         CommandCSSetPeace(Module *creator, const Anope::string &cname = "chanserv/set/peace") : Command(creator, cname, 2, 2)
00455         {
00456                 this->SetDesc(_("Regulate the use of critical commands"));
00457                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00458         }
00459 
00460         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00461         {
00462                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00463                 if (ci == NULL)
00464                 {
00465                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00466                         return;
00467                 }
00468                 EventReturn MOD_RESULT;
00469                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00470                 if (MOD_RESULT == EVENT_STOP)
00471                         return;
00472 
00473                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00474                 {
00475                         source.Reply(ACCESS_DENIED);
00476                         return;
00477                 }
00478 
00479                 if (params[1].equals_ci("ON"))
00480                 {
00481                         ci->ExtendMetadata("PEACE");
00482                         source.Reply(_("Peace option for %s is now \002on\002."), ci->name.c_str());
00483                 }
00484                 else if (params[1].equals_ci("OFF"))
00485                 {
00486                         ci->Shrink("PEACE");
00487                         source.Reply(_("Peace option for %s is now \002off\002."), ci->name.c_str());
00488                 }
00489                 else
00490                         this->OnSyntaxError(source, "PEACE");
00491 
00492                 return;
00493         }
00494 
00495         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00496         {
00497                 this->SendSyntax(source);
00498                 source.Reply(" ");
00499                 source.Reply(_("Enables or disables the \002peace\002 option for a channel.\n"
00500                                 "When \002peace\002 is set, a user won't be able to kick,\n"
00501                                 "ban or remove a channel status of a user that has\n"
00502                                 "a level superior or equal to his via %s commands."), source.service->nick.c_str());
00503                 return true;
00504         }
00505 };
00506 
00507 class CommandCSSetPersist : public Command
00508 {
00509  public:
00510         CommandCSSetPersist(Module *creator, const Anope::string &cname = "chanserv/set/persist") : Command(creator, cname, 2, 2)
00511         {
00512                 this->SetDesc(_("Set the channel as permanent"));
00513                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00514         }
00515 
00516         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00517         {
00518                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00519                 if (ci == NULL)
00520                 {
00521                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00522                         return;
00523                 }
00524 
00525                 EventReturn MOD_RESULT;
00526                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00527                 if (MOD_RESULT == EVENT_STOP)
00528                         return;
00529 
00530                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00531                 {
00532                         source.Reply(ACCESS_DENIED);
00533                         return;
00534                 }
00535 
00536                 ChannelMode *cm = ModeManager::FindChannelModeByName("PERM");
00537 
00538                 if (params[1].equals_ci("ON"))
00539                 {
00540                         if (!ci->HasExt("PERSIST"))
00541                         {
00542                                 ci->ExtendMetadata("PERSIST");
00543                                 if (ci->c)
00544                                         ci->c->Extend("PERSIST");
00545 
00546                                 /* Channel doesn't exist, create it */
00547                                 if (!ci->c)
00548                                 {
00549                                         Channel *c = new Channel(ci->name);
00550                                         if (ci->bi)
00551                                                 ci->bi->Join(c);
00552                                 }
00553 
00554                                 /* No botserv bot, no channel mode, give them ChanServ.
00555                                  * Yes, this works fine with no Config->BotServ.
00556                                  */
00557                                 if (!ci->bi && !cm)
00558                                 {
00559                                         if (!ChanServ)
00560                                         {
00561                                                 source.Reply(_("ChanServ is required to enable persist on this network."));
00562                                                 return;
00563                                         }
00564                                         ChanServ->Assign(NULL, ci);
00565                                         if (!ci->c->FindUser(ChanServ))
00566                                                 ChanServ->Join(ci->c);
00567                                 }
00568 
00569                                 /* Set the perm mode */
00570                                 if (cm)
00571                                 {
00572                                         if (ci->c && !ci->c->HasMode("PERM"))
00573                                                 ci->c->SetMode(NULL, cm);
00574                                         /* Add it to the channels mlock */
00575                                         ci->SetMLock(cm, true);
00576                                 }
00577                         }
00578 
00579                         source.Reply(_("Channel \002%s\002 is now persistent."), ci->name.c_str());
00580                 }
00581                 else if (params[1].equals_ci("OFF"))
00582                 {
00583                         if (ci->HasExt("PERSIST"))
00584                         {
00585                                 ci->Shrink("PERSIST");
00586                                 if (ci->c)
00587                                         ci->c->Shrink("PERSIST");
00588 
00589                                 /* Unset perm mode */
00590                                 if (cm)
00591                                 {
00592                                         if (ci->c && ci->c->HasMode("PERM"))
00593                                                 ci->c->RemoveMode(NULL, cm);
00594                                         /* Remove from mlock */
00595                                         ci->RemoveMLock(cm, true);
00596                                 }
00597 
00598                                 /* No channel mode, no BotServ, but using ChanServ as the botserv bot
00599                                  * which was assigned when persist was set on
00600                                  */
00601                                 if (!cm && Config->BotServ.empty() && ci->bi)
00602                                 {
00603                                         if (!ChanServ)
00604                                         {
00605                                                 source.Reply(_("ChanServ is required to enable persist on this network."));
00606                                                 return;
00607                                         }
00608                                         /* Unassign bot */
00609                                         ChanServ->UnAssign(NULL, ci);
00610                                 }
00611                         }
00612 
00613                         source.Reply(_("Channel \002%s\002 is no longer persistent."), ci->name.c_str());
00614                 }
00615                 else
00616                         this->OnSyntaxError(source, "PERSIST");
00617 
00618                 return;
00619         }
00620 
00621         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00622         {
00623                 this->SendSyntax(source);
00624                 source.Reply(" ");
00625                 source.Reply(_("Enables or disables the persistent channel setting.\n"
00626                                 "When persistent is set, the service bot will remain\n"
00627                                 "in the channel when it has emptied of users.\n"
00628                                 " \n"
00629                                 "If your IRCd does not have a permanent (persistent) channel\n"
00630                                 "mode you must have a service bot in your channel to\n"
00631                                 "set persist on, and it can not be unassigned while persist\n"
00632                                 "is on.\n"
00633                                 " \n"
00634                                 "If this network does not have BotServ enabled and does\n"
00635                                 "not have a permanent channel mode, ChanServ will\n"
00636                                 "join your channel when you set persist on (and leave when\n"
00637                                 "it has been set off).\n"
00638                                 " \n"
00639                                 "If your IRCd has a permanent (persistent) channel mode\n"
00640                                 "and it is set or unset (for any reason, including MODE LOCK),\n"
00641                                 "persist is automatically set and unset for the channel aswell.\n"
00642                                 "Additionally, services will set or unset this mode when you\n"
00643                                 "set persist on or off."));
00644                 return true;
00645         }
00646 };
00647 
00648 class CommandCSSetPrivate : public Command
00649 {
00650  public:
00651         CommandCSSetPrivate(Module *creator, const Anope::string &cname = "chanserv/set/private") : Command(creator, cname, 2, 2)
00652         {
00653                 this->SetDesc(_("Hide channel from the LIST command"));
00654                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00655         }
00656 
00657         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00658         {
00659                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00660                 if (ci == NULL)
00661                 {
00662                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00663                         return;
00664                 }
00665 
00666                 EventReturn MOD_RESULT;
00667                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00668                 if (MOD_RESULT == EVENT_STOP)
00669                         return;
00670 
00671                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00672                 {
00673                         source.Reply(ACCESS_DENIED);
00674                         return;
00675                 }
00676 
00677                 if (params[1].equals_ci("ON"))
00678                 {
00679                         ci->ExtendMetadata("PRIVATE");
00680                         source.Reply(_("Private option for %s is now \002on\002."), ci->name.c_str());
00681                 }
00682                 else if (params[1].equals_ci("OFF"))
00683                 {
00684                         ci->Shrink("PRIVATE");
00685                         source.Reply(_("Private option for %s is now \002off\002."), ci->name.c_str());
00686                 }
00687                 else
00688                         this->OnSyntaxError(source, "PRIVATE");
00689 
00690                 return;
00691         }
00692 
00693         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00694         {
00695                 this->SendSyntax(source);
00696                 source.Reply(" ");
00697                 source.Reply(_("Enables or disables the \002private\002 option for a channel.\n"
00698                                 "When \002private\002 is set, a \002%s%s LIST\002 will not\n"
00699                                 "include the channel in any lists."),
00700                                 Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str());
00701                 return true;
00702         }
00703 };
00704 
00705 class CommandCSSetRestricted : public Command
00706 {
00707  public:
00708         CommandCSSetRestricted(Module *creator, const Anope::string &cname = "chanserv/set/restricted") : Command(creator, cname, 2, 2)
00709         {
00710                 this->SetDesc(_("Restrict access to the channel"));
00711                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00712         }
00713 
00714         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00715         {
00716                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00717                 if (ci == NULL)
00718                 {
00719                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00720                         return;
00721                 }
00722 
00723                 EventReturn MOD_RESULT;
00724                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00725                 if (MOD_RESULT == EVENT_STOP)
00726                         return;
00727 
00728                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00729                 {
00730                         source.Reply(ACCESS_DENIED);
00731                         return;
00732                 }
00733 
00734                 if (params[1].equals_ci("ON"))
00735                 {
00736                         ci->ExtendMetadata("RESTRICTED");
00737                         source.Reply(_("Restricted access option for %s is now \002on\002."), ci->name.c_str());
00738                 }
00739                 else if (params[1].equals_ci("OFF"))
00740                 {
00741                         ci->Shrink("RESTRICTED");
00742                         source.Reply(_("Restricted access option for %s is now \002off\002."), ci->name.c_str());
00743                 }
00744                 else
00745                         this->OnSyntaxError(source, "RESTRICTED");
00746 
00747                 return;
00748         }
00749 
00750         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00751         {
00752                 this->SendSyntax(source);
00753                 source.Reply(" ");
00754                 source.Reply(_("Enables or disables the \002restricted access\002 option for a\n"
00755                                 "channel. When \002restricted access\002 is set, users not on the access list will\n"
00756                                 "instead be kicked and banned from the channel."));
00757                 return true;
00758         }
00759 };
00760 
00761 class CommandCSSetSecure : public Command
00762 {
00763  public:
00764         CommandCSSetSecure(Module *creator, const Anope::string &cname = "chanserv/set/secure") : Command(creator, cname, 2, 2)
00765         {
00766                 this->SetDesc(_("Activate security features"));
00767                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00768         }
00769 
00770         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00771         {
00772                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00773                 if (ci == NULL)
00774                 {
00775                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00776                         return;
00777                 }
00778 
00779                 EventReturn MOD_RESULT;
00780                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00781                 if (MOD_RESULT == EVENT_STOP)
00782                         return;
00783 
00784                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00785                 {
00786                         source.Reply(ACCESS_DENIED);
00787                         return;
00788                 }
00789 
00790                 if (params[1].equals_ci("ON"))
00791                 {
00792                         ci->ExtendMetadata("SECURE");
00793                         source.Reply(_("Secure option for %s is now \002on\002."), ci->name.c_str());
00794                 }
00795                 else if (params[1].equals_ci("OFF"))
00796                 {
00797                         ci->Shrink("SECURE");
00798                         source.Reply(_("Secure option for %s is now \002off\002."), ci->name.c_str());
00799                 }
00800                 else
00801                         this->OnSyntaxError(source, "SECURE");
00802 
00803                 return;
00804         }
00805 
00806         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00807         {
00808                 this->SendSyntax(source);
00809                 source.Reply(" ");
00810                 source.Reply(_("Enables or disables security features for a\n"
00811                         "channel. When \002%s\002 is set, only users who have\n"
00812                         "registered their nicknames and IDENTIFY'd\n"
00813                         "with their password will be given access to the channel\n"
00814                         "as controlled by the access list."), this->name.c_str());
00815                 return true;
00816         }
00817 };
00818 
00819 class CommandCSSetSecureFounder : public Command
00820 {
00821  public:
00822         CommandCSSetSecureFounder(Module *creator, const Anope::string &cname = "chanserv/set/securefounder") : Command(creator, cname, 2, 2)
00823         {
00824                 this->SetDesc(_("Stricter control of channel founder status"));
00825                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00826         }
00827 
00828         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00829         {
00830                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00831                 if (ci == NULL)
00832                 {
00833                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00834                         return;
00835                 }
00836 
00837                 EventReturn MOD_RESULT;
00838                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00839                 if (MOD_RESULT == EVENT_STOP)
00840                         return;
00841 
00842                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00843                 {
00844                         source.Reply(ACCESS_DENIED);
00845                         return;
00846                 }
00847 
00848                 if (params[1].equals_ci("ON"))
00849                 {
00850                         ci->ExtendMetadata("SECUREFOUNDER");
00851                         source.Reply(_("Secure founder option for %s is now \002on\002."), ci->name.c_str());
00852                 }
00853                 else if (params[1].equals_ci("OFF"))
00854                 {
00855                         ci->Shrink("SECUREFOUNDER");
00856                         source.Reply(_("Secure founder option for %s is now \002off\002."), ci->name.c_str());
00857                 }
00858                 else
00859                         this->OnSyntaxError(source, "SECUREFOUNDER");
00860 
00861                 return;
00862         }
00863 
00864         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00865         {
00866                 this->SendSyntax(source);
00867                 source.Reply(" ");
00868                 source.Reply(_("Enables or disables the \002secure founder\002 option for a channel.\n"
00869                         "When \002secure founder\002 is set, only the real founder will be\n"
00870                         "able to drop the channel, change its founder and its successor,\n"
00871                         "and not those who have founder level access through\n"
00872                         "the access/qop command."));
00873                 return true;
00874         }
00875 };
00876 
00877 class CommandCSSetSecureOps : public Command
00878 {
00879  public:
00880         CommandCSSetSecureOps(Module *creator, const Anope::string &cname = "chanserv/set/secureops") : Command(creator, cname, 2, 2)
00881         {
00882                 this->SetDesc(_("Stricter control of chanop status"));
00883                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
00884         }
00885 
00886         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00887         {
00888                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00889                 if (ci == NULL)
00890                 {
00891                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00892                         return;
00893                 }
00894 
00895                 EventReturn MOD_RESULT;
00896                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00897                 if (MOD_RESULT == EVENT_STOP)
00898                         return;
00899 
00900                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00901                 {
00902                         source.Reply(ACCESS_DENIED);
00903                         return;
00904                 }
00905 
00906                 if (params[1].equals_ci("ON"))
00907                 {
00908                         ci->ExtendMetadata("SECUREOPS");
00909                         source.Reply(_("Secure ops option for %s is now \002on\002."), ci->name.c_str());
00910                 }
00911                 else if (params[1].equals_ci("OFF"))
00912                 {
00913                         ci->Shrink("SECUREOPS");
00914                         source.Reply(_("Secure ops option for %s is now \002off\002."), ci->name.c_str());
00915                 }
00916                 else
00917                         this->OnSyntaxError(source, "SECUREOPS");
00918 
00919                 return;
00920         }
00921 
00922         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00923         {
00924                 this->SendSyntax(source);
00925                 source.Reply(" ");
00926                 source.Reply(_("Enables or disables the \002secure ops\002 option for a channel.\n"
00927                                 "When \002secure ops\002 is set, users who are not on the userlist\n"
00928                                 "will not be allowed chanop status."));
00929                 return true;
00930         }
00931 };
00932 
00933 class CommandCSSetSignKick : public Command
00934 {
00935  public:
00936         CommandCSSetSignKick(Module *creator, const Anope::string &cname = "chanserv/set/signkick") : Command(creator, cname, 2, 2)
00937         {
00938                 this->SetDesc(_("Sign kicks that are done with the KICK command"));
00939                 this->SetSyntax(_("\037channel\037 SIGNKICK {ON | LEVEL | OFF}"));
00940         }
00941 
00942         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00943         {
00944                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
00945                 if (ci == NULL)
00946                 {
00947                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
00948                         return;
00949                 }
00950 
00951                 EventReturn MOD_RESULT;
00952                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
00953                 if (MOD_RESULT == EVENT_STOP)
00954                         return;
00955 
00956                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
00957                 {
00958                         source.Reply(ACCESS_DENIED);
00959                         return;
00960                 }
00961 
00962                 if (params[1].equals_ci("ON"))
00963                 {
00964                         ci->ExtendMetadata("SIGNKICK");
00965                         ci->Shrink("SIGNKICK_LEVEL");
00966                         source.Reply(_("Signed kick option for %s is now \002on\002."), ci->name.c_str());
00967                 }
00968                 else if (params[1].equals_ci("LEVEL"))
00969                 {
00970                         ci->ExtendMetadata("SIGNKICK_LEVEL");
00971                         ci->Shrink("SIGNKICK");
00972                         source.Reply(_("Signed kick option for %s is now \002on\002, but depends of the\n"
00973                                 "level of the user that is using the command."), ci->name.c_str());
00974                 }
00975                 else if (params[1].equals_ci("OFF"))
00976                 {
00977                         ci->Shrink("SIGNKICK");
00978                         ci->Shrink("SIGNKICK_LEVEL");
00979                         source.Reply(_("Signed kick option for %s is now \002off\002."), ci->name.c_str());
00980                 }
00981                 else
00982                         this->OnSyntaxError(source, "SIGNKICK");
00983         }
00984 
00985         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
00986         {
00987                 this->SendSyntax(source);
00988                 source.Reply(" ");
00989                 source.Reply(_("Enables or disables signed kicks for a\n"
00990                                 "channel.  When \002SIGNKICK\002 is set, kicks issued with\n"
00991                                 "the \002KICK\002 command will have the nick that used the\n"
00992                                 "command in their reason.\n"
00993                                 " \n"
00994                                 "If you use \002LEVEL\002, those who have a level that is superior\n"
00995                                 "or equal to the SIGNKICK level on the channel won't have their\n"
00996                                 "kicks signed."));
00997                 return true;
00998         }
00999 };
01000 
01001 class CommandCSSetSuccessor : public Command
01002 {
01003  public:
01004         CommandCSSetSuccessor(Module *creator, const Anope::string &cname = "chanserv/set/successor") : Command(creator, cname, 1, 2)
01005         {
01006                 this->SetDesc(_("Set the successor for a channel"));
01007                 this->SetSyntax(_("\037channel\037 \037nick\037"));
01008         }
01009 
01010         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
01011         {
01012                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
01013                 if (ci == NULL)
01014                 {
01015                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
01016                         return;
01017                 }
01018 
01019                 EventReturn MOD_RESULT;
01020                 FOREACH_RESULT(I_OnSetChannelOption, OnSetChannelOption(source, this, ci, params[1]));
01021                 if (MOD_RESULT == EVENT_STOP)
01022                         return;
01023 
01024                 if (MOD_RESULT != EVENT_ALLOW && source.permission.empty())
01025                 {
01026                         if (!source.AccessFor(ci).HasPriv("SET"))
01027                         {
01028                                 source.Reply(ACCESS_DENIED);
01029                                 return;
01030                         }
01031 
01032                         if (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER"))
01033                         {
01034                                 source.Reply(ACCESS_DENIED);
01035                                 return;
01036                         }
01037                 }
01038 
01039                 NickCore *nc;
01040 
01041                 if (params.size() > 1)
01042                 {
01043                         const NickAlias *na = NickAlias::Find(params[1]);
01044 
01045                         if (!na)
01046                         {
01047                                 source.Reply(NICK_X_NOT_REGISTERED, params[1].c_str());
01048                                 return;
01049                         }
01050                         if (na->nc == ci->GetFounder())
01051                         {
01052                                 source.Reply(_("%s cannot be the successor on channel %s as they are the founder."), na->nick.c_str(), ci->name.c_str());
01053                                 return;
01054                         }
01055                         nc = na->nc;
01056                 }
01057                 else
01058                         nc = NULL;
01059 
01060                 Log(!source.permission.empty() ? LOG_ADMIN : LOG_COMMAND, source, this, ci) << "to change the successor from " << (ci->GetSuccessor() ? ci->GetSuccessor()->display : "(none)") << " to " << (nc ? nc->display : "(none)");
01061 
01062                 ci->SetSuccessor(nc);
01063 
01064                 if (nc)
01065                         source.Reply(_("Successor for \002%s\002 changed to \002%s\002."), ci->name.c_str(), nc->display.c_str());
01066                 else
01067                         source.Reply(_("Successor for \002%s\002 unset."), ci->name.c_str());
01068 
01069                 return;
01070         }
01071 
01072         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
01073         {
01074                 this->SendSyntax(source);
01075                 source.Reply(" ");
01076                 source.Reply(_("Changes the successor of a channel. If the founder's\n"
01077                                 "nickname expires or is dropped while the channel is still\n"
01078                                 "registered, the successor will become the new founder of the\n"
01079                                 "channel.  However, if the successor already has too many\n"
01080                                 "channels registered (%d), the channel will be dropped\n"
01081                                 "instead, just as if no successor had been set.  The new\n"
01082                                 "nickname must be a registered one."), Config->CSMaxReg);
01083                 return true;
01084         }
01085 };
01086 
01087 class CommandCSSASetNoexpire : public Command
01088 {
01089  public:
01090         CommandCSSASetNoexpire(Module *creator) : Command(creator, "chanserv/saset/noexpire", 2, 2)
01091         {
01092                 this->SetDesc(_("Prevent the channel from expiring"));
01093                 this->SetSyntax(_("\037channel\037 {ON | OFF}"));
01094         }
01095 
01096         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
01097         {
01098                 ChannelInfo *ci = ChannelInfo::Find(params[0]);
01099                 if (ci == NULL)
01100                 {
01101                         source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
01102                         return;
01103                 }
01104 
01105                 if (source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
01106                 {
01107                         source.Reply(ACCESS_DENIED);
01108                         return;
01109                 }
01110 
01111                 if (params[1].equals_ci("ON"))
01112                 {
01113                         ci->ExtendMetadata("NO_EXPIRE");
01114                         source.Reply(_("Channel %s \002will not\002 expire."), ci->name.c_str());
01115                 }
01116                 else if (params[1].equals_ci("OFF"))
01117                 {
01118                         ci->Shrink("NO_EXPIRE");
01119                         source.Reply(_("Channel %s \002will\002 expire."), ci->name.c_str());
01120                 }
01121                 else
01122                         this->OnSyntaxError(source, "NOEXPIRE");
01123 
01124                 return;
01125         }
01126 
01127         bool OnHelp(CommandSource &source, const Anope::string &) anope_override
01128         {
01129                 this->SendSyntax(source);
01130                 source.Reply(" ");
01131                 source.Reply(_("Sets whether the given channel will expire.  Setting this\n"
01132                                 "to ON prevents the channel from expiring."));
01133                 return true;
01134         }
01135 };
01136 
01137 class CSSet : public Module
01138 {
01139         CommandCSSet commandcsset;
01140         CommandCSSASet commandcssaset;
01141         CommandCSSetAutoOp commandcssetautoop;
01142         CommandCSSetBanType commandcssetbantype;
01143         CommandCSSetChanstats commandcssetchanstats;
01144         bool CSDefChanstats;
01145         CommandCSSetDescription commandcssetdescription;
01146         CommandCSSetFounder commandcssetfounder;
01147         CommandCSSetKeepTopic commandcssetkeeptopic;
01148         CommandCSSetPeace commandcssetpeace;
01149         CommandCSSetPersist commandcssetpersist;
01150         CommandCSSetPrivate commandcssetprivate;
01151         CommandCSSetRestricted commandcssetrestricted;
01152         CommandCSSetSecure commandcssetsecure;
01153         CommandCSSetSecureFounder commandcssetsecurefounder;
01154         CommandCSSetSecureOps commandcssetsecureops;
01155         CommandCSSetSignKick commandcssetsignkick;
01156         CommandCSSetSuccessor commandcssetsuccessor;
01157         CommandCSSASetNoexpire commandcssasetnoexpire;
01158 
01159  public:
01160         CSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
01161                 commandcsset(this), commandcssaset(this), commandcssetautoop(this), commandcssetbantype(this), commandcssetchanstats(this),
01162                 CSDefChanstats(false), commandcssetdescription(this), commandcssetfounder(this), commandcssetkeeptopic(this),
01163                 commandcssetpeace(this), commandcssetpersist(this), commandcssetprivate(this), commandcssetrestricted(this),
01164                 commandcssetsecure(this), commandcssetsecurefounder(this), commandcssetsecureops(this), commandcssetsignkick(this),
01165                 commandcssetsuccessor(this), commandcssasetnoexpire(this)
01166         {
01167                 this->SetAuthor("Anope");
01168 
01169                 Implementation i[] = { I_OnReload, I_OnChanRegistered, I_OnCheckKick };
01170                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
01171 
01172                 this->OnReload();
01173         }
01174 
01175         void OnReload() anope_override
01176         {
01177                 ConfigReader config;
01178                 CSDefChanstats = config.ReadFlag("chanstats", "CSDefChanstats", "0", 0);
01179         }
01180 
01181         void OnChanRegistered(ChannelInfo *ci) anope_override
01182         {
01183                 if (CSDefChanstats)
01184                         ci->ExtendMetadata("STATS");
01185         }
01186 
01187         EventReturn OnCheckKick(User *u, ChannelInfo *ci, Anope::string &mask, Anope::string &reason) anope_override
01188         {
01189                 if (!ci->HasExt("RESTRICTED") || ci->c->MatchesList(u, "EXCEPT"))
01190                         return EVENT_CONTINUE;
01191 
01192                 if (ci->AccessFor(u).empty() && (!ci->GetFounder() || u->Account() != ci->GetFounder()))
01193                         return EVENT_STOP;
01194 
01195                 return EVENT_CONTINUE;
01196         }
01197 };
01198 
01199 MODULE_INIT(CSSet)