diff options
Diffstat (limited to 'src/config.cpp')
-rw-r--r-- | src/config.cpp | 734 |
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 ®ex_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)); } + |