summaryrefslogtreecommitdiff
path: root/modules/operserv
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2015-12-14 16:52:24 -0500
committerAdam <Adam@anope.org>2015-12-14 16:52:24 -0500
commit6302f980fe6dad83aab7d2dc1046dadea5ffd939 (patch)
tree4c27d33f55fc32ce34827977932dac4b3e5ceedd /modules/operserv
parent64dac60071fab652745a6e7a06cf6b7bdbbd3625 (diff)
New source tree structure for modules. From commands/cs_access => chanserv/access etc.
Diffstat (limited to 'modules/operserv')
-rw-r--r--modules/operserv/CMakeLists.txt1
-rw-r--r--modules/operserv/akill.cpp437
-rw-r--r--modules/operserv/chankill.cpp113
-rw-r--r--modules/operserv/config.cpp147
-rw-r--r--modules/operserv/defcon.cpp619
-rw-r--r--modules/operserv/dns.cpp1012
-rw-r--r--modules/operserv/forbid.cpp577
-rw-r--r--modules/operserv/ignore.cpp393
-rw-r--r--modules/operserv/info.cpp260
-rw-r--r--modules/operserv/jupe.cpp72
-rw-r--r--modules/operserv/kick.cpp81
-rw-r--r--modules/operserv/kill.cpp63
-rw-r--r--modules/operserv/list.cpp238
-rw-r--r--modules/operserv/login.cpp148
-rw-r--r--modules/operserv/logsearch.cpp151
-rw-r--r--modules/operserv/main/CMakeLists.txt1
-rw-r--r--modules/operserv/main/operserv.cpp337
-rw-r--r--modules/operserv/mode.cpp187
-rw-r--r--modules/operserv/modinfo.cpp214
-rw-r--r--modules/operserv/module.cpp179
-rw-r--r--modules/operserv/news.cpp459
-rw-r--r--modules/operserv/noop.cpp98
-rw-r--r--modules/operserv/oline.cpp74
-rw-r--r--modules/operserv/oper.cpp241
-rw-r--r--modules/operserv/reload.cpp62
-rw-r--r--modules/operserv/session.cpp768
-rw-r--r--modules/operserv/set.cpp243
-rw-r--r--modules/operserv/shutdown.cpp101
-rw-r--r--modules/operserv/stats.cpp271
-rw-r--r--modules/operserv/svs.cpp171
-rw-r--r--modules/operserv/sxline.cpp673
-rw-r--r--modules/operserv/update.cpp49
32 files changed, 8440 insertions, 0 deletions
diff --git a/modules/operserv/CMakeLists.txt b/modules/operserv/CMakeLists.txt
new file mode 100644
index 000000000..cd225a94d
--- /dev/null
+++ b/modules/operserv/CMakeLists.txt
@@ -0,0 +1 @@
+build_modules(${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/modules/operserv/akill.cpp b/modules/operserv/akill.cpp
new file mode 100644
index 000000000..7f366e0c9
--- /dev/null
+++ b/modules/operserv/akill.cpp
@@ -0,0 +1,437 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2014 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "module.h"
+
+static ServiceReference<XLineManager> akills("XLineManager", "xlinemanager/sgline");
+
+class CommandOSAKill : public Command
+{
+ private:
+ void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
+ {
+ Anope::string expiry, mask;
+
+ if (params.size() < 2)
+ {
+ this->OnSyntaxError(source, "ADD");
+ return;
+ }
+
+ spacesepstream sep(params[1]);
+ sep.GetToken(mask);
+
+ if (mask[0] == '+')
+ {
+ expiry = mask;
+ sep.GetToken(mask);
+ }
+
+ time_t expires = !expiry.empty() ? Anope::DoTime(expiry) : Config->GetModule("operserv")->Get<time_t>("autokillexpiry", "30d");
+ /* If the expiry given does not contain a final letter, it's in days,
+ * said the doc. Ah well.
+ */
+ if (!expiry.empty() && isdigit(expiry[expiry.length() - 1]))
+ expires *= 86400;
+ /* Do not allow less than a minute expiry time */
+ if (expires && expires < 60)
+ {
+ source.Reply(_("Invalid expiry time \002{0}\002."), expiry);
+ return;
+ }
+ else if (expires > 0)
+ expires += Anope::CurTime;
+
+ if (sep.StreamEnd())
+ {
+ this->OnSyntaxError(source, "ADD");
+ return;
+ }
+
+ Anope::string reason;
+ if (mask.find('#') != Anope::string::npos)
+ {
+ Anope::string remaining = sep.GetRemaining();
+
+ size_t co = remaining[0] == ':' ? 0 : remaining.rfind(" :");
+ if (co == Anope::string::npos)
+ {
+ this->OnSyntaxError(source, "ADD");
+ return;
+ }
+
+ if (co != 0)
+ ++co;
+
+ reason = remaining.substr(co + 1);
+ mask += " " + remaining.substr(0, co);
+ mask.trim();
+ }
+ else
+ reason = sep.GetRemaining();
+
+ if (mask[0] == '/' && mask[mask.length() - 1] == '/')
+ {
+ if (!Config->regex_flags)
+ {
+ source.Reply(_("Regex is disabled."));
+ return;
+ }
+
+ Anope::string stripped_mask = mask.substr(1, mask.length() - 2);
+ try
+ {
+ std::regex(stripped_mask.str(), Config->regex_flags);
+ }
+ catch (const std::regex_error &ex)
+ {
+ source.Reply("%s", ex.what());
+ return;
+ }
+ }
+
+ User *targ = User::Find(mask, true);
+ if (targ)
+ mask = "*@" + targ->host;
+
+ if (Config->GetModule("operserv")->Get<bool>("addakiller", "yes") && !source.GetNick().empty())
+ reason = "[" + source.GetNick() + "] " + reason;
+
+ if (!akills->CanAdd(source, mask, expires, reason))
+ return;
+
+ if (mask.find_first_not_of("/~@.*?") == Anope::string::npos)
+ {
+ source.Reply(_("\002{0}\002 coverage is too wide; Please use a more specific mask."), mask);
+ return;
+ }
+
+ if (mask.find('@') == Anope::string::npos)
+ {
+ source.Reply(_("Mask must be in the form \037user\037@\037host\037."));
+ return;
+ }
+
+ XLine *x = new XLine(mask, source.GetNick(), expires, reason);
+ if (Config->GetModule("operserv")->Get<bool>("akillids"))
+ x->SetID(XLineManager::GenerateUID());
+
+ unsigned int affected = 0;
+ for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
+ if (akills->Check(it->second, x))
+ ++affected;
+ float percent = static_cast<float>(affected) / static_cast<float>(UserListByNick.size()) * 100.0;
+
+ if (percent > 95)
+ {
+ source.Reply(_("\002{0}\002 coverage is too wide; Please use a more specific mask."), mask);
+ Log(LOG_ADMIN, source, this) << "tried to akill " << percent << "% of the network (" << affected << " users)";
+ delete x;
+ return;
+ }
+
+ EventReturn MOD_RESULT;
+ MOD_RESULT = Event::OnAddXLine(&Event::AddXLine::OnAddXLine, source, x, akills);
+ if (MOD_RESULT == EVENT_STOP)
+ {
+ delete x;
+ return;
+ }
+
+ akills->AddXLine(x);
+ if (Config->GetModule("operserv")->Get<bool>("akillonadd"))
+ akills->Send(NULL, x);
+
+ source.Reply(_("\002{0}\002 added to the akill list."), mask);
+
+ Log(LOG_ADMIN, source, this) << "on " << mask << " (" << x->GetReason() << "), expires in " << (expires ? Anope::Duration(expires - Anope::CurTime) : "never") << " [affects " << affected << " user(s) (" << percent << "%)]";
+ if (Anope::ReadOnly)
+ source.Reply(_("Services are in read-only mode. Any changes made may not persist."));
+ }
+
+ void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
+ {
+ const Anope::string &mask = params.size() > 1 ? params[1] : "";
+
+ if (mask.empty())
+ {
+ this->OnSyntaxError(source, "DEL");
+ return;
+ }
+
+ if (akills->GetXLines().empty())
+ {
+ source.Reply(_("The akill list is empty."));
+ return;
+ }
+
+ if (isdigit(mask[0]) && mask.find_first_not_of("1234567890,-") == Anope::string::npos)
+ {
+ unsigned int deleted = 0;
+
+ NumberList(mask, true,
+ [&](unsigned int number)
+ {
+ XLine *x = akills->GetEntry(number - 1);
+
+ if (!x)
+ return;
+
+ Log(LOG_ADMIN, source, this) << "to remove " << x->GetMask() << " from the list";
+
+ ++deleted;
+ x->Delete();
+ },
+ [&]()
+ {
+ if (!deleted)
+ source.Reply(_("No matching entries on the akill list."));
+ else if (deleted == 1)
+ source.Reply(_("Deleted \0021\002 entry from the akill list."));
+ else
+ source.Reply(_("Deleted \002{0}\002 entries from the akill list."), deleted);
+ });
+ }
+ else
+ {
+ XLine *x = akills->HasEntry(mask);
+
+ if (!x)
+ {
+ source.Reply(_("\002{0}\002 was not found on the akill list."), mask);
+ return;
+ }
+
+ do
+ {
+ Event::OnDelXLine(&Event::DelXLine::OnDelXLine, source, x, akills);
+
+ Log(LOG_ADMIN, source, this) << "to remove " << x->GetMask() << " from the list";
+ source.Reply(_("\002{0}\002 deleted from the akill list."), x->GetMask());
+ x->Delete();
+ }
+ while ((x = akills->HasEntry(mask)));
+
+ }
+
+ if (Anope::ReadOnly)
+ source.Reply(_("Services are in read-only mode. Any changes made may not persist."));
+ }
+
+ void ProcessList(CommandSource &source, const std::vector<Anope::string> &params, ListFormatter &list)
+ {
+ const Anope::string &mask = params.size() > 1 ? params[1] : "";
+
+ if (!mask.empty() && isdigit(mask[0]) && mask.find_first_not_of("1234567890,-") == Anope::string::npos)
+ {
+ NumberList(mask, false,
+ [&](unsigned int number)
+ {
+ XLine *x = akills->GetEntry(number - 1);
+
+ if (!x)
+ return;
+
+ ListFormatter::ListEntry entry;
+ entry["Number"] = stringify(number);
+ entry["Mask"] = x->GetMask();
+ entry["Creator"] = x->GetBy();
+ entry["Created"] = Anope::strftime(x->GetCreated(), NULL, true);
+ entry["Expires"] = Anope::Expires(x->GetExpires(), source.nc);
+ entry["Reason"] = x->GetReason();
+ list.AddEntry(entry);
+ },
+ [&]{});
+ }
+ else
+ {
+ unsigned int i = 0;
+ for (XLine *x : akills->GetXLines())
+ {
+ if (mask.empty() || mask.equals_ci(x->GetMask()) || mask == x->id || Anope::Match(x->GetMask(), mask, false, true))
+ {
+ ListFormatter::ListEntry entry;
+ entry["Number"] = stringify(++i);
+ entry["Mask"] = x->GetMask();
+ entry["Creator"] = x->GetBy();
+ entry["Created"] = Anope::strftime(x->GetCreated(), NULL, true);
+ entry["Expires"] = Anope::Expires(x->GetExpires(), source.nc);
+ entry["Reason"] = x->GetReason();
+ list.AddEntry(entry);
+ }
+ }
+ }
+
+ if (list.IsEmpty())
+ {
+ source.Reply(_("There are no matching entries on the akill list."));
+ return;
+ }
+
+ source.Reply(_("Current akill list:"));
+
+ std::vector<Anope::string> replies;
+ list.Process(replies);
+
+ for (unsigned i = 0; i < replies.size(); ++i)
+ source.Reply(replies[i]);
+
+ source.Reply(_("End of akill list."));
+ }
+
+ void DoList(CommandSource &source, const std::vector<Anope::string> &params)
+ {
+ if (akills->GetXLines().empty())
+ {
+ source.Reply(_("The akill list is empty."));
+ return;
+ }
+
+ ListFormatter list(source.GetAccount());
+ list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Reason"));
+
+ this->ProcessList(source, params, list);
+ }
+
+ void DoView(CommandSource &source, const std::vector<Anope::string> &params)
+ {
+ if (akills->GetXLines().empty())
+ {
+ source.Reply(_("The akill list is empty."));
+ return;
+ }
+
+ ListFormatter list(source.GetAccount());
+ list.AddColumn(_("Number")).AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Expires")).AddColumn(_("Reason"));
+
+ this->ProcessList(source, params, list);
+ }
+
+ void DoClear(CommandSource &source)
+ {
+ for (XLine *x : akills->GetXLines())
+ {
+ Event::OnDelXLine(&Event::DelXLine::OnDelXLine, source, x, akills);
+ x->Delete();
+ }
+
+ Log(LOG_ADMIN, source, this) << "to CLEAR the list";
+ source.Reply(_("The akill list has been cleared."));
+
+ if (Anope::ReadOnly)
+ source.Reply(_("Services are in read-only mode. Any changes made may not persist."));
+ }
+ public:
+ CommandOSAKill(Module *creator) : Command(creator, "operserv/akill", 1, 2)
+ {
+ this->SetDesc(_("Manipulate the AKILL list"));
+ this->SetSyntax(_("ADD [+\037expiry\037] \037mask\037 \037reason\037"));
+ this->SetSyntax(_("DEL {\037mask\037 | \037entry-num\037 | \037list\037 | \037id\037}"));
+ this->SetSyntax(_("LIST [\037mask\037 | \037list\037 | \037id\037]"));
+ this->SetSyntax(_("VIEW [\037mask\037 | \037list\037 | \037id\037]"));
+ this->SetSyntax("CLEAR");
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
+ {
+ const Anope::string &cmd = params[0];
+
+ if (!akills)
+ return;
+
+ if (cmd.equals_ci("ADD"))
+ return this->DoAdd(source, params);
+ else if (cmd.equals_ci("DEL"))
+ return this->DoDel(source, params);
+ else if (cmd.equals_ci("LIST"))
+ return this->DoList(source, params);
+ else if (cmd.equals_ci("VIEW"))
+ return this->DoView(source, params);
+ else if (cmd.equals_ci("CLEAR"))
+ return this->DoClear(source);
+ else
+ this->OnSyntaxError(source, "");
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
+ {
+ if (subcommand.equals_ci("ADD"))
+ {
+ source.Reply(_("The \002{0} ADD\002 command adds \037mask\037 to the auto kill list with the given \037reason\037."
+ "\037mask\037 can be in the format of nickname!username@hostname#realname."
+ " If a real name is specified, the reason must be prefixed with a :."
+ " \037expiry\037 is optional, and if specified must be an integer followed by one of \037d\037 (days), \037h\037 (hours), or \037m\037 (minutes)."
+ " If a unit specifier is not included, the default is days, so \037+30\037 means 30 days."
+ " To add an auto kill which does not expire, use \037+0\037. "
+ " The default auto kill expiry time is \002{1}\002"),
+ source.command, Anope::Duration(Config->GetModule("operserv")->Get<time_t>("autokillexpiry", "30d"), source.GetAccount()));
+
+ const Anope::string &regexengine = Config->GetBlock("options")->Get<Anope::string>("regexengine");
+ if (!regexengine.empty())
+ {
+ source.Reply(" ");
+ source.Reply(_("Regex matches are also supported using the %s engine. Enclose your mask in // if this is desired."), regexengine);
+ }
+ }
+ else if (subcommand.equals_ci("DEL"))
+ source.Reply(_("The \002{0} DEL\002 command removes the given \037mask\037 from the auto kill list, if present."
+ " If a list of entry numbers is given, those entries are deleted."),
+ source.command);
+ else if (subcommand.equals_ci("LIST") || subcommand.equals_ci("VIEW"))
+ source.Reply(_("The \002{0} LIST\002 and \002{0} VIEW\002 commands display the auto kill list."
+ " If a wildcard \037mask\037 is given, only those entries matching the mask are displayed."
+ " If a list of entry numbers is given, only those entries are shown."
+ " \002VIEW\002 is similar to \002LIST\002 but also shows who created the auto kill, when it was created, and when it expires.\n"
+ "\n"
+ "Example:\n"
+ "\n"
+ " {0} LIST 2-5,7-9\n"
+ " Lists auto kill entries numbered 2 through 5 and 7 through 9."),
+ source.command);
+ else if (subcommand.equals_ci("CLEAR"))
+ source.Reply(_("The \002{0} CLEAR\002 command removes all auto kills from the auto kill list."),
+ source.command);
+ else
+ {
+ CommandInfo *help = source.service->FindCommand("generic/help");
+ source.Reply(_("Allows manipulating the AKILL list."
+ " If a user matching an AKILL mask connects, services will issue a kill the user and prevent them from reconnecting.\n"
+ "\n"
+ "The \002ADD\002 command adds \037mask\037 to the auto kill list.\n"
+ "\002{msg}{service} {help} {command} ADD\002 for more information.\n"
+ "\n"
+ "The \002DEL\002 command removes \037mask\037 from the auto kill list.\n"
+ "\002{msg}{service} {help} {command} DEL\002 for more information.\n"
+ "\n"
+ "The \002LIST\002 and \002VIEW\002 commands both show the auto kill list, but \002VIEW\002 also shows who created the auto kill entry, when it was created, and when it expires.\n"
+ "\002{msg}{service} {help} {command} [LIST | VIEW]\002 for more information.\n"
+ "\n"
+ "The \002CLEAR\002 command clears th auto kill list."
+ "\002{msg}{service} {help} {command} CLEAR\002 for more information.\n"),
+ "msg"_kw = Config->StrictPrivmsg, "service"_kw = source.service->nick, "help"_kw = help->cname, "command"_kw = source.command);
+ }
+ return true;
+ }
+};
+
+class OSAKill : public Module
+{
+ CommandOSAKill commandosakill;
+
+ public:
+ OSAKill(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
+ , commandosakill(this)
+ {
+
+ }
+};
+
+MODULE_INIT(OSAKill)
diff --git a/modules/operserv/chankill.cpp b/modules/operserv/chankill.cpp
new file mode 100644
index 000000000..8d3773e9d
--- /dev/null
+++ b/modules/operserv/chankill.cpp
@@ -0,0 +1,113 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2014 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "module.h"
+
+static ServiceReference<XLineManager> akills("XLineManager", "xlinemanager/sgline");
+
+class CommandOSChanKill : public Command
+{
+ public:
+ CommandOSChanKill(Module *creator) : Command(creator, "operserv/chankill", 2, 3)
+ {
+ this->SetDesc(_("AKILL all users on a specific channel"));
+ this->SetSyntax(_("[+\037expiry\037] \037channel\037 \037reason\037"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
+ {
+ if (!akills)
+ return;
+
+ Anope::string expiry, channel;
+ unsigned last_param = 1;
+
+ channel = params[0];
+ if (!channel.empty() && channel[0] == '+')
+ {
+ expiry = channel;
+ channel = params[1];
+ last_param = 2;
+ }
+
+ time_t expires = !expiry.empty() ? Anope::DoTime(expiry) : Config->GetModule("operserv")->Get<time_t>("autokillexpiry", "30d");
+ if (!expiry.empty() && isdigit(expiry[expiry.length() - 1]))
+ expires *= 86400;
+
+ if (expires)
+ {
+ if (expires < 60)
+ {
+ source.Reply(_("Invalid expiry time \002{0}\002."), expiry);
+ return;
+ }
+
+ expires += Anope::CurTime;
+ }
+
+ if (params.size() <= last_param)
+ {
+ this->OnSyntaxError(source, "");
+ return;
+ }
+
+ Anope::string reason = params[last_param];
+ if (params.size() > last_param + 1)
+ reason += params[last_param + 1];
+
+ Anope::string realreason;
+ if (Config->GetModule("operserv")->Get<bool>("addakiller") && !source.GetNick().empty())
+ realreason = "[" + source.GetNick() + "] " + reason;
+ else
+ realreason = reason;
+
+ Channel *c = Channel::Find(channel);
+ if (!c)
+ {
+ source.Reply(_("Channel \002{0}\002 doesn't exist."), channel);
+ return;
+ }
+
+ for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ++it)
+ {
+ ChanUserContainer *uc = it->second;
+
+ if (uc->user->server == Me || uc->user->HasMode("OPER"))
+ continue;
+
+ XLine *x = new XLine("*@" + uc->user->host, source.GetNick(), expires, realreason, XLineManager::GenerateUID());
+ akills->AddXLine(x);
+ akills->OnMatch(uc->user, x);
+ }
+
+ Log(LOG_ADMIN, source, this) << "on " << c->name << " (" << realreason << ")";
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
+ {
+ source.Reply(_("Adds an auto kill for every user on \037channel\037, except for IRC operators."));
+ return true;
+ }
+};
+
+class OSChanKill : public Module
+{
+ CommandOSChanKill commandoschankill;
+
+ public:
+ OSChanKill(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
+ , commandoschankill(this)
+ {
+
+ }
+};
+
+MODULE_INIT(OSChanKill)
diff --git a/modules/operserv/config.cpp b/modules/operserv/config.cpp
new file mode 100644
index 000000000..257f8fee4
--- /dev/null
+++ b/modules/operserv/config.cpp
@@ -0,0 +1,147 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2014 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "module.h"
+
+class CommandOSConfig : public Command
+{
+ public:
+ CommandOSConfig(Module *creator) : Command(creator, "operserv/config", 1, 4)
+ {
+ this->SetDesc(_("View and change configuration file settings"));
+ this->SetSyntax(_("{\037MODIFY\037|\037VIEW\037} [\037block name\037 \037item name\037 \037item value\037]"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
+ {
+ const Anope::string &what = params[0];
+
+ if (what.equals_ci("MODIFY") && params.size() > 3)
+ {
+ if (!source.HasPriv("operserv/config"))
+ {
+ source.Reply(_("Access denied. You do not have the operator privilege \002{0}\002."), "operserv/config");
+ return;
+ }
+
+ Configuration::Block *block = Config->GetBlock(params[1]);
+ if (!block)
+ block = Config->GetModule(params[1]);
+
+ if (!block)
+ {
+ source.Reply(_("There is no such configuration block \002{0}\002."), params[1]);
+ return;
+ }
+
+ block->Set(params[2], params[3]);
+
+ Log(LOG_ADMIN, source, this) << "to change the configuration value of " << params[1] << ":" << params[2] << " to " << params[3];
+ source.Reply(_("Value of \002{0}:{1}\002 changed to \002{2}\002."), params[1], params[2], params[3]);
+ }
+ else if (what.equals_ci("VIEW"))
+ {
+ /* Blocks we should show */
+ const Anope::string show_blocks[] = { "serverinfo", "networkinfo", "options", "" };
+
+ Log(LOG_ADMIN, source, this) << "VIEW";
+
+ for (unsigned i = 0; !show_blocks[i].empty(); ++i)
+ {
+ Configuration::Block *block = Config->GetBlock(show_blocks[i]);
+ const Configuration::Block::item_map *items = block->GetItems();
+
+ if (!items)
+ continue;
+
+ ListFormatter lflist(source.GetAccount());
+ lflist.AddColumn(_("Name")).AddColumn(_("Value"));
+
+ for (Configuration::Block::item_map::const_iterator it = items->begin(), it_end = items->end(); it != it_end; ++it)
+ {
+ ListFormatter::ListEntry entry;
+ entry["Name"] = it->first;
+ entry["Value"] = it->second;
+ lflist.AddEntry(entry);
+ }
+
+ std::vector<Anope::string> replies;
+ lflist.Process(replies);
+
+ source.Reply(_("%s settings:"), block->GetName());
+
+ for (unsigned j = 0; j < replies.size(); ++j)
+ source.Reply(replies[j]);
+
+ source.Reply(" ");
+ }
+
+ ListFormatter lflist(source.GetAccount());
+ lflist.AddColumn(_("Module Name")).AddColumn(_("Name")).AddColumn(_("Value"));
+
+ for (int i = 0; i < Config->CountBlock("module"); ++i)
+ {
+ Configuration::Block *block = Config->GetBlock("module", i);
+ const Configuration::Block::item_map *items = block->GetItems();
+
+ if (!items || items->size() <= 1)
+ continue;
+
+ ListFormatter::ListEntry entry;
+ entry["Module Name"] = block->Get<Anope::string>("name");
+
+ for (Configuration::Block::item_map::const_iterator it = items->begin(), it_end = items->end(); it != it_end; ++it)
+ {
+ entry["Name"] = it->first;
+ entry["Value"] = it->second;
+ lflist.AddEntry(entry);
+ }
+ }
+
+ std::vector<Anope::string> replies;
+ lflist.Process(replies);
+
+ source.Reply(_("Module settings:"));
+
+ for (unsigned j = 0; j < replies.size(); ++j)
+ source.Reply(replies[j]);
+
+ source.Reply(_("End of configuration."));
+ }
+ else
+ this->OnSyntaxError(source, what);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
+ {
+ source.Reply(_("Allows you to change and view configuration settings. Settings changed by this command are temporary and will not be reflected back into the configuration file, and will be lost if Anope is shut down, restarted, or the configuration is reloaded.\n"
+ "Use of the \002MODIFY\002 command requires the \002{0}\002 operator privilege.\n"
+ "\n"
+ "Example:\n"
+ " {0} MODIFY nickserv forcemail no"
+ " Changes the \"forceemail\" setting of the module configuration for \"nickserv\" to \"no\""));
+ return true;
+ }
+};
+
+class OSConfig : public Module
+{
+ CommandOSConfig commandosconfig;
+
+ public:
+ OSConfig(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
+ , commandosconfig(this)
+ {
+
+ }
+};
+
+MODULE_INIT(OSConfig)
diff --git a/modules/operserv/defcon.cpp b/modules/operserv/defcon.cpp
new file mode 100644
index 000000000..804b66c27
--- /dev/null
+++ b/modules/operserv/defcon.cpp
@@ -0,0 +1,619 @@
+/* OperServ core functions
+ *
+ * (C) 2003-2014 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "module.h"
+#include "modules/os_session.h"
+#include "modules/os_defcon.h"
+#include "modules/global.h"
+
+enum DefconLevel
+{
+ DEFCON_NO_NEW_CHANNELS,
+ DEFCON_NO_NEW_NICKS,
+ DEFCON_NO_MLOCK_CHANGE,
+ DEFCON_FORCE_CHAN_MODES,
+ DEFCON_REDUCE_SESSION,
+ DEFCON_NO_NEW_CLIENTS,
+ DEFCON_OPER_ONLY,
+ DEFCON_SILENT_OPER_ONLY,
+ DEFCON_AKILL_NEW_CLIENTS,
+ DEFCON_NO_NEW_MEMOS
+};
+
+bool DefConModesSet = false;
+
+struct DefconConfig
+{
+ std::vector<std::bitset<32> > DefCon;
+ std::set<Anope::string> DefConModesOn, DefConModesOff;
+ std::map<Anope::string, Anope::string> DefConModesOnParams;
+
+ int defaultlevel, sessionlimit;
+ Anope::string chanmodes, message, offmessage, akillreason;
+ std::vector<Anope::string> defcons;
+ time_t akillexpire, timeout;
+ bool globalondefcon;
+
+ unsigned max_session_kill;
+ time_t session_autokill_expiry;
+ Anope::string sle_reason, sle_detailsloc;
+
+ DefconConfig()
+ {
+ this->DefCon.resize(6);
+ this->defcons.resize(5);
+ }
+
+ bool Check(DefconLevel level)
+ {
+ return this->Check(this->defaultlevel, level);
+ }
+
+ bool Check(int dlevel, DefconLevel level)
+ {
+ return this->DefCon[dlevel].test(level);
+ }
+
+ void Add(int dlevel, DefconLevel level)
+ {
+ this->DefCon[dlevel][level] = true;
+ }
+
+ void Del(int dlevel, DefconLevel level)
+ {
+ this->DefCon[dlevel][level] = false;
+ }
+
+ bool SetDefConParam(const Anope::string &name, const Anope::string &buf)
+ {
+ return DefConModesOnParams.insert(std::make_pair(name, buf)).second;
+ }
+
+ void UnsetDefConParam(const Anope::string &name)
+ {
+ DefConModesOnParams.erase(name);
+ }
+
+ bool GetDefConParam(const Anope::string &name, Anope::string &buf)
+ {
+ std::map<Anope::string, Anope::string>::iterator it = DefConModesOnParams.find(name);
+
+ buf.clear();
+
+ if (it != DefConModesOnParams.end())
+ {
+ buf = it->second;
+ return true;
+ }
+
+ return false;
+ }
+};
+
+static DefconConfig DConfig;
+
+static void runDefCon();
+static Anope::string defconReverseModes(const Anope::string &modes);
+
+static Timer *timeout;
+
+class DefConTimeout : public Timer
+{
+ EventHandlers<Event::DefconLevel> &eventdefcon;
+ int level;
+
+ public:
+ DefConTimeout(EventHandlers<Event::DefconLevel> &ev, Module *mod, int newlevel) : Timer(mod, DConfig.timeout), eventdefcon(ev), level(newlevel)
+ {
+ timeout = this;
+ }
+
+ ~DefConTimeout()
+ {
+ timeout = NULL;
+ }
+
+ v