anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
cs_set.cpp (41155B)
1 /* ChanServ core functions 2 * 3 * (C) 2003-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 * 8 * Based on the original code of Epona by Lara. 9 * Based on the original code of Services by Andy Church. 10 */ 11 12 #include "module.h" 13 #include "modules/cs_mode.h" 14 15 class CommandCSSet : public Command 16 { 17 public: 18 CommandCSSet(Module *creator) : Command(creator, "chanserv/set", 2, 3) 19 { 20 this->SetDesc(_("Set channel options and information")); 21 this->SetSyntax(_("\037option\037 \037channel\037 \037parameters\037")); 22 } 23 24 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 25 { 26 this->OnSyntaxError(source, ""); 27 } 28 29 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 30 { 31 this->SendSyntax(source); 32 source.Reply(" "); 33 source.Reply(_("Allows the channel founder to set various channel options\n" 34 "and other information.\n" 35 " \n" 36 "Available options:")); 37 Anope::string this_name = source.command; 38 bool hide_privileged_commands = Config->GetBlock("options")->Get<bool>("hideprivilegedcommands"), 39 hide_registered_commands = Config->GetBlock("options")->Get<bool>("hideregisteredcommands"); 40 for (CommandInfo::map::const_iterator it = source.service->commands.begin(), it_end = source.service->commands.end(); it != it_end; ++it) 41 { 42 const Anope::string &c_name = it->first; 43 const CommandInfo &info = it->second; 44 if (c_name.find_ci(this_name + " ") == 0) 45 { 46 if (info.hide) 47 continue; 48 49 ServiceReference<Command> c("Command", info.name); 50 51 // XXX dup 52 if (!c) 53 continue; 54 else if (hide_registered_commands && !c->AllowUnregistered() && !source.GetAccount()) 55 continue; 56 else if (hide_privileged_commands && !info.permission.empty() && !source.HasCommand(info.permission)) 57 continue; 58 59 source.command = it->first; 60 c->OnServHelp(source); 61 } 62 } 63 source.Reply(_("Type \002%s%s HELP %s \037option\037\002 for more information on a\n" 64 "particular option."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), this_name.c_str()); 65 return true; 66 } 67 }; 68 69 class CommandCSSetAutoOp : public Command 70 { 71 public: 72 CommandCSSetAutoOp(Module *creator, const Anope::string &cname = "chanserv/set/autoop") : Command(creator, cname, 2, 2) 73 { 74 this->SetDesc(_("Should services automatically give status to users")); 75 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 76 } 77 78 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 79 { 80 if (Anope::ReadOnly) 81 { 82 source.Reply(READ_ONLY_MODE); 83 return; 84 } 85 86 ChannelInfo *ci = ChannelInfo::Find(params[0]); 87 if (ci == NULL) 88 { 89 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 90 return; 91 } 92 93 EventReturn MOD_RESULT; 94 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 95 if (MOD_RESULT == EVENT_STOP) 96 return; 97 98 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 99 { 100 source.Reply(ACCESS_DENIED); 101 return; 102 } 103 104 if (params[1].equals_ci("ON")) 105 { 106 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable autoop"; 107 ci->Shrink<bool>("NOAUTOOP"); 108 source.Reply(_("Services will now automatically give modes to users in \002%s\002."), ci->name.c_str()); 109 } 110 else if (params[1].equals_ci("OFF")) 111 { 112 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable autoop"; 113 ci->Extend<bool>("NOAUTOOP"); 114 source.Reply(_("Services will no longer automatically give modes to users in \002%s\002."), ci->name.c_str()); 115 } 116 else 117 this->OnSyntaxError(source, "AUTOOP"); 118 } 119 120 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 121 { 122 this->SendSyntax(source); 123 source.Reply(" "); 124 source.Reply(_("Enables or disables %s's autoop feature for a\n" 125 "channel. When disabled, users who join the channel will\n" 126 "not automatically gain any status from %s."), source.service->nick.c_str(), 127 source.service->nick.c_str(), this->name.c_str()); 128 return true; 129 } 130 }; 131 132 class CommandCSSetBanType : public Command 133 { 134 public: 135 CommandCSSetBanType(Module *creator, const Anope::string &cname = "chanserv/set/bantype") : Command(creator, cname, 2, 2) 136 { 137 this->SetDesc(_("Set how Services make bans on the channel")); 138 this->SetSyntax(_("\037channel\037 \037bantype\037")); 139 } 140 141 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 142 { 143 if (Anope::ReadOnly) 144 { 145 source.Reply(READ_ONLY_MODE); 146 return; 147 } 148 149 ChannelInfo *ci = ChannelInfo::Find(params[0]); 150 if (ci == NULL) 151 { 152 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 153 return; 154 } 155 156 EventReturn MOD_RESULT; 157 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 158 if (MOD_RESULT == EVENT_STOP) 159 return; 160 161 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 162 { 163 source.Reply(ACCESS_DENIED); 164 return; 165 } 166 167 try 168 { 169 int16_t new_type = convertTo<int16_t>(params[1]); 170 if (new_type < 0 || new_type > 3) 171 throw ConvertException("Invalid range"); 172 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to change the ban type to " << new_type; 173 ci->bantype = new_type; 174 source.Reply(_("Ban type for channel %s is now #%d."), ci->name.c_str(), ci->bantype); 175 } 176 catch (const ConvertException &) 177 { 178 source.Reply(_("\002%s\002 is not a valid ban type."), params[1].c_str()); 179 } 180 } 181 182 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 183 { 184 this->SendSyntax(source); 185 source.Reply(" "); 186 source.Reply(_("Sets the ban type that will be used by services whenever\n" 187 "they need to ban someone from your channel.\n" 188 " \n" 189 "Bantype is a number between 0 and 3 that means:\n" 190 " \n" 191 "0: ban in the form *!user@host\n" 192 "1: ban in the form *!*user@host\n" 193 "2: ban in the form *!*@host\n" 194 "3: ban in the form *!*user@*.domain"), this->name.c_str()); 195 return true; 196 } 197 }; 198 199 class CommandCSSetDescription : public Command 200 { 201 public: 202 CommandCSSetDescription(Module *creator, const Anope::string &cname = "chanserv/set/description") : Command(creator, cname, 1, 2) 203 { 204 this->SetDesc(_("Set the channel description")); 205 this->SetSyntax(_("\037channel\037 [\037description\037]")); 206 } 207 208 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 209 { 210 if (Anope::ReadOnly) 211 { 212 source.Reply(READ_ONLY_MODE); 213 return; 214 } 215 216 ChannelInfo *ci = ChannelInfo::Find(params[0]); 217 const Anope::string ¶m = params.size() > 1 ? params[1] : ""; 218 if (ci == NULL) 219 { 220 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 221 return; 222 } 223 224 EventReturn MOD_RESULT; 225 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, param)); 226 if (MOD_RESULT == EVENT_STOP) 227 return; 228 229 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 230 { 231 source.Reply(ACCESS_DENIED); 232 return; 233 } 234 235 if (!param.empty()) 236 { 237 ci->desc = param; 238 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to change the description to " << ci->desc; 239 source.Reply(_("Description of %s changed to \002%s\002."), ci->name.c_str(), ci->desc.c_str()); 240 } 241 else 242 { 243 ci->desc.clear(); 244 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to unset the description"; 245 source.Reply(_("Description of %s unset."), ci->name.c_str()); 246 } 247 248 return; 249 } 250 251 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 252 { 253 this->SendSyntax(source); 254 source.Reply(" "); 255 source.Reply(_("Sets the description for the channel, which shows up with\n" 256 "the \002LIST\002 and \002INFO\002 commands."), this->name.c_str()); 257 return true; 258 } 259 }; 260 261 class CommandCSSetFounder : public Command 262 { 263 public: 264 CommandCSSetFounder(Module *creator, const Anope::string &cname = "chanserv/set/founder") : Command(creator, cname, 2, 2) 265 { 266 this->SetDesc(_("Set the founder of a channel")); 267 this->SetSyntax(_("\037channel\037 \037nick\037")); 268 } 269 270 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 271 { 272 if (Anope::ReadOnly) 273 { 274 source.Reply(READ_ONLY_MODE); 275 return; 276 } 277 278 ChannelInfo *ci = ChannelInfo::Find(params[0]); 279 if (ci == NULL) 280 { 281 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 282 return; 283 } 284 285 EventReturn MOD_RESULT; 286 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 287 if (MOD_RESULT == EVENT_STOP) 288 return; 289 290 if (MOD_RESULT != EVENT_ALLOW && (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")) && source.permission.empty() && !source.HasPriv("chanserv/administration")) 291 { 292 source.Reply(ACCESS_DENIED); 293 return; 294 } 295 296 const NickAlias *na = NickAlias::Find(params[1]); 297 if (!na) 298 { 299 source.Reply(NICK_X_NOT_REGISTERED, params[1].c_str()); 300 return; 301 } 302 303 NickCore *nc = na->nc; 304 unsigned max_reg = Config->GetModule("chanserv")->Get<unsigned>("maxregistered"); 305 if (max_reg && nc->channelcount >= max_reg && !source.HasPriv("chanserv/no-register-limit")) 306 { 307 source.Reply(_("\002%s\002 has too many channels registered."), na->nick.c_str()); 308 return; 309 } 310 311 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to change the founder from " << (ci->GetFounder() ? ci->GetFounder()->display : "(none)") << " to " << nc->display; 312 313 ci->SetFounder(nc); 314 315 source.Reply(_("Founder of \002%s\002 changed to \002%s\002."), ci->name.c_str(), na->nick.c_str()); 316 317 return; 318 } 319 320 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 321 { 322 this->SendSyntax(source); 323 source.Reply(" "); 324 source.Reply(_("Changes the founder of a channel. The new nickname must\n" 325 "be a registered one."), this->name.c_str()); 326 return true; 327 } 328 }; 329 330 class CommandCSSetKeepModes : public Command 331 { 332 public: 333 CommandCSSetKeepModes(Module *creator, const Anope::string &cname = "chanserv/set/keepmodes") : Command(creator, cname, 2, 2) 334 { 335 this->SetDesc(_("Retain modes when channel is not in use")); 336 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 337 } 338 339 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 340 { 341 if (Anope::ReadOnly) 342 { 343 source.Reply(READ_ONLY_MODE); 344 return; 345 } 346 347 ChannelInfo *ci = ChannelInfo::Find(params[0]); 348 if (ci == NULL) 349 { 350 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 351 return; 352 } 353 354 EventReturn MOD_RESULT; 355 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 356 if (MOD_RESULT == EVENT_STOP) 357 return; 358 359 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 360 { 361 source.Reply(ACCESS_DENIED); 362 return; 363 } 364 365 if (params[1].equals_ci("ON")) 366 { 367 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable keep modes"; 368 ci->Extend<bool>("CS_KEEP_MODES"); 369 source.Reply(_("Keep modes for %s is now \002on\002."), ci->name.c_str()); 370 if (ci->c) 371 ci->last_modes = ci->c->GetModes(); 372 } 373 else if (params[1].equals_ci("OFF")) 374 { 375 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable keep modes"; 376 ci->Shrink<bool>("CS_KEEP_MODES"); 377 source.Reply(_("Keep modes for %s is now \002off\002."), ci->name.c_str()); 378 ci->last_modes.clear(); 379 } 380 else 381 this->OnSyntaxError(source, "KEEPMODES"); 382 } 383 384 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 385 { 386 this->SendSyntax(source); 387 source.Reply(" "); 388 source.Reply(_("Enables or disables keepmodes for the given channel. If keep\n" 389 "modes is enabled, services will remember modes set on the channel\n" 390 "and attempt to re-set them the next time the channel is created.")); 391 return true; 392 } 393 }; 394 395 class CommandCSSetPeace : public Command 396 { 397 public: 398 CommandCSSetPeace(Module *creator, const Anope::string &cname = "chanserv/set/peace") : Command(creator, cname, 2, 2) 399 { 400 this->SetDesc(_("Regulate the use of critical commands")); 401 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 402 } 403 404 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 405 { 406 if (Anope::ReadOnly) 407 { 408 source.Reply(READ_ONLY_MODE); 409 return; 410 } 411 412 ChannelInfo *ci = ChannelInfo::Find(params[0]); 413 if (ci == NULL) 414 { 415 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 416 return; 417 } 418 419 EventReturn MOD_RESULT; 420 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 421 if (MOD_RESULT == EVENT_STOP) 422 return; 423 424 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 425 { 426 source.Reply(ACCESS_DENIED); 427 return; 428 } 429 430 if (params[1].equals_ci("ON")) 431 { 432 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable peace"; 433 ci->Extend<bool>("PEACE"); 434 source.Reply(_("Peace option for %s is now \002on\002."), ci->name.c_str()); 435 } 436 else if (params[1].equals_ci("OFF")) 437 { 438 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable peace"; 439 ci->Shrink<bool>("PEACE"); 440 source.Reply(_("Peace option for %s is now \002off\002."), ci->name.c_str()); 441 } 442 else 443 this->OnSyntaxError(source, "PEACE"); 444 445 return; 446 } 447 448 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 449 { 450 this->SendSyntax(source); 451 source.Reply(" "); 452 source.Reply(_("Enables or disables the \002peace\002 option for a channel.\n" 453 "When \002peace\002 is set, a user won't be able to kick,\n" 454 "ban or remove a channel status of a user that has\n" 455 "a level superior or equal to his via %s commands."), source.service->nick.c_str()); 456 return true; 457 } 458 }; 459 460 inline static Anope::string BotModes() 461 { 462 return Config->GetModule("botserv")->Get<Anope::string>("botmodes", 463 Config->GetModule("chanserv")->Get<Anope::string>("botmodes", "o") 464 ); 465 } 466 467 class CommandCSSetPersist : public Command 468 { 469 public: 470 CommandCSSetPersist(Module *creator, const Anope::string &cname = "chanserv/set/persist") : Command(creator, cname, 2, 2) 471 { 472 this->SetDesc(_("Set the channel as permanent")); 473 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 474 } 475 476 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 477 { 478 if (Anope::ReadOnly) 479 { 480 source.Reply(READ_ONLY_MODE); 481 return; 482 } 483 484 ChannelInfo *ci = ChannelInfo::Find(params[0]); 485 if (ci == NULL) 486 { 487 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 488 return; 489 } 490 491 EventReturn MOD_RESULT; 492 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 493 if (MOD_RESULT == EVENT_STOP) 494 return; 495 496 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 497 { 498 source.Reply(ACCESS_DENIED); 499 return; 500 } 501 502 ChannelMode *cm = ModeManager::FindChannelModeByName("PERM"); 503 504 if (params[1].equals_ci("ON")) 505 { 506 if (!ci->HasExt("PERSIST")) 507 { 508 ci->Extend<bool>("PERSIST"); 509 510 /* Set the perm mode */ 511 if (cm) 512 { 513 if (ci->c && !ci->c->HasMode("PERM")) 514 ci->c->SetMode(NULL, cm); 515 /* Add it to the channels mlock */ 516 ModeLocks *ml = ci->Require<ModeLocks>("modelocks"); 517 if (ml) 518 ml->SetMLock(cm, true, "", source.GetNick()); 519 } 520 /* No botserv bot, no channel mode, give them ChanServ. 521 * Yes, this works fine with no BotServ. 522 */ 523 else if (!ci->bi) 524 { 525 BotInfo *ChanServ = Config->GetClient("ChanServ"); 526 if (!ChanServ) 527 { 528 source.Reply(_("ChanServ is required to enable persist on this network.")); 529 return; 530 } 531 532 ChanServ->Assign(NULL, ci); 533 if (ci->c && !ci->c->FindUser(ChanServ)) 534 { 535 ChannelStatus status(BotModes()); 536 ChanServ->Join(ci->c, &status); 537 } 538 } 539 } 540 541 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable persist"; 542 source.Reply(_("Channel \002%s\002 is now persistent."), ci->name.c_str()); 543 } 544 else if (params[1].equals_ci("OFF")) 545 { 546 if (ci->HasExt("PERSIST")) 547 { 548 ci->Shrink<bool>("PERSIST"); 549 550 BotInfo *ChanServ = Config->GetClient("ChanServ"), 551 *BotServ = Config->GetClient("BotServ"); 552 553 /* Unset perm mode */ 554 if (cm) 555 { 556 if (ci->c && ci->c->HasMode("PERM")) 557 ci->c->RemoveMode(NULL, cm); 558 /* Remove from mlock */ 559 ModeLocks *ml = ci->GetExt<ModeLocks>("modelocks"); 560 if (ml) 561 ml->RemoveMLock(cm, true); 562 } 563 /* No channel mode, no BotServ, but using ChanServ as the botserv bot 564 * which was assigned when persist was set on 565 */ 566 else if (!cm && !BotServ && ci->bi) 567 { 568 if (!ChanServ) 569 { 570 source.Reply(_("ChanServ is required to enable persist on this network.")); 571 return; 572 } 573 574 /* Unassign bot */ 575 ChanServ->UnAssign(NULL, ci); 576 } 577 } 578 579 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable persist"; 580 source.Reply(_("Channel \002%s\002 is no longer persistent."), ci->name.c_str()); 581 } 582 else 583 this->OnSyntaxError(source, "PERSIST"); 584 } 585 586 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 587 { 588 BotInfo *BotServ = Config->GetClient("BotServ"); 589 BotInfo *ChanServ = Config->GetClient("ChanServ"); 590 this->SendSyntax(source); 591 source.Reply(" "); 592 source.Reply(_("Enables or disables the persistent channel setting.\n" 593 "When persistent is set, the service bot will remain\n" 594 "in the channel when it has emptied of users.\n" 595 " \n" 596 "If your IRCd does not have a permanent (persistent) channel\n" 597 "mode you must have a service bot in your channel to\n" 598 "set persist on, and it can not be unassigned while persist\n" 599 "is on.\n" 600 " \n" 601 "If this network does not have %s enabled and does\n" 602 "not have a permanent channel mode, %s will\n" 603 "join your channel when you set persist on (and leave when\n" 604 "it has been set off).\n" 605 " \n" 606 "If your IRCd has a permanent (persistent) channel mode\n" 607 "and it is set or unset (for any reason, including MODE LOCK),\n" 608 "persist is automatically set and unset for the channel as well.\n" 609 "Additionally, services will set or unset this mode when you\n" 610 "set persist on or off."), BotServ ? BotServ->nick.c_str() : "BotServ", 611 ChanServ ? ChanServ->nick.c_str() : "ChanServ"); 612 return true; 613 } 614 }; 615 616 class CommandCSSetRestricted : public Command 617 { 618 public: 619 CommandCSSetRestricted(Module *creator, const Anope::string &cname = "chanserv/set/restricted") : Command(creator, cname, 2, 2) 620 { 621 this->SetDesc(_("Restrict access to the channel")); 622 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 623 } 624 625 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 626 { 627 if (Anope::ReadOnly) 628 { 629 source.Reply(READ_ONLY_MODE); 630 return; 631 } 632 633 ChannelInfo *ci = ChannelInfo::Find(params[0]); 634 if (ci == NULL) 635 { 636 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 637 return; 638 } 639 640 EventReturn MOD_RESULT; 641 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 642 if (MOD_RESULT == EVENT_STOP) 643 return; 644 645 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 646 { 647 source.Reply(ACCESS_DENIED); 648 return; 649 } 650 651 if (params[1].equals_ci("ON")) 652 { 653 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable restricted"; 654 ci->Extend<bool>("RESTRICTED"); 655 source.Reply(_("Restricted access option for %s is now \002on\002."), ci->name.c_str()); 656 } 657 else if (params[1].equals_ci("OFF")) 658 { 659 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable restricted"; 660 ci->Shrink<bool>("RESTRICTED"); 661 source.Reply(_("Restricted access option for %s is now \002off\002."), ci->name.c_str()); 662 } 663 else 664 this->OnSyntaxError(source, "RESTRICTED"); 665 } 666 667 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 668 { 669 this->SendSyntax(source); 670 source.Reply(" "); 671 source.Reply(_("Enables or disables the \002restricted access\002 option for a\n" 672 "channel. When \002restricted access\002 is set, users not on the access list will\n" 673 "instead be kicked and banned from the channel.")); 674 return true; 675 } 676 }; 677 678 class CommandCSSetSecure : public Command 679 { 680 public: 681 CommandCSSetSecure(Module *creator, const Anope::string &cname = "chanserv/set/secure") : Command(creator, cname, 2, 2) 682 { 683 this->SetDesc(_("Activate security features")); 684 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 685 } 686 687 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 688 { 689 if (Anope::ReadOnly) 690 { 691 source.Reply(READ_ONLY_MODE); 692 return; 693 } 694 695 ChannelInfo *ci = ChannelInfo::Find(params[0]); 696 if (ci == NULL) 697 { 698 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 699 return; 700 } 701 702 EventReturn MOD_RESULT; 703 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 704 if (MOD_RESULT == EVENT_STOP) 705 return; 706 707 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 708 { 709 source.Reply(ACCESS_DENIED); 710 return; 711 } 712 713 if (params[1].equals_ci("ON")) 714 { 715 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure"; 716 ci->Extend<bool>("CS_SECURE"); 717 source.Reply(_("Secure option for %s is now \002on\002."), ci->name.c_str()); 718 } 719 else if (params[1].equals_ci("OFF")) 720 { 721 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure"; 722 ci->Shrink<bool>("CS_SECURE"); 723 source.Reply(_("Secure option for %s is now \002off\002."), ci->name.c_str()); 724 } 725 else 726 this->OnSyntaxError(source, "SECURE"); 727 } 728 729 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 730 { 731 this->SendSyntax(source); 732 source.Reply(" "); 733 source.Reply(_("Enables or disables security features for a\n" 734 "channel. When \002SECURE\002 is set, only users who have\n" 735 "identified to services, and are not only recognized, will be\n" 736 "given access to channels from account-based access entries.")); 737 return true; 738 } 739 }; 740 741 class CommandCSSetSecureFounder : public Command 742 { 743 public: 744 CommandCSSetSecureFounder(Module *creator, const Anope::string &cname = "chanserv/set/securefounder") : Command(creator, cname, 2, 2) 745 { 746 this->SetDesc(_("Stricter control of channel founder status")); 747 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 748 } 749 750 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 751 { 752 if (Anope::ReadOnly) 753 { 754 source.Reply(READ_ONLY_MODE); 755 return; 756 } 757 758 ChannelInfo *ci = ChannelInfo::Find(params[0]); 759 if (ci == NULL) 760 { 761 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 762 return; 763 } 764 765 EventReturn MOD_RESULT; 766 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 767 if (MOD_RESULT == EVENT_STOP) 768 return; 769 770 if (MOD_RESULT != EVENT_ALLOW && (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")) && source.permission.empty() && !source.HasPriv("chanserv/administration")) 771 { 772 source.Reply(ACCESS_DENIED); 773 return; 774 } 775 776 if (params[1].equals_ci("ON")) 777 { 778 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure founder"; 779 ci->Extend<bool>("SECUREFOUNDER"); 780 source.Reply(_("Secure founder option for %s is now \002on\002."), ci->name.c_str()); 781 } 782 else if (params[1].equals_ci("OFF")) 783 { 784 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure founder"; 785 ci->Shrink<bool>("SECUREFOUNDER"); 786 source.Reply(_("Secure founder option for %s is now \002off\002."), ci->name.c_str()); 787 } 788 else 789 this->OnSyntaxError(source, "SECUREFOUNDER"); 790 } 791 792 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 793 { 794 this->SendSyntax(source); 795 source.Reply(" "); 796 source.Reply(_("Enables or disables the \002secure founder\002 option for a channel.\n" 797 "When \002secure founder\002 is set, only the real founder will be\n" 798 "able to drop the channel, change its founder and its successor,\n" 799 "and not those who have founder level access through\n" 800 "the access/qop command.")); 801 return true; 802 } 803 }; 804 805 class CommandCSSetSecureOps : public Command 806 { 807 public: 808 CommandCSSetSecureOps(Module *creator, const Anope::string &cname = "chanserv/set/secureops") : Command(creator, cname, 2, 2) 809 { 810 this->SetDesc(_("Stricter control of chanop status")); 811 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 812 } 813 814 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 815 { 816 if (Anope::ReadOnly) 817 { 818 source.Reply(READ_ONLY_MODE); 819 return; 820 } 821 822 ChannelInfo *ci = ChannelInfo::Find(params[0]); 823 if (ci == NULL) 824 { 825 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 826 return; 827 } 828 829 EventReturn MOD_RESULT; 830 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 831 if (MOD_RESULT == EVENT_STOP) 832 return; 833 834 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 835 { 836 source.Reply(ACCESS_DENIED); 837 return; 838 } 839 840 if (params[1].equals_ci("ON")) 841 { 842 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure ops"; 843 ci->Extend<bool>("SECUREOPS"); 844 source.Reply(_("Secure ops option for %s is now \002on\002."), ci->name.c_str()); 845 } 846 else if (params[1].equals_ci("OFF")) 847 { 848 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure ops"; 849 ci->Shrink<bool>("SECUREOPS"); 850 source.Reply(_("Secure ops option for %s is now \002off\002."), ci->name.c_str()); 851 } 852 else 853 this->OnSyntaxError(source, "SECUREOPS"); 854 } 855 856 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 857 { 858 this->SendSyntax(source); 859 source.Reply(" "); 860 source.Reply(_("Enables or disables the \002secure ops\002 option for a channel.\n" 861 "When \002secure ops\002 is set, users who are not on the access list\n" 862 "will not be allowed channel operator status.")); 863 return true; 864 } 865 }; 866 867 class CommandCSSetSignKick : public Command 868 { 869 public: 870 CommandCSSetSignKick(Module *creator, const Anope::string &cname = "chanserv/set/signkick") : Command(creator, cname, 2, 2) 871 { 872 this->SetDesc(_("Sign kicks that are done with the KICK command")); 873 this->SetSyntax(_("\037channel\037 {ON | LEVEL | OFF}")); 874 } 875 876 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 877 { 878 if (Anope::ReadOnly) 879 { 880 source.Reply(READ_ONLY_MODE); 881 return; 882 } 883 884 ChannelInfo *ci = ChannelInfo::Find(params[0]); 885 if (ci == NULL) 886 { 887 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 888 return; 889 } 890 891 EventReturn MOD_RESULT; 892 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1])); 893 if (MOD_RESULT == EVENT_STOP) 894 return; 895 896 if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration")) 897 { 898 source.Reply(ACCESS_DENIED); 899 return; 900 } 901 902 if (params[1].equals_ci("ON")) 903 { 904 ci->Extend<bool>("SIGNKICK"); 905 ci->Shrink<bool>("SIGNKICK_LEVEL"); 906 source.Reply(_("Signed kick option for %s is now \002on\002."), ci->name.c_str()); 907 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable sign kick"; 908 } 909 else if (params[1].equals_ci("LEVEL")) 910 { 911 ci->Extend<bool>("SIGNKICK_LEVEL"); 912 ci->Shrink<bool>("SIGNKICK"); 913 source.Reply(_("Signed kick option for %s is now \002on\002, but depends of the\n" 914 "level of the user that is using the command."), ci->name.c_str()); 915 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable sign kick level"; 916 } 917 else if (params[1].equals_ci("OFF")) 918 { 919 ci->Shrink<bool>("SIGNKICK"); 920 ci->Shrink<bool>("SIGNKICK_LEVEL"); 921 source.Reply(_("Signed kick option for %s is now \002off\002."), ci->name.c_str()); 922 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable sign kick"; 923 } 924 else 925 this->OnSyntaxError(source, "SIGNKICK"); 926 } 927 928 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 929 { 930 this->SendSyntax(source); 931 source.Reply(" "); 932 source.Reply(_("Enables or disables signed kicks for a\n" 933 "channel. When \002SIGNKICK\002 is set, kicks issued with\n" 934 "the \002KICK\002 command will have the nick that used the\n" 935 "command in their reason.\n" 936 " \n" 937 "If you use \002LEVEL\002, those who have a level that is superior\n" 938 "or equal to the SIGNKICK level on the channel won't have their\n" 939 "kicks signed.")); 940 return true; 941 } 942 }; 943 944 class CommandCSSetSuccessor : public Command 945 { 946 public: 947 CommandCSSetSuccessor(Module *creator, const Anope::string &cname = "chanserv/set/successor") : Command(creator, cname, 1, 2) 948 { 949 this->SetDesc(_("Set the successor for a channel")); 950 this->SetSyntax(_("\037channel\037 [\037nick\037]")); 951 } 952 953 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 954 { 955 if (Anope::ReadOnly) 956 { 957 source.Reply(READ_ONLY_MODE); 958 return; 959 } 960 961 ChannelInfo *ci = ChannelInfo::Find(params[0]); 962 const Anope::string ¶m = params.size() > 1 ? params[1] : ""; 963 if (ci == NULL) 964 { 965 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 966 return; 967 } 968 969 EventReturn MOD_RESULT; 970 FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, param)); 971 if (MOD_RESULT == EVENT_STOP) 972 return; 973 974 if (MOD_RESULT != EVENT_ALLOW && (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")) && source.permission.empty() && !source.HasPriv("chanserv/administration")) 975 { 976 source.Reply(ACCESS_DENIED); 977 return; 978 } 979 980 NickCore *nc; 981 982 if (!param.empty()) 983 { 984 const NickAlias *na = NickAlias::Find(param); 985 986 if (!na) 987 { 988 source.Reply(NICK_X_NOT_REGISTERED, param.c_str()); 989 return; 990 } 991 if (na->nc == ci->GetFounder()) 992 { 993 source.Reply(_("%s cannot be the successor on channel %s as they are the founder."), na->nick.c_str(), ci->name.c_str()); 994 return; 995 } 996 nc = na->nc; 997 } 998 else 999 nc = NULL; 1000 1001 Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to change the successor from " << (ci->GetSuccessor() ? ci->GetSuccessor()->display : "(none)") << " to " << (nc ? nc->display : "(none)"); 1002 1003 ci->SetSuccessor(nc); 1004 1005 if (nc) 1006 source.Reply(_("Successor for \002%s\002 changed to \002%s\002."), ci->name.c_str(), nc->display.c_str()); 1007 else 1008 source.Reply(_("Successor for \002%s\002 unset."), ci->name.c_str()); 1009 1010 return; 1011 } 1012 1013 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 1014 { 1015 this->SendSyntax(source); 1016 source.Reply(" "); 1017 source.Reply(_("Changes the successor of a channel. If the founder's\n" 1018 "nickname expires or is dropped while the channel is still\n" 1019 "registered, the successor will become the new founder of the\n" 1020 "channel. The successor's nickname must be a registered one.\n" 1021 "If there's no successor set, then the first nickname on the\n" 1022 "access list (with the highest access, if applicable) will\n" 1023 "become the new founder, but if the access list is empty, the\n" 1024 "channel will be dropped.")); 1025 unsigned max_reg = Config->GetModule("chanserv")->Get<unsigned>("maxregistered"); 1026 if (max_reg) 1027 { 1028 source.Reply(" "); 1029 source.Reply(_("Note, however, if the successor already has too many\n" 1030 "channels registered (%d), they will not be able to\n" 1031 "become the new founder and it will be as if the\n" 1032 "channel had no successor set."), max_reg); 1033 } 1034 return true; 1035 } 1036 }; 1037 1038 class CommandCSSetNoexpire : public Command 1039 { 1040 public: 1041 CommandCSSetNoexpire(Module *creator) : Command(creator, "chanserv/saset/noexpire", 2, 2) 1042 { 1043 this->SetDesc(_("Prevent the channel from expiring")); 1044 this->SetSyntax(_("\037channel\037 {ON | OFF}")); 1045 } 1046 1047 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 1048 { 1049 if (Anope::ReadOnly) 1050 { 1051 source.Reply(READ_ONLY_MODE); 1052 return; 1053 } 1054 1055 ChannelInfo *ci = ChannelInfo::Find(params[0]); 1056 if (ci == NULL) 1057 { 1058 source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); 1059 return; 1060 } 1061 1062 if (source.permission.empty() && !source.AccessFor(ci).HasPriv("SET")) 1063 { 1064 source.Reply(ACCESS_DENIED); 1065 return; 1066 } 1067 1068 if (params[1].equals_ci("ON")) 1069 { 1070 Log(LOG_ADMIN, source, this, ci) << "to enable noexpire"; 1071 ci->Extend<bool>("CS_NO_EXPIRE"); 1072 source.Reply(_("Channel %s \002will not\002 expire."), ci->name.c_str()); 1073 } 1074 else if (params[1].equals_ci("OFF")) 1075 { 1076 Log(LOG_ADMIN, source, this, ci) << "to disable noexpire"; 1077 ci->Shrink<bool>("CS_NO_EXPIRE"); 1078 source.Reply(_("Channel %s \002will\002 expire."), ci->name.c_str()); 1079 } 1080 else 1081 this->OnSyntaxError(source, "NOEXPIRE"); 1082 1083 return; 1084 } 1085 1086 bool OnHelp(CommandSource &source, const Anope::string &) anope_override 1087 { 1088 this->SendSyntax(source); 1089 source.Reply(" "); 1090 source.Reply(_("Sets whether the given channel will expire. Setting this\n" 1091 "to ON prevents the channel from expiring.")); 1092 return true; 1093 } 1094 }; 1095 1096 class CSSet : public Module 1097 { 1098 SerializableExtensibleItem<bool> noautoop, peace, securefounder, 1099 restricted, secure, secureops, signkick, signkick_level, noexpire, 1100 persist; 1101 1102 struct KeepModes : SerializableExtensibleItem<bool> 1103 { 1104 KeepModes(Module *m, const Anope::string &n) : SerializableExtensibleItem<bool>(m, n) { } 1105 1106 void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override 1107 { 1108 SerializableExtensibleItem<bool>::ExtensibleSerialize(e, s, data); 1109 1110 if (s->GetSerializableType()->GetName() != "ChannelInfo") 1111 return; 1112 1113 const ChannelInfo *ci = anope_dynamic_static_cast<const ChannelInfo *>(s); 1114 Anope::string modes; 1115 for (Channel::ModeList::const_iterator it = ci->last_modes.begin(); it != ci->last_modes.end(); ++it) 1116 { 1117 if (!modes.empty()) 1118 modes += " "; 1119 modes += it->first; 1120 if (!it->second.empty()) 1121 modes += "," + it->second; 1122 } 1123 data["last_modes"] << modes; 1124 } 1125 1126 void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override 1127 { 1128 SerializableExtensibleItem<bool>::ExtensibleUnserialize(e, s, data); 1129 1130 if (s->GetSerializableType()->GetName() != "ChannelInfo") 1131 return; 1132 1133 ChannelInfo *ci = anope_dynamic_static_cast<ChannelInfo *>(s); 1134 Anope::string modes; 1135 data["last_modes"] >> modes; 1136 ci->last_modes.clear(); 1137 for (spacesepstream sep(modes); sep.GetToken(modes);) 1138 { 1139 size_t c = modes.find(','); 1140 if (c == Anope::string::npos) 1141 ci->last_modes.insert(std::make_pair(modes, "")); 1142 else 1143 ci->last_modes.insert(std::make_pair(modes.substr(0, c), modes.substr(c + 1))); 1144 } 1145 } 1146 } keep_modes; 1147 1148 CommandCSSet commandcsset; 1149 CommandCSSetAutoOp commandcssetautoop; 1150 CommandCSSetBanType commandcssetbantype; 1151 CommandCSSetDescription commandcssetdescription; 1152 CommandCSSetFounder commandcssetfounder; 1153 CommandCSSetKeepModes commandcssetkeepmodes; 1154 CommandCSSetPeace commandcssetpeace; 1155 CommandCSSetPersist commandcssetpersist; 1156 CommandCSSetRestricted commandcssetrestricted; 1157 CommandCSSetSecure commandcssetsecure; 1158 CommandCSSetSecureFounder commandcssetsecurefounder; 1159 CommandCSSetSecureOps commandcssetsecureops; 1160 CommandCSSetSignKick commandcssetsignkick; 1161 CommandCSSetSuccessor commandcssetsuccessor; 1162 CommandCSSetNoexpire commandcssetnoexpire; 1163 1164 ExtensibleRef<bool> inhabit; 1165 1166 bool persist_lower_ts; 1167 1168 public: 1169 CSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), 1170 noautoop(this, "NOAUTOOP"), peace(this, "PEACE"), 1171 securefounder(this, "SECUREFOUNDER"), restricted(this, "RESTRICTED"), 1172 secure(this, "CS_SECURE"), secureops(this, "SECUREOPS"), signkick(this, "SIGNKICK"), 1173 signkick_level(this, "SIGNKICK_LEVEL"), noexpire(this, "CS_NO_EXPIRE"), 1174 persist(this, "PERSIST"), 1175 keep_modes(this, "CS_KEEP_MODES"), 1176 1177 commandcsset(this), commandcssetautoop(this), commandcssetbantype(this), 1178 commandcssetdescription(this), commandcssetfounder(this), commandcssetkeepmodes(this), 1179 commandcssetpeace(this), commandcssetpersist(this), commandcssetrestricted(this), 1180 commandcssetsecure(this), commandcssetsecurefounder(this), commandcssetsecureops(this), commandcssetsignkick(this), 1181 commandcssetsuccessor(this), commandcssetnoexpire(this), 1182 1183 inhabit("inhabit") 1184 { 1185 } 1186 1187 void OnReload(Configuration::Conf *conf) anope_override 1188 { 1189 persist_lower_ts = conf->GetModule(this)->Get<bool>("persist_lower_ts"); 1190 } 1191 1192 void OnCreateChan(ChannelInfo *ci) anope_override 1193 { 1194 ci->bantype = Config->GetModule(this)->Get<int>("defbantype", "2"); 1195 } 1196 1197 void OnChannelSync(Channel *c) anope_override 1198 { 1199 if (c->ci && keep_modes.HasExt(c->ci)) 1200 { 1201 Channel::ModeList ml = c->ci->last_modes; 1202 for (Channel::ModeList::iterator it = ml.begin(); it != ml.end(); ++it) 1203 c->SetMode(c->ci->WhoSends(), it->first, it->second); 1204 } 1205 } 1206 1207 EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override 1208 { 1209 if (!c->ci || !restricted.HasExt(c->ci) || c->MatchesList(u, "EXCEPT")) 1210 return EVENT_CONTINUE; 1211 1212 if (c->ci->AccessFor(u).empty() && (!c->ci->GetFounder() || u->Account() != c->ci->GetFounder())) 1213 return EVENT_STOP; 1214 1215 return EVENT_CONTINUE; 1216 } 1217 1218 void OnDelChan(ChannelInfo *ci) anope_override 1219 { 1220 if (ci->c && persist.HasExt(ci)) 1221 ci->c->RemoveMode(ci->WhoSends(), "PERM", "", false); 1222 persist.Unset(ci); 1223 } 1224 1225 EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) anope_override 1226 { 1227 if (c->ci) 1228 { 1229 /* Channel mode +P or so was set, mark this channel as persistent */ 1230 if (mode->name == "PERM") 1231 persist.Set(c->ci, true); 1232 1233 if (mode->type != MODE_STATUS && !c->syncing && Me->IsSynced() && (!inhabit || !inhabit->HasExt(c))) 1234 c->ci->last_modes = c->GetModes(); 1235 } 1236 1237 return EVENT_CONTINUE; 1238 } 1239 1240 EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) anope_override 1241 { 1242 if (mode->name == "PERM") 1243 { 1244 if (c->ci) 1245 persist.Unset(c->ci); 1246 } 1247 1248 if (c->ci && mode->type != MODE_STATUS && !c->syncing && Me->IsSynced() && (!inhabit || !inhabit->HasExt(c))) 1249 c->ci->last_modes = c->GetModes(); 1250 1251 return EVENT_CONTINUE; 1252 } 1253 1254 void OnJoinChannel(User *u, Channel *c) anope_override 1255 { 1256 if (u->server != Me && persist_lower_ts && c->ci && persist.HasExt(c->ci) && c->creation_time > c->ci->time_registered) 1257 { 1258 Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->creation_time << " to " << c->ci->time_registered; 1259 c->creation_time = c->ci->time_registered; 1260 IRCD->SendChannel(c); 1261 c->Reset(); 1262 } 1263 } 1264 1265 void OnSetCorrectModes(User *user, Channel *chan, AccessGroup &access, bool &give_modes, bool &take_modes) anope_override 1266 { 1267 if (chan->ci) 1268 { 1269 if (noautoop.HasExt(chan->ci)) 1270 give_modes = false; 1271 if (secureops.HasExt(chan->ci) && !user->HasPriv("chanserv/administration")) 1272 // This overrides what chanserv does because it is loaded after chanserv 1273 take_modes = true; 1274 } 1275 } 1276 1277 void OnPreChanExpire(ChannelInfo *ci, bool &expire) anope_override 1278 { 1279 if (noexpire.HasExt(ci)) 1280 expire = false; 1281 } 1282 1283 void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override 1284 { 1285 if (!show_all) 1286 return; 1287 1288 if (peace.HasExt(ci)) 1289 info.AddOption(_("Peace")); 1290 if (restricted.HasExt(ci)) 1291 info.AddOption(_("Restricted access")); 1292 if (secure.HasExt(ci)) 1293 info.AddOption(_("Security")); 1294 if (securefounder.HasExt(ci)) 1295 info.AddOption(_("Secure founder")); 1296 if (secureops.HasExt(ci)) 1297 info.AddOption(_("Secure ops")); 1298 if (signkick.HasExt(ci) || signkick_level.HasExt(ci)) 1299 info.AddOption(_("Signed kicks")); 1300 if (persist.HasExt(ci)) 1301 info.AddOption(_("Persistent")); 1302 if (noexpire.HasExt(ci)) 1303 info.AddOption(_("No expire")); 1304 if (keep_modes.HasExt(ci)) 1305 info.AddOption(_("Keep modes")); 1306 if (noautoop.HasExt(ci)) 1307 info.AddOption(_("No auto-op")); 1308 } 1309 }; 1310 1311 MODULE_INIT(CSSet)