os_defcon.cpp

Go to the documentation of this file.
00001 /* OperServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 #include "global.h"
00016 #include "os_session.h"
00017 
00018 enum DefconLevel
00019 {
00020         DEFCON_NO_NEW_CHANNELS,
00021         DEFCON_NO_NEW_NICKS,
00022         DEFCON_NO_MLOCK_CHANGE,
00023         DEFCON_FORCE_CHAN_MODES,
00024         DEFCON_REDUCE_SESSION,
00025         DEFCON_NO_NEW_CLIENTS,
00026         DEFCON_OPER_ONLY,
00027         DEFCON_SILENT_OPER_ONLY,
00028         DEFCON_AKILL_NEW_CLIENTS,
00029         DEFCON_NO_NEW_MEMOS
00030 };
00031 
00032 bool DefConModesSet = false;
00033 
00034 struct DefconConfig
00035 {
00036         std::vector<std::bitset<32> > DefCon;
00037         std::set<Anope::string> DefConModesOn, DefConModesOff;
00038         std::map<Anope::string, Anope::string> DefConModesOnParams;
00039 
00040         int defaultlevel, sessionlimit;
00041         Anope::string chanmodes, message, offmessage, akillreason;
00042         std::vector<Anope::string> defcons;
00043         time_t akillexpire, timeout;
00044         bool globalondefcon;
00045 
00046         DefconConfig()
00047         {
00048                 this->DefCon.resize(6);
00049                 this->defcons.resize(5);
00050         }
00051 
00052         bool Check(DefconLevel level)
00053         {
00054                 return this->Check(this->defaultlevel, level);
00055         }
00056 
00057         bool Check(int dlevel, DefconLevel level)
00058         {
00059                 return this->DefCon[dlevel].test(level);
00060         }
00061 
00062         void Add(int dlevel, DefconLevel level)
00063         {
00064                 this->DefCon[dlevel][level] = true;
00065         }
00066 
00067         void Del(int dlevel, DefconLevel level)
00068         {
00069                 this->DefCon[dlevel][level] = false;
00070         }
00071 
00072         bool SetDefConParam(const Anope::string &name, const Anope::string &buf)
00073         {
00074                return DefConModesOnParams.insert(std::make_pair(name, buf)).second;
00075         }
00076 
00077         void UnsetDefConParam(const Anope::string &name)
00078         {
00079                 DefConModesOnParams.erase(name);
00080         }
00081         
00082         bool GetDefConParam(const Anope::string &name, Anope::string &buf)
00083         {
00084                std::map<Anope::string, Anope::string>::iterator it = DefConModesOnParams.find(name);
00085         
00086                buf.clear();
00087         
00088                if (it != DefConModesOnParams.end())
00089                {
00090                        buf = it->second;
00091                        return true;
00092                }
00093         
00094                return false;
00095         }
00096 };
00097 
00098 static DefconConfig DConfig;
00099 
00100 static void runDefCon();
00101 static Anope::string defconReverseModes(const Anope::string &modes);
00102 
00103 static ServiceReference<GlobalService> GlobalService("GlobalService", "Global");
00104 
00105 static Timer *timeout;
00106 
00107 class DefConTimeout : public CallBack
00108 {
00109         int level;
00110 
00111  public:
00112         DefConTimeout(Module *mod, int newlevel) : CallBack(mod, DConfig.timeout), level(newlevel)
00113         {
00114                 timeout = this;
00115         }
00116 
00117         ~DefConTimeout()
00118         {
00119                 timeout = NULL;
00120         }
00121 
00122         void Tick(time_t) anope_override
00123         {
00124                 if (DConfig.defaultlevel != level)
00125                 {
00126                         DConfig.defaultlevel = level;
00127                         FOREACH_MOD(I_OnDefconLevel, OnDefconLevel(level));
00128                         Log(OperServ, "operserv/defcon") << "Defcon level timeout, returning to level " << level;
00129 
00130                         if (DConfig.globalondefcon)
00131                         {
00132                                 if (!DConfig.offmessage.empty())
00133                                         GlobalService->SendGlobal(Global, "", DConfig.offmessage);
00134                                 else
00135                                         GlobalService->SendGlobal(Global, "", Anope::printf(Language::Translate(_("The Defcon Level is now at Level: \002%d\002")), DConfig.defaultlevel));
00136 
00137                                 if (!DConfig.message.empty())
00138                                         GlobalService->SendGlobal(Global, "", DConfig.message);
00139                         }
00140 
00141                         runDefCon();
00142                 }
00143         }
00144 };
00145 
00146 class CommandOSDefcon : public Command
00147 {
00148         void SendLevels(CommandSource &source)
00149         {
00150                 if (DConfig.Check(DEFCON_NO_NEW_CHANNELS))
00151                         source.Reply(_("* No new channel registrations"));
00152                 if (DConfig.Check(DEFCON_NO_NEW_NICKS))
00153                         source.Reply(_("* No new nick registrations"));
00154                 if (DConfig.Check(DEFCON_NO_MLOCK_CHANGE))
00155                         source.Reply(_("* No mode lock changes"));
00156                 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && !DConfig.chanmodes.empty())
00157                         source.Reply(_("* Force Chan Modes (%s) to be set on all channels"), DConfig.chanmodes.c_str());
00158                 if (DConfig.Check(DEFCON_REDUCE_SESSION))
00159                         source.Reply(_("* Use the reduced session limit of %d"), DConfig.sessionlimit);
00160                 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS))
00161                         source.Reply(_("* Kill any NEW clients connecting"));
00162                 if (DConfig.Check(DEFCON_OPER_ONLY))
00163                         source.Reply(_("* Ignore any non-opers with message"));
00164                 if (DConfig.Check(DEFCON_SILENT_OPER_ONLY))
00165                         source.Reply(_("* Silently ignore non-opers"));
00166                 if (DConfig.Check(DEFCON_AKILL_NEW_CLIENTS))
00167                         source.Reply(_("* AKILL any new clients connecting"));
00168                 if (DConfig.Check(DEFCON_NO_NEW_MEMOS))
00169                         source.Reply(_("* No new memos sent"));
00170         }
00171 
00172  public:
00173         CommandOSDefcon(Module *creator) : Command(creator, "operserv/defcon", 1, 1)
00174         {
00175                 this->SetDesc(_("Manipulate the DefCon system"));
00176                 this->SetSyntax(_("[\0021\002|\0022\002|\0023\002|\0024\002|\0025\002]"));
00177         }
00178 
00179         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00180         {
00181                 const Anope::string &lvl = params[0];
00182 
00183                 if (lvl.empty())
00184                 {
00185                         source.Reply(_("Services are now at DEFCON \002%d\002."), DConfig.defaultlevel);
00186                         this->SendLevels(source);
00187                         return;
00188                 }
00189 
00190                 int newLevel = 0;
00191                 try
00192                 {
00193                         newLevel = convertTo<int>(lvl);
00194                 }
00195                 catch (const ConvertException &) { }
00196 
00197                 if (newLevel < 1 || newLevel > 5)
00198                 {
00199                         this->OnSyntaxError(source, "");
00200                         return;
00201                 }
00202 
00203                 DConfig.defaultlevel = newLevel;
00204 
00205                 FOREACH_MOD(I_OnDefconLevel, OnDefconLevel(newLevel));
00206 
00207                 delete timeout;
00208 
00209                 if (DConfig.timeout)
00210                         timeout = new DefConTimeout(this->module, 5);
00211 
00212                 source.Reply(_("Services are now at DEFCON \002%d\002."), DConfig.defaultlevel);
00213                 this->SendLevels(source);
00214                 Log(LOG_ADMIN, source, this) << "to change defcon level to " << newLevel;
00215 
00216                 /* Global notice the user what is happening. Also any Message that
00217                    the Admin would like to add. Set in config file. */
00218                 if (DConfig.globalondefcon)
00219                 {
00220                         if (DConfig.defaultlevel == 5 && !DConfig.offmessage.empty())
00221                                 GlobalService->SendGlobal(Global, "", DConfig.offmessage);
00222                         else if (DConfig.defaultlevel != 5)
00223                         {
00224                                 GlobalService->SendGlobal(Global, "", Anope::printf(_("The Defcon level is now at: \002%d\002"), DConfig.defaultlevel));
00225                                 if (!DConfig.message.empty())
00226                                         GlobalService->SendGlobal(Global, "", DConfig.message);
00227                         }
00228                 }
00229 
00230                 /* Run any defcon functions, e.g. FORCE CHAN MODE */
00231                 runDefCon();
00232                 return;
00233         }
00234 
00235         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00236         {
00237                 this->SendSyntax(source);
00238                 source.Reply(" ");
00239                 source.Reply(_("The defcon system can be used to implement a pre-defined\n"
00240                                 "set of restrictions to services useful during an attempted\n"
00241                                 "attack on the network."));
00242                 return true;
00243         }
00244 };
00245 
00246 class OSDefcon : public Module
00247 {
00248         ServiceReference<SessionService> session_service;
00249         ServiceReference<XLineManager> akills;
00250         CommandOSDefcon commandosdefcon;
00251 
00252         void ParseModeString()
00253         {
00254                 int add = -1; /* 1 if adding, 0 if deleting, -1 if neither */
00255                 unsigned char mode;
00256                 ChannelMode *cm;
00257                 ChannelModeParam *cmp;
00258                 Anope::string modes, param;
00259 
00260                 spacesepstream ss(DConfig.chanmodes);
00261 
00262                 DConfig.DefConModesOn.clear();
00263                 DConfig.DefConModesOff.clear();
00264                 ss.GetToken(modes);
00265 
00266                 /* Loop while there are modes to set */
00267                 for (unsigned i = 0, end = modes.length(); i < end; ++i)
00268                 {
00269                         mode = modes[i];
00270 
00271                         switch (mode)
00272                         {
00273                                 case '+':
00274                                         add = 1;
00275                                         continue;
00276                                 case '-':
00277                                         add = 0;
00278                                         continue;
00279                                 default:
00280                                         if (add < 0)
00281                                                 continue;
00282                         }
00283 
00284                         if ((cm = ModeManager::FindChannelModeByChar(mode)))
00285                         {
00286                                 if (cm->type == MODE_STATUS || cm->type == MODE_LIST || !cm->CanSet(NULL))
00287                                 {
00288                                         Log(this) << "DefConChanModes mode character '" << mode << "' cannot be locked";
00289                                         continue;
00290                                 }
00291                                 else if (add)
00292                                 {
00293                                         DConfig.DefConModesOn.insert(cm->name);
00294                                         DConfig.DefConModesOff.erase(cm->name);
00295 
00296                                         if (cm->type == MODE_PARAM)
00297                                         {
00298                                                 cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
00299 
00300                                                 if (!ss.GetToken(param))
00301                                                 {
00302                                                         Log(this) << "DefConChanModes mode character '" << mode << "' has no parameter while one is expected";
00303                                                         continue;
00304                                                 }
00305 
00306                                                 if (!cmp->IsValid(param))
00307                                                         continue;
00308 
00309                                                 DConfig.SetDefConParam(cmp->name, param);
00310                                         }
00311                                 }
00312                                 else if (DConfig.DefConModesOn.count(cm->name))
00313                                 {
00314                                         DConfig.DefConModesOn.erase(cm->name);
00315 
00316                                         if (cm->type == MODE_PARAM)
00317                                                 DConfig.UnsetDefConParam(cm->name);
00318                                 }
00319                         }
00320                 }
00321 
00322                 /* We can't mlock +L if +l is not mlocked as well. */
00323                 if ((cm = ModeManager::FindChannelModeByName("REDIRECT")) && DConfig.DefConModesOn.count(cm->name) && !DConfig.DefConModesOn.count("LIMIT"))
00324                 {
00325                         DConfig.DefConModesOn.erase("REDIRECT");
00326         
00327                         Log(this) << "DefConChanModes must lock mode +l as well to lock mode +L";
00328                 }
00329         }
00330 
00331  public:
00332         OSDefcon(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), session_service("SessionService", "session"), akills("XLineManager", "xlinemanager/sgline"), commandosdefcon(this)
00333         {
00334                 this->SetAuthor("Anope");
00335 
00336                 Implementation i[] = { I_OnReload, I_OnChannelModeSet, I_OnChannelModeUnset, I_OnPreCommand, I_OnUserConnect, I_OnChannelModeAdd, I_OnChannelCreate };
00337                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00338 
00339 
00340                 try
00341                 {
00342                         this->OnReload();
00343                 }
00344                 catch (const ConfigException &ex)
00345                 {
00346                         throw ModuleException(ex.GetReason());
00347                 }
00348         }
00349 
00350         void OnReload() anope_override
00351         {
00352                 ConfigReader config;
00353                 DefconConfig dconfig;
00354 
00355                 dconfig.defaultlevel = config.ReadInteger("defcon", "defaultlevel", 0, 0);
00356                 dconfig.defcons[4] = config.ReadValue("defcon", "level4", 0);
00357                 dconfig.defcons[3] = config.ReadValue("defcon", "level3", 0);
00358                 dconfig.defcons[2] = config.ReadValue("defcon", "level2", 0);
00359                 dconfig.defcons[1] = config.ReadValue("defcon", "level1", 0);
00360                 dconfig.sessionlimit = config.ReadInteger("defcon", "sessionlimit", 0, 0);
00361                 dconfig.akillreason = config.ReadValue("defcon", "akillreason", 0);
00362                 dconfig.akillexpire = Anope::DoTime(config.ReadValue("defcon", "akillexpire", 0));
00363                 dconfig.chanmodes = config.ReadValue("defcon", "chanmodes", 0);
00364                 dconfig.timeout = Anope::DoTime(config.ReadValue("defcon", "timeout", 0));
00365                 dconfig.globalondefcon = config.ReadFlag("defcon", "globalondefcon", 0);
00366                 dconfig.message = config.ReadValue("defcon", "message", 0);
00367                 dconfig.offmessage = config.ReadValue("defcon", "offmessage", 0);
00368 
00369                 if (dconfig.defaultlevel < 1 || dconfig.defaultlevel > 5)
00370                         throw ConfigException("The value for <defcon:defaultlevel> must be between 1 and 5");
00371                 else if (dconfig.akillexpire <= 0)
00372                         throw ConfigException("The value for <defcon:akillexpire> must be greater than zero!");
00373 
00374                 for (unsigned level = 1; level < 5; ++level)
00375                 {
00376                         spacesepstream operations(dconfig.defcons[level]);
00377                         Anope::string operation;
00378                         while (operations.GetToken(operation))
00379                         {
00380                                 if (operation.equals_ci("nonewchannels"))
00381                                         dconfig.Add(level, DEFCON_NO_NEW_CHANNELS);
00382                                 else if (operation.equals_ci("nonewnicks"))
00383                                         dconfig.Add(level, DEFCON_NO_NEW_NICKS);
00384                                 else if (operation.equals_ci("nomlockchanges"))
00385                                         dconfig.Add(level, DEFCON_NO_MLOCK_CHANGE);
00386                                 else if (operation.equals_ci("forcechanmodes"))
00387                                         dconfig.Add(level, DEFCON_FORCE_CHAN_MODES);
00388                                 else if (operation.equals_ci("reducedsessions"))
00389                                         dconfig.Add(level, DEFCON_REDUCE_SESSION);
00390                                 else if (operation.equals_ci("nonewclients"))
00391                                         dconfig.Add(level, DEFCON_NO_NEW_CLIENTS);
00392                                 else if (operation.equals_ci("operonly"))
00393                                         dconfig.Add(level, DEFCON_OPER_ONLY);
00394                                 else if (operation.equals_ci("silentoperonly"))
00395                                         dconfig.Add(level, DEFCON_SILENT_OPER_ONLY);
00396                                 else if (operation.equals_ci("akillnewclients"))
00397                                         dconfig.Add(level, DEFCON_AKILL_NEW_CLIENTS);
00398                                 else if (operation.equals_ci("nonewmemos"))
00399                                         dconfig.Add(level, DEFCON_NO_NEW_MEMOS);
00400                         }
00401 
00402                         if (dconfig.Check(level, DEFCON_REDUCE_SESSION) && dconfig.sessionlimit <= 0)
00403                                 throw ConfigException("The value for <defcon:sessionlimit> must be greater than zero!");
00404                         else if (dconfig.Check(level, DEFCON_AKILL_NEW_CLIENTS) && dconfig.akillreason.empty())
00405                                 throw ConfigException("The value for <defcon:akillreason> must not be empty!");
00406                         else if (dconfig.Check(level, DEFCON_FORCE_CHAN_MODES) && dconfig.chanmodes.empty())
00407                                 throw ConfigException("The value for <defcon:chanmodes> must not be empty!");
00408                 }
00409 
00410                 DConfig = dconfig;
00411                 this->ParseModeString();
00412         }
00413 
00414         EventReturn OnChannelModeSet(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string &param) anope_override
00415         {
00416                 ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
00417 
00418                 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOff.count(mname))
00419                 {
00420                         c->RemoveMode(OperServ, cm, param);
00421 
00422                         return EVENT_STOP;
00423                 }
00424 
00425                 return EVENT_CONTINUE;
00426         }
00427 
00428         EventReturn OnChannelModeUnset(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string &) anope_override
00429         {
00430                 ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
00431 
00432                 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOn.count(mname))
00433                 {
00434                         Anope::string param;
00435 
00436                         if (DConfig.GetDefConParam(mname, param))
00437                                 c->SetMode(OperServ, cm, param);
00438                         else
00439                                 c->SetMode(OperServ, cm);
00440 
00441                         return EVENT_STOP;
00442 
00443                 }
00444 
00445                 return EVENT_CONTINUE;
00446         }
00447 
00448         EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) anope_override
00449         {
00450                 if (command->name == "nickserv/register" || command->name == "nickserv/group")
00451                 {
00452                         if (DConfig.Check(DEFCON_NO_NEW_NICKS))
00453                         {
00454                                 source.Reply(_("Services are in DefCon mode, please try again later."));
00455                                 return EVENT_STOP;
00456                         }
00457                 }
00458                 else if (command->name == "chanserv/mode" && params.size() > 1 && params[1].equals_ci("LOCK"))
00459                 {
00460                         if (DConfig.Check(DEFCON_NO_MLOCK_CHANGE))
00461                         {
00462                                 source.Reply(_("Services are in DefCon mode, please try again later."));
00463                                 return EVENT_STOP;
00464                         }
00465                 }
00466                 else if (command->name == "chanserv/register")
00467                 {
00468                         if (DConfig.Check(DEFCON_NO_NEW_CHANNELS))
00469                         {
00470                                 source.Reply(_("Services are in DefCon mode, please try again later."));
00471                                 return EVENT_STOP;
00472                         }
00473                 }
00474                 else if (command->name == "memoserv/send")
00475                 {
00476                         if (DConfig.Check(DEFCON_NO_NEW_MEMOS))
00477                         {
00478                                 source.Reply(_("Services are in DefCon mode, please try again later."));
00479                                 return EVENT_STOP;
00480                         }
00481                 }
00482 
00483                 return EVENT_CONTINUE;
00484         }
00485 
00486         void OnUserConnect(User *u, bool &exempt) anope_override
00487         {
00488                 if (exempt || !u->Quitting() || !u->server->IsSynced() || u->server->IsULined())
00489                         return;
00490 
00491                 if (DConfig.Check(DEFCON_AKILL_NEW_CLIENTS) && akills)
00492                 {
00493                         Log(OperServ, "operserv/defcon") << "DEFCON: adding akill for *@" << u->host;
00494                         XLine x("*@" + u->host, Config->OperServ, Anope::CurTime + DConfig.akillexpire, DConfig.akillreason, XLineManager::GenerateUID());
00495                         x.by = Config->OperServ;
00496                         akills->Send(NULL, &x);
00497                 }
00498                 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS) || DConfig.Check(DEFCON_AKILL_NEW_CLIENTS))
00499                 {
00500                         u->Kill(Config->OperServ, DConfig.akillreason);
00501                         return;
00502                 }
00503 
00504                 if (DConfig.Check(DEFCON_NO_NEW_CLIENTS) || DConfig.Check(DEFCON_AKILL_NEW_CLIENTS))
00505                 {
00506                         u->Kill(Config->OperServ, DConfig.akillreason);
00507                         return;
00508                 }
00509 
00510                 if (DConfig.sessionlimit <= 0 || !session_service)
00511                         return;
00512 
00513                 Session *session;
00514                 try
00515                 {
00516                         session = session_service->FindSession(u->ip);
00517                 }
00518                 catch (const SocketException &)
00519                 {
00520                         return;
00521                 }
00522                 Exception *exception = session_service->FindException(u);
00523 
00524                 if (DConfig.Check(DEFCON_REDUCE_SESSION) && !exception)
00525                 {
00526                         if (session && session->count > static_cast<unsigned>(DConfig.sessionlimit))
00527                         {
00528                                 if (!Config->SessionLimitExceeded.empty())
00529                                         IRCD->SendMessage(OperServ, u->nick, Config->SessionLimitExceeded.c_str(), u->host.c_str());
00530                                 if (!Config->SessionLimitDetailsLoc.empty())
00531                                         IRCD->SendMessage(OperServ, u->nick, "%s", Config->SessionLimitDetailsLoc.c_str());
00532 
00533                                 ++session->hits;
00534                                 if (akills && Config->MaxSessionKill && session->hits >= Config->MaxSessionKill)
00535                                 {
00536                                         XLine x("*@" + u->host, Config->OperServ, Anope::CurTime + Config->SessionAutoKillExpiry, "Defcon session limit exceeded", XLineManager::GenerateUID());
00537                                         akills->Send(NULL, &x);
00538                                         Log(OperServ, "akill/defcon") << "[DEFCON] Added a temporary AKILL for \002*@" << u->host << "\002 due to excessive connections";
00539                                 }
00540                                 else
00541                                 {
00542                                         u->Kill(Config->OperServ, "Defcon session limit exceeded");
00543                                         u = NULL; /* No guarentee u still exists */
00544                                 }
00545                         }
00546                 }
00547         }
00548 
00549         void OnChannelModeAdd(ChannelMode *cm) anope_override
00550         {
00551                 if (DConfig.chanmodes.find(cm->mchar) != Anope::string::npos)
00552                         this->ParseModeString();
00553         }
00554 
00555         void OnChannelCreate(Channel *c) anope_override
00556         {
00557                 if (DConfig.Check(DEFCON_FORCE_CHAN_MODES))
00558                         c->SetModes(OperServ, false, "%s", DConfig.chanmodes.c_str());
00559         }
00560 };
00561 
00562 static void runDefCon()
00563 {
00564         if (DConfig.Check(DEFCON_FORCE_CHAN_MODES))
00565         {
00566                 if (!DConfig.chanmodes.empty() && !DefConModesSet)
00567                 {
00568                         if (DConfig.chanmodes[0] == '+' || DConfig.chanmodes[0] == '-')
00569                         {
00570                                 Log(OperServ, "operserv/defcon") << "DEFCON: setting " << DConfig.chanmodes << " on all channels";
00571                                 DefConModesSet = true;
00572                                 for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
00573                                         it->second->SetModes(OperServ, false, "%s", DConfig.chanmodes.c_str());
00574                         }
00575                 }
00576         }
00577         else
00578         {
00579                 if (!DConfig.chanmodes.empty() && DefConModesSet)
00580                 {
00581                         if (DConfig.chanmodes[0] == '+' || DConfig.chanmodes[0] == '-')
00582                         {
00583                                 DefConModesSet = false;
00584                                 Anope::string newmodes = defconReverseModes(DConfig.chanmodes);
00585                                 if (!newmodes.empty())
00586                                 {
00587                                         Log(OperServ, "operserv/defcon") << "DEFCON: setting " << newmodes << " on all channels";
00588                                         for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
00589                                                 it->second->SetModes(OperServ, false, "%s", newmodes.c_str());
00590                                 }
00591                         }
00592                 }
00593         }
00594 }
00595 
00596 static Anope::string defconReverseModes(const Anope::string &modes)
00597 {
00598         if (modes.empty())
00599                 return "";
00600         Anope::string newmodes;
00601         for (unsigned i = 0, end = modes.length(); i < end; ++i)
00602         {
00603                 if (modes[i] == '+')
00604                         newmodes += '-';
00605                 else if (modes[i] == '-')
00606                         newmodes += '+';
00607                 else
00608                         newmodes += modes[i];
00609         }
00610         return newmodes;
00611 }
00612 
00613 MODULE_INIT(OSDefcon)