summaryrefslogtreecommitdiff
path: root/src/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.cpp')
-rw-r--r--src/config.cpp734
1 files changed, 457 insertions, 277 deletions
diff --git a/src/config.cpp b/src/config.cpp
index 5d20caf82..0222f0e97 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -1,25 +1,37 @@
-/* Configuration file handling.
+/*
+ * Anope IRC Services
*
- * (C) 2003-2017 Anope Team
- * Contact us at team@anope.org
+ * Copyright (C) 2003-2017 Anope Team <team@anope.org>
*
- * Please read COPYING and README for further details.
+ * This file is part of Anope. Anope is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation, version 2.
*
- * Based on the original code of Epona by Lara.
- * Based on the original code of Services by Andy Church.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see see <http://www.gnu.org/licenses/>.
*/
#include "services.h"
#include "config.h"
-#include "bots.h"
-#include "access.h"
#include "opertype.h"
#include "channels.h"
#include "hashcomp.h"
+#include "event.h"
+#include "bots.h"
+#include "modules.h"
+#include "servers.h"
+#include "protocol.h"
+#include "modules/nickserv.h"
using namespace Configuration;
-File ServicesConf("services.conf", false); // Services configuration file name
+File ServicesConf("anope.conf", false); // Services configuration file name
Conf *Config = NULL;
Block::Block(const Anope::string &n) : name(n), linenum(-1)
@@ -33,47 +45,37 @@ const Anope::string &Block::GetName() const
int Block::CountBlock(const Anope::string &bname)
{
- if (!this)
- return 0;
-
return blocks.count(bname);
}
-Block* Block::GetBlock(const Anope::string &bname, int num)
+Block* Block::GetBlock(const Anope::string &bname)
{
- if (!this)
- return NULL;
+ auto it = blocks.find(bname);
- std::pair<block_map::iterator, block_map::iterator> it = blocks.equal_range(bname);
+ if (it != blocks.end())
+ return &it->second;
- for (int i = 0; it.first != it.second; ++it.first, ++i)
- if (i == num)
- return &it.first->second;
- return NULL;
+ blocks.emplace(bname, bname);
+ return GetBlock(bname);
}
-bool Block::Set(const Anope::string &tag, const Anope::string &value)
+Block* Block::GetBlock(const Anope::string &bname, int num)
{
- if (!this)
- return false;
+ std::pair<block_map::iterator, block_map::iterator> it = blocks.equal_range(bname);
- items[tag] = value;
- return true;
+ for (int i = 0; it.first != it.second; ++it.first, ++i)
+ if (i == num)
+ return &it.first->second;
+ return nullptr;
}
const Block::item_map* Block::GetItems() const
{
- if (this)
- return &items;
- else
- return NULL;
+ return &items;
}
-template<> const Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const
+template<> Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const
{
- if (!this)
- return def;
-
Anope::map<Anope::string>::const_iterator it = items.find(tag);
if (it != items.end())
return it->second;
@@ -83,15 +85,41 @@ template<> const Anope::string Block::Get(const Anope::string &tag, const Anope:
template<> time_t Block::Get(const Anope::string &tag, const Anope::string &def) const
{
- return Anope::DoTime(Get<const Anope::string>(tag, def));
+ return Anope::DoTime(Get<Anope::string>(tag, def));
}
template<> bool Block::Get(const Anope::string &tag, const Anope::string &def) const
{
- const Anope::string &str = Get<const Anope::string>(tag, def);
+ const Anope::string &str = Get<Anope::string>(tag, def);
return !str.empty() && !str.equals_ci("no") && !str.equals_ci("off") && !str.equals_ci("false") && !str.equals_ci("0");
}
+template<> unsigned int Block::Get(const Anope::string &tag, const Anope::string &def) const
+{
+ const Anope::string &str = Get<Anope::string>(tag, def);
+ std::size_t pos = str.length();
+ unsigned long l;
+
+ try
+ {
+ l = std::stoul(str.str(), &pos, 0);
+ }
+ catch (...)
+ {
+ return 0;
+ }
+
+ if (pos != str.length())
+ return 0;
+
+ return l;
+}
+
+template<> void Block::Set(const Anope::string &tag, const Anope::string &value)
+{
+ items[tag] = value;
+}
+
static void ValidateNotEmpty(const Anope::string &block, const Anope::string &name, const Anope::string &value)
{
if (value.empty())
@@ -121,14 +149,17 @@ Conf::Conf() : Block("")
{
Block *include = this->GetBlock("include", i);
- const Anope::string &type = include->Get<const Anope::string>("type"),
- &file = include->Get<const Anope::string>("name");
+ const Anope::string &type = include->Get<Anope::string>("type"),
+ &file = include->Get<Anope::string>("name");
+
+ ValidateNotEmpty("include", "name", file);
File f(file, type == "executable");
this->LoadConf(f);
}
- FOREACH_MOD(OnReload, (this));
+ for (Module *m : ModuleManager::Modules)
+ m->OnReload(this);
/* Check for modified values that aren't allowed to be modified */
if (Config)
@@ -147,20 +178,21 @@ Conf::Conf() : Block("")
{"networkinfo", "userlen"},
{"networkinfo", "hostlen"},
{"networkinfo", "chanlen"},
+ {"options", "casemap"},
};
for (unsigned i = 0; i < sizeof(noreload) / sizeof(noreload[0]); ++i)
- if (this->GetBlock(noreload[i].block)->Get<const Anope::string>(noreload[i].name) != Config->GetBlock(noreload[i].block)->Get<const Anope::string>(noreload[i].name))
+ if (this->GetBlock(noreload[i].block)->Get<Anope::string>(noreload[i].name) != Config->GetBlock(noreload[i].block)->Get<Anope::string>(noreload[i].name))
throw ConfigException("<" + noreload[i].block + ":" + noreload[i].name + "> can not be modified once set");
}
Block *serverinfo = this->GetBlock("serverinfo"), *options = this->GetBlock("options"),
*mail = this->GetBlock("mail"), *networkinfo = this->GetBlock("networkinfo");
- ValidateNotEmpty("serverinfo", "name", serverinfo->Get<const Anope::string>("name"));
- ValidateNotEmpty("serverinfo", "description", serverinfo->Get<const Anope::string>("description"));
- ValidateNotEmpty("serverinfo", "pid", serverinfo->Get<const Anope::string>("pid"));
- ValidateNotEmpty("serverinfo", "motd", serverinfo->Get<const Anope::string>("motd"));
+ ValidateNotEmpty("serverinfo", "name", serverinfo->Get<Anope::string>("name"));
+ ValidateNotEmpty("serverinfo", "description", serverinfo->Get<Anope::string>("description"));
+ ValidateNotEmpty("serverinfo", "pid", serverinfo->Get<Anope::string>("pid"));
+ ValidateNotEmpty("serverinfo", "motd", serverinfo->Get<Anope::string>("motd"));
ValidateNotZero("options", "readtimeout", options->Get<time_t>("readtimeout"));
ValidateNotZero("options", "warningtimeout", options->Get<time_t>("warningtimeout"));
@@ -170,13 +202,13 @@ Conf::Conf() : Block("")
ValidateNotZero("networkinfo", "hostlen", networkinfo->Get<unsigned>("hostlen"));
ValidateNotZero("networkinfo", "chanlen", networkinfo->Get<unsigned>("chanlen"));
- spacesepstream(options->Get<const Anope::string>("ulineservers")).GetTokens(this->Ulines);
+ spacesepstream(options->Get<Anope::string>("ulineservers")).GetTokens(this->Ulines);
if (mail->Get<bool>("usemail"))
{
Anope::string check[] = { "sendmailpath", "sendfrom", "registration_subject", "registration_message", "emailchange_subject", "emailchange_message", "memo_subject", "memo_message" };
for (unsigned i = 0; i < sizeof(check) / sizeof(Anope::string); ++i)
- ValidateNotEmpty("mail", check[i], mail->Get<const Anope::string>(check[i]));
+ ValidateNotEmpty("mail", check[i], mail->Get<Anope::string>(check[i]));
}
this->ReadTimeout = options->Get<time_t>("readtimeout");
@@ -185,21 +217,42 @@ Conf::Conf() : Block("")
this->StrictPrivmsg = !UseStrictPrivmsg ? "/msg " : "/";
{
std::vector<Anope::string> defaults;
- spacesepstream(this->GetModule("nickserv")->Get<const Anope::string>("defaults")).GetTokens(defaults);
+ spacesepstream(this->GetModule("nickserv/main")->Get<Anope::string>("defaults")).GetTokens(defaults);
this->DefPrivmsg = std::find(defaults.begin(), defaults.end(), "msg") != defaults.end();
}
- this->DefLanguage = options->Get<const Anope::string>("defaultlanguage");
+ this->DefLanguage = options->Get<Anope::string>("defaultlanguage");
this->TimeoutCheck = options->Get<time_t>("timeoutcheck");
this->NickChars = networkinfo->Get<Anope::string>("nick_chars");
+ Anope::string locale = options->Get<Anope::string>("locale");
+ Anope::string casemap = options->Get<Anope::string>("casemap");
+
+ if (locale.empty() == casemap.empty())
+ throw ConfigException("One of options:locale and options:casemap must be set");
+
+ if (locale.empty())
+ {
+ // load locale conf
+ File f(casemap + ".conf", false);
+ this->LoadConf(f);
+ }
+ else
+ {
+#if Boost_FOUND
+ this->locale = new std::locale(Anope::locale::generate(locale.str()));
+#else
+ throw ConfigException("Boost.Locale is not enabled, cannot use locale " + locale);
+#endif
+ }
+
for (int i = 0; i < this->CountBlock("uplink"); ++i)
{
Block *uplink = this->GetBlock("uplink", i);
- const Anope::string &host = uplink->Get<const Anope::string>("host");
+ const Anope::string &host = uplink->Get<Anope::string>("host");
bool ipv6 = uplink->Get<bool>("ipv6");
int port = uplink->Get<int>("port");
- const Anope::string &password = uplink->Get<const Anope::string>("password");
+ const Anope::string &password = uplink->Get<Anope::string>("password");
ValidateNotEmpty("uplink", "host", host);
ValidateNotZero("uplink", "port", port);
@@ -212,7 +265,7 @@ Conf::Conf() : Block("")
{
Block *module = this->GetBlock("module", i);
- const Anope::string &modname = module->Get<const Anope::string>("name");
+ const Anope::string &modname = module->Get<Anope::string>("name");
ValidateNotEmpty("module", "name", modname);
@@ -223,11 +276,11 @@ Conf::Conf() : Block("")
{
Block *opertype = this->GetBlock("opertype", i);
- const Anope::string &oname = opertype->Get<const Anope::string>("name"),
- &modes = opertype->Get<const Anope::string>("modes"),
- &inherits = opertype->Get<const Anope::string>("inherits"),
- &commands = opertype->Get<const Anope::string>("commands"),
- &privs = opertype->Get<const Anope::string>("privs");
+ const Anope::string &oname = opertype->Get<Anope::string>("name"),
+ &modes = opertype->Get<Anope::string>("modes"),
+ &inherits = opertype->Get<Anope::string>("inherits"),
+ &commands = opertype->Get<Anope::string>("commands"),
+ &privs = opertype->Get<Anope::string>("privs");
ValidateNotEmpty("opertype", "name", oname);
@@ -254,7 +307,7 @@ Conf::Conf() : Block("")
if (ot2->GetName().equals_ci(str))
{
- Log() << "Inheriting commands and privs from " << ot2->GetName() << " to " << ot->GetName();
+ Anope::Logger.Log(_("Inheriting commands and privs from {0} to {1}"), ot2->GetName(), ot->GetName());
ot->Inherits(ot2);
break;
}
@@ -264,125 +317,7 @@ Conf::Conf() : Block("")
this->MyOperTypes.push_back(ot);
}
- for (int i = 0; i < this->CountBlock("oper"); ++i)
- {
- Block *oper = this->GetBlock("oper", i);
-
- const Anope::string &nname = oper->Get<const Anope::string>("name"),
- &type = oper->Get<const Anope::string>("type"),
- &password = oper->Get<const Anope::string>("password"),
- &certfp = oper->Get<const Anope::string>("certfp"),
- &host = oper->Get<const Anope::string>("host"),
- &vhost = oper->Get<const Anope::string>("vhost");
- bool require_oper = oper->Get<bool>("require_oper");
-
- ValidateNotEmpty("oper", "name", nname);
- ValidateNotEmpty("oper", "type", type);
-
- OperType *ot = NULL;
- for (unsigned j = 0; j < this->MyOperTypes.size(); ++j)
- if (this->MyOperTypes[j]->GetName() == type)
- ot = this->MyOperTypes[j];
- if (ot == NULL)
- throw ConfigException("Oper block for " + nname + " has invalid oper type " + type);
-
- Oper *o = new Oper(nname, ot);
- o->require_oper = require_oper;
- o->password = password;
- o->certfp = certfp;
- spacesepstream(host).GetTokens(o->hosts);
- o->vhost = vhost;
-
- this->Opers.push_back(o);
- }
-
- for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
- it->second->conf = false;
- for (int i = 0; i < this->CountBlock("service"); ++i)
- {
- Block *service = this->GetBlock("service", i);
-
- const Anope::string &nick = service->Get<const Anope::string>("nick"),
- &user = service->Get<const Anope::string>("user"),
- &host = service->Get<const Anope::string>("host"),
- &gecos = service->Get<const Anope::string>("gecos"),
- &modes = service->Get<const Anope::string>("modes"),
- &channels = service->Get<const Anope::string>("channels");
-
- ValidateNotEmpty("service", "nick", nick);
- ValidateNotEmpty("service", "user", user);
- ValidateNotEmpty("service", "host", host);
- ValidateNotEmpty("service", "gecos", gecos);
- ValidateNoSpaces("service", "channels", channels);
-
- BotInfo *bi = BotInfo::Find(nick, true);
- if (!bi)
- bi = new BotInfo(nick, user, host, gecos, modes);
- bi->conf = true;
-
- std::vector<Anope::string> oldchannels = bi->botchannels;
- bi->botchannels.clear();
- commasepstream sep(channels);
- for (Anope::string token; sep.GetToken(token);)
- {
- bi->botchannels.push_back(token);
- size_t ch = token.find('#');
- Anope::string chname, want_modes;
- if (ch == Anope::string::npos)
- chname = token;
- else
- {
- want_modes = token.substr(0, ch);
- chname = token.substr(ch);
- }
- bi->Join(chname);
- Channel *c = Channel::Find(chname);
- if (!c)
- continue; // Can't happen
-
- c->botchannel = true;
-
- /* Remove all existing modes */
- ChanUserContainer *cu = c->FindUser(bi);
- if (cu != NULL)
- for (size_t j = 0; j < cu->status.Modes().length(); ++j)
- c->RemoveMode(bi, ModeManager::FindChannelModeByChar(cu->status.Modes()[j]), bi->GetUID());
- /* Set the new modes */
- for (unsigned j = 0; j < want_modes.length(); ++j)
- {
- ChannelMode *cm = ModeManager::FindChannelModeByChar(want_modes[j]);
- if (cm == NULL)
- cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_modes[j]));
- if (cm && cm->type == MODE_STATUS)
- c->SetMode(bi, cm, bi->GetUID());
- }
- }
- for (unsigned k = 0; k < oldchannels.size(); ++k)
- {
- size_t ch = oldchannels[k].find('#');
- Anope::string chname = oldchannels[k].substr(ch != Anope::string::npos ? ch : 0);
-
- bool found = false;
- for (unsigned j = 0; j < bi->botchannels.size(); ++j)
- {
- ch = bi->botchannels[j].find('#');
- Anope::string ochname = bi->botchannels[j].substr(ch != Anope::string::npos ? ch : 0);
-
- if (chname.equals_ci(ochname))
- found = true;
- }
-
- if (found)
- continue;
-
- Channel *c = Channel::Find(chname);
- if (c)
- {
- c->botchannel = false;
- bi->Part(c);
- }
- }
- }
+ this->LoadBots();
for (int i = 0; i < this->CountBlock("log"); ++i)
{
@@ -394,38 +329,45 @@ Conf::Conf() : Block("")
LogInfo l(logage, rawio, debug);
- l.bot = BotInfo::Find(log->Get<const Anope::string>("bot", "Global"), true);
- spacesepstream(log->Get<const Anope::string>("target")).GetTokens(l.targets);
- spacesepstream(log->Get<const Anope::string>("source")).GetTokens(l.sources);
- spacesepstream(log->Get<const Anope::string>("admin")).GetTokens(l.admin);
- spacesepstream(log->Get<const Anope::string>("override")).GetTokens(l.override);
- spacesepstream(log->Get<const Anope::string>("commands")).GetTokens(l.commands);
- spacesepstream(log->Get<const Anope::string>("servers")).GetTokens(l.servers);
- spacesepstream(log->Get<const Anope::string>("channels")).GetTokens(l.channels);
- spacesepstream(log->Get<const Anope::string>("users")).GetTokens(l.users);
- spacesepstream(log->Get<const Anope::string>("other")).GetTokens(l.normal);
+ l.bot = ServiceBot::Find(log->Get<Anope::string>("bot", "Global"), true);
+ spacesepstream(log->Get<Anope::string>("target")).GetTokens(l.targets);
+ spacesepstream(log->Get<Anope::string>("source")).GetTokens(l.sources);
+ spacesepstream(log->Get<Anope::string>("admin")).GetTokens(l.admin);
+ spacesepstream(log->Get<Anope::string>("override")).GetTokens(l.override);
+ spacesepstream(log->Get<Anope::string>("commands")).GetTokens(l.commands);
+ spacesepstream(log->Get<Anope::string>("servers")).GetTokens(l.servers);
+ spacesepstream(log->Get<Anope::string>("channels")).GetTokens(l.channels);
+ spacesepstream(log->Get<Anope::string>("users")).GetTokens(l.users);
+ spacesepstream(log->Get<Anope::string>("other")).GetTokens(l.normal);
this->LogInfos.push_back(l);
}
- for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
- it->second->commands.clear();
+ for (std::pair<Anope::string, User *> p : UserListByNick)
+ {
+ User *u = p.second;
+ if (u->type != UserType::BOT)
+ continue;
+
+ ServiceBot *bi = anope_dynamic_static_cast<ServiceBot *>(u);
+ bi->commands.clear();
+ }
for (int i = 0; i < this->CountBlock("command"); ++i)
{
Block *command = this->GetBlock("command", i);
- const Anope::string &service = command->Get<const Anope::string>("service"),
- &nname = command->Get<const Anope::string>("name"),
- &cmd = command->Get<const Anope::string>("command"),
- &permission = command->Get<const Anope::string>("permission"),
- &group = command->Get<const Anope::string>("group");
+ const Anope::string &service = command->Get<Anope::string>("service"),
+ &nname = command->Get<Anope::string>("name"),
+ &cmd = command->Get<Anope::string>("command"),
+ &permission = command->Get<Anope::string>("permission"),
+ &group = command->Get<Anope::string>("group");
bool hide = command->Get<bool>("hide");
ValidateNotEmpty("command", "service", service);
ValidateNotEmpty("command", "name", nname);
ValidateNotEmpty("command", "command", cmd);
- BotInfo *bi = this->GetClient(service);
+ ServiceBot *bi = this->GetClient(service);
if (!bi)
continue;
@@ -434,26 +376,14 @@ Conf::Conf() : Block("")
ci.hide = hide;
}
- PrivilegeManager::ClearPrivileges();
- for (int i = 0; i < this->CountBlock("privilege"); ++i)
- {
- Block *privilege = this->GetBlock("privilege", i);
-
- const Anope::string &nname = privilege->Get<const Anope::string>("name"),
- &desc = privilege->Get<const Anope::string>("desc");
- int rank = privilege->Get<int>("rank");
-
- PrivilegeManager::AddPrivilege(Privilege(nname, desc, rank));
- }
-
for (int i = 0; i < this->CountBlock("fantasy"); ++i)
{
Block *fantasy = this->GetBlock("fantasy", i);
- const Anope::string &nname = fantasy->Get<const Anope::string>("name"),
- &service = fantasy->Get<const Anope::string>("command"),
- &permission = fantasy->Get<const Anope::string>("permission"),
- &group = fantasy->Get<const Anope::string>("group");
+ const Anope::string &nname = fantasy->Get<Anope::string>("name"),
+ &service = fantasy->Get<Anope::string>("command"),
+ &permission = fantasy->Get<Anope::string>("permission"),
+ &group = fantasy->Get<Anope::string>("group");
bool hide = fantasy->Get<bool>("hide"),
prepend_channel = fantasy->Get<bool>("prepend_channel", "yes");
@@ -462,6 +392,7 @@ Conf::Conf() : Block("")
CommandInfo &c = this->Fantasy[nname];
c.name = service;
+ c.cname = nname;
c.permission = permission;
c.group = group;
c.hide = hide;
@@ -472,8 +403,8 @@ Conf::Conf() : Block("")
{
Block *command_group = this->GetBlock("command_group", i);
- const Anope::string &nname = command_group->Get<const Anope::string>("name"),
- &description = command_group->Get<const Anope::string>("description");
+ const Anope::string &nname = command_group->Get<Anope::string>("name"),
+ &description = command_group->Get<Anope::string>("description");
CommandGroup gr;
gr.name = nname;
@@ -482,64 +413,152 @@ Conf::Conf() : Block("")
this->CommandGroups.push_back(gr);
}
- /* Below here can't throw */
+ for (int i = 0; i < this->CountBlock("usermode"); ++i)
+ {
+ Block *usermode = this->GetBlock("usermode", i);
- if (Config)
- /* Clear existing conf opers */
- for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it)
- {
- NickCore *nc = it->second;
- if (nc->o && std::find(Config->Opers.begin(), Config->Opers.end(), nc->o) != Config->Opers.end())
- nc->o = NULL;
- }
- /* Apply new opers */
- for (unsigned i = 0; i < this->Opers.size(); ++i)
+ Anope::string nname = usermode->Get<Anope::string>("name"),
+ character = usermode->Get<Anope::string>("character");
+ bool oper_only = usermode->Get<bool>("oper_only"),
+ setable = usermode->Get<bool>("setable"),
+ param = usermode->Get<bool>("param");
+
+ ValidateNotEmpty("usermode", "name", nname);
+
+ if (character.length() != 1)
+ throw ConfigException("Usermode character length must be 1");
+
+ Usermode um;
+ um.name = nname;
+ um.character = character[0];
+ um.param = param;
+ um.oper_only = oper_only;
+ um.setable = setable;
+
+ this->Usermodes.push_back(um);
+ }
+
+ for (int i = 0; i < this->CountBlock("channelmode"); ++i)
{
- Oper *o = this->Opers[i];
+ Block *channelmode = this->GetBlock("channelmode", i);
+
+ Anope::string nname = channelmode->Get<Anope::string>("name"),
+ character = channelmode->Get<Anope::string>("character"),
+ status = channelmode->Get<Anope::string>("status"),
+ param_regex = channelmode->Get<Anope::string>("param_regex");
+ bool oper_only = channelmode->Get<bool>("oper_only"),
+ setable = channelmode->Get<bool>("setable"),
+ list = channelmode->Get<bool>("list"),
+ param = channelmode->Get<bool>("param"),
+ param_unset = channelmode->Get<bool>("param_unset", "yes");
+ int level = channelmode->Get<int>("level");
+
+ ValidateNotEmpty("usermode", "name", nname);
+
+ if (character.length() != 1)
+ throw ConfigException("Channelmode character length must be 1");
+
+ if (status.length() > 1)
+ throw ConfigException("Channelmode status must be at most one character");
+
+ if (list || !param_regex.empty() || !status.empty())
+ param = true;
+
+ Channelmode cm;
+ cm.name = nname;
+ cm.character = character[0];
+ cm.status = !status.empty() ? status[0] : 0;
+ cm.param_regex = param_regex;
+ cm.oper_only = oper_only;
+ cm.setable = setable;
+ cm.list = list;
+ cm.param = param;
+ cm.param_unset = param_unset;
+ cm.level = level;
+
+ this->Channelmodes.push_back(cm);
+ }
- NickAlias *na = NickAlias::Find(o->name);
- if (!na)
- continue;
+ for (int i = 0; i < this->CountBlock("casemap"); ++i)
+ {
+ Block *casemap = this->GetBlock("casemap", i);
- if (!na->nc || na->nc->o)
+ unsigned char upper = casemap->Get<unsigned int>("upper"),
+ lower = casemap->Get<unsigned int>("lower");
+
+ if (!upper)
{
- // If the account is already an oper it might mean two oper blocks for the same nick, or
- // something else has configured them as an oper (like a module)
- continue;
+ Anope::string s = casemap->Get<Anope::string>("upper");
+ if (s.length() == 1)
+ upper = s[0];
}
- na->nc->o = o;
- Log() << "Tied oper " << na->nc->display << " to type " << o->ot->GetName();
- }
+ if (!lower)
+ {
+ Anope::string s = casemap->Get<Anope::string>("lower");
+ if (s.length() == 1)
+ lower = s[0];
+ }
- if (options->Get<const Anope::string>("casemap", "ascii") == "ascii")
- Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype<char>());
- else if (options->Get<const Anope::string>("casemap") == "rfc1459")
- Anope::casemap = std::locale(std::locale(), new Anope::rfc1459_ctype<char>());
- else
- {
- try
+ if (upper && lower)
{
- Anope::casemap = std::locale(options->Get<const Anope::string>("casemap").c_str());
+ CaseMapUpper[lower] = CaseMapUpper[upper] = upper;
+ CaseMapLower[lower] = CaseMapLower[upper] = lower;
}
- catch (const std::runtime_error &)
+ }
+
+ /* Below here can't throw */
+
+ /* Clear existing conf opers */
+ if (Config)
+ {
+ for (int i = 0; i < Config->CountBlock("oper"); ++i)
{
- Log() << "Unknown casemap " << options->Get<const Anope::string>("casemap") << " - casemap not changed";
+ Block *oper = Config->GetBlock("oper", i);
+
+ const Anope::string &nname = oper->Get<Anope::string>("name");
+
+ Oper *o = Oper::Find(nname);
+ if (o != nullptr)
+ {
+ o->Delete();
+ }
}
}
- Anope::CaseMapRebuild();
/* Check the user keys */
if (!options->Get<unsigned>("seed"))
- Log() << "Configuration option options:seed should be set. It's for YOUR safety! Remember that!";
+ Anope::Logger.Log(_("Configuration option options:seed should be set. It's for YOUR safety! Remember that!"));
+
+ /* check regexengine */
+ const Anope::string &regex_engine = options->Get<Anope::string>("regexengine");
+ if (regex_engine == "ecmascript")
+ regex_flags = std::regex::ECMAScript;
+ else if (regex_engine == "basic")
+ regex_flags = std::regex::basic;
+ else if (regex_engine == "extended")
+ regex_flags = std::regex::extended;
+ else if (regex_engine == "awk")
+ regex_flags = std::regex::awk;
+ else if (regex_engine == "grep")
+ regex_flags = std::regex::grep;
+ else if (regex_engine == "egrep")
+ regex_flags = std::regex::egrep;
+ else
+ regex_flags = static_cast<std::basic_regex<char>::flag_type>(0);
+ /* always enable icase and optimize */
+ if (regex_flags)
+ regex_flags |= std::regex::icase | std::regex::optimize;
+
+ this->LineWrap = options->Get<unsigned>("linewrap", "200");
}
Conf::~Conf()
{
for (unsigned i = 0; i < MyOperTypes.size(); ++i)
delete MyOperTypes[i];
- for (unsigned i = 0; i < Opers.size(); ++i)
- delete Opers[i];
+
+ delete locale;
}
void Conf::Post(Conf *old)
@@ -552,35 +571,188 @@ void Conf::Post(Conf *old)
if (std::find(old->ModulesAutoLoad.begin(), old->ModulesAutoLoad.end(), this->ModulesAutoLoad[i]) == old->ModulesAutoLoad.end())
ModuleManager::LoadModule(this->ModulesAutoLoad[i], NULL);
- /* Apply opertype changes, as non-conf opers still point to the old oper types */
- for (unsigned i = Oper::opers.size(); i > 0; --i)
+ LoadOpers();
+ ApplyBots();
+
+ ModeManager::Apply(old);
+
+ for (BotInfo *bi : Serialize::GetObjects<BotInfo *>())
{
- Oper *o = Oper::opers[i - 1];
+ if (!bi->conf)
+ {
+ bi->Delete();
+ continue;
+ }
- /* Oper's type is in the old config, so update it */
- if (std::find(old->MyOperTypes.begin(), old->MyOperTypes.end(), o->ot) != old->MyOperTypes.end())
+ for (int i = 0; i < bi->conf->CountBlock("channel"); ++i)
{
- OperType *ot = o->ot;
- o->ot = NULL;
+ Block *channel = bi->conf->GetBlock("channel", i);
+
+ const Anope::string &chname = channel->Get<Anope::string>("name"),
+ &modes = channel->Get<Anope::string>("modes");
+
+ bi->bot->Join(chname);
+
+ Channel *c = Channel::Find(chname);
+ if (!c)
+ continue; // Can't happen
- for (unsigned j = 0; j < MyOperTypes.size(); ++j)
- if (ot->GetName() == MyOperTypes[j]->GetName())
- o->ot = MyOperTypes[j];
+ c->botchannel = true;
- if (o->ot == NULL)
+ /* Remove all existing modes */
+ ChanUserContainer *cu = c->FindUser(bi->bot);
+ if (cu != NULL)
+ for (size_t j = 0; j < cu->status.Modes().length(); ++j)
+ c->RemoveMode(bi->bot, ModeManager::FindChannelModeByChar(cu->status.Modes()[j]), bi->bot->GetUID());
+ /* Set the new modes */
+ for (unsigned j = 0; j < modes.length(); ++j)
{
- /* Oper block has lost type */
- std::vector<Oper *>::iterator it = std::find(old->Opers.begin(), old->Opers.end(), o);
- if (it != old->Opers.end())
- old->Opers.erase(it);
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[j]);
+ if (cm == NULL)
+ cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(modes[j]));
+ if (cm && cm->type == MODE_STATUS)
+ c->SetMode(bi->bot, cm, bi->bot->GetUID());
+ }
+ }
+ }
+}
- it = std::find(this->Opers.begin(), this->Opers.end(), o);
- if (it != this->Opers.end())
- this->Opers.erase(it);
+void Conf::LoadBots()
+{
+ for (BotInfo *bi : Serialize::GetObjects<BotInfo *>())
+ bi->conf = nullptr;
+ for (int i = 0; i < this->CountBlock("service"); ++i)
+ {
+ Block *service = this->GetBlock("service", i);
+
+ const Anope::string &nick = service->Get<Anope::string>("nick"),
+ &user = service->Get<Anope::string>("user"),
+ &host = service->Get<Anope::string>("host"),
+ &gecos = service->Get<Anope::string>("gecos"),
+ &modes = service->Get<Anope::string>("modes"),
+ &channels = service->Get<Anope::string>("channels");
+
+ ValidateNotEmpty("service", "nick", nick);
+ ValidateNotEmpty("service", "user", user);
+ ValidateNotEmpty("service", "host", host);
+ ValidateNotEmpty("service", "gecos", gecos);
+ ValidateNoSpaces("service", "channels", channels);
- delete o;
+ if (User *u = User::Find(nick, true))
+ {
+ if (u->type != UserType::BOT)
+ {
+ u->Kill(Me, "Nickname required by services");
}
}
+
+ ServiceBot *sb = ServiceBot::Find(nick, true);
+ if (!sb)
+ sb = new ServiceBot(nick, user, host, gecos, modes);
+ }
+}
+
+void Conf::ApplyBots()
+{
+ /* Associate conf bots with db bots */
+ for (BotInfo *bi : Serialize::GetObjects<BotInfo *>())
+ {
+ ServiceBot *sb = ServiceBot::Find(bi->GetNick());
+
+ if (sb == nullptr)
+ continue;
+
+ bi->bot = sb;
+ sb->bi = bi;
+ }
+
+ /* Apply conf to conf bots */
+ for (int i = 0; i < this->CountBlock("service"); ++i)
+ {
+ Block *service = this->GetBlock("service", i);
+
+ const Anope::string &nick = service->Get<Anope::string>("nick");
+
+ for (BotInfo *bi : Serialize::GetObjects<BotInfo *>())
+ if (bi->GetNick().equals_ci(nick))
+ bi->conf = this;
+ }
+
+ /* Create new bots for new conf bots */
+ for (std::pair<Anope::string, User *> p : UserListByNick)
+ {
+ User *u = p.second;
+ if (u->type != UserType::BOT)
+ continue;
+
+ ServiceBot *sb = anope_dynamic_static_cast<ServiceBot *>(u);
+ if (sb->bi != nullptr)
+ continue;
+
+ sb->bi = Serialize::New<BotInfo *>();
+ sb->bi->bot = sb;
+
+ sb->bi->conf = this;
+
+ sb->bi->SetNick(sb->nick);
+ sb->bi->SetUser(sb->GetIdent());
+ sb->bi->SetHost(sb->host);
+ sb->bi->SetRealName(sb->realname);
+ sb->bi->SetCreated(Anope::CurTime);
+ }
+}
+
+void Conf::LoadOpers()
+{
+ for (int i = 0; i < this->CountBlock("oper"); ++i)
+ {
+ Block *oper = this->GetBlock("oper", i);
+
+ const Anope::string &nname = oper->Get<Anope::string>("name"),
+ &type = oper->Get<Anope::string>("type"),
+ &password = oper->Get<Anope::string>("password"),
+ &certfp = oper->Get<Anope::string>("certfp"),
+ &host = oper->Get<Anope::string>("host"),
+ &vhost = oper->Get<Anope::string>("vhost");
+ bool require_oper = oper->Get<bool>("require_oper");
+
+ ValidateNotEmpty("oper", "name", nname);
+ ValidateNotEmpty("oper", "type", type);
+
+ OperType *ot = NULL;
+ for (unsigned j = 0; j < this->MyOperTypes.size(); ++j)
+ if (this->MyOperTypes[j]->GetName() == type)
+ ot = this->MyOperTypes[j];
+ if (ot == NULL)
+ {
+ Anope::Logger.Log(_("Oper block for {0} has invalid oper type {1}"), nname, type);
+ continue;
+ }
+
+ Oper *o = Oper::Find(nname);
+ if (o == nullptr)
+ o = Serialize::New<Oper *>();
+
+ o->SetName(nname);
+ o->SetType(ot);
+ o->SetRequireOper(require_oper);
+ o->SetPassword(password);
+ o->SetCertFP(certfp);
+ o->SetHost(host);
+ o->SetVhost(vhost);
+
+ Anope::Logger.Debug(_("Creating oper {0} of type {1}"), nname, ot->GetName());
+ }
+
+ /* Apply new opers */
+ for (Oper *o : Serialize::GetObjects<Oper *>())
+ {
+ NickServ::Nick *na = NickServ::FindNick(o->GetName());
+ if (!na)
+ continue;
+
+ na->GetAccount()->SetOper(o);
+ Anope::Logger.Log(_("Tied oper {0} to type {1}"), na->GetAccount()->GetDisplay(), o->GetType()->GetName());
}
}
@@ -605,24 +777,31 @@ Block *Conf::GetModule(const Anope::string &mname)
{
Block *b = &iters.first->second;
- if (b->Get<const Anope::string>("name") == mname)
+ if (b->Get<Anope::string>("name") == mname)
{
block = b;
break;
}
}
- return GetModule(mname);
+ if (block == nullptr)
+ {
+ /* not found, create new block */
+ auto it2 = blocks.emplace(mname, mname);
+ block = &it2->second;
+ }
+
+ return block;
}
-BotInfo *Conf::GetClient(const Anope::string &cname)
+ServiceBot *Conf::GetClient(const Anope::string &cname)
{
Anope::map<Anope::string>::iterator it = bots.find(cname);
if (it != bots.end())
- return BotInfo::Find(!it->second.empty() ? it->second : cname, true);
+ return ServiceBot::Find(!it->second.empty() ? it->second : cname, true);
Block *block = GetModule(cname.lower());
- const Anope::string &client = block->Get<const Anope::string>("client");
+ const Anope::string &client = block->Get<Anope::string>("client");
bots[cname] = client;
return GetClient(cname);
}
@@ -635,7 +814,7 @@ Block *Conf::GetCommand(CommandSource &source)
{
Block *b = &iters.first->second;
- if (b->Get<Anope::string>("name") == source.command)
+ if (b->Get<Anope::string>("name") == source.GetCommand())
return b;
}
@@ -720,7 +899,7 @@ void Conf::LoadConf(File &file)
int linenumber = 0;
bool in_word = false, in_quote = false, in_comment = false;
- Log(LOG_DEBUG) << "Start to read conf " << file.GetName();
+ Anope::Logger.Debug("Start to read conf {0}", file.GetName());
// Start reading characters...
while (!file.End())
{
@@ -731,7 +910,7 @@ void Conf::LoadConf(File &file)
if (line.empty() && in_quote)
wordbuffer += "\n";
- for (unsigned c = 0, len = line.length(); c < len; ++c)
+ for (unsigned int c = 0, len = line.length(); c < len; ++c)
{
char ch = line[c];
if (in_quote)
@@ -880,17 +1059,17 @@ void Conf::LoadConf(File &file)
Block *b = block_stack.top();
if (b)
- Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'";
+ Anope::Logger.Debug("ln {0} EOL: s='{1}' '{2}' set to '{3}'", linenumber, b->name, itemname, wordbuffer);
/* Check defines */
for (int i = 0; i < this->CountBlock("define"); ++i)
{
Block *define = this->GetBlock("define", i);
- const Anope::string &dname = define->Get<const Anope::string>("name");
+ const Anope::string &dname = define->Get<Anope::string>("name");
if (dname == wordbuffer && define != b)
- wordbuffer = define->Get<const Anope::string>("value");
+ wordbuffer = define->Get<Anope::string>("value");
}
if (b)
@@ -925,3 +1104,4 @@ void Conf::LoadConf(File &file)
if (!block_stack.empty())
throw ConfigException("Unterminated block at end of file: " + file.GetName() + ". Block was opened on line " + stringify(block_stack.top()->linenum));
}
+