From 1d0bb9b26b7ad58ab0bf979ac046f4511b3bf12b Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 5 May 2013 01:55:04 -0400 Subject: Rework the config file reader to be much more flexible and move many configuration directives to the actual modules they are used in. --- src/bots.cpp | 68 +- src/channels.cpp | 97 +-- src/command.cpp | 6 +- src/config.cpp | 2119 ++++++++++++------------------------------------- src/configreader.cpp | 116 --- src/init.cpp | 24 +- src/language.cpp | 15 +- src/logger.cpp | 5 +- src/mail.cpp | 21 +- src/main.cpp | 6 +- src/messages.cpp | 46 +- src/misc.cpp | 40 +- src/modes.cpp | 82 +- src/modulemanager.cpp | 3 +- src/nickalias.cpp | 9 +- src/nickcore.cpp | 14 +- src/opertype.cpp | 4 +- src/protocol.cpp | 37 +- src/regchannel.cpp | 42 +- src/servers.cpp | 34 +- src/uplink.cpp | 24 +- src/users.cpp | 75 +- src/xline.cpp | 8 +- 23 files changed, 714 insertions(+), 2181 deletions(-) delete mode 100644 src/configreader.cpp (limited to 'src') diff --git a/src/bots.cpp b/src/bots.cpp index f1a96eacf..fcbedeeb3 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -23,7 +23,7 @@ Serialize::Checker BotListByNick("BotInfo"), BotListByUID("BotInfo" BotInfo *BotServ = NULL, *ChanServ = NULL, *Global = NULL, *HostServ = NULL, *MemoServ = NULL, *NickServ = NULL, *OperServ = NULL; -BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const Anope::string &nhost, const Anope::string &nreal, const Anope::string &bmodes) : User(nnick, nuser, nhost, "", "", Me, nreal, Anope::CurTime, "", Servers::TS6_UID_Retrieve()), Serializable("BotInfo"), botmodes(bmodes) +BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const Anope::string &nhost, const Anope::string &nreal, const Anope::string &bmodes) : User(nnick, nuser, nhost, "", "", Me, nreal, Anope::CurTime, "", Servers::TS6_UID_Retrieve()), Serializable("BotInfo"), channels("ChannelInfo"), botmodes(bmodes) { this->lastmsg = this->created = Anope::CurTime; this->introduced = false; @@ -58,15 +58,10 @@ BotInfo::~BotInfo() IRCD->SendSQLineDel(&x); } - for (registered_channel_map::const_iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it) + for (std::set::iterator it = this->channels->begin(), it_end = this->channels->end(); it != it_end; ++it) { - ChannelInfo *ci = it->second; - - if (ci->bi == this) - { - ci->QueueUpdate(); - ci->bi = NULL; - } + ChannelInfo *ci = *it; + this->UnAssign(NULL, ci); } BotListByNick->erase(this->nick); @@ -129,21 +124,15 @@ void BotInfo::SetNewNick(const Anope::string &newnick) (*BotListByNick)[this->nick] = this; } -void BotInfo::RejoinAll() +const std::set &BotInfo::GetChannels() const { - for (registered_channel_map::const_iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it) - { - const ChannelInfo *ci = it->second; - - if (ci->bi == this && ci->c && ci->c->users.size() >= Config->BSMinUsers) - this->Join(ci->c); - } + return this->channels; } void BotInfo::Assign(User *u, ChannelInfo *ci) { EventReturn MOD_RESULT = EVENT_CONTINUE; - FOREACH_RESULT(I_OnBotAssign, OnBotAssign(u, ci, this)); + FOREACH_RESULT(I_OnPreBotAssign, OnPreBotAssign(u, ci, this)); if (MOD_RESULT == EVENT_STOP) return; @@ -151,8 +140,10 @@ void BotInfo::Assign(User *u, ChannelInfo *ci) ci->bi->UnAssign(u, ci); ci->bi = this; - if (Me->IsSynced() && ci->c && ci->c->users.size() >= Config->BSMinUsers) - this->Join(ci->c, &ModeManager::DefaultBotModes); + this->channels->insert(ci); + + ChannelStatus status; + FOREACH_MOD(I_OnBotAssign, OnBotAssign(u, ci, this)); } void BotInfo::UnAssign(User *u, ChannelInfo *ci) @@ -171,19 +162,12 @@ void BotInfo::UnAssign(User *u, ChannelInfo *ci) } ci->bi = NULL; + this->channels->erase(ci); } unsigned BotInfo::GetChannelCount() const { - unsigned count = 0; - for (registered_channel_map::const_iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it) - { - const ChannelInfo *ci = it->second; - - if (ci->bi == this) - ++count; - } - return count; + return this->channels->size(); } void BotInfo::Join(Channel *c, ChannelStatus *status) @@ -191,35 +175,9 @@ void BotInfo::Join(Channel *c, ChannelStatus *status) if (c->FindUser(this) != NULL) return; - if (Config && IRCD && Config->BSSmartJoin) - { - std::pair bans = c->GetModeList("BAN"); - - /* We check for bans */ - for (; bans.first != bans.second; ++bans.first) - { - Entry ban("BAN", bans.first->second); - if (ban.Matches(this)) - c->RemoveMode(NULL, "BAN", ban.GetMask()); - } - - Anope::string Limit; - unsigned limit = 0; - if (c->GetParam("LIMIT", Limit) && Limit.is_pos_number_only()) - limit = convertTo(Limit); - - /* Should we be invited? */ - if (c->HasMode("INVITE") || (limit && c->users.size() >= limit)) - IRCD->SendNotice(this, "@" + c->name, "%s invited %s into the channel.", this->nick.c_str(), this->nick.c_str()); - - ModeManager::ProcessModes(); - } - c->JoinUser(this); if (IRCD) IRCD->SendJoin(this, c, status); - - FOREACH_MOD(I_OnBotJoin, OnBotJoin(c, this)); } void BotInfo::Join(const Anope::string &chname, ChannelStatus *status) diff --git a/src/channels.cpp b/src/channels.cpp index 4d08661ef..5001869da 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -89,17 +89,7 @@ void Channel::Reset() void Channel::Sync() { - if (!this->HasMode("PERM") && (this->users.empty() || (this->users.size() == 1 && this->ci && this->ci->bi && *this->ci->bi == this->users.begin()->second->user))) - { - this->Hold(); - } - if (this->ci) - { - this->CheckModes(); - - if (Me && Me->IsSynced()) - this->ci->RestoreTopic(); - } + FOREACH_MOD(I_OnChannelSync, OnChannelSync(this)); } void Channel::CheckModes() @@ -168,6 +158,8 @@ ChanUserContainer* Channel::JoinUser(User *user) if (user->server && user->server->IsSynced()) Log(user, this, "join"); + FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(user, this)); + ChanUserContainer *cuc = new ChanUserContainer(user, this); user->chans[this] = cuc; this->users[user] = cuc; @@ -401,16 +393,8 @@ void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *cm, const A FOREACH_RESULT(I_OnChannelModeUnset, OnChannelModeUnset(this, setter, cm->name, param)); if (enforce_mlock && MOD_RESULT != EVENT_STOP) - { - /* Reset modes on bots if we're supposed to */ - if (this->ci && this->ci->bi && this->ci->bi == bi) - { - if (ModeManager::DefaultBotModes.HasMode(cm->mchar)) - this->SetMode(bi, cm, bi->GetUID()); - } - this->SetCorrectModes(u, false, false); - } + return; } @@ -790,22 +774,19 @@ void Channel::KickInternal(MessageSource &source, const Anope::string &nick, con Anope::string chname = this->name; - if (target->FindChannel(this)) + ChanUserContainer *cu = target->FindChannel(this); + if (cu == NULL) { - FOREACH_MOD(I_OnUserKicked, OnUserKicked(this, target, source, reason)); - if (bi) - this->Extend("INHABIT"); - this->DeleteUser(target); - } - else Log() << "Channel::KickInternal got kick for user " << target->nick << " from " << source.GetSource() << " who isn't on channel " << this->name; - - /* Bots get rejoined */ - if (bi) - { - bi->Join(this, &ModeManager::DefaultBotModes); - this->Shrink("INHABIT"); + return; } + + Anope::string this_name = this->name; + ChannelStatus status = cu->status; + + FOREACH_MOD(I_OnPreUserKicked, OnPreUserKicked(source, cu, reason)); + this->DeleteUser(target); /* This can delete this; */ + FOREACH_MOD(I_OnUserKicked, OnUserKicked(source, target, this_name, status, reason)); } bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...) @@ -873,54 +854,6 @@ void Channel::ChangeTopic(const Anope::string &user, const Anope::string &newtop this->ci->CheckTopic(); } -void Channel::Hold() -{ - /** A timer used to keep the BotServ bot/ChanServ in the channel - * after kicking the last user in a channel - */ - class ChanServTimer : public Timer - { - private: - Reference c; - - public: - /** Constructor - * @param chan The channel - */ - ChanServTimer(Channel *chan) : Timer(Config->CSInhabit), c(chan) - { - if (!ChanServ || !c) - return; - c->Extend("INHABIT"); - if (!c->ci || !c->ci->bi) - ChanServ->Join(c); - else if (!c->FindUser(c->ci->bi)) - c->ci->bi->Join(c); - } - - /** Called when the delay is up - * @param The current time - */ - void Tick(time_t) anope_override - { - if (!c) - return; - - c->Shrink("INHABIT"); - - if (!c->ci || !c->ci->bi) - { - if (ChanServ) - ChanServ->Part(c); - } - else if (c->users.size() == 1 || c->users.size() < Config->BSMinUsers) - c->ci->bi->Part(c); - } - }; - - new ChanServTimer(this); -} - void Channel::SetCorrectModes(User *user, bool give_modes, bool check_noop) { if (user == NULL) @@ -980,6 +913,8 @@ void Channel::SetCorrectModes(User *user, bool give_modes, bool check_noop) } } } + + FOREACH_MOD(I_OnSetCorrectModes, OnSetCorrectModes(user, this, u_access, give_modes)); } bool Channel::Unban(User *u, bool full) diff --git a/src/command.cpp b/src/command.cpp index dc095fdd8..db4bb9996 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -191,7 +191,7 @@ void Command::OnSyntaxError(CommandSource &source, const Anope::string &subcomma this->SendSyntax(source); bool has_help = source.service->commands.find("HELP") != source.service->commands.end(); if (has_help) - source.Reply(MORE_INFO, Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str(), source.command.c_str()); + source.Reply(MORE_INFO, Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), source.command.c_str()); } void RunCommand(CommandSource &source, const Anope::string &message) @@ -216,7 +216,7 @@ void RunCommand(CommandSource &source, const Anope::string &message) if (it == source.service->commands.end()) { if (has_help) - source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str()); + source.Reply(_("Unknown command \002%s\002. \"%s %s HELP\" for help."), message.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str()); else source.Reply(_("Unknown command \002%s\002."), message.c_str()); return; @@ -227,7 +227,7 @@ void RunCommand(CommandSource &source, const Anope::string &message) if (!c) { if (has_help) - source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->UseStrictPrivMsgString.c_str(), source.service->nick.c_str()); + source.Reply(_("Unknown command \002%s\002. \"%s%s HELP\" for help."), message.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str()); else source.Reply(_("Unknown command \002%s\002."), message.c_str()); Log(source.service) << "Command " << it->first << " exists on me, but its service " << info.name << " was not found!"; diff --git a/src/config.cpp b/src/config.cpp index bc01a1589..38e072de8 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -25,1020 +25,588 @@ #include #endif -/*************************************************************************/ +using namespace Configuration; -ConfigurationFile ServicesConf("services.conf", false); // Services configuration file name -ServerConfig *Config = NULL; +File ServicesConf("services.conf", false); // Services configuration file name +Conf *Config = NULL; -static Anope::string UlineServers; -static Anope::string BSDefaults; -static Anope::string CSDefaults; -static Anope::string NSDefaults; - -/*************************************************************************/ - -ServerConfig::ServerConfig() +Block::Block(const Anope::string &n) : name(n) { - this->Read(); - - if (NSDefaults.empty()) - { - this->NSDefFlags.insert("SECURE"); - this->NSDefFlags.insert("MEMO_SIGNON"); - this->NSDefFlags.insert("MEMO_RECEIVE"); - } - else if (!NSDefaults.equals_ci("none")) - { - spacesepstream options(NSDefaults); - Anope::string option; - while (options.GetToken(option)) - { - if (option.equals_ci("msg")) - { - if (!this->UsePrivmsg) - Log() << "msg in can only be used when options:useprivmsg is set"; - else - this->NSDefFlags.insert(option.upper()); - } - else - this->NSDefFlags.insert(option.upper()); - } - } - - if (this->CSDefBantype < 0 || this->CSDefBantype > 3) - { - throw ConfigException("Value of CSDefBantype must be between 0 and 3 included"); - } - - if (CSDefaults.empty()) - { - this->CSDefFlags.insert("KEEPTOPIC"); - this->CSDefFlags.insert("SECURE"); - this->CSDefFlags.insert("SECUREFOUNDER"); - this->CSDefFlags.insert("SIGNKICK"); - } - else if (!CSDefaults.equals_ci("none")) - { - spacesepstream options(CSDefaults); - Anope::string option; - while (options.GetToken(option)) - this->CSDefFlags.insert(option.upper()); - } - - if (UseStrictPrivMsg) - UseStrictPrivMsgString = "/"; - else - UseStrictPrivMsgString ="/msg "; - - - if (!BSDefaults.empty()) - { - spacesepstream options(BSDefaults); - Anope::string option; - while (options.GetToken(option)) - this->BSDefFlags.insert("BS_" + option.upper()); - } - - /* Ulines */ - if (!UlineServers.empty()) - { - this->Ulines.clear(); - - spacesepstream ulines(UlineServers); - Anope::string uline; - while (ulines.GetToken(uline)) - this->Ulines.push_back(uline); - } - - if (this->LimitSessions) - { - if (this->MaxSessionKill && !this->SessionAutoKillExpiry) - this->SessionAutoKillExpiry = 1800; /* 30 minutes */ - } - - /* Check the user keys */ - if (this->Seed == 0) - Log() << "Configuration option options:seed should be set. It's for YOUR safety! Remember that!"; - - ModeManager::UpdateDefaultMLock(this); - - if (this->CaseMap == "ascii") - Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype()); - else if (this->CaseMap == "rfc1459") - Anope::casemap = std::locale(std::locale(), new Anope::rfc1459_ctype()); - else - { - try - { - Anope::casemap = std::locale(this->CaseMap.c_str()); - } - catch (const std::runtime_error &) - { - Log() << "Unknown casemap " << this->CaseMap << " - casemap not changed"; - } - } - Anope::CaseMapRebuild(); - - if (this->SessionIPv4CIDR > 32 || this->SessionIPv6CIDR > 128) - throw ConfigException("Session CIDR value out of range"); - - ConfigReader reader(this); - FOREACH_MOD(I_OnReload, OnReload(this, reader)); - -#ifndef _WIN32 - if (!this->User.empty()) - { - errno = 0; - struct passwd *u = getpwnam(this->User.c_str()); - if (u == NULL) - Log() << "Unable to setuid to " << this->User << ": " << Anope::LastError(); - else if (setuid(u->pw_uid) == -1) - Log() << "Unable to setuid to " << this->User << ": " << Anope::LastError(); - else - Log() << "Successfully set user to " << this->User; - } - if (!this->Group.empty()) - { - errno = 0; - struct group *g = getgrnam(this->Group.c_str()); - if (g == NULL) - Log() << "Unable to setgid to " << this->Group << ": " << Anope::LastError(); - else if (setuid(g->gr_gid) == -1) - Log() << "Unable to setgid to " << this->Group << ": " << Anope::LastError(); - else - Log() << "Successfully set group to " << this->Group; - } -#endif } -bool ServerConfig::CheckOnce(const Anope::string &tag) +const Anope::string &Block::GetName() const { - int count = ConfValueEnum(config_data, tag); - if (count > 1) - throw ConfigException("You have more than one <" + tag + "> tag, this is not permitted."); - if (count < 1) - throw ConfigException("You have not defined a <" + tag + "> tag, this is required."); - return true; + return name; } -bool NoValidation(ServerConfig *, const Anope::string &, const Anope::string &, ValueItem &) +int Block::CountBlock(const Anope::string &bname) { - return true; -} - -void ServerConfig::ValidateNoSpaces(const Anope::string &p, const Anope::string &tag, const Anope::string &val) const -{ - for (Anope::string::const_iterator ptr = p.begin(), end = p.end(); ptr != end; ++ptr) - if (*ptr == ' ') - throw ConfigException("The value of <" + tag + ":" + val + "> cannot contain spaces"); -} - -/* NOTE: Before anyone asks why we're not using inet_pton for this, it is because inet_pton and friends do not return so much detail, - * even in LastError(). They just return 'yes' or 'no' to an address without such detail as to whats WRONG with the address. - * Because ircd users arent as technical as they used to be (;)) we are going to give more of a useful error message. - */ -void ServerConfig::ValidateIP(const Anope::string &p, const Anope::string &tag, const Anope::string &val, bool wild) const -{ - int num_dots = 0, num_seps = 0; - bool not_numbers = false, not_hex = false; - - if (!p.empty()) - { - if (p[0] == '.') - throw ConfigException("The value of <" + tag + ":" + val + "> is not an IP address"); - - for (Anope::string::const_iterator ptr = p.begin(), end = p.end(); ptr != end; ++ptr) - { - if (wild && (*ptr == '*' || *ptr == '?' || *ptr == '/')) - continue; - - if (*ptr != ':' && *ptr != '.' && (*ptr < '0' || *ptr > '9')) - { - not_numbers = true; - if (toupper(*ptr) < 'A' || toupper(*ptr) > 'F') - not_hex = true; - } - switch (*ptr) - { - case ' ': - throw ConfigException("The value of <" + tag + ":" + val + "> is not an IP address"); - case '.': - ++num_dots; - break; - case ':': - ++num_seps; - } - } - if (num_dots > 3) - throw ConfigException("The value of <" + tag + ":" + val + "> is an IPv4 address with too many fields!"); - - if (num_seps > 8) - throw ConfigException("The value of <" + tag + ":" + val + "> is an IPv6 address with too many fields!"); - - if (!num_seps && num_dots < 3 && !wild) - throw ConfigException("The value of <" + tag + ":" + val + "> looks to be a malformed IPv4 address"); - - if (!num_seps && num_dots == 3 && not_numbers) - throw ConfigException("The value of <" + tag + ":" + val + "> contains non-numeric characters in an IPv4 address"); - - if (num_seps && not_hex) - throw ConfigException("The value of <" + tag + ":" + val + "> contains non-hexdecimal characters in an IPv6 address"); - - if (num_seps && num_dots != 3 && num_dots && !wild) - throw ConfigException("The value of <" + tag + ":" + val + "> is a malformed IPv6 4in6 address"); - } + if (!this) + return 0; + + return blocks.count(bname); } -void ServerConfig::ValidateHostname(const Anope::string &p, const Anope::string &tag, const Anope::string &val) const +Block* Block::GetBlock(const Anope::string &bname, int num) { - if (p.equals_ci("localhost")) - return; + if (!this) + return NULL; + + std::pair it = blocks.equal_range(bname); - int num_dots = 0, num_seps = 0; - if (!p.empty()) - { - if (p[0] == '.') - throw ConfigException("The value of <" + tag + ":" + val + "> is not a valid hostname"); - for (unsigned i = 0, end = p.length(); i < end; ++i) - { - switch (p[i]) - { - case ' ': - throw ConfigException("The value of <" + tag + ":" + val + "> is not a valid hostname"); - case '.': - ++num_dots; - break; - case ':': - ++num_seps; - break; - } - } - if (!num_dots && !num_seps) - throw ConfigException("The value of <" + tag + ":" + val + "> is not a valid hostname"); - } + for (int i = 0; it.first != it.second; ++it.first, ++i) + if (i == num) + return &it.first->second; + return NULL; } -static bool ValidateNotEmpty(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data) +bool Block::Set(const Anope::string &tag, const Anope::string &value) { - if (data.GetValue().empty()) - throw ConfigException("The value for <" + tag + ":" + value + "> cannot be empty!"); - return true; -} + if (!this) + return false; -static bool ValidateNotZero(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data) -{ - if (!data.GetInteger() && Anope::DoTime(data.GetValue()) <= 0) - throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero!"); + items[tag] = value; return true; } -static bool ValidateEmailReg(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) +const Block::item_map* Block::GetItems() const { - if (!config->NSRegistration.equals_ci("none") && !config->NSRegistration.equals_ci("disable")) - { - if (value.equals_ci("unconfirmedexpire")) - { - if (!data.GetInteger() && Anope::DoTime(data.GetValue()) <= 0) - throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero when e-mail or admin registration is enabled!"); - } - else - { - if (!data.GetBool()) - throw ConfigException("The value for <" + tag + ":" + value + "> must be set to yes when e-mail or admin registrations is enabled!"); - } - } - return true; + if (this) + return &items; + else + return NULL; } -static bool ValidatePort(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data) +template<> const Anope::string& Block::Get(const Anope::string &tag, const Anope::string& def) const { - int port = data.GetInteger(); - if (!port) - return true; - if (port < 1 || port > 65535) - throw ConfigException("The value for <" + tag + ":" + value + "> is not a value port, it must be between 1 and 65535!"); - return true; -} + if (!this) + return def; -static bool ValidateBantype(ServerConfig *, const Anope::string &, const Anope::string &, ValueItem &data) -{ - int bantype = data.GetInteger(); - if (bantype < 0 || bantype > 3) - throw ConfigException("The value for must be between 0 and 3!"); - return true; -} + Anope::map::const_iterator it = items.find(tag); + if (it != items.end()) + return it->second; -static bool ValidateNickServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) -{ - if (!config->NickServ.empty()) - { - if (value.equals_ci("releasetimeout") || value.equals_ci("accessmax") || value.equals_ci("listmax")) - return ValidateNotZero(config, tag, value, data); - else if (value.equals_ci("enforceruser") || value.equals_ci("enforcerhost")) - return ValidateNotEmpty(config, tag, value, data); - else if (value.equals_ci("guestnickprefix")) - { - ValidateNotEmpty(config, tag, value, data); - if (data.GetValue().length() > 21) - throw ConfigException("The value for cannot exceed 21 characters in length!"); - } - else if (value.equals_ci("registration")) - if (!data.GetValue().equals_ci("none") && !data.GetValue().equals_ci("mail") && !data.GetValue().equals_ci("admin") && !data.GetValue().equals_ci("disable")) - throw ConfigException("The value for must be one of \"none\", \"mail\", \"admin\", or \"disable\""); - } - return true; + return def; } -static bool ValidateChanServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) +template<> time_t Block::Get(const Anope::string &tag, const Anope::string &def) const { - if (!config->ChanServ.empty()) - { - if ((value.equals_ci("decription") || value.equals_ci("autokickreason")) && data.GetValue().empty()) - throw ConfigException("The value for <" + tag + ":" + value + "> cannot be empty when ChanServ is enabled!"); - else if (value.equals_ci("defbantype")) - return ValidateBantype(config, tag, value, data); - else if (value.equals_ci("accessmax") || value.equals_ci("autokickmax") || value.equals_ci("inhabit") || value.equals_ci("listmax")) - return ValidateNotZero(config, tag, value, data); - } - return true; + return Anope::DoTime(Get(tag, def)); } -static bool ValidateBotServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) +template<> const char* Block::Get(const Anope::string &tag, const Anope::string &def) const { - if (!config->BotServ.empty()) - { - if (value.equals_ci("badwordsmax") || value.equals_ci("keepdata")) - { - if (!data.GetInteger() && Anope::DoTime(data.GetValue()) <= 0) - throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero when BotServ is enabled!"); - } - else if (value.equals_ci("minusers")) - { - if (data.GetInteger() < 0) - throw ConfigException("The value for <" + tag + ":" + value + "> must be greater than or equal to zero!"); - } - } - return true; + return this->Get(tag, def).c_str(); } -static bool ValidateLimitSessions(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) +template<> bool Block::Get(const Anope::string &tag, const Anope::string &def) const { - if (config->LimitSessions) - { - if (value.equals_ci("maxsessionlimit") || value.equals_ci("exceptionexpiry")) - { - if (!data.GetInteger() && Anope::DoTime(data.GetValue()) <= 0) - throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero when session limiting is enabled!"); - } - } - return true; + const Anope::string &str = Get(tag, def); + return str.equals_ci("yes") || str.equals_ci("on") || str.equals_ci("true"); } -static bool ValidateOperServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) +static void ValidateNotEmpty(const Anope::string &block, const Anope::string &name, const Anope::string &value) { - if (!config->OperServ.empty()) - { - if (value.equals_ci("autokillexpiry") || value.equals_ci("chankillexpiry") || value.equals_ci("snlineexpiry") || value.equals_ci("sqlineexpiry")) - return ValidateNotZero(config, tag, value, data); - else if (value.equals_ci("maxsessionlimit") || value.equals_ci("exceptionexpiry")) - return ValidateLimitSessions(config, tag, value, data); - } - return true; + if (value.empty()) + throw ConfigException("The value for <" + block + ":" + name + "> cannot be empty!"); } -static bool ValidateNickLen(ServerConfig *, const Anope::string &, const Anope::string &, ValueItem &data) +template static void ValidateNotZero(const Anope::string &block, const Anope::string &name, T value) { - int nicklen = data.GetInteger(); - if (!nicklen) - { - Log() << "You have not defined the directive. It is strongly"; - Log() << "adviced that you do configure this correctly in your services.conf"; - data.Set(31); - } - else if (nicklen < 1) - { - Log() << " has an invalid value; setting to 31"; - data.Set(31); - } - return true; + if (!value) + throw ConfigException("The value for <" + block + ":" + name + "> cannot be zero!"); } -static bool ValidateMail(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) +Conf::Conf() : Block("") { - if (config->UseMail) - { - Anope::string check[] = { "sendmailpath", "sendfrom", "registration_subject", "registration_message", "emailchange_subject", "emailchange_message", "memo_subject", "memo_message", "" }; - for (int i = 0; !check[i].empty(); ++i) - if (value.equals_ci(check[i])) - if (data.GetValue().empty()) - throw ConfigException("The value for <" + tag + ":" + value + "> cannot be empty when e-mail is enabled!"); - } - return true; -} + ReadTimeout = 0; + UsePrivmsg = DefPrivmsg = false; -static bool ValidateGlobalOnCycle(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) -{ - if (config->GlobalOnCycle) - { - if (data.GetValue().empty()) - { - Log() << "<" << tag << ":" << value << "> was undefined, disabling "; - config->GlobalOnCycle = false; - } - } - return true; -} + this->LoadConf(ServicesConf); -static bool InitUplinks(ServerConfig *config, const Anope::string &) -{ - if (!config->Uplinks.empty()) + for (int i = 0; i < this->CountBlock("include"); ++i) { - std::vector::iterator curr_uplink = config->Uplinks.begin(), end_uplink = config->Uplinks.end(); - for (; curr_uplink != end_uplink; ++curr_uplink) - delete *curr_uplink; - } - config->Uplinks.clear(); - return true; -} - -static bool DoUplink(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - // Validation variables - Anope::string host = values[0].GetValue(), password = values[3].GetValue(); - int port = values[2].GetInteger(); - bool ipv6 = values[1].GetBool(); - ValueItem vi_host(host), vi_port(port), vi_password(password); - // Validate the host to make sure it is not empty - if (!ValidateNotEmpty(config, "uplink", "host", vi_host)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - // Validate the port to make sure it is a valid port - if (!ValidatePort(config, "uplink", "port", vi_port)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - // Validate the password to make sure it is not empty - if (!ValidateNotEmpty(config, "uplink", "password", vi_password)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - // If we get here, all the values are valid, we'll add it to the Uplinks list - config->Uplinks.push_back(new ServerConfig::Uplink(host, port, password, ipv6)); - return true; -} + Block *include = this->GetBlock("include", i); -static bool DoneUplinks(ServerConfig *config, const Anope::string &) -{ - if (config->Uplinks.empty()) - throw ConfigException("You must define at least one uplink block!"); - return true; -} + const Anope::string &type = include->Get("type"), + &file = include->Get("name"); -static bool InitOperTypes(ServerConfig *config, const Anope::string &) -{ - for (std::list::iterator it = config->MyOperTypes.begin(), it_end = config->MyOperTypes.end(); it != it_end; ++it) - delete *it; + File f(file, type == "executable"); + this->LoadConf(f); + } - config->MyOperTypes.clear(); - return true; -} + FOREACH_MOD(I_OnReload, OnReload(this)); -static bool DoOperType(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string name = values[0].GetValue(); - Anope::string inherits = values[1].GetValue(); - Anope::string commands = values[2].GetValue(); - Anope::string privs = values[3].GetValue(); - Anope::string modes = values[4].GetValue(); - - ValueItem vi(name); - if (!ValidateNotEmpty(config, "opertype", "name", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - OperType *ot = new OperType(name); - ot->modes = modes; - - Anope::string tok; - spacesepstream cmdstr(commands); - while (cmdstr.GetToken(tok)) - ot->AddCommand(tok); - - spacesepstream privstr(privs); - while (privstr.GetToken(tok)) - ot->AddPriv(tok); - - commasepstream inheritstr(inherits); - while (inheritstr.GetToken(tok)) + /* Check for modified values that aren't allowed to be modified */ + if (Config) { - /* Strip leading ' ' after , */ - if (tok.length() > 1 && tok[0] == ' ') - tok.erase(tok.begin()); - for (std::list::iterator it = config->MyOperTypes.begin(), it_end = config->MyOperTypes.end(); it != it_end; ++it) + struct { - if ((*it)->GetName().equals_ci(tok)) - { - Log() << "Inheriting commands and privs from " << (*it)->GetName() << " to " << ot->GetName(); - ot->Inherits(*it); - break; - } - } + Anope::string block; + Anope::string name; + Anope::string def; + } noreload[] = { + {"serverinfo", "name", ""}, + {"serverinfo", "description", ""}, + {"serverinfo", "localhost", ""}, + {"serverinfo", "id", ""}, + {"serverinfo", "pid", ""}, + {"networkinfo", "nicklen", "31"}, + {"networkinfo", "userlen", "10"}, + {"networkinfo", "hostlen", "64"}, + {"networkinfo", "chanlen", "32"}, + {"options", "passlen", "32"}, + }; + + for (unsigned i = 0; i < sizeof(noreload) / sizeof(noreload[0]); ++i) + if (this->GetBlock(noreload[i].block)->Get(noreload[i].name, noreload[i].def) != Config->GetBlock(noreload[i].block)->Get(noreload[i].name, noreload[i].def)) + throw ConfigException("<" + noreload[i].block + ":" + noreload[i].name + "> can not be modified once set"); } - config->MyOperTypes.push_back(ot); - return true; -} + Block *options = this->GetBlock("options"), *mail = this->GetBlock("mail"); -static bool DoneOperTypes(ServerConfig *, const Anope::string &) -{ - return true; -} + ValidateNotZero("options", "releasetimeout", options->Get("releasetimeout")); + ValidateNotEmpty("options", "enforceruser", options->Get("enforceruser")); + ValidateNotEmpty("options", "enforcerhost", options->Get("enforcerhost")); + ValidateNotEmpty("options", "guestnickprefix", options->Get("guestnickprefix")); + spacesepstream(options->Get("ulineservers")).GetTokens(this->Ulines); -/*************************************************************************/ + if (mail->Get("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(check[i])); + } -static bool InitOpers(ServerConfig *config, const Anope::string &) -{ - for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it) + this->ReadTimeout = options->Get("readtimeout"); + this->UsePrivmsg = options->Get("useprivmsg"); + this->StrictPrivmsg = options->Get("usestrictprivmsg") ? "/msg " : "/"; { - NickCore *nc = it->second; - nc->QueueUpdate(); - if (nc->o && nc->o->config) - nc->o = NULL; + std::vector defaults; + spacesepstream(this->GetModule("nickserv")->Get("defaults")).GetTokens(defaults); + this->DefPrivmsg = std::find(defaults.begin(), defaults.end(), "msg") != defaults.end(); } + this->DefLanguage = options->Get("defaultlanguage"); - for (unsigned i = 0; i < config->Opers.size(); ++i) - delete config->Opers[i]; - config->Opers.clear(); + for (int i = 0; i < this->CountBlock("uplink"); ++i) + { + Block *uplink = this->GetBlock("uplink", i); - return true; -} + const Anope::string &host = uplink->Get("host"); + bool ipv6 = uplink->Get("ipv6"); + int port = uplink->Get("port"); + const Anope::string &password = uplink->Get("password"); -static bool DoOper(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string name = values[0].GetValue(); - Anope::string type = values[1].GetValue(); - bool require_oper = values[2].GetBool(); - Anope::string password = values[3].GetValue(); - Anope::string certfp = values[4].GetValue(); - Anope::string host = values[5].GetValue(); - Anope::string vhost = values[6].GetValue(); - - ValueItem vi(name); - if (!ValidateNotEmpty(config, "oper", "name", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - ValueItem vi2(type); - if (!ValidateNotEmpty(config, "oper", "type", vi2)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - OperType *ot = NULL; - for (std::list::iterator it = config->MyOperTypes.begin(), it_end = config->MyOperTypes.end(); it != it_end; ++it) - if ((*it)->GetName() == type) - ot = *it; - if (ot == NULL) - throw ConfigException("Oper block for " + name + " has invalid oper type " + type); - - Oper *o = new Oper(name, ot); - o->require_oper = require_oper; - o->config = true; - o->password = password; - o->certfp = certfp; - spacesepstream(host).GetTokens(o->hosts); - o->vhost = vhost; - config->Opers.push_back(o); + ValidateNotEmpty("uplink", "host", host); + ValidateNotEmpty("uplink", "password", password); - return true; -} + this->Uplinks.push_back(Uplink(host, port, password, ipv6)); + } -static bool DoneOpers(ServerConfig *config, const Anope::string &) -{ - for (unsigned i = 0; i < config->Opers.size(); ++i) + for (int i = 0; i < this->CountBlock("module"); ++i) { - Oper *o = config->Opers[i]; + Block *module = this->GetBlock("module", i); - const NickAlias *na = NickAlias::Find(o->name); - if (!na) - // Nonexistant nick - continue; + const Anope::string &modname = module->Get("name"); - na->nc->o = o; - Log() << "Tied oper " << na->nc->display << " to type " << o->ot->GetName(); + ValidateNotEmpty("module", "name", modname); + + this->ModulesAutoLoad.push_back(modname); } - return true; -} + for (int i = 0; i < this->CountBlock("opertype"); ++i) + { + Block *opertype = this->GetBlock("opertype", i); -/*************************************************************************/ + const Anope::string &oname = opertype->Get("name"), + &modes = opertype->Get("modes"), + &inherits = opertype->Get("inherits"), + &commands = opertype->Get("commands"), + &privs = opertype->Get("privs"); -static std::map defines; -static bool InitDefine(ServerConfig *config, const Anope::string &) -{ - defines.clear(); - return true; -} + ValidateNotEmpty("opertype", "name", oname); -static bool DoDefine(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string name = values[0].GetValue(), value = values[1].GetValue(); - defines[name] = value; - return true; -} + OperType *ot = new OperType(oname); + ot->modes = modes; -static bool DoneDefine(ServerConfig *config, const Anope::string &) -{ - return true; -} + spacesepstream cmdstr(commands); + for (Anope::string str; cmdstr.GetToken(str);) + ot->AddCommand(str); -/*************************************************************************/ + spacesepstream privstr(privs); + for (Anope::string str; cmdstr.GetToken(str);) + ot->AddPriv(str); -static bool InitInclude(ServerConfig *config, const Anope::string &) -{ - return true; -} + commasepstream inheritstr(inherits); + for (Anope::string str; inheritstr.GetToken(str);) + { + /* Strip leading ' ' after , */ + if (str.length() > 1 && str[0] == ' ') + str.erase(str.begin()); + for (unsigned j = 0; j < this->MyOperTypes.size(); ++j) + { + OperType *ot2 = this->MyOperTypes[j]; -static bool DoInclude(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string type = values[0].GetValue(); - Anope::string file = values[1].GetValue(); + if (ot2->GetName().equals_ci(str)) + { + Log() << "Inheriting commands and privs from " << ot2->GetName() << " to " << ot->GetName(); + ot->Inherits(ot2); + break; + } + } + } - if (type != "file" && type != "executable") - throw ConfigException("include:type must be either \"file\" or \"executable\""); - - ConfigurationFile f(file, type == "executable"); - config->LoadConf(f); + this->MyOperTypes.push_back(ot); + } - return true; -} + for (int i = 0; i < this->CountBlock("oper"); ++i) + { + Block *oper = this->GetBlock("oper", i); -static bool DoneInclude(ServerConfig *config, const Anope::string &) -{ - return true; -} + const Anope::string &nname = oper->Get("name"), + &type = oper->Get("type"), + &password = oper->Get("password"), + &certfp = oper->Get("certfp"), + &host = oper->Get("host"), + &vhost = oper->Get("vhost"); + bool require_oper = oper->Get("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); -static bool InitModules(ServerConfig *, const Anope::string &) -{ - return true; -} + Oper *o = new Oper(nname, ot); + o->require_oper = require_oper; + o->config = true; + o->password = password; + o->certfp = certfp; + spacesepstream(host).GetTokens(o->hosts); + o->vhost = vhost; -static bool DoModule(ServerConfig *conf, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - // First we validate that there was a name in the module block - Anope::string module = values[0].GetValue(); - ValueItem vi(module); - if (!ValidateNotEmpty(conf, "module", "name", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - conf->ModulesAutoLoad.push_back(module); - return true; -} + this->Opers.push_back(o); + } -static bool DoneModules(ServerConfig *config, const Anope::string &) -{ - if (Config) - { - for (std::list::iterator it = Config->ModulesAutoLoad.begin(); it != Config->ModulesAutoLoad.end(); ++it) - if (std::find(config->ModulesAutoLoad.begin(), config->ModulesAutoLoad.end(), *it) == config->ModulesAutoLoad.end()) - ModuleManager::UnloadModule(ModuleManager::FindModule(*it), NULL); - for (std::list::iterator it = config->ModulesAutoLoad.begin(); it != config->ModulesAutoLoad.end(); ++it) - if (std::find(Config->ModulesAutoLoad.begin(), Config->ModulesAutoLoad.end(), *it) == Config->ModulesAutoLoad.end()) - ModuleManager::LoadModule(*it, NULL); + 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("nick"), + &user = service->Get("user"), + &host = service->Get("host"), + &gecos = service->Get("gecos"), + &modes = service->Get("modes"), + &channels = service->Get("channels"); + + ValidateNotEmpty("service", "nick", nick); + ValidateNotEmpty("service", "user", user); + ValidateNotEmpty("service", "host", host); + ValidateNotEmpty("service", "gecos", gecos); + + BotInfo *bi = BotInfo::Find(nick, true); + if (!bi) + bi = new BotInfo(nick, user, host, gecos, modes); + bi->conf = true; + + std::vector 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 + + /* 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) + bi->Part(c); + } + } + + for (int i = 0; i < this->CountBlock("log"); ++i) + { + Block *log = this->GetBlock("log", i); + + int logage = log->Get("logage"); + bool rawio = log->Get("rawio"); + bool debug = log->Get("debug"); + + LogInfo l(logage, rawio, debug); + + spacesepstream(log->Get("target")).GetTokens(l.targets); + spacesepstream(log->Get("source")).GetTokens(l.sources); + spacesepstream(log->Get("admin")).GetTokens(l.admin); + spacesepstream(log->Get("override")).GetTokens(l.override); + spacesepstream(log->Get("commands")).GetTokens(l.commands); + spacesepstream(log->Get("servers")).GetTokens(l.servers); + spacesepstream(log->Get("channels")).GetTokens(l.channels); + spacesepstream(log->Get("users")).GetTokens(l.users); + spacesepstream(log->Get("normal")).GetTokens(l.normal); + + this->LogInfos.push_back(l); } - return true; -} -static bool InitLogs(ServerConfig *config, const Anope::string &) -{ - config->LogInfos.clear(); - return true; -} + for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) + it->second->commands.clear(); + for (int i = 0; i < this->CountBlock("command"); ++i) + { + Block *command = this->GetBlock("command", i); -static bool DoLogs(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - //{"target", "source", "logage", "inhabit", "admin", "override", "commands", "servers", "channels", "users", "other", "rawio", "debug"}, - Anope::string targets = values[0].GetValue(); - ValueItem vi(targets); - if (!ValidateNotEmpty(config, "log", "target", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - Anope::string source = values[1].GetValue(); - int logage = values[2].GetInteger(); - Anope::string admin = values[3].GetValue(); - Anope::string override = values[4].GetValue(); - Anope::string commands = values[5].GetValue(); - Anope::string servers = values[6].GetValue(); - Anope::string channels = values[7].GetValue(); - Anope::string users = values[8].GetValue(); - Anope::string normal = values[9].GetValue(); - bool rawio = values[10].GetBool(); - bool ldebug = values[11].GetBool(); - - LogInfo *l = new LogInfo(logage, rawio, ldebug); - spacesepstream(targets).GetTokens(l->targets); - spacesepstream(source).GetTokens(l->sources); - spacesepstream(admin).GetTokens(l->admin); - spacesepstream(override).GetTokens(l->override); - spacesepstream(commands).GetTokens(l->commands); - spacesepstream(servers).GetTokens(l->servers); - spacesepstream(channels).GetTokens(l->channels); - spacesepstream(users).GetTokens(l->users); - spacesepstream(normal).GetTokens(l->normal); - - config->LogInfos.push_back(l); + const Anope::string &service = command->Get("service"), + &nname = command->Get("name"), + &cmd = command->Get("command"), + &permission = command->Get("permission"), + &group = command->Get("group"); + bool hide = command->Get("hide"); - return true; -} + ValidateNotEmpty("command", "service", service); + ValidateNotEmpty("command", "name", nname); + ValidateNotEmpty("command", "command", cmd); -static bool DoneLogs(ServerConfig *config, const Anope::string &) -{ - Log() << "Loaded " << config->LogInfos.size() << " log blocks"; - return true; -} + BotInfo *bi = BotInfo::Find(service, true); + if (!bi) + continue; -/*************************************************************************/ + CommandInfo &ci = bi->SetCommand(nname, cmd, permission); + ci.group = group; + ci.hide = hide; + } -static bool InitCommands(ServerConfig *config, const Anope::string &) -{ - for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) + PrivilegeManager::ClearPrivileges(); + for (int i = 0; i < this->CountBlock("privilege"); ++i) { - BotInfo *bi = it->second; - if (bi) - { - bi->QueueUpdate(); - bi->commands.clear(); - } + Block *privilege = this->GetBlock("privilege", i); + + const Anope::string &nname = privilege->Get("name"), + &desc = privilege->Get("desc"); + int rank = privilege->Get("rank"); + + PrivilegeManager::AddPrivilege(Privilege(nname, desc, rank)); } - return true; -} -static bool DoCommands(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string service = values[0].GetValue(); - Anope::string name = values[1].GetValue(); - Anope::string command = values[2].GetValue(); - Anope::string permission = values[3].GetValue(); - Anope::string group = values[4].GetValue(); - bool hide = values[5].GetBool(); - - ValueItem vi(service); - if (!ValidateNotEmpty(config, "command", "service", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - vi = ValueItem(name); - if (!ValidateNotEmpty(config, "command", "name", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - vi = ValueItem(command); - if (!ValidateNotEmpty(config, "command", "command", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - BotInfo *bi = BotInfo::Find(service); - if (bi == NULL) - throw ConfigException("Command " + name + " exists for nonexistant service " + service); + for (int i = 0; i < this->CountBlock("fantasy"); ++i) + { + Block *fantasy = this->GetBlock("fantasy", i); - if (bi->commands.count(name)) - throw ConfigException("Command name " + name + " already exists on " + bi->nick); + const Anope::string &nname = fantasy->Get("name"), + &service = fantasy->Get("command"), + &permission = fantasy->Get("permission"), + &group = fantasy->Get("group"); + bool hide = fantasy->Get("hide"), + prepend_channel = fantasy->Get("prepend_channel"); - CommandInfo &ci = bi->SetCommand(name, command, permission); - ci.group = group; - ci.hide = hide; - return true; -} + ValidateNotEmpty("fantasy", "name", nname); + ValidateNotEmpty("fantasy", "command", service); -static bool DoneCommands(ServerConfig *config, const Anope::string &) -{ - return true; -} + CommandInfo &c = this->Fantasy[name]; + c.name = service; + c.permission = permission; + c.group = group; + c.hide = hide; + c.prepend_channel = prepend_channel; + } -/*************************************************************************/ + for (int i = 0; i < this->CountBlock("command_group"); ++i) + { + Block *command_group = this->GetBlock("command_group", i); -static bool InitPrivileges(ServerConfig *config, const Anope::string &) -{ - PrivilegeManager::ClearPrivileges(); - return true; -} + const Anope::string &nname = command_group->Get("name"), + &description = command_group->Get("description"); -static bool DoPrivileges(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string name = values[0].GetValue(); - Anope::string desc = values[1].GetValue(); - int rank = values[2].GetInteger(); + CommandGroup gr; + gr.name = nname; + gr.description = description; - ValueItem vi(name); - if (!ValidateNotEmpty(config, "privilege", "name", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); + this->CommandGroups.push_back(gr); + } - PrivilegeManager::AddPrivilege(Privilege(name, desc, rank)); - return true; -} + /* Below here can't throw */ -static bool DonePrivileges(ServerConfig *config, const Anope::string &) -{ - Log(LOG_DEBUG) << "Loaded " << PrivilegeManager::GetPrivileges().size() << " privileges"; - return true; -} + for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it) + { + NickCore *nc = it->second; + if (nc->o && nc->o->config) + nc->o = NULL; + } + for (unsigned i = 0; i < this->Opers.size(); ++i) + { + Oper *o = this->Opers[i]; -/*************************************************************************/ + NickAlias *na = NickAlias::Find(o->name); + if (!na) + continue; -static std::set services; -static bool InitServices(ServerConfig *config, const Anope::string &) -{ - services.clear(); - return true; -} + na->nc->o = o; + Log() << "Tied oper " << na->nc->display << " to type " << o->ot->GetName(); + } -static bool DoServices(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string nick = values[0].GetValue(); - Anope::string user = values[1].GetValue(); - Anope::string host = values[2].GetValue(); - Anope::string gecos = values[3].GetValue(); - Anope::string modes = values[4].GetValue(); - Anope::string channels = values[5].GetValue(); - - ValueItem vi(nick); - if (!ValidateNotEmpty(config, "service", "nick", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - vi = ValueItem(user); - if (!ValidateNotEmpty(config, "service", "user", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - vi = ValueItem(host); - if (!ValidateNotEmpty(config, "service", "host", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - vi = ValueItem(gecos); - if (!ValidateNotEmpty(config, "service", "gecos", vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your log for more information."); - - services.insert(nick); - BotInfo* bi = BotInfo::Find(nick); - if (!bi) - bi = new BotInfo(nick, user, host, gecos, modes); - bi->conf = true; - - Anope::string token; - commasepstream sep(channels); - std::vector oldchannels = bi->botchannels; - bi->botchannels.clear(); - while (sep.GetToken(token)) + if (options->Get("casemap", "ascii") == "ascii") + Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype()); + else if (options->Get("casemap") == "rfc1459") + Anope::casemap = std::locale(std::locale(), new Anope::rfc1459_ctype()); + else { - bi->botchannels.push_back(token); - size_t ch = token.find('#'); - Anope::string chname, want_modes; - if (ch == Anope::string::npos) - chname = token; - else + try { - want_modes = token.substr(0, ch); - chname = token.substr(ch); + Anope::casemap = std::locale(options->Get("casemap")); } - bi->Join(chname); - Channel *c = Channel::Find(chname); - if (!c) - continue; // Can't happen - - /* Remove all existing modes */ - ChanUserContainer *cu = c->FindUser(bi); - if (cu != NULL) - for (size_t i = 0; i < cu->status.Modes().length(); ++i) - c->RemoveMode(bi, ModeManager::FindChannelModeByChar(cu->status.Modes()[i]), bi->GetUID()); - /* Set the new modes */ - for (unsigned j = 0; j < want_modes.length(); ++j) + catch (const std::runtime_error &) { - 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()); + Log() << "Unknown casemap " << options->Get("casemap") << " - casemap not changed"; } } - for (unsigned i = 0; i < oldchannels.size(); ++i) - { - size_t ch = oldchannels[i].find('#'); - Anope::string chname = oldchannels[i].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; - } + Anope::CaseMapRebuild(); - if (found) - continue; + /* Check the user keys */ + if (!options->Get("seed")) + Log() << "Configuration option options:seed should be set. It's for YOUR safety! Remember that!"; - Channel *c = Channel::Find(chname); - if (c) - bi->Part(c); +#ifndef _WIN32 + if (!options->Get("user").empty()) + { + errno = 0; + struct passwd *u = getpwnam(options->Get("user")); + if (u == NULL) + Log() << "Unable to setuid to " << options->Get("user") << ": " << Anope::LastError(); + else if (setuid(u->pw_uid) == -1) + Log() << "Unable to setuid to " << options->Get("user") << ": " << Anope::LastError(); + else + Log() << "Successfully set user to " << options->Get("user"); } - - return true; -} - -static bool DoneServices(ServerConfig *config, const Anope::string &) -{ - for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end;) + if (!options->Get("group").empty()) { - BotInfo *bi = it->second; - ++it; - - if (bi->conf && services.count(bi->nick) == 0) - delete bi; + errno = 0; + struct group *g = getgrnam(options->Get("group")); + if (g == NULL) + Log() << "Unable to setgid to " << options->Get("group") << ": " << Anope::LastError(); + else if (setuid(g->gr_gid) == -1) + Log() << "Unable to setgid to " << options->Get("group") << ": " << Anope::LastError(); + else + Log() << "Successfully set group to " << options->Get("group"); } - services.clear(); - return true; -} - -/*************************************************************************/ - -static bool InitFantasy(ServerConfig *config, const Anope::string &) -{ - config->Fantasy.clear(); - return true; -} - -static bool DoFantasy(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) -{ - Anope::string name = values[0].GetValue(); - Anope::string service = values[1].GetValue(); - Anope::string permission = values[2].GetValue(); - Anope::string group = values[3].GetValue(); - bool hide = values[4].GetBool(); - bool prepend_channel = values[5].GetBool(); - - CommandInfo &c = config->Fantasy[name]; - - c.name = service; - c.permission = permission; - c.group = group; - c.hide = hide; - c.prepend_channel = prepend_channel; - - return true; -} +#endif -static bool DoneFantasy(ServerConfig *config, const Anope::string &) -{ - return true; + /* Apply module chnages */ + if (Config) + { + for (unsigned i = 0; i < Config->ModulesAutoLoad.size(); ++i) + if (std::find(this->ModulesAutoLoad.begin(), this->ModulesAutoLoad.end(), Config->ModulesAutoLoad[i]) == this->ModulesAutoLoad.end()) + ModuleManager::UnloadModule(ModuleManager::FindModule(Config->ModulesAutoLoad[i]), NULL); + for (unsigned i = 0; i < this->ModulesAutoLoad.size(); ++i) + if (std::find(Config->ModulesAutoLoad.begin(), Config->ModulesAutoLoad.end(), this->ModulesAutoLoad[i]) == Config->ModulesAutoLoad.end()) + ModuleManager::LoadModule(this->ModulesAutoLoad[i], NULL); + } } -/*************************************************************************/ - -static bool InitCommandGroups(ServerConfig *config, const Anope::string &) +Block *Conf::GetModule(Module *m) { - config->CommandGroups.clear(); - return true; + if (!m) + return NULL; + + return GetModule(m->name); } -static bool DoCommandGroups(ServerConfig *config, const Anope::string &, const Anope::string *, ValueList &values, int *) +Block *Conf::GetModule(const Anope::string &mname) { - Anope::string name = values[0].GetValue(); - Anope::string description = values[1].GetValue(); + std::map::iterator it = modules.find(mname); + if (it != modules.end()) + return it->second; - if (name.empty() || description.empty()) - return true; - - CommandGroup gr; - gr.name = name; - gr.description = description; + Block* &block = modules[mname]; + + /* Search for the block */ + for (std::pair iters = blocks.equal_range("module"); iters.first != iters.second; ++iters.first) + { + Block *b = &iters.first->second; - config->CommandGroups.push_back(gr); - return true; -} + if (b->Get("name") == mname) + { + block = b; + break; + } + } -static bool DoneCommandGroups(ServerConfig *config, const Anope::string &) -{ - return true; + return GetModule(mname); } -/*************************************************************************/ - -ConfigurationFile::ConfigurationFile(const Anope::string &n, bool e) : name(n), executable(e), fp(NULL) +File::File(const Anope::string &n, bool e) : name(n), executable(e), fp(NULL) { } -ConfigurationFile::~ConfigurationFile() +File::~File() { this->Close(); } -const Anope::string &ConfigurationFile::GetName() const +const Anope::string &File::GetName() const { return this->name; } -bool ConfigurationFile::IsOpen() const +bool File::IsOpen() const { return this->fp != NULL; } -bool ConfigurationFile::Open() +bool File::Open() { this->Close(); this->fp = (this->executable ? popen(this->name.c_str(), "r") : fopen((Anope::ConfigDir + "/" + this->name).c_str(), "r")); return this->fp != NULL; } -void ConfigurationFile::Close() +void File::Close() { if (this->fp != NULL) { @@ -1050,12 +618,12 @@ void ConfigurationFile::Close() } } -bool ConfigurationFile::End() const +bool File::End() const { return !this->IsOpen() || feof(this->fp); } -Anope::string ConfigurationFile::Read() +Anope::string File::Read() { Anope::string ret; char buf[BUFSIZE]; @@ -1077,552 +645,50 @@ Anope::string ConfigurationFile::Read() return ret; } -ConfigItems::ConfigItems(ServerConfig *conf) -{ - // These tags can occur ONCE or not at all - const Item Items[] = { - /* The following comments are from CyberBotX to w00t as examples to use: - * - * The last argument, for validation, must use one of the functions with the following signature: