diff options
author | Adam <Adam@anope.org> | 2013-05-05 01:55:04 -0400 |
---|---|---|
committer | Adam <Adam@anope.org> | 2013-05-05 01:55:04 -0400 |
commit | 1d0bb9b26b7ad58ab0bf979ac046f4511b3bf12b (patch) | |
tree | 4486f0784bdf050fd7eb225c0cb9df352ce1f45a /src | |
parent | 781defb7076ddfddf723ca08cd0a518b6657b64f (diff) |
Rework the config file reader to be much more flexible and move many configuration directives to the actual modules they are used in.
Diffstat (limited to 'src')
-rw-r--r-- | src/bots.cpp | 68 | ||||
-rw-r--r-- | src/channels.cpp | 97 | ||||
-rw-r--r-- | src/command.cpp | 6 | ||||
-rw-r--r-- | src/config.cpp | 2119 | ||||
-rw-r--r-- | src/configreader.cpp | 116 | ||||
-rw-r--r-- | src/init.cpp | 24 | ||||
-rw-r--r-- | src/language.cpp | 15 | ||||
-rw-r--r-- | src/logger.cpp | 5 | ||||
-rw-r--r-- | src/mail.cpp | 21 | ||||
-rw-r--r-- | src/main.cpp | 6 | ||||
-rw-r--r-- | src/messages.cpp | 46 | ||||
-rw-r--r-- | src/misc.cpp | 40 | ||||
-rw-r--r-- | src/modes.cpp | 82 | ||||
-rw-r--r-- | src/modulemanager.cpp | 3 | ||||
-rw-r--r-- | src/nickalias.cpp | 9 | ||||
-rw-r--r-- | src/nickcore.cpp | 14 | ||||
-rw-r--r-- | src/opertype.cpp | 4 | ||||
-rw-r--r-- | src/protocol.cpp | 37 | ||||
-rw-r--r-- | src/regchannel.cpp | 42 | ||||
-rw-r--r-- | src/servers.cpp | 34 | ||||
-rw-r--r-- | src/uplink.cpp | 24 | ||||
-rw-r--r-- | src/users.cpp | 75 | ||||
-rw-r--r-- | src/xline.cpp | 8 |
23 files changed, 714 insertions, 2181 deletions
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<botinfo_map> 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<ChannelInfo *>::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<ChannelInfo *> &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<Channel::ModeList::iterator, Channel::ModeList::iterator> 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<unsigned>(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<Channel> 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 <grp.h> #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 <nickserv:defaults> 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<char>()); - else if (this->CaseMap == "rfc1459") - Anope::casemap = std::locale(std::locale(), new Anope::rfc1459_ctype<char>()); - 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"); + if (!this) + return 0; + + return blocks.count(bname); } -/* 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 +Block* Block::GetBlock(const Anope::string &bname, int num) { - 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 (!this) + return NULL; + + std::pair<block_map::iterator, block_map::iterator> it = blocks.equal_range(bname); - if (num_seps && num_dots != 3 && num_dots && !wild) - throw ConfigException("The value of <" + tag + ":" + val + "> is a malformed IPv6 4in6 address"); - } + for (int i = 0; it.first != it.second; ++it.first, ++i) + if (i == num) + return &it.first->second; + return NULL; } -void ServerConfig::ValidateHostname(const Anope::string &p, const Anope::string &tag, const Anope::string &val) const +bool Block::Set(const Anope::string &tag, const Anope::string &value) { - if (p.equals_ci("localhost")) - return; - - 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"); - } -} + if (!this) + return false; -static bool ValidateNotEmpty(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data) -{ - if (data.GetValue().empty()) - throw ConfigException("The value for <" + tag + ":" + value + "> cannot be empty!"); + items[tag] = value; return true; } -static bool ValidateNotZero(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data) +const Block::item_map* Block::GetItems() const { - if (!data.GetInteger() && Anope::DoTime(data.GetValue()) <= 0) - throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero!"); - return true; + if (this) + return &items; + else + return NULL; } -static bool ValidateEmailReg(ServerConfig *config, 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 { - 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 def; -static bool ValidatePort(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data) -{ - 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; -} + Anope::map<Anope::string>::const_iterator it = items.find(tag); + if (it != items.end()) + return it->second; -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 <chanserv:defbantype> must be between 0 and 3!"); - return true; + return def; } -static bool ValidateNickServ(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->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 <nickserv:guestnickprefix> 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 <nickserv:registration> must be one of \"none\", \"mail\", \"admin\", or \"disable\""); - } - return true; + return Anope::DoTime(Get<const Anope::string &>(tag, def)); } -static bool ValidateChanServ(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->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 this->Get<const Anope::string &>(tag, def).c_str(); } -static bool ValidateBotServ(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->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; + const Anope::string &str = Get<const Anope::string &>(tag, def); + return str.equals_ci("yes") || str.equals_ci("on") || str.equals_ci("true"); } -static bool ValidateLimitSessions(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->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; + if (value.empty()) + throw ConfigException("The value for <" + block + ":" + name + "> cannot be empty!"); } -static bool ValidateOperServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) +template<typename T> static void ValidateNotZero(const Anope::string &block, const Anope::string &name, T 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) + throw ConfigException("The value for <" + block + ":" + name + "> cannot be zero!"); } -static bool ValidateNickLen(ServerConfig *, const Anope::string &, const Anope::string &, ValueItem &data) +Conf::Conf() : Block("") { - int nicklen = data.GetInteger(); - if (!nicklen) - { - Log() << "You have not defined the <networkinfo:nicklen> directive. It is strongly"; - Log() << "adviced that you do configure this correctly in your services.conf"; - data.Set(31); - } - else if (nicklen < 1) - { - Log() << "<networkinfo:nicklen> has an invalid value; setting to 31"; - data.Set(31); - } - return true; -} + ReadTimeout = 0; + UsePrivmsg = DefPrivmsg = false; -static bool ValidateMail(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) -{ - 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; -} + this->LoadConf(ServicesConf); -static bool ValidateGlobalOnCycle(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data) -{ - if (config->GlobalOnCycle) + for (int i = 0; i < this->CountBlock("include"); ++i) { - if (data.GetValue().empty()) - { - Log() << "<" << tag << ":" << value << "> was undefined, disabling <options:globaloncycle>"; - config->GlobalOnCycle = false; - } - } - return true; -} + Block *include = this->GetBlock("include", i); -static bool InitUplinks(ServerConfig *config, const Anope::string &) -{ - if (!config->Uplinks.empty()) - { - std::vector<ServerConfig::Uplink *>::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; -} + const Anope::string &type = include->Get<const Anope::string &>("type"), + &file = include->Get<const Anope::string &>("name"); -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; -} - -static bool DoneUplinks(ServerConfig *config, const Anope::string &) -{ - if (config->Uplinks.empty()) - throw ConfigException("You must define at least one uplink block!"); - return true; -} - -static bool InitOperTypes(ServerConfig *config, const Anope::string &) -{ - for (std::list<OperType *>::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<OperType *>::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<const Anope::string &>(noreload[i].name, noreload[i].def) != Config->GetBlock(noreload[i].block)->Get<const Anope::string &>(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<time_t>("releasetimeout")); + ValidateNotEmpty("options", "enforceruser", options->Get<const Anope::string &>("enforceruser")); + ValidateNotEmpty("options", "enforcerhost", options->Get<const Anope::string &>("enforcerhost")); + ValidateNotEmpty("options", "guestnickprefix", options->Get<const Anope::string &>("guestnickprefix")); + spacesepstream(options->Get<const 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])); + } -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<unsigned>("readtimeout"); + this->UsePrivmsg = options->Get<bool>("useprivmsg"); + this->StrictPrivmsg = options->Get<bool>("usestrictprivmsg") ? "/msg " : "/"; { - NickCore *nc = it->second; - nc->QueueUpdate(); - if (nc->o && nc->o->config) - nc->o = NULL; + std::vector<Anope::string> defaults; + spacesepstream(this->GetModule("nickserv")->Get<const Anope::string &>("defaults")).GetTokens(defaults); + this->DefPrivmsg = std::find(defaults.begin(), defaults.end(), "msg") != defaults.end(); } + this->DefLanguage = options->Get<const Anope::string &>("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<const 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"); -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<OperType *>::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<const Anope::string &>("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<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"); -static std::map<Anope::string, Anope::string> 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<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); -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<Anope::string>::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<Anope::string>::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<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); + + 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 + + /* 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<int>("logage"); + bool rawio = log->Get<bool>("rawio"); + bool debug = log->Get<bool>("debug"); + + LogInfo l(logage, rawio, debug); + + 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 &>("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<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"); + bool hide = command->Get<bool>("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<const Anope::string &>("name"), + &desc = privilege->Get<const Anope::string &>("desc"); + int rank = privilege->Get<int>("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<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"); + bool hide = fantasy->Get<bool>("hide"), + prepend_channel = fantasy->Get<bool>("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<const Anope::string &>("name"), + &description = command_group->Get<const Anope::string &>("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<Anope::string> 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<Anope::string> oldchannels = bi->botchannels; - bi->botchannels.clear(); - while (sep.GetToken(token)) + 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 { - 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<const char *>("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<const Anope::string &>("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<unsigned>("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<const Anope::string &>("user").empty()) + { + errno = 0; + struct passwd *u = getpwnam(options->Get<const char *>("user")); + if (u == NULL) + Log() << "Unable to setuid to " << options->Get<const Anope::string &>("user") << ": " << Anope::LastError(); + else if (setuid(u->pw_uid) == -1) + Log() << "Unable to setuid to " << options->Get<const Anope::string &>("user") << ": " << Anope::LastError(); + else + Log() << "Successfully set user to " << options->Get<const Anope::string &>("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<const Anope::string &>("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<const char *>("group")); + if (g == NULL) + Log() << "Unable to setgid to " << options->Get<const Anope::string &>("group") << ": " << Anope::LastError(); + else if (setuid(g->gr_gid) == -1) + Log() << "Unable to setgid to " << options->Get<const Anope::string &>("group") << ": " << Anope::LastError(); + else + Log() << "Successfully set group to " << options->Get<const Anope::string &>("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<Anope::string, Block *>::iterator it = modules.find(mname); + if (it != modules.end()) + return it->second; - if (name.empty() || description.empty()) - return true; + Block* &block = modules[mname]; + + /* Search for the block */ + for (std::pair<block_map::iterator, block_map::iterator> iters = blocks.equal_range("module"); iters.first != iters.second; ++iters.first) + { + Block *b = &iters.first->second; - CommandGroup gr; - gr.name = name; - gr.description = description; + if (b->Get<const Anope::string &>("name") == mname) + { + block = b; + break; + } + } - config->CommandGroups.push_back(gr); - return true; + return GetModule(mname); } -static bool DoneCommandGroups(ServerConfig *config, const Anope::string &) +File::File(const Anope::string &n, bool e) : name(n), executable(e), fp(NULL) { - return true; } -/*************************************************************************/ - -ConfigurationFile::ConfigurationFile(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) +void Conf::LoadConf(File &file) { - // 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: - * bool <function>(ServerConfig *, const char *, const char *, ValueItem &) - * Examples are: NoValidation, ValidateNotEmpty, etc. - * - * If you want to create a directive using an integer: - * int blarg; - * {"tag", "value", "0", new ValueContainerInt(&conf->blarg), DT_INTEGER, <validation>}, - * - * If you want to create a directive using an unsigned integer: - * unsigned blarg; - * {"tag", "value", "0", new ValueContainerUInt(&conf->blarg), DT_UINTEGER, <validation>}, - * - * If you want to create a directive using a string: - * Anope::string blarg; - * {"tag", "value", "", new ValueContainerString(&conf->blarg), DT_STRING, <validation>}, - * - * If you want to create a directive using a boolean: - * bool blarg; - * {"tag", "value", "no", new ValueContainerBool(&conf->blarg), DT_BOOLEAN, <validation>}, - * - * If you want to create a directive using a character pointer specifically to hold a hostname (this will call ValidateHostname automatically): - * char *blarg; - * {"tag", "value", "", new ValueContainerChar(&conf->blarg), DT_HOSTNAME, <validation>}, - * - * If you want to create a directive using a character pointer that specifically can not have spaces in it (this will call ValidateNoSpaces automatically): - * char *blarg; - * {"tag", "value", "", new ValueContainerChar(&conf->blarg), DT_NOSPACES, <validation>}, - * - * If you want to create a directive using a character pointer specifically to hold an IP address (this will call ValidateIP automatically): - * char *blarg; - * {"tag", "value", "", new ValueContainerChar(&conf->blarg), DT_IPADDRESS, <validation>}, - * - * If you want to create a directive using a time (a time_t variable converted from a string): - * time_t blarg; - * {"tag", "value", "", new ValueContainterTime(&conf->blarg), DT_TIME, <validation>}, - * - * For the second-to-last argument, you can or (|) in the following values: - * DT_NORELOAD - The variable can't be changed on a reload of the configuration - * DT_ALLOW_WILD - Allows wildcards/CIDR in DT_IPADDRESS - * DT_ALLOW_NEWLINE - Allows new line characters in DT_STRING - * - * We may need to add some other validation functions to handle certain things, we can handle that later. - * Any questions about these, w00t, feel free to ask. */ - {"serverinfo", "name", "", new ValueContainerString(&conf->ServerName), DT_HOSTNAME | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "description", "", new ValueContainerString(&conf->ServerDesc), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "localhost", "", new ValueContainerString(&conf->LocalHost), DT_HOSTNAME | DT_NORELOAD, NoValidation}, - {"serverinfo", "id", "", new ValueContainerString(&conf->Numeric), DT_NOSPACES | DT_NORELOAD, NoValidation}, - {"serverinfo", "pid", "data/services.pid", new ValueContainerString(&conf->PIDFilename), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "motd", "conf/services.motd", new ValueContainerString(&conf->MOTDFilename), DT_STRING, ValidateNotEmpty}, - {"networkinfo", "networkname", "", new ValueContainerString(&conf->NetworkName), DT_STRING, ValidateNotEmpty}, - {"networkinfo", "nicklen", "31", new ValueContainerUInt(&conf->NickLen), DT_UINTEGER | DT_NORELOAD, ValidateNickLen}, - {"networkinfo", "userlen", "10", new ValueContainerUInt(&conf->UserLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, - {"networkinfo", "hostlen", "64", new ValueContainerUInt(&conf->HostLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, - {"networkinfo", "chanlen", "32", new ValueContainerUInt(&conf->ChanLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, - {"networkinfo", "modelistsize", "0", new ValueContainerUInt(&conf->ListSize), DT_UINTEGER, NoValidation}, - {"options", "user", "", new ValueContainerString(&conf->User), DT_STRING, NoValidation}, - {"options", "group", "", new ValueContainerString(&conf->Group), DT_STRING, NoValidation}, - {"options", "casemap", "ascii", new ValueContainerString(&conf->CaseMap), DT_STRING, NoValidation}, - {"options", "passlen", "32", new ValueContainerUInt(&conf->PassLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, - {"options", "seed", "0", new ValueContainerLUInt(&conf->Seed), DT_LUINTEGER, NoValidation}, - {"options", "nobackupokay", "no", new ValueContainerBool(&conf->NoBackupOkay), DT_BOOLEAN, NoValidation}, - {"options", "strictpasswords", "no", new ValueContainerBool(&conf->StrictPasswords), DT_BOOLEAN, NoValidation}, - {"options", "badpasslimit", "0", new ValueContainerUInt(&conf->BadPassLimit), DT_UINTEGER, NoValidation}, - {"options", "badpasstimeout", "0", new ValueContainerTime(&conf->BadPassTimeout), DT_TIME, NoValidation}, - {"options", "updatetimeout", "0", new ValueContainerTime(&conf->UpdateTimeout), DT_TIME, ValidateNotZero}, - {"options", "expiretimeout", "0", new ValueContainerTime(&conf->ExpireTimeout), DT_TIME, ValidateNotZero}, - {"options", "readtimeout", "0", new ValueContainerTime(&conf->ReadTimeout), DT_TIME, ValidateNotZero}, - {"options", "warningtimeout", "0", new ValueContainerTime(&conf->WarningTimeout), DT_TIME, ValidateNotZero}, - {"options", "timeoutcheck", "0", new ValueContainerTime(&conf->TimeoutCheck), DT_TIME, NoValidation}, - {"options", "keepbackups", "0", new ValueContainerInt(&conf->KeepBackups), DT_INTEGER, NoValidation}, - {"options", "forceforbidreason", "no", new ValueContainerBool(&conf->ForceForbidReason), DT_BOOLEAN, NoValidation}, - {"options", "useprivmsg", "no", new ValueContainerBool(&conf->UsePrivmsg), DT_BOOLEAN, NoValidation}, - {"options", "usestrictprivmsg", "no", new ValueContainerBool(&conf->UseStrictPrivMsg), DT_BOOLEAN, NoValidation}, - {"options", "hidestatso", "no", new ValueContainerBool(&conf->HideStatsO), DT_BOOLEAN, NoValidation}, - {"options", "nickregdelay", "0", new ValueContainerUInt(&conf->NickRegDelay), DT_UINTEGER, NoValidation}, - {"options", "restrictopernicks", "no", new ValueContainerBool(&conf->RestrictOperNicks), DT_BOOLEAN, NoValidation}, - {"options", "newscount", "3", new ValueContainerUInt(&conf->NewsCount), DT_UINTEGER, NoValidation}, - {"options", "ulineservers", "", new ValueContainerString(&UlineServers), DT_STRING, NoValidation}, - {"options", "botmodes", "", new ValueContainerString(&conf->BotModes), DT_STRING, NoValidation}, - {"options", "retrywait", "60", new ValueContainerInt(&conf->RetryWait), DT_INTEGER, ValidateNotZero}, - {"options", "hideprivilegedcommands", "yes", new ValueContainerBool(&conf->HidePrivilegedCommands), DT_BOOLEAN, NoValidation}, - {"options", "nonicknameownership", "no", new ValueContainerBool(&conf->NoNicknameOwnership), DT_BOOLEAN | DT_NORELOAD, NoValidation}, - {"options", "regexengine", "", new ValueContainerString(&conf->RegexEngine), DT_STRING, NoValidation}, - {"nickserv", "name", "", new ValueContainerString(&conf->NickServ), DT_STRING, NoValidation}, - {"nickserv", "registration", "none", new ValueContainerString(&conf->NSRegistration), DT_STRING, ValidateNickServ}, - {"nickserv", "unregistered_notice", "", new ValueContainerString(&conf->NSUnregisteredNotice), DT_STRING, NoValidation}, - {"nickserv", "forceemail", "no", new ValueContainerBool(&conf->NSForceEmail), DT_BOOLEAN, ValidateEmailReg}, - {"nickserv", "confirmemailchanges", "no", new ValueContainerBool(&conf->NSConfirmEmailChanges), DT_BOOLEAN, NoValidation}, - {"nickserv", "defaults", "secure memo_signon memo_receive", new ValueContainerString(&NSDefaults), DT_STRING, NoValidation}, - {"nickserv", "languages", "", new ValueContainerString(&conf->Languages), DT_STRING, NoValidation}, - {"nickserv", "defaultlanguage", "0", new ValueContainerString(&conf->NSDefLanguage), DT_STRING, NoValidation}, - {"nickserv", "regdelay", "0", new ValueContainerTime(&conf->NSRegDelay), DT_TIME, NoValidation}, - {"nickserv", "resenddelay", "0", new ValueContainerTime(&conf->NSResendDelay), DT_TIME, NoValidation}, - {"nickserv", "expire", "21d", new ValueContainerTime(&conf->NSExpire), DT_TIME, NoValidation}, - {"nickserv", "suspendexpire", "0", new ValueContainerTime(&conf->NSSuspendExpire), DT_TIME, NoValidation}, - {"nickserv", "unconfirmedexpire", "0", new ValueContainerTime(&conf->NSUnconfirmedExpire), DT_TIME, ValidateEmailReg}, - {"nickserv", "maxaliases", "0", new ValueContainerUInt(&conf->NSMaxAliases), DT_UINTEGER, NoValidation}, - {"nickserv", "accessmax", "0", new ValueContainerUInt(&conf->NSAccessMax), DT_UINTEGER, ValidateNickServ}, - {"nickserv", "enforceruser", "", new ValueContainerString(&conf->NSEnforcerUser), DT_STRING, ValidateNickServ}, - {"nickserv", "enforcerhost", "", new ValueContainerString(&conf->NSEnforcerHost), DT_STRING, ValidateNickServ}, - {"nickserv", "releasetimeout", "0", new ValueContainerTime(&conf->NSReleaseTimeout), DT_TIME, ValidateNickServ}, - {"nickserv", "allowkillimmed", "no", new ValueContainerBool(&conf->NSAllowKillImmed), DT_BOOLEAN | DT_NORELOAD, NoValidation}, - {"nickserv", "nogroupchange", "no", new ValueContainerBool(&conf->NSNoGroupChange), DT_BOOLEAN, NoValidation}, - {"nickserv", "listmax", "0", new ValueContainerUInt(&conf->NSListMax), DT_UINTEGER, ValidateNickServ}, - {"nickserv", "guestnickprefix", "", new ValueContainerString(&conf->NSGuestNickPrefix), DT_STRING, ValidateNickServ}, - {"nickserv", "secureadmins", "no", new ValueContainerBool(&conf->NSSecureAdmins), DT_BOOLEAN, NoValidation}, - {"nickserv", "strictprivileges", "no", new ValueContainerBool(&conf->NSStrictPrivileges), DT_BOOLEAN, NoValidation}, - {"nickserv", "modeonid", "no", new ValueContainerBool(&conf->NSModeOnID), DT_BOOLEAN, NoValidation}, - {"nickserv", "addaccessonreg", "no", new ValueContainerBool(&conf->NSAddAccessOnReg), DT_BOOLEAN, NoValidation}, - {"nickserv", "ajoinmax", "10", new ValueContainerUInt(&conf->AJoinMax), DT_UINTEGER, NoValidation}, - {"nickserv", "killquick", "20", new ValueContainerTime(&conf->NSKillQuick), DT_TIME, NoValidation}, - {"nickserv", "kill", "60", new ValueContainerTime(&conf->NSKill), DT_TIME, NoValidation}, - {"nickserv", "modesonid", "", new ValueContainerString(&conf->NSModesOnID), DT_STRING, NoValidation}, - {"nickserv", "restoreonrecover", "yes", new ValueContainerBool(&conf->NSRestoreOnRecover), DT_BOOLEAN, NoValidation}, - {"nickserv", "sasl", "yes", new ValueContainerBool(&conf->NSSASL), DT_BOOLEAN, NoValidation}, - {"nickserv", "hidenetsplitquit", "no", new ValueContainerBool(&conf->NSHideNetSplitQuit), DT_BOOLEAN, NoValidation}, - {"mail", "usemail", "no", new ValueContainerBool(&conf->UseMail), DT_BOOLEAN, ValidateEmailReg}, - {"mail", "sendmailpath", "", new ValueContainerString(&conf->SendMailPath), DT_STRING, ValidateMail}, - {"mail", "sendfrom", "", new ValueContainerString(&conf->SendFrom), DT_STRING, ValidateMail}, - {"mail", "restrict", "no", new ValueContainerBool(&conf->RestrictMail), DT_BOOLEAN, NoValidation}, - {"mail", "delay", "0", new ValueContainerTime(&conf->MailDelay), DT_TIME, NoValidation}, - {"mail", "dontquoteaddresses", "no", new ValueContainerBool(&conf->DontQuoteAddresses), DT_BOOLEAN, NoValidation}, - {"mail", "registration_subject", "", new ValueContainerString(&conf->MailRegistrationSubject), DT_STRING, ValidateMail}, - {"mail", "registration_message", "", new ValueContainerString(&conf->MailRegistrationMessage), DT_STRING | DT_ALLOW_NEWLINE, ValidateMail}, - {"mail", "reset_subject", "", new ValueContainerString(&conf->MailResetSubject), DT_STRING, ValidateMail}, - {"mail", "reset_message", "", new ValueContainerString(&conf->MailResetMessage), DT_STRING | DT_ALLOW_NEWLINE, ValidateMail}, - {"mail", "emailchange_subject", "", new ValueContainerString(&conf->MailEmailchangeSubject), DT_STRING, ValidateMail}, - {"mail", "emailchange_message", "", new ValueContainerString(&conf->MailEmailchangeMessage), DT_STRING | DT_ALLOW_NEWLINE, ValidateMail}, - {"mail", "memo_subject", "", new ValueContainerString(&conf->MailMemoSubject), DT_STRING, ValidateMail}, - {"mail", "memo_message", "", new ValueContainerString(&conf->MailMemoMessage), DT_STRING | DT_ALLOW_NEWLINE, ValidateMail}, - {"chanserv", "name", "", new ValueContainerString(&conf->ChanServ), DT_STRING, NoValidation}, - {"chanserv", "defaults", "keeptopic secure securefounder signkick", new ValueContainerString(&CSDefaults), DT_STRING, ValidateChanServ}, - {"chanserv", "maxregistered", "0", new ValueContainerUInt(&conf->CSMaxReg), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "expire", "14d", new ValueContainerTime(&conf->CSExpire), DT_TIME, ValidateChanServ}, - {"chanserv", "suspendexpire", "0", new ValueContainerTime(&conf->CSSuspendExpire), DT_TIME, NoValidation}, - {"chanserv", "forbidexpire", "0", new ValueContainerTime(&conf->CSForbidExpire), DT_TIME, NoValidation}, - {"chanserv", "defbantype", "2", new ValueContainerInt(&conf->CSDefBantype), DT_INTEGER, ValidateChanServ}, - {"chanserv", "accessmax", "0", new ValueContainerUInt(&conf->CSAccessMax), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "autokickmax", "0", new ValueContainerUInt(&conf->CSAutokickMax), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "autokickreason", "User has been banned from the channel", new ValueContainerString(&conf->CSAutokickReason), DT_STRING, ValidateChanServ}, - {"chanserv", "inhabit", "0", new ValueContainerTime(&conf->CSInhabit), DT_TIME, ValidateChanServ}, - {"chanserv", "listmax", "0", new ValueContainerUInt(&conf->CSListMax), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "opersonly", "no", new ValueContainerBool(&conf->CSOpersOnly), DT_BOOLEAN, ValidateChanServ}, - {"chanserv", "mlock", "+nrt", new ValueContainerString(&conf->MLock), DT_STRING | DT_ALLOW_EMPTY, NoValidation}, - {"chanserv", "nomlock", "", new ValueContainerString(&conf->NoMLock), DT_STRING, NoValidation}, - {"chanserv", "require", "", new ValueContainerString(&conf->CSRequire), DT_STRING, NoValidation}, - {"chanserv", "use_server_side_mlock", "yes", new ValueContainerBool(&conf->UseServerSideMLock), DT_BOOLEAN, NoValidation}, - {"chanserv", "use_server_side_topiclock", "yes", new ValueContainerBool(&conf->UseServerSideTopicLock), DT_BOOLEAN, NoValidation}, - {"chanserv", "reasonmax", "200", new ValueContainerUInt(&conf->CSReasonMax), DT_UINTEGER, NoValidation}, - {"memoserv", "name", "", new ValueContainerString(&conf->MemoServ), DT_STRING, NoValidation}, - {"memoserv", "maxmemos", "0", new ValueContainerUInt(&conf->MSMaxMemos), DT_UINTEGER, NoValidation}, - {"memoserv", "senddelay", "0", new ValueContainerTime(&conf->MSSendDelay), DT_TIME, NoValidation}, - {"memoserv", "notifyall", "no", new ValueContainerBool(&conf->MSNotifyAll), DT_BOOLEAN, NoValidation}, - {"memoserv", "memoreceipt", "0", new ValueContainerUInt(&conf->MSMemoReceipt), DT_UINTEGER, NoValidation}, - {"hostserv", "name", "", new ValueContainerString(&conf->HostServ), DT_STRING, NoValidation}, - {"hostserv", "vhost_chars", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJMLMNOPQRSTUVWXYZ0123456789.-", new ValueContainerString(&conf->VhostChars), DT_STRING, NoValidation}, - {"hostserv", "allow_undotted_vhosts", "false", new ValueContainerBool(&conf->VhostUndotted), DT_BOOLEAN, NoValidation}, - {"hostserv", "disallow_start_or_end", "", new ValueContainerString(&conf->VhostDisallowBE), DT_STRING, NoValidation}, - {"botserv", "name", "", new ValueContainerString(&conf->BotServ), DT_STRING, NoValidation}, - {"botserv", "defaults", "", new ValueContainerString(&BSDefaults), DT_STRING, NoValidation}, - {"botserv", "minusers", "0", new ValueContainerUInt(&conf->BSMinUsers), DT_UINTEGER, ValidateBotServ}, - {"botserv", "badwordsmax", "0", new ValueContainerUInt(&conf->BSBadWordsMax), DT_UINTEGER, ValidateBotServ}, - {"botserv", "keepdata", "0", new ValueContainerTime(&conf->BSKeepData), DT_TIME, ValidateBotServ}, - {"botserv", "smartjoin", "no", new ValueContainerBool(&conf->BSSmartJoin), DT_BOOLEAN, NoValidation}, - {"botserv", "gentlebadwordreason", "no", new ValueContainerBool(&conf->BSGentleBWReason), DT_BOOLEAN, NoValidation}, - {"botserv", "casesensitive", "no", new ValueContainerBool(&conf->BSCaseSensitive), DT_BOOLEAN, NoValidation}, - {"botserv", "fantasycharacter", "!", new ValueContainerString(&conf->BSFantasyCharacter), DT_STRING | DT_ALLOW_EMPTY, NoValidation}, - {"operserv", "name", "", new ValueContainerString(&conf->OperServ), DT_STRING, NoValidation}, - {"operserv", "superadmin", "no", new ValueContainerBool(&conf->SuperAdmin), DT_BOOLEAN, NoValidation}, - {"operserv", "autokillexpiry", "0", new ValueContainerTime(&conf->AutokillExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "chankillexpiry", "0", new ValueContainerTime(&conf->ChankillExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "snlineexpiry", "0", new ValueContainerTime(&conf->SNLineExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "sqlineexpiry", "0", new ValueContainerTime(&conf->SQLineExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "akillonadd", "no", new ValueContainerBool(&conf->AkillOnAdd), DT_BOOLEAN, NoValidation}, - {"operserv", "killonsnline", "no", new ValueContainerBool(&conf->KillonSNline), DT_BOOLEAN, NoValidation}, - {"operserv", "killonsqline", "no", new ValueContainerBool(&conf->KillonSQline), DT_BOOLEAN, NoValidation}, - {"operserv", "limitsessions", "no", new ValueContainerBool(&conf->LimitSessions), DT_BOOLEAN, NoValidation}, - {"operserv", "defaultsessionlimit", "0", new ValueContainerUInt(&conf->DefSessionLimit), DT_UINTEGER, NoValidation}, - {"operserv", "maxsessionlimit", "0", new ValueContainerUInt(&conf->MaxSessionLimit), DT_UINTEGER, ValidateOperServ}, - {"operserv", "exceptionexpiry", "0", new ValueContainerTime(&conf->ExceptionExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "sessionlimitexceeded", "", new ValueContainerString(&conf->SessionLimitExceeded), DT_STRING, NoValidation}, - {"operserv", "sessionlimitdetailsloc", "", new ValueContainerString(&conf->SessionLimitDetailsLoc), DT_STRING, NoValidation}, - {"operserv", "maxsessionkill", "0", new ValueContainerUInt(&conf->MaxSessionKill), DT_UINTEGER, NoValidation}, - {"operserv", "sessionautokillexpiry", "0", new ValueContainerTime(&conf->SessionAutoKillExpiry), DT_TIME, NoValidation}, - {"operserv", "session_ipv4_cidr", "32", new ValueContainerUInt(&conf->SessionIPv4CIDR), DT_UINTEGER | DT_NORELOAD, NoValidation}, - {"operserv", "session_ipv6_cidr", "128", new ValueContainerUInt(&conf->SessionIPv6CIDR), DT_UINTEGER | DT_NORELOAD, NoValidation}, - {"operserv", "addakiller", "no", new ValueContainerBool(&conf->AddAkiller), DT_BOOLEAN, NoValidation}, - {"operserv", "akillids", "no", new ValueContainerBool(&conf->AkillIds), DT_BOOLEAN, NoValidation}, - {"operserv", "opersonly", "no", new ValueContainerBool(&conf->OSOpersOnly), DT_BOOLEAN, NoValidation}, - {"global", "name", "", new ValueContainerString(&conf->Global), DT_STRING, NoValidation}, - {"global", "globaloncycle", "no", new ValueContainerBool(&conf->GlobalOnCycle), DT_BOOLEAN, NoValidation}, - {"global", "globaloncycledown", "", new ValueContainerString(&conf->GlobalOnCycleMessage), DT_STRING, ValidateGlobalOnCycle}, - {"global", "globaloncycleup", "", new ValueContainerString(&conf->GlobalOnCycleUP), DT_STRING, ValidateGlobalOnCycle}, - {"global", "anonymousglobal", "no", new ValueContainerBool(&conf->AnonymousGlobal), DT_BOOLEAN, NoValidation}, - {"", "", "", NULL, DT_NOTHING, NoValidation} - }; - - /* These tags can occur multiple times, and therefore they have special code to read them - * which is different to the code for reading the singular tags listed above. */ - MultiItem MultiItems[] = { - /* Include must be first so we can pull in the extra files before processing - * anything else! */ - {"include", - {"type", "name", ""}, - {"", "", ""}, - {DT_STRING, DT_STRING}, - InitInclude, DoInclude, DoneInclude}, - {"define", - {"name", "value", ""}, - {"", "", ""}, - {DT_STRING, DT_STRING}, - InitDefine, DoDefine, DoneDefine}, - {"uplink", - {"host", "ipv6", "port", "password", ""}, - {"", "no", "0", "", ""}, - {DT_HOSTNAME | DT_NORELOAD, DT_BOOLEAN | DT_NORELOAD, DT_UINTEGER | DT_NORELOAD, DT_NOSPACES | DT_NORELOAD}, - InitUplinks, DoUplink, DoneUplinks}, - {"module", - {"name", ""}, - {"", ""}, - {DT_STRING}, - InitModules, DoModule, DoneModules}, - {"opertype", - {"name", "inherits", "commands", "privs", "modes", ""}, - {"", "", "", "", "", ""}, - {DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_STRING}, - InitOperTypes, DoOperType, DoneOperTypes}, - {"oper", - {"name", "type", "require_oper", "password", "certfp", "host", "vhost", ""}, - {"", "", "yes", "", "", "", "", ""}, - {DT_STRING, DT_STRING, DT_BOOLEAN, DT_STRING, DT_STRING, DT_STRING, DT_STRING}, - InitOpers, DoOper, DoneOpers}, - {"service", - {"nick", "user", "host", "gecos", "modes", "channels", ""}, - {"", "", "", "", "", "", ""}, - {DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_STRING}, - InitServices, DoServices, DoneServices}, - {"log", - {"target", "source", "logage", "admin", "override", "commands", "servers", "channels", "users", "other", "rawio", "debug", ""}, - {"", "", "7", "", "", "", "", "", "", "", "no", "no", ""}, - {DT_STRING, DT_STRING, DT_INTEGER, DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_BOOLEAN, DT_BOOLEAN}, - InitLogs, DoLogs, DoneLogs}, - {"command", - {"service", "name", "command", "permission", "group", "hide", ""}, - {"", "", "", "", "", "no", ""}, - {DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_BOOLEAN}, - InitCommands, DoCommands, DoneCommands}, - {"privilege", - {"name", "desc", "rank", ""}, - {"", "", "", ""}, - {DT_STRING, DT_STRING, DT_INTEGER, DT_STRING}, - InitPrivileges, DoPrivileges, DonePrivileges}, - {"fantasy", - {"name", "command", "permission", "group", "hide", "prepend_channel", ""}, - {"", "", "", "", "no", "yes", ""}, - {DT_STRING, DT_STRING, DT_STRING, DT_STRING, DT_BOOLEAN, DT_BOOLEAN}, - InitFantasy, DoFantasy, DoneFantasy}, - {"command_group", - {"name", "description", ""}, - {"", "", ""}, - {DT_STRING, DT_STRING}, - InitCommandGroups, DoCommandGroups, DoneCommandGroups}, - {"", - {""}, - {""}, - {0}, - NULL, NULL, NULL} - }; - - this->Values = new Item[sizeof(Items) / sizeof(Item)]; - for (unsigned i = 0; i < sizeof(Items) / sizeof(Item); ++i) - this->Values[i] = Items[i]; - - this->MultiValues = new MultiItem[sizeof(MultiItems) / sizeof(MultiItem)]; - for (unsigned i = 0; i < sizeof(MultiItems) / sizeof(MultiItem); ++i) - this->MultiValues[i] = MultiItems[i]; -} - -ConfigItems::~ConfigItems() -{ - for (unsigned i = 0; !this->Values[i].tag.empty(); ++i) - delete this->Values[i].val; - delete [] this->Values; - delete [] this->MultiValues; -} - -void ServerConfig::Read() -{ - // These tags MUST occur and must ONLY occur once in the config file - static const Anope::string Once[] = {"serverinfo", "networkinfo", "options", ""}; - - this->LoadConf(ServicesConf); - - ConfigItems configitems(this); - - /* Read the multiple-tag items (class tags, connect tags, etc) - * and call the callbacks associated with them. We have three - * callbacks for these, a 'start', 'item' and 'end' callback. */ - for (int Index = 0; !configitems.MultiValues[Index].tag.empty(); ++Index) - { - configitems.MultiValues[Index].init_function(this, configitems.MultiValues[Index].tag); - int number_of_tags = ConfValueEnum(config_data, configitems.MultiValues[Index].tag); - for (int tagnum = 0; tagnum < number_of_tags; ++tagnum) - { - ValueList vl; - vl.clear(); - for (int valuenum = 0; !configitems.MultiValues[Index].items[valuenum].empty(); ++valuenum) - { - int dt = configitems.MultiValues[Index].datatype[valuenum]; - bool allow_newlines = dt & DT_ALLOW_NEWLINE, allow_wild = dt & DT_ALLOW_WILD, noreload = dt & DT_NORELOAD, allow_empty = dt & DT_ALLOW_EMPTY; - dt &= ~DT_ALLOW_NEWLINE; - dt &= ~DT_ALLOW_WILD; - dt &= ~DT_NORELOAD; - dt &= ~DT_ALLOW_EMPTY; - - ConfigDataHash &hash = (noreload && Config ? Config->config_data : this->config_data); - Anope::string item; - bool has_value = ConfValue(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines); - if (defines.count(item) > 0) - item = defines[item]; - - if (has_value && item.empty() && !allow_empty) - throw ConfigException("Item without value: " + configitems.MultiValues[Index].tag + ":" + configitems.MultiValues[Index].items[valuenum]); - - switch (dt) - { - case DT_NOSPACES: - { - if (has_value) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem()); - ValidateNoSpaces(vl[vl.size() - 1].GetValue(), configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum]); - break; - } - case DT_HOSTNAME: - { - if (has_value) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem()); - ValidateHostname(vl[vl.size() - 1].GetValue(), configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum]); - break; - } - case DT_IPADDRESS: - { - if (has_value) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem()); - ValidateIP(vl[vl.size() - 1].GetValue(), configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], allow_wild); - break; - } - case DT_STRING: - { - if (has_value) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem()); - break; - } - case DT_INTEGER: - case DT_UINTEGER: - case DT_LUINTEGER: - { - int titem = 0; - if (ConfValueInteger(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, titem)) - vl.push_back(ValueItem(titem)); - else - vl.push_back(ValueItem(0)); - break; - } - case DT_TIME: - { - if (has_value) - { -#ifdef _WIN32 - long time = static_cast<long>(Anope::DoTime(item)); -#else - time_t time = Anope::DoTime(item); -#endif - vl.push_back(ValueItem(time)); - } - else - vl.push_back(ValueItem(0)); - break; - } - case DT_BOOLEAN: - { - bool titem = ConfValueBool(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum); - vl.push_back(ValueItem(titem)); - } - } - } - configitems.MultiValues[Index].validation_function(this, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items, vl, configitems.MultiValues[Index].datatype); - } - configitems.MultiValues[Index].finish_function(this, configitems.MultiValues[Index].tag); - } - - // Read the values of all the tags which occur once or not at all, and call their callbacks. - for (int Index = 0; !configitems.Values[Index].tag.empty(); ++Index) - { - Anope::string item; - int dt = configitems.Values[Index].datatype; - bool allow_newlines = dt & DT_ALLOW_NEWLINE, allow_wild = dt & DT_ALLOW_WILD, noreload = dt & DT_NORELOAD, allow_empty = dt & DT_ALLOW_EMPTY; - dt &= ~DT_ALLOW_NEWLINE; - dt &= ~DT_ALLOW_WILD; - dt &= ~DT_NORELOAD; - dt &= ~DT_ALLOW_EMPTY; - - ConfigDataHash &hash = (noreload && Config ? Config->config_data : this->config_data); - bool has_value = ConfValue(hash, configitems.Values[Index].tag, configitems.Values[Index].value, configitems.Values[Index].default_value, 0, item, allow_newlines); - if (defines.count(item) > 0) - item = defines[item]; - - if (has_value && item.empty() && !allow_empty) - throw ConfigException("Item without value: " + configitems.Values[Index].tag + ":" + configitems.Values[Index].value); - - ValueItem vi(item); - - if (!configitems.Values[Index].validation_function(this, configitems.Values[Index].tag, configitems.Values[Index].value, vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your logfiles for more information."); - - switch (dt) - { - case DT_NOSPACES: - { - ValueContainerString *vcs = anope_dynamic_static_cast<ValueContainerString *>(configitems.Values[Index].val); - ValidateNoSpaces(vi.GetValue(), configitems.Values[Index].tag, configitems.Values[Index].value); - vcs->Set(vi.GetValue()); - break; - } - case DT_HOSTNAME: - { - ValueContainerString *vcs = anope_dynamic_static_cast<ValueContainerString *>(configitems.Values[Index].val); - ValidateHostname(vi.GetValue(), configitems.Values[Index].tag, configitems.Values[Index].value); - vcs->Set(vi.GetValue()); - break; - } - case DT_IPADDRESS: - { - ValueContainerString *vcs = anope_dynamic_static_cast<ValueContainerString *>(configitems.Values[Index].val); - ValidateIP(vi.GetValue(), configitems.Values[Index].tag, configitems.Values[Index].value, allow_wild); - vcs->Set(vi.GetValue()); - break; - } - case DT_STRING: - { - ValueContainerString *vcs = anope_dynamic_static_cast<ValueContainerString *>(configitems.Values[Index].val); - vcs->Set(vi.GetValue()); - break; - } - case DT_INTEGER: - { - int val = vi.GetInteger(); - ValueContainerInt *vci = anope_dynamic_static_cast<ValueContainerInt *>(configitems.Values[Index].val); - vci->Set(&val, sizeof(int)); - break; - } - case DT_UINTEGER: - { - unsigned val = vi.GetInteger(); - ValueContainerUInt *vci = anope_dynamic_static_cast<ValueContainerUInt *>(configitems.Values[Index].val); - vci->Set(&val, sizeof(unsigned)); - break; - } - case DT_LUINTEGER: - { - unsigned long val = vi.GetInteger(); - ValueContainerLUInt *vci = anope_dynamic_static_cast<ValueContainerLUInt *>(configitems.Values[Index].val); - vci->Set(&val, sizeof(unsigned long)); - break; - } - case DT_TIME: - { - time_t time = Anope::DoTime(vi.GetValue()); - ValueContainerTime *vci = anope_dynamic_static_cast<ValueContainerTime *>(configitems.Values[Index].val); - vci->Set(&time, sizeof(time_t)); - break; - } - case DT_BOOLEAN: - { - bool val = vi.GetBool(); - ValueContainerBool *vcb = anope_dynamic_static_cast<ValueContainerBool *>(configitems.Values[Index].val); - vcb->Set(&val, sizeof(bool)); - break; - } - default: - break; - } - } - - Log(LOG_DEBUG) << "End config " << ServicesConf.GetName(); - for (int Index = 0; !Once[Index].empty(); ++Index) - CheckOnce(Once[Index]); - Log() << "Done reading configuration file " << ServicesConf.GetName(); -} - -void ServerConfig::LoadConf(ConfigurationFile &file) -{ - Anope::string section, wordbuffer, itemname; - int linenumber = 0; - bool in_word = false, in_quote = false, in_ml_comment = false; - KeyValList sectiondata; if (!file.Open()) - { throw ConfigException("File " + file.GetName() + " could not be opened."); - } + + Anope::string itemname, wordbuffer; + std::stack<Block *> block_stack; + int linenumber = 0; + bool in_word = false, in_quote = false, in_comment = false; + Log(LOG_DEBUG) << "Start to read conf " << file.GetName(); // Start reading characters... while (!file.End()) { Anope::string line = file.Read(); ++linenumber; - unsigned c = 0, len = line.length(); - for (; c < len; ++c) + + for (unsigned c = 0, len = line.length(); c < len; ++c) { char ch = line[c]; if (in_quote) { - /* Strip leading white spaces from multi line comments */ + /* Strip leading white spaces from multi line quotes */ if (c == 0) { + wordbuffer += "\n"; while (c < len && isspace(line[c])) ++c; ch = line[c]; } + /* Allow \" in quotes */ if (ch == '\\' && c + 1 < len && line[c + 1] == '"') wordbuffer += line[++c]; else if (ch == '"') in_quote = in_word = false; - else + else if (ch) wordbuffer += ch; } - else if (in_ml_comment) + else if (in_comment) { if (ch == '*' && c + 1 < len && line[c + 1] == '/') { - in_ml_comment = false; + in_comment = false; ++c; } continue; @@ -1632,7 +698,7 @@ void ServerConfig::LoadConf(ConfigurationFile &file) else if (ch == '/' && c + 1 < len && line[c + 1] == '*') { // Multiline (or less than one line) comment - in_ml_comment = true; + in_comment = true; ++c; continue; } @@ -1641,7 +707,7 @@ void ServerConfig::LoadConf(ConfigurationFile &file) else if (ch == '"') { // Quotes are valid only in the value position - if (section.empty() || itemname.empty()) + if (block_stack.empty() || itemname.empty()) { file.Close(); throw ConfigException("Unexpected quoted string: " + file.GetName() + ":" + stringify(linenumber)); @@ -1655,36 +721,45 @@ void ServerConfig::LoadConf(ConfigurationFile &file) } else if (ch == '=') { - if (section.empty()) + if (block_stack.empty()) { file.Close(); throw ConfigException("Config item outside of section (or stray '='): " + file.GetName() + ":" + stringify(linenumber)); } - if (!itemname.empty()) + + if (!itemname.empty() || wordbuffer.empty()) { file.Close(); throw ConfigException("Stray '=' sign or item without value: " + file.GetName() + ":" + stringify(linenumber)); } - if (in_word) - in_word = false; + + in_word = false; itemname = wordbuffer; wordbuffer.clear(); } else if (ch == '{') { - if (!section.empty()) - { - file.Close(); - throw ConfigException("Section inside another section: " + file.GetName() + ":" + stringify(linenumber)); - } if (wordbuffer.empty()) { - file.Close(); - throw ConfigException("Section without a name or unexpected '{': " + file.GetName() + ":" + stringify(linenumber)); + block_stack.push(NULL); + // Commented or unnamed section + continue; } - if (in_word) + + if (!block_stack.empty() && !block_stack.top()) + { + // Named block inside of a commented block in_word = false; - section = wordbuffer; + wordbuffer.clear(); + block_stack.push(NULL); + continue; + } + + Block *b = block_stack.empty() ? this : block_stack.top(); + block_map::iterator it = b->blocks.insert(std::make_pair(wordbuffer, Configuration::Block(wordbuffer))); + block_stack.push(&it->second); + + in_word = false; wordbuffer.clear(); continue; } @@ -1720,30 +795,59 @@ void ServerConfig::LoadConf(ConfigurationFile &file) wordbuffer += "\n"; continue; } + in_word = false; if (!itemname.empty()) { - Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << section << "' '" << itemname << "' set to '" << wordbuffer << "'"; - sectiondata.push_back(KeyVal(itemname, wordbuffer)); + if (block_stack.empty()) + { + file.Close(); + throw ConfigException("Stray ';' outside of block: " + file.GetName() + ":" + stringify(linenumber)); + } + + Block *b = block_stack.top(); + + if (b) + Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'"; + + if (itemname.empty()) + { + file.Close(); + throw ConfigException("Item without a name: " + file.GetName() + ":" + stringify(linenumber)); + } + + /* 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"); + + if (dname == wordbuffer) + wordbuffer = define->Get<const Anope::string &>("value"); + } + + if (b) + b->items[itemname] = wordbuffer; + wordbuffer.clear(); itemname.clear(); } if (ch == '}') { - if (section.empty()) + if (block_stack.empty()) { file.Close(); throw ConfigException("Stray '}': " + file.GetName() + ":" + stringify(linenumber)); } - this->config_data.insert(std::pair<Anope::string, KeyValList>(section, sectiondata)); - section.clear(); - sectiondata.clear(); + + block_stack.pop(); } } } } - if (in_ml_comment) + if (in_comment) { file.Close(); throw ConfigException("Unterminated multiline comment at end of file: " + file.GetName()); @@ -1758,212 +862,7 @@ void ServerConfig::LoadConf(ConfigurationFile &file) file.Close(); throw ConfigException("Unexpected garbage at end of file: " + file.GetName()); } - if (!section.empty()) - { - file.Close(); - throw ConfigException("Unterminated section at end of file: " + file.GetName()); - } file.Close(); } -bool ServerConfig::ConfValue(ConfigDataHash &target, const Anope::string &tag, const Anope::string &var, int index, Anope::string &result, bool allow_linefeeds) -{ - return ConfValue(target, tag, var, "", index, result, allow_linefeeds); -} - -bool ServerConfig::ConfValue(ConfigDataHash &target, const Anope::string &tag, const Anope::string &var, const Anope::string &default_value, int index, Anope::string &result, bool allow_linefeeds) -{ - ConfigDataHash::size_type pos = index; - if (pos < target.count(tag)) - { - ConfigDataHash::iterator iter = target.find(tag); - - for (int i = 0; i < index; ++i) - ++iter; - - KeyValList::iterator j = iter->second.begin(), jend = iter->second.end(); - for (; j != jend; ++j) - { - if (j->first.equals_ci(var)) - { - if (!allow_linefeeds && j->second.find('\n') != Anope::string::npos) - { - Log(LOG_DEBUG) << "Value of <" << tag << ":" << var << "> contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces."; - j->second.replace_all_cs("\n", " "); - } - else - { - result = j->second; - return true; - } - } - } - if (!default_value.empty()) - { - result = default_value; - return true; - } - } - else if (!pos) - { - if (!default_value.empty()) - { - result = default_value; - return true; - } - } - return false; -} - -bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const Anope::string &tag, const Anope::string &var, int index, int &result) -{ - return ConfValueInteger(target, tag, var, "", index, result); -} - -bool ServerConfig::ConfValueInteger(ConfigDataHash &target, const Anope::string &tag, const Anope::string &var, const Anope::string &default_value, int index, int &result) -{ - Anope::string value; - std::istringstream stream; - bool r = ConfValue(target, tag, var, default_value, index, value); - stream.str(value.str()); - if (!(stream >> result)) - return false; - else - { - if (!value.empty()) - { - if (value.substr(0, 2).equals_ci("0x")) - { - char *endptr; - - value.erase(0, 2); - result = strtol(value.c_str(), &endptr, 16); - - /* No digits found */ - if (endptr == value.c_str()) - return false; - } - else - { - char denominator = *(value.end() - 1); - switch (toupper(denominator)) - { - case 'K': - // Kilobytes -> bytes - result = result * 1024; - break; - case 'M': - // Megabytes -> bytes - result = result * 1048576; - break; - case 'G': - // Gigabytes -> bytes - result = result * 1073741824; - } - } - } - } - return r; -} - -bool ServerConfig::ConfValueBool(ConfigDataHash &target, const Anope::string &tag, const Anope::string &var, int index) -{ - return ConfValueBool(target, tag, var, "", index); -} - -bool ServerConfig::ConfValueBool(ConfigDataHash &target, const Anope::string &tag, const Anope::string &var, const Anope::string &default_value, int index) -{ - Anope::string result; - if (!ConfValue(target, tag, var, default_value, index, result)) - return false; - - return result.equals_ci("yes") || result.equals_ci("true") || result.equals_ci("1"); -} - -int ServerConfig::ConfValueEnum(const ConfigDataHash &target, const Anope::string &tag) -{ - return target.count(tag); -} - -int ServerConfig::ConfVarEnum(ConfigDataHash &target, const Anope::string &tag, int index) -{ - ConfigDataHash::size_type pos = index; - - if (pos < target.count(tag)) - { - ConfigDataHash::const_iterator iter = target.find(tag); - - for (int i = 0; i < index; ++i) - ++iter; - - return iter->second.size(); - } - - return 0; -} - -ValueItem::ValueItem() { } - -ValueItem::ValueItem(int value) : v("") -{ - std::stringstream n; - n << value; - v = n.str(); -} - -ValueItem::ValueItem(long value) : v("") -{ - std::stringstream n; - n << value; - v = n.str(); -} - -ValueItem::ValueItem(bool value) : v("") -{ - std::stringstream n; - n << value; - v = n.str(); -} - -ValueItem::ValueItem(const Anope::string &value) : v(value) { } - -void ValueItem::Set(const Anope::string &value) -{ - v = value; -} - -void ValueItem::Set(int value) -{ - std::stringstream n; - n << value; - v = n.str(); -} - -int ValueItem::GetInteger() const -{ - if (v.empty() || !v.is_number_only()) - return 0; - try - { - return convertTo<int>(v); - } - catch (const ConvertException &) - { - Log() << "Unable to convert configuration value " << this->v << " to an integer. Value too large?"; - } - - return 0; -} - -const char *ValueItem::GetString() const -{ - return v.c_str(); -} - -bool ValueItem::GetBool() const -{ - return GetInteger() || v == "yes" || v == "true"; -} - - diff --git a/src/configreader.cpp b/src/configreader.cpp deleted file mode 100644 index ca5a64a60..000000000 --- a/src/configreader.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* Configuration file handling. - * - * (C) 2003-2013 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - * - */ - -/* Taken from: - * +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ - * - * InspIRCd: (C) 2002-2011 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits - * - * This program is free but copyrighted software; see - * the file COPYING for details. - * - * --------------------------------------------------- - */ - -#include "services.h" -#include "config.h" - -ConfigReader::ConfigReader() : conf(Config), error(CONF_NO_ERROR) -{ -} - -ConfigReader::ConfigReader(const Anope::string &filename) : conf(Config), error(CONF_NO_ERROR) -{ -} - -ConfigReader::ConfigReader(ServerConfig *c) : conf(c), error(CONF_NO_ERROR) -{ -} - -ConfigReader::~ConfigReader() -{ -} - -Anope::string ConfigReader::ReadValue(const Anope::string &tag, const Anope::string &name, const Anope::string &default_value, int index, bool allow_linefeeds) -{ - /* Don't need to strlcpy() tag and name anymore, ReadConf() takes const char* */ - Anope::string result; - - if (!conf->ConfValue(conf->config_data, tag, name, default_value, index, result, allow_linefeeds)) - this->error = CONF_VALUE_NOT_FOUND; - - return result; -} - -Anope::string ConfigReader::ReadValue(const Anope::string &tag, const Anope::string &name, int index, bool allow_linefeeds) -{ - return ReadValue(tag, name, "", index, allow_linefeeds); -} - -bool ConfigReader::ReadFlag(const Anope::string &tag, const Anope::string &name, const Anope::string &default_value, int index) -{ - return conf->ConfValueBool(conf->config_data, tag, name, default_value, index); -} - -bool ConfigReader::ReadFlag(const Anope::string &tag, const Anope::string &name, int index) -{ - return ReadFlag(tag, name, "", index); -} - -int ConfigReader::ReadInteger(const Anope::string &tag, const Anope::string &name, const Anope::string &default_value, int index, bool need_positive) -{ - int result; - - if (!conf->ConfValueInteger(conf->config_data, tag, name, default_value, index, result)) - { - this->error = CONF_VALUE_NOT_FOUND; - return 0; - } - - if (need_positive && result < 0) - { - this->error = CONF_INT_NEGATIVE; - return 0; - } - - return result; -} - -int ConfigReader::ReadInteger(const Anope::string &tag, const Anope::string &name, int index, bool need_positive) -{ - return ReadInteger(tag, name, "", index, need_positive); -} - -long ConfigReader::GetError() -{ - long olderr = this->error; - this->error = 0; - return olderr; -} - -int ConfigReader::Enumerate(const Anope::string &tag) const -{ - return conf->ConfValueEnum(conf->config_data, tag); -} - -int ConfigReader::EnumerateValues(const Anope::string &tag, int index) -{ - return conf->ConfVarEnum(conf->config_data, tag, index); -} - -bool ConfigReader::Verify() -{ - return this->readerror; -} diff --git a/src/init.cpp b/src/init.cpp index b0812fedc..27f0a8689 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -120,8 +120,8 @@ void Anope::HandleSignal() try { - ServerConfig *new_config = new ServerConfig(); - delete Config; + Configuration::Conf *new_config = new Configuration::Conf(); + delete new_config; Config = new_config; } catch (const ConfigException &ex) @@ -197,14 +197,14 @@ static void InitSignals() static void remove_pidfile() { - remove(Config->PIDFilename.c_str()); + remove(Config->GetBlock("serverinfo")->Get<const char *>("pid")); } /* Create our PID file and write the PID to it. */ static void write_pidfile() { - FILE *pidfile = fopen(Config->PIDFilename.c_str(), "w"); + FILE *pidfile = fopen(Config->GetBlock("serverinfo")->Get<const char *>("pid"), "w"); if (pidfile) { #ifdef _WIN32 @@ -216,7 +216,7 @@ static void write_pidfile() atexit(remove_pidfile); } else - throw CoreException("Can not write to PID file " + Config->PIDFilename); + throw CoreException("Can not write to PID file " + Config->GetBlock("serverinfo")->Get<const Anope::string &>("pid")); } void Anope::Init(int ac, char **av) @@ -303,7 +303,7 @@ void Anope::Init(int ac, char **av) { if (arg.empty()) throw CoreException("The --config option requires a file name"); - ServicesConf = ConfigurationFile(arg, false); + ServicesConf = Configuration::File(arg, false); } if (GetCommandLineArgument("confdir", 0, arg)) @@ -413,7 +413,7 @@ void Anope::Init(int ac, char **av) /* Read configuration file; exit if there are problems. */ try { - Config = new ServerConfig(); + Config = new Configuration::Conf(); } catch (const ConfigException &ex) { @@ -429,7 +429,8 @@ void Anope::Init(int ac, char **av) write_pidfile(); /* Create me */ - Me = new Server(NULL, Config->ServerName, 0, Config->ServerDesc, Config->Numeric); + Configuration::Block *block = Config->GetBlock("serverinfo"); + Me = new Server(NULL, block->Get<const Anope::string &>("name"), 0, block->Get<const Anope::string &>("description"), block->Get<const Anope::string &>("id")); for (botinfo_map::const_iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it) { it->second->server = Me; @@ -445,12 +446,13 @@ void Anope::Init(int ac, char **av) Language::InitLanguages(); /* Initialize random number generator */ - srand(Config->Seed); + block = Config->GetBlock("options"); + srand(block->Get<unsigned>("seed")); /* load modules */ Log() << "Loading modules..."; - for (std::list<Anope::string>::iterator it = Config->ModulesAutoLoad.begin(), it_end = Config->ModulesAutoLoad.end(); it != it_end; ++it) - ModuleManager::LoadModule(*it, NULL); + for (int i = 0; i < Config->CountBlock("module"); ++i) + ModuleManager::LoadModule(Config->GetBlock("module", i)->Get<const Anope::string &>("name"), NULL); Module *protocol = ModuleManager::FindFirstOf(PROTOCOL); if (protocol == NULL) diff --git a/src/language.cpp b/src/language.cpp index ec2e0e39b..80f4477c2 100644 --- a/src/language.cpp +++ b/src/language.cpp @@ -37,7 +37,7 @@ void Language::InitLanguages() setlocale(LC_ALL, ""); - spacesepstream sep(Config->Languages); + spacesepstream sep(Config->GetBlock("options")->Get<const Anope::string &>("languages")); Anope::string language; while (sep.GetToken(language)) { @@ -58,7 +58,7 @@ void Language::InitLanguages() const char *Language::Translate(const char *string) { - return Translate(Config->NSDefLanguage.c_str(), string); + return Translate("", string); } const char *Language::Translate(User *u, const char *string) @@ -66,12 +66,12 @@ const char *Language::Translate(User *u, const char *string) if (u && u->Account()) return Translate(u->Account(), string); else - return Translate(string); + return Translate("", string); } const char *Language::Translate(const NickCore *nc, const char *string) { - return Translate(nc ? nc->language.c_str() : Config->NSDefLanguage.c_str(), string); + return Translate(nc ? nc->language.c_str() : "", string); } #if GETTEXT_FOUND @@ -81,8 +81,11 @@ extern "C" int _nl_msg_cat_cntr; const char *Language::Translate(const char *lang, const char *string) { - if (!string || !*string || !lang || !*lang) - return string ? string : ""; + if (!string || !*string) + return ""; + + if (!lang || !*lang) + lang = Config->DefLanguage.c_str(); ++_nl_msg_cat_cntr; #ifdef _WIN32 diff --git a/src/logger.cpp b/src/logger.cpp index f738cb2e1..d071b7cc3 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -21,7 +21,6 @@ #include "servers.h" #include "uplink.h" #include "protocol.h" -#include "global.h" #ifndef _WIN32 #include <sys/time.h> @@ -149,8 +148,8 @@ Log::~Log() if (Config) for (unsigned i = 0; i < Config->LogInfos.size(); ++i) - if (Config->LogInfos[i]->HasType(this->type, this->category)) - Config->LogInfos[i]->ProcessMessage(this); + if (Config->LogInfos[i].HasType(this->type, this->category)) + Config->LogInfos[i].ProcessMessage(this); FOREACH_MOD(I_OnLog, OnLog(this)); } diff --git a/src/mail.cpp b/src/mail.cpp index 851fe6d4e..3b2b1272f 100644 --- a/src/mail.cpp +++ b/src/mail.cpp @@ -14,7 +14,7 @@ #include "mail.h" #include "config.h" -Mail::Message::Message(const Anope::string &sf, const Anope::string &mailto, const Anope::string &a, const Anope::string &s, const Anope::string &m) : Thread(), sendmail_path(Config->SendMailPath), send_from(sf), mail_to(mailto), addr(a), subject(s), message(m), dont_quote_addresses(Config->DontQuoteAddresses), success(false) +Mail::Message::Message(const Anope::string &sf, const Anope::string &mailto, const Anope::string &a, const Anope::string &s, const Anope::string &m) : Thread(), sendmail_path(Config->GetBlock("mail")->Get<const Anope::string &>("sendmailpath")), send_from(sf), mail_to(mailto), addr(a), subject(s), message(m), dont_quote_addresses(Config->GetBlock("mail")->Get<bool>("dontquoteaddresses")), success(false) { } @@ -55,31 +55,33 @@ bool Mail::Send(User *u, NickCore *nc, const BotInfo *service, const Anope::stri { if (!nc || !service || subject.empty() || message.empty()) return false; + + Configuration::Block *b = Config->GetBlock("mail"); if (!u) { - if (!Config->UseMail) + if (!b->Get<bool>("usemail") || b->Get<const Anope::string &>("sendfrom").empty()) return false; else if (nc->email.empty()) return false; nc->lastmail = Anope::CurTime; - Thread *t = new Mail::Message(Config->SendFrom, nc->display, nc->email, subject, message); + Thread *t = new Mail::Message(b->Get<const Anope::string &>("sendfrom"), nc->display, nc->email, subject, message); t->Start(); return true; } else { - if (!Config->UseMail) + if (!b->Get<bool>("usemail") || b->Get<const Anope::string &>("sendfrom").empty()) u->SendMessage(service, _("Services have been configured to not send mail.")); - else if (Anope::CurTime - u->lastmail < Config->MailDelay) - u->SendMessage(service, _("Please wait \002%d\002 seconds and retry."), Config->MailDelay - (Anope::CurTime - u->lastmail)); + else if (Anope::CurTime - u->lastmail < b->Get<time_t>("delay")) + u->SendMessage(service, _("Please wait \002%d\002 seconds and retry."), b->Get<time_t>("delay") - (Anope::CurTime - u->lastmail)); else if (nc->email.empty()) u->SendMessage(service, _("E-mail for \002%s\002 is invalid."), nc->display.c_str()); else { u->lastmail = nc->lastmail = Anope::CurTime; - Thread *t = new Mail::Message(Config->SendFrom, nc->display, nc->email, subject, message); + Thread *t = new Mail::Message(b->Get<const Anope::string &>("sendfrom"), nc->display, nc->email, subject, message); t->Start(); return true; } @@ -90,11 +92,12 @@ bool Mail::Send(User *u, NickCore *nc, const BotInfo *service, const Anope::stri bool Mail::Send(NickCore *nc, const Anope::string &subject, const Anope::string &message) { - if (!Config->UseMail || !nc || nc->email.empty() || subject.empty() || message.empty()) + Configuration::Block *b = Config->GetBlock("mail"); + if (!b->Get<bool>("usemail") || b->Get<const Anope::string &>("sendfrom").empty() || !nc || nc->email.empty() || subject.empty() || message.empty()) return false; nc->lastmail = Anope::CurTime; - Thread *t = new Mail::Message(Config->SendFrom, nc->display, nc->email, subject, message); + Thread *t = new Mail::Message(b->Get<const Anope::string &>("sendfrom"), nc->display, nc->email, subject, message); t->Start(); return true; diff --git a/src/main.cpp b/src/main.cpp index 059650df0..12fc1335c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -144,12 +144,12 @@ int main(int ac, char **av, char **envp) } catch (const SocketException &ex) { - Log(LOG_TERMINAL) << "Unable to connect to uplink #" << Anope::CurrentUplink << " (" << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port << "): " << ex.GetReason(); + Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << "): " << ex.GetReason(); } /* Set up timers */ time_t last_check = Anope::CurTime; - UpdateTimer updateTimer(Config->UpdateTimeout); + UpdateTimer updateTimer(Config->GetBlock("options")->Get<time_t>("updatetimeout")); /*** Main loop. ***/ while (!Anope::Quitting) @@ -157,7 +157,7 @@ int main(int ac, char **av, char **envp) Log(LOG_DEBUG_2) << "Top of main loop"; /* Process timers */ - if (Anope::CurTime - last_check >= Config->TimeoutCheck) + if (Anope::CurTime - last_check >= Config->GetBlock("options")->Get<time_t>("timeoutcheck")) { TimerManager::TickTimers(Anope::CurTime); last_check = Anope::CurTime; diff --git a/src/messages.cpp b/src/messages.cpp index c9ffd3c59..9bbfb42c0 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -126,9 +126,6 @@ void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, co const ChannelStatus &status = it->first; User *u = it->second; - EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); - /* Add the user to the channel */ ChanUserContainer *cc = c->JoinUser(u); @@ -141,14 +138,8 @@ void Join::SJoin(MessageSource &source, const Anope::string &chan, time_t ts, co */ c->SetCorrectModes(u, true, true); - /* Check to see if modules want the user to join, if they do - * check to see if they are allowed to join (CheckKick will kick/ban them - * if they aren't). - */ - if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u)) - continue; - - FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); + if (c->ci) + c->ci->CheckKick(u); } /* Channel is done syncing */ @@ -234,10 +225,10 @@ void MOTD::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) if (s != Me) return; - FILE *f = fopen(Config->MOTDFilename.c_str(), "r"); + FILE *f = fopen(Config->GetBlock("serverinfo")->Get<const char *>("motd"), "r"); if (f) { - IRCD->SendNumeric(375, source.GetSource(), ":- %s Message of the Day", Config->ServerName.c_str()); + IRCD->SendNumeric(375, source.GetSource(), ":- %s Message of the Day", s->GetName().c_str()); char buf[BUFSIZE]; while (fgets(buf, sizeof(buf), f)) { @@ -304,16 +295,16 @@ void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> ¶m { Anope::string servername(receiver.begin() + s + 1, receiver.end()); botname = botname.substr(0, s); - if (!servername.equals_ci(Config->ServerName)) + if (!servername.equals_ci(Me->GetName())) return; } - else if (Config->UseStrictPrivMsg) + else if (Config->GetBlock("options")->Get<bool>("usestrictprivmsg")) { const BotInfo *bi = BotInfo::Find(receiver); if (!bi) return; Log(LOG_DEBUG) << "Ignored PRIVMSG without @ from " << u->nick; - u->SendMessage(bi, _("\"/msg %s\" is no longer supported. Use \"/msg %s@%s\" or \"/%s\" instead."), bi->nick.c_str(), bi->nick.c_str(), Config->ServerName.c_str(), bi->nick.c_str()); + u->SendMessage(bi, _("\"/msg %s\" is no longer supported. Use \"/msg %s@%s\" or \"/%s\" instead."), bi->nick.c_str(), bi->nick.c_str(), Me->GetName().c_str(), bi->nick.c_str()); return; } @@ -338,7 +329,7 @@ void Privmsg::Run(MessageSource &source, const std::vector<Anope::string> ¶m else if (message.substr(0, 9).equals_ci("\1VERSION\1")) { Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - IRCD->SendCTCP(bi, u->nick, "VERSION Anope-%s %s :%s - (%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); + IRCD->SendCTCP(bi, u->nick, "VERSION Anope-%s %s :%s - (%s) -- %s", Anope::Version().c_str(), Me->GetName().c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); } return; } @@ -357,16 +348,7 @@ void Quit::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) Log(user, "quit") << "quit (Reason: " << (!reason.empty() ? reason : "no reason") << ")"; - NickAlias *na = NickAlias::Find(user->nick); - if (na && !na->nc->HasExt("SUSPENDED") && (user->IsRecognized() || user->IsIdentified(true))) - { - na->last_seen = Anope::CurTime; - na->last_quit = reason; - } - FOREACH_MOD(I_OnUserQuit, OnUserQuit(user, reason)); user->Quit(reason); - - return; } void SQuit::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) @@ -382,8 +364,6 @@ void SQuit::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) FOREACH_MOD(I_OnServerQuit, OnServerQuit(s)); s->Delete(s->GetName() + " " + s->GetUplink()->GetName()); - - return; } void Stats::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) @@ -396,7 +376,7 @@ void Stats::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) if (u->HasMode("OPER")) { IRCD->SendNumeric(211, source.GetSource(), "Server SendBuf SentBytes SentMsgs RecvBuf RecvBytes RecvMsgs ConnTime"); - IRCD->SendNumeric(211, source.GetSource(), "%s %d %d %d %d %d %d %ld", Config->Uplinks[Anope::CurrentUplink]->host.c_str(), UplinkSock->WriteBufferLen(), TotalWritten, -1, UplinkSock->ReadBufferLen(), TotalRead, -1, static_cast<long>(Anope::CurTime - Anope::StartTime)); + IRCD->SendNumeric(211, source.GetSource(), "%s %d %d %d %d %d %d %ld", Config->Uplinks[Anope::CurrentUplink].host.c_str(), UplinkSock->WriteBufferLen(), TotalWritten, -1, UplinkSock->ReadBufferLen(), TotalRead, -1, static_cast<long>(Anope::CurTime - Anope::StartTime)); } IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]); @@ -404,7 +384,7 @@ void Stats::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) case 'o': case 'O': /* Check whether the user is an operator */ - if (!u->HasMode("OPER") && Config->HideStatsO) + if (!u->HasMode("OPER") && Config->GetBlock("options")->Get<bool>("hidestatso")) IRCD->SendNumeric(219, source.GetSource(), "%c :End of /STATS report.", params[0][0]); else { @@ -444,7 +424,7 @@ void Time::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) struct tm *tm = localtime(&t); char buf[64]; strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y %Z", tm); - IRCD->SendNumeric(391, source.GetSource(), "%s :%s", Config->ServerName.c_str(), buf); + IRCD->SendNumeric(391, source.GetSource(), "%s :%s", Me->GetName().c_str(), buf); return; } @@ -460,7 +440,7 @@ void Topic::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) void Version::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) { Module *enc = ModuleManager::FindFirstOf(ENCRYPTION); - IRCD->SendNumeric(351, source.GetSource(), "Anope-%s %s :%s -(%s) -- %s", Anope::Version().c_str(), Config->ServerName.c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); + IRCD->SendNumeric(351, source.GetSource(), "Anope-%s %s :%s -(%s) -- %s", Anope::Version().c_str(), Me->GetName().c_str(), IRCD->GetProtocolName().c_str(), enc ? enc->name.c_str() : "(none)", Anope::VersionBuildString().c_str()); return; } @@ -474,7 +454,7 @@ void Whois::Run(MessageSource &source, const std::vector<Anope::string> ¶ms) IRCD->SendNumeric(311, source.GetSource(), "%s %s %s * :%s", u->nick.c_str(), u->GetIdent().c_str(), u->host.c_str(), u->realname.c_str()); if (bi) IRCD->SendNumeric(307, source.GetSource(), "%s :is a registered nick", bi->nick.c_str()); - IRCD->SendNumeric(312, source.GetSource(), "%s %s :%s", u->nick.c_str(), Config->ServerName.c_str(), Config->ServerDesc.c_str()); + IRCD->SendNumeric(312, source.GetSource(), "%s %s :%s", u->nick.c_str(), Me->GetName().c_str(), Config->GetBlock("serverinfo")->Get<const char *>("description")); if (bi) IRCD->SendNumeric(317, source.GetSource(), "%s %ld %ld :seconds idle, signon time", bi->nick.c_str(), static_cast<long>(Anope::CurTime - bi->lastmsg), static_cast<long>(bi->signon)); IRCD->SendNumeric(318, source.GetSource(), "%s :End of /WHOIS list.", params[0].c_str()); diff --git a/src/misc.cpp b/src/misc.cpp index 20a53e7cc..86328b6b3 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -43,10 +43,18 @@ NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(tr if (t == Anope::string::npos) { - unsigned num = convertTo<unsigned>(token, error, false); - if (error.empty()) - numbers.insert(num); - else + try + { + unsigned num = convertTo<unsigned>(token, error, false); + if (error.empty()) + numbers.insert(num); + } + catch (const ConvertException &) + { + error = "1"; + } + + if (!error.empty()) { if (!this->InvalidRange(list)) { @@ -58,14 +66,20 @@ NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(tr else { Anope::string error2; - unsigned num1 = convertTo<unsigned>(token.substr(0, t), error, false); - unsigned num2 = convertTo<unsigned>(token.substr(t + 1), error2, false); - if (error.empty() && error2.empty()) + try { - for (unsigned i = num1; i <= num2; ++i) - numbers.insert(i); + unsigned num1 = convertTo<unsigned>(token.substr(0, t), error, false); + unsigned num2 = convertTo<unsigned>(token.substr(t + 1), error2, false); + if (error.empty() && error2.empty()) + for (unsigned i = num1; i <= num2; ++i) + numbers.insert(i); } - else + catch (const ConvertException &) + { + error = "1"; + } + + if (!error.empty() || !error2.empty()) { if (!this->InvalidRange(list)) { @@ -232,7 +246,7 @@ bool Anope::IsFile(const Anope::string &filename) time_t Anope::DoTime(const Anope::string &s) { if (s.empty()) - return -1; + return 0; int amount = 0; Anope::string end; @@ -257,7 +271,7 @@ time_t Anope::DoTime(const Anope::string &s) case 'y': return amount * 86400 * 365; default: - return -1; + break; } } } @@ -368,7 +382,7 @@ bool Anope::Match(const Anope::string &str, const Anope::string &mask, bool case if (r == NULL || r->GetExpression() != stripped_mask) { - ServiceReference<RegexProvider> provider("Regex", Config->RegexEngine); + ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options")->Get<const Anope::string &>("regexengine")); if (provider) { try diff --git a/src/modes.cpp b/src/modes.cpp index 6cdeb6565..9481f570e 100644 --- a/src/modes.cpp +++ b/src/modes.cpp @@ -31,12 +31,13 @@ static std::vector<ChannelModeStatus *> ChannelModesByStatus; /* Number of generic modes we support */ unsigned ModeManager::GenericChannelModes = 0, ModeManager::GenericUserModes = 0; -/* Default channel mode lock */ -std::list<std::pair<Anope::string, Anope::string> > ModeManager::ModeLockOn; -std::list<Anope::string> ModeManager::ModeLockOff; +ChannelStatus::ChannelStatus() +{ +} -/* Default modes bots have on channels */ -ChannelStatus ModeManager::DefaultBotModes; +ChannelStatus::ChannelStatus(const Anope::string &m) : modes(m) +{ +} void ChannelStatus::AddMode(char c) { @@ -75,7 +76,7 @@ Anope::string ChannelStatus::BuildModePrefixList() const for (size_t i = 0; i < modes.length(); ++i) { - ChannelMode *cm = ModeManager::FindChannelModeByName(modes[i]); + ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); if (cm != NULL && cm->type == MODE_STATUS) { ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm); @@ -117,9 +118,9 @@ ChannelMode::~ChannelMode() bool ChannelMode::CanSet(User *u) const { - if (Config->NoMLock.find(this->mchar) != Anope::string::npos || Config->CSRequire.find(this->mchar) != Anope::string::npos) - return false; - return true; + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnCanSet, OnCanSet(u, this)); + return MOD_RESULT == EVENT_ALLOW; } ChannelModeList::ChannelModeList(const Anope::string &cm, char mch) : ChannelMode(cm, mch) @@ -358,9 +359,6 @@ bool ModeManager::AddChannelMode(ChannelMode *cm) ChannelModesByName[cm->name] = cm; - /* Apply this mode to the new default mlock if its used */ - UpdateDefaultMLock(Config); - FOREACH_MOD(I_OnChannelModeAdd, OnChannelModeAdd(cm)); return true; @@ -621,66 +619,6 @@ void ModeManager::StackerDel(Mode *m) } } -void ModeManager::UpdateDefaultMLock(ServerConfig *config) -{ - ModeLockOn.clear(); - ModeLockOff.clear(); - - Anope::string modes; - spacesepstream sep(config->MLock); - sep.GetToken(modes); - - int adding = -1; - for (unsigned i = 0, end_mode = modes.length(); i < end_mode; ++i) - { - if (modes[i] == '+') - adding = 1; - else if (modes[i] == '-') - adding = 0; - else if (adding != -1) - { - ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]); - - if (cm && cm->type != MODE_STATUS) - { - Anope::string param; - if (adding == 1 && cm->type != MODE_REGULAR && !sep.GetToken(param)) // MODE_LIST OR MODE_PARAM - { - Log() << "Warning: Got default mlock mode " << cm->mchar << " with no param?"; - continue; - } - - if (cm->type != MODE_LIST) // Only MODE_LIST can have duplicates - { - for (std::list<std::pair<Anope::string, Anope::string> >::iterator it = ModeLockOn.begin(), it_end = ModeLockOn.end(); it != it_end; ++it) - if (it->first == cm->name) - { - ModeLockOn.erase(it); - break; - } - - for (std::list<Anope::string>::iterator it = ModeLockOff.begin(), it_end = ModeLockOff.end(); it != it_end; ++it) - if (*it == cm->name) - { - ModeLockOff.erase(it); - break; - } - } - - if (adding) - ModeLockOn.push_back(std::make_pair(cm->name, param)); - else - ModeLockOff.push_back(cm->name); - } - } - } - - /* Set Bot Modes */ - DefaultBotModes.Clear(); - for (unsigned i = 0; i < config->BotModes.length(); ++i) - DefaultBotModes.AddMode(config->BotModes[i]); -} - Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0) { Anope::string n, u, h; diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp index 82691822f..211304cae 100644 --- a/src/modulemanager.cpp +++ b/src/modulemanager.cpp @@ -229,10 +229,9 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) /* If the module is hooked to the reload event it wants to initialize its config here */ if (std::find(EventHandlers[I_OnReload].begin(), EventHandlers[I_OnReload].end(), m) != EventHandlers[I_OnReload].end()) { - ConfigReader reader; try { - m->OnReload(Config, reader); + m->OnReload(Config); } catch (const ConfigException &ex) { diff --git a/src/nickalias.cpp b/src/nickalias.cpp index 5e6960cc6..0de2f6d0a 100644 --- a/src/nickalias.cpp +++ b/src/nickalias.cpp @@ -139,7 +139,8 @@ class CoreExport NickServRelease : public User, public Timer * @param na The nick * @param delay The delay before the nick is released */ - NickServRelease(NickAlias *na, time_t delay) : User(na->nick, Config->NSEnforcerUser, Config->NSEnforcerHost, "", "", Me, "Services Enforcer", Anope::CurTime, "", Servers::TS6_UID_Retrieve()), Timer(delay), nick(na->nick) + NickServRelease(NickAlias *na, time_t delay) : User(na->nick, Config->GetBlock("options")->Get<const Anope::string &>("enforceruser"), + Config->GetBlock("options")->Get<const Anope::string &>("enforcerhost"), "", "", Me, "Services Enforcer", Anope::CurTime, "", Servers::TS6_UID_Retrieve()), Timer(delay), nick(na->nick) { /* Erase the current release timer and use the new one */ std::map<Anope::string, NickServRelease *>::iterator nit = NickServReleases.find(this->nick); @@ -176,12 +177,12 @@ void NickAlias::OnCancel(User *) this->Extend("HELD"); this->Shrink("COLLIDED"); - new NickServHeld(this, Config->NSReleaseTimeout); + new NickServHeld(this, Config->GetBlock("options")->Get<time_t>("releasetimeout")); if (IRCD->CanSVSHold) - IRCD->SendSVSHold(this->nick); + IRCD->SendSVSHold(this->nick, Config->GetBlock("options")->Get<time_t>("releasetimeout")); else - new NickServRelease(this, Config->NSReleaseTimeout); + new NickServRelease(this, Config->GetBlock("options")->Get<time_t>("releasetimeout")); } } diff --git a/src/nickcore.cpp b/src/nickcore.cpp index dcd324846..e2b47e953 100644 --- a/src/nickcore.cpp +++ b/src/nickcore.cpp @@ -25,19 +25,16 @@ NickCore::NickCore(const Anope::string &coredisplay) : Serializable("NickCore"), this->o = NULL; this->channelcount = 0; this->lastmail = 0; - this->memos.memomax = Config->MSMaxMemos; - this->language = Config->NSDefLanguage; + this->memos.memomax = 0; this->display = coredisplay; - /* Set default nick core flags */ - for (std::set<Anope::string>::const_iterator it = Config->NSDefFlags.begin(), it_end = Config->NSDefFlags.end(); it != it_end; ++it) - this->ExtendMetadata(*it); - size_t old = NickCoreList->size(); (*NickCoreList)[this->display] = this; if (old == NickCoreList->size()) Log(LOG_DEBUG) << "Duplicate account " << coredisplay << " in nickcore table?"; + + FOREACH_MOD(I_OnNickCoreCreate, OnNickCoreCreate(this)); } NickCore::~NickCore() @@ -174,6 +171,11 @@ Anope::string NickCore::GetAccess(unsigned entry) const return this->access[entry]; } +unsigned NickCore::GetAccessCount() const +{ + return this->access.size(); +} + bool NickCore::FindAccess(const Anope::string &entry) { for (unsigned i = 0, end = this->access.size(); i < end; ++i) diff --git a/src/opertype.cpp b/src/opertype.cpp index eb73c20f4..0db17464d 100644 --- a/src/opertype.cpp +++ b/src/opertype.cpp @@ -27,9 +27,9 @@ Oper *Oper::Find(const Anope::string &name) OperType *OperType::Find(const Anope::string &name) { - for (std::list<OperType *>::iterator it = Config->MyOperTypes.begin(), it_end = Config->MyOperTypes.end(); it != it_end; ++it) + for (unsigned i = 0; i < Config->MyOperTypes.size(); ++i) { - OperType *ot = *it; + OperType *ot = Config->MyOperTypes[i]; if (ot->GetName() == name) return ot; diff --git a/src/protocol.cpp b/src/protocol.cpp index a66bf8227..14739d24b 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -67,14 +67,6 @@ void IRCDProto::SendKickInternal(const BotInfo *bi, const Channel *c, const User UplinkSocket::Message(bi) << "KICK " << c->name << " " << u->GetUID(); } -void IRCDProto::SendMessageInternal(const BotInfo *bi, const Anope::string &dest, const Anope::string &buf) -{ - if (Config->NSDefFlags.count("msg")) - SendPrivmsgInternal(bi, dest, buf); - else - SendNoticeInternal(bi, dest, buf); -} - void IRCDProto::SendNoticeInternal(const BotInfo *bi, const Anope::string &dest, const Anope::string &msg) { UplinkSocket::Message(bi) << "NOTICE " << dest << " :" << msg; @@ -176,16 +168,6 @@ void IRCDProto::SendKick(const BotInfo *bi, const Channel *chan, const User *use SendKickInternal(bi, chan, user, buf); } -void IRCDProto::SendMessage(const BotInfo *bi, const Anope::string &dest, const char *fmt, ...) -{ - va_list args; - char buf[BUFSIZE] = ""; - va_start(args, fmt); - vsnprintf(buf, BUFSIZE - 1, fmt, args); - va_end(args); - SendMessageInternal(bi, dest, buf); -} - void IRCDProto::SendNotice(const BotInfo *bi, const Anope::string &dest, const char *fmt, ...) { va_list args; @@ -339,7 +321,7 @@ bool IRCDProto::IsNickValid(const Anope::string &nick) bool IRCDProto::IsChannelValid(const Anope::string &chan) { - if (chan.empty() || chan[0] != '#' || chan.length() > Config->ChanLen) + if (chan.empty() || chan[0] != '#' || chan.length() > Config->GetBlock("networkinfo")->Get<unsigned>("chanlen")) return false; return true; @@ -347,7 +329,7 @@ bool IRCDProto::IsChannelValid(const Anope::string &chan) bool IRCDProto::IsIdentValid(const Anope::string &ident) { - if (ident.empty() || ident.length() > Config->UserLen) + if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("chanlen")) return false; for (unsigned i = 0; i < ident.length(); ++i) @@ -364,12 +346,15 @@ bool IRCDProto::IsIdentValid(const Anope::string &ident) bool IRCDProto::IsHostValid(const Anope::string &host) { - if (host.empty() || host.length() > Config->HostLen) + if (host.empty() || host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen")) return false; - if (Config->VhostDisallowBE.find_first_of(host[0]) != Anope::string::npos) + const Anope::string &vhostdisablebe = Config->GetBlock("networkinfo")->Get<const Anope::string &>("disallow_start_or_end"), + vhostchars = Config->GetBlock("networkinfo")->Get<const Anope::string &>("vhost_chars"); + + if (vhostdisablebe.find_first_of(host[0]) != Anope::string::npos) return false; - else if (Config->VhostDisallowBE.find_first_of(host[host.length() - 1]) != Anope::string::npos) + else if (vhostdisablebe.find_first_of(host[host.length() - 1]) != Anope::string::npos) return false; int dots = 0; @@ -377,11 +362,11 @@ bool IRCDProto::IsHostValid(const Anope::string &host) { if (host[i] == '.') ++dots; - if (Config->VhostChars.find_first_of(host[i]) == Anope::string::npos) + if (vhostchars.find_first_of(host[i]) == Anope::string::npos) return false; } - return Config->VhostUndotted || dots > 0; + return dots > 0 || Config->GetBlock("networkinfo")->Get<bool>("allow_undotted_vhosts"); } void IRCDProto::SendOper(User *u) @@ -392,7 +377,7 @@ void IRCDProto::SendOper(User *u) unsigned IRCDProto::GetMaxListFor(Channel *c) { - return c->HasMode("LBAN") ? 0 : Config->ListSize; + return c->HasMode("LBAN") ? 0 : Config->GetBlock("networkinfo")->Get<int>("modelistsize"); } MessageSource::MessageSource(const Anope::string &src) : source(src), u(NULL), s(NULL) diff --git a/src/regchannel.cpp b/src/regchannel.cpp index 48d039be3..12655533b 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -276,22 +276,12 @@ ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInf this->repeattimes = 0; this->banexpire = 0; this->bi = NULL; - - this->last_topic_setter = Config->ChanServ; - this->last_topic_time = Anope::CurTime; + this->last_topic_time = 0; this->name = chname; - /* Set default channel flags */ - for (std::set<Anope::string>::const_iterator it = Config->CSDefFlags.begin(), it_end = Config->CSDefFlags.end(); it != it_end; ++it) - this->ExtendMetadata(*it); - - /* Set default bot flags */ - for (std::set<Anope::string>::const_iterator it = Config->BSDefFlags.begin(), it_end = Config->BSDefFlags.end(); it != it_end; ++it) - this->ExtendMetadata(*it); - - this->bantype = Config->CSDefBantype; - this->memos.memomax = Config->MSMaxMemos; + this->bantype = 2; + this->memos.memomax = 0; this->last_used = this->time_registered = Anope::CurTime; for (int i = 0; i < TTB_SIZE; ++i) @@ -357,6 +347,8 @@ ChannelInfo::ChannelInfo(const ChannelInfo &ci) : Serializable("ChannelInfo"), l->ci = this; this->log_settings->push_back(l); } + + FOREACH_MOD(I_OnCreateChan, OnCreateChan(this)); } ChannelInfo::~ChannelInfo() @@ -474,11 +466,10 @@ Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data) BotInfo *bi = BotInfo::Find(sbi); if (*ci->bi != bi) { - if (ci->bi) + if (bi) + bi->Assign(NULL, ci); + else if (ci->bi) ci->bi->UnAssign(NULL, ci); - ci->bi = bi; - if (ci->bi) - ci->bi->Assign(NULL, ci); } { Anope::string ttb, tok; @@ -1035,23 +1026,6 @@ bool ChannelInfo::CheckKick(User *user) Log(LOG_DEBUG) << "Autokicking " << user->nick << " (" << mask << ") from " << this->name; - /* If the channel isn't syncing and doesn't have any users, join ChanServ - * Note that the user AND POSSIBLY the botserv bot exist here - * ChanServ always enforces channels like this to keep people from deleting bots etc - * that are holding channels. - */ - if (this->c->users.size() == (this->bi && this->c->FindUser(this->bi) ? 2 : 1) && !this->c->HasExt("INHABIT") && !this->c->HasExt("SYNCING")) - { - /* Set +ntsi to prevent rejoin */ - c->SetMode(NULL, "NOEXTERNAL"); - c->SetMode(NULL, "TOPIC"); - c->SetMode(NULL, "SECRET"); - c->SetMode(NULL, "INVITE"); - - /* Join ChanServ and set a timer for this channel to part ChanServ later */ - this->c->Hold(); - } - this->c->SetMode(NULL, "BAN", mask); this->c->Kick(NULL, user, "%s", reason.c_str()); diff --git a/src/servers.cpp b/src/servers.cpp index 28ff7bf17..2f87d66e4 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -127,21 +127,12 @@ Server::~Server() if (Servers::Capab.count("NOQUIT") > 0 || Servers::Capab.count("QS") > 0) { - for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();) + for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) { User *u = it->second; - ++it; if (u->server == this) { - NickAlias *na = NickAlias::Find(u->nick); - if (na && !na->nc->HasExt("SUSPENDED") && (u->IsRecognized() || u->IsIdentified())) - { - na->last_seen = Anope::CurTime; - if (!Config->NSHideNetSplitQuit) - na->last_quit = this->quit_reason; - } - u->Quit(this->quit_reason); u->server = NULL; } @@ -201,6 +192,11 @@ const Anope::string &Server::GetSID() const return this->name; } +const Anope::string &Server::GetQuitReason() const +{ + return this->quit_reason; +} + const std::vector<Server *> &Server::GetLinks() const { return this->links; @@ -313,8 +309,8 @@ bool Server::IsULined() const if (this == Me) return true; - for (std::list<Anope::string>::const_iterator it = Config->Ulines.begin(), it_end = Config->Ulines.end(); it != it_end; ++it) - if (it->equals_ci(this->GetName())) + for (unsigned i = 0; i < Config->Ulines.size(); ++i) + if (Config->Ulines[i].equals_ci(this->GetName())) return true; return false; } @@ -326,7 +322,7 @@ bool Server::IsJuped() const void Server::Notice(const BotInfo *source, const Anope::string &message) { - if (Config->NSDefFlags.count("MSG")) + if (Config->UsePrivmsg && Config->DefPrivmsg) IRCD->SendGlobalPrivmsg(source, this, message); else IRCD->SendGlobalNotice(source, this, message); @@ -370,13 +366,13 @@ const Anope::string Servers::TS6_UID_Retrieve() static Anope::string current_uid = "AAAAAA"; - while (User::Find(Config->Numeric + current_uid) != NULL) + while (User::Find(Me->GetSID() + current_uid) != NULL) { int current_len = current_uid.length() - 1; while (current_len >= 0 && nextID(current_uid[current_len--]) == 'A'); } - return Config->Numeric + current_uid; + return Me->GetSID() + current_uid; } const Anope::string Servers::TS6_SID_Retrieve() @@ -384,13 +380,9 @@ const Anope::string Servers::TS6_SID_Retrieve() if (!IRCD || !IRCD->RequiresID) return ""; - static Anope::string current_sid; + static Anope::string current_sid = Config->GetBlock("options")->Get<const Anope::string &>("id"); if (current_sid.empty()) - { - current_sid = Config->Numeric; - if (current_sid.empty()) - current_sid = "00A"; - } + current_sid = "00A"; while (Server::Find(current_sid) != NULL) { diff --git a/src/uplink.cpp b/src/uplink.cpp index f8841c58f..ff90ee53c 100644 --- a/src/uplink.cpp +++ b/src/uplink.cpp @@ -31,7 +31,7 @@ class ReconnectTimer : public Timer } catch (const SocketException &ex) { - Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port << "): " << ex.GetReason(); + Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << "): " << ex.GetReason(); } } }; @@ -41,19 +41,19 @@ void Uplink::Connect() if (static_cast<unsigned>(++Anope::CurrentUplink) >= Config->Uplinks.size()) Anope::CurrentUplink = 0; - ServerConfig::Uplink *u = Config->Uplinks[Anope::CurrentUplink]; + Configuration::Uplink &u = Config->Uplinks[Anope::CurrentUplink]; new UplinkSocket(); - if (!Config->LocalHost.empty()) - UplinkSock->Bind(Config->LocalHost); + if (!Config->GetBlock("serverinfo")->Get<const Anope::string &>("localhost").empty()) + UplinkSock->Bind(Config->GetBlock("serverinfo")->Get<const Anope::string &>("localhost")); FOREACH_MOD(I_OnPreServerConnect, OnPreServerConnect()); - Anope::string ip = Anope::Resolve(u->host, u->ipv6 ? AF_INET6 : AF_INET); - Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << u->host << " (" << ip << "), port " << u->port; - UplinkSock->Connect(ip, u->port); + Anope::string ip = Anope::Resolve(u.host, u.ipv6 ? AF_INET6 : AF_INET); + Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << u.host << " (" << ip << "), port " << u.port; + UplinkSock->Connect(ip, u.port); } -UplinkSocket::UplinkSocket() : Socket(-1, Config->Uplinks[Anope::CurrentUplink]->ipv6), ConnectionSocket(), BufferedSocket() +UplinkSocket::UplinkSocket() : Socket(-1, Config->Uplinks[Anope::CurrentUplink].ipv6), ConnectionSocket(), BufferedSocket() { UplinkSock = this; } @@ -107,9 +107,7 @@ UplinkSocket::~UplinkSocket() } else if (!Anope::Quitting) { - int retry = Config->RetryWait; - if (retry <= 0) - retry = 60; + time_t retry = Config->GetBlock("options")->Get<time_t>("retrywait"); Log() << "Disconnected, retrying in " << retry << " seconds"; new ReconnectTimer(retry); @@ -129,14 +127,14 @@ bool UplinkSocket::ProcessRead() void UplinkSocket::OnConnect() { - Log(LOG_TERMINAL) << "Successfully connected to uplink #" << (Anope::CurrentUplink + 1) << " " << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port; + Log(LOG_TERMINAL) << "Successfully connected to uplink #" << (Anope::CurrentUplink + 1) << " " << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port; IRCD->SendConnect(); FOREACH_MOD(I_OnServerConnect, OnServerConnect()); } void UplinkSocket::OnError(const Anope::string &error) { - Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink]->host << ":" << Config->Uplinks[Anope::CurrentUplink]->port << ")" << (!error.empty() ? (": " + error) : ""); + Log(LOG_TERMINAL) << "Unable to connect to uplink #" << (Anope::CurrentUplink + 1) << " (" << Config->Uplinks[Anope::CurrentUplink].host << ":" << Config->Uplinks[Anope::CurrentUplink].port << ")" << (!error.empty() ? (": " + error) : ""); } UplinkSocket::Message::Message() : server(NULL), user(NULL) diff --git a/src/users.cpp b/src/users.cpp index 691653055..26d5b31c5 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -279,10 +279,9 @@ void User::SendMessage(const BotInfo *source, const Anope::string &msg) * - The user is registered and has set /ns set msg on */ sepstream sep(translated_message, '\n'); - Anope::string tok; - while (sep.GetToken(tok)) + for (Anope::string tok; sep.GetToken(tok);) { - if (Config->UsePrivmsg && ((!this->nc && Config->NSDefFlags.count("msg")) || (this->nc && this->nc->HasExt("MSG")))) + if (Config->UsePrivmsg && ((!this->nc && Config->DefPrivmsg) || (this->nc && this->nc->HasExt("MSG")))) IRCD->SendPrivmsg(source, this->GetUID(), "%s", tok.c_str()); else IRCD->SendNotice(source, this->GetUID(), "%s", tok.c_str()); @@ -291,17 +290,16 @@ void User::SendMessage(const BotInfo *source, const Anope::string &msg) /** Collides a nick. * - * First, it marks the nick (if the user is on a registered nick, we don't use it without but it could be) - * as COLLIDED, this is checked in NickAlias::OnCancel. + * First, it marks the nick as COLLIDED, this is checked in NickAlias::OnCancel. * * Then it does one of two things. * * 1. This will force change the users nick to the guest nick. This gets processed by the IRCd and comes - * back to call do_nick. do_nick changes the nick of the use to the new one, then calls NickAlias::OnCancel + * back as a nick change, which calls NickAlias::OnCancel * with the users old nick's nickalias (if there is one). * - * 2. Calls User::Kill, which will either delete the user immediatly or kill them, wait for the QUIT, - * then delete the user then. Users destructor then calls NickAlias::OnCancel + * 2. Calls User::Kill, which kills the user and deletes the user at the end of the I/O loop. + * Users destructor then calls NickAlias::OnCancel * * NickAlias::OnCancel checks for NS_COLLIDED, it then does one of two things. * @@ -309,40 +307,13 @@ void User::SendMessage(const BotInfo *source, const Anope::string &msg) * * 2. We create a new client with SendClientIntroduction(). Note that is it important that this is called either after the * user has been removed from our internal list of user or after the users nick has been updated completely internally. - * This is beacuse SendClientIntroduction will destroy any users we think are currently on the nickname (which causes a - * lot of problems, eg, deleting the user which recalls OnCancel), whether they really are or not. We then create a - * release timer for this new client that waits and later on sends a QUIT for the client. Release timers are never used - * for SVSHolds. Ever. + * We then create a release timer for this new client that waits and later on sends a QUIT for the client. Release timers + * are never used for SVSHolds. Ever. * * * Note that now for the timers we only store the users name, not the NickAlias* pointer. We never remove timers when * a user changes nick or a nick is deleted, the timers must assume that either of these may have happend. * - * Storing NickAlias* pointers caused quite a problem, some of which are: - * - * Having a valid timer alive that calls User::Collide would either: - * - * 1. Kill the user, causing users destructor to cancel all timers for the nick (as it should, it has no way of knowing - * if we are in a timer or not) which would delete the currently active timer while it was running, causing TimerManager - * to explode. - * - * 2. Force a user off of their nick, this would call NickAlias::Cancel before updating the user internally (to cancel the - * current nicks timers, granted we could have easially saved this and called it after) which could possibly try to - * introduce an enforcer nick. We would then check to see if the nick is already in use (it is, internally) and send - * a kill for that nick. That may in turn delete the user immediatly, calling users destructor, which would attempt to - * delete the timer, causing TimerManager to explode. - * - * Additionally, if we marked the timer as "in use" so that calling the ClearTimer function wouldn't delete them, users - * destructor would then call NickAlias::OnCancel, which would (at this point, it was unsetting GUESTED after introducing - * the new client) introduce the same new client again, without actually deleting the originial user, causing an infinite - * loop. - * - * This is why we remove NS_GUESTED first in NickAlias::OnCancel before introducing a new client, although this should - * not happen anymore. If I must emphasize this again, users need to be GONE from the internal list before calling - * NickAlias::OnCancel. NickAlias::OnCancel intentionally reffers to this->nick, not the user passed to it. They *can* - * (but not always) be different, depending if the user changed nicks or disconnected. - * - * * Adam */ void User::Collide(NickAlias *na) @@ -352,16 +323,18 @@ void User::Collide(NickAlias *na) if (IRCD->CanSVSNick) { + const Anope::string &guestprefix = Config->GetBlock("options")->Get<const Anope::string &>("guestnickprefix"); + Anope::string guestnick; int i = 0; do { - guestnick = Config->NSGuestNickPrefix + stringify(static_cast<uint16_t>(rand())); + guestnick = guestprefix + stringify(static_cast<uint16_t>(rand())); } while (User::Find(guestnick) && i++ < 10); if (i == 11) - this->Kill(Config->NickServ, "Services nickname-enforcer kill"); + this->Kill(NickServ ? NickServ->nick : "", "Services nickname-enforcer kill"); else { if (NickServ) @@ -370,7 +343,7 @@ void User::Collide(NickAlias *na) } } else - this->Kill(Config->NickServ, "Services nickname-enforcer kill"); + this->Kill(NickServ ? NickServ->nick : "", "Services nickname-enforcer kill"); } void User::Identify(NickAlias *na) @@ -395,7 +368,7 @@ void User::Identify(NickAlias *na) IRCD->SendLogin(this); const NickAlias *this_na = NickAlias::Find(this->nick); - if (!Config->NoNicknameOwnership && this_na && this_na->nc == *na->nc && na->nc->HasExt("UNCONFIRMED") == false) + if (!Config->GetBlock("options")->Get<bool>("nonicknameownership") && this_na && this_na->nc == *na->nc && na->nc->HasExt("UNCONFIRMED") == false) this->SetMode(NickServ, "REGISTERED"); FOREACH_MOD(I_OnNickIdentify, OnNickIdentify(this)); @@ -738,8 +711,7 @@ bool User::IsProtected() const void User::Kill(const Anope::string &source, const Anope::string &reason) { - Anope::string real_source = source.empty() ? Config->ServerName : source; - Anope::string real_reason = real_source + " (" + reason + ")"; + Anope::string real_reason = (source.empty() ? Me->GetName() : source) + " (" + reason + ")"; IRCD->SendSVSKill(BotInfo::Find(source), this, "%s", real_reason.c_str()); } @@ -754,12 +726,7 @@ void User::KillInternal(const Anope::string &source, const Anope::string &reason Log(this, "killed") << "was killed by " << source << " (Reason: " << reason << ")"; - NickAlias *na = NickAlias::Find(this->nick); - if (na && !na->nc->HasExt("SUSPENDED") && (this->IsRecognized() || this->IsIdentified(true))) - { - na->last_seen = Anope::CurTime; - na->last_quit = reason; - } + this->Quit(reason); this->quit = true; quitting_users.push_back(this); @@ -773,6 +740,8 @@ void User::Quit(const Anope::string &reason) return; } + FOREACH_MOD(I_OnUserQuit, OnUserQuit(this, reason)); + this->quit = true; quitting_users.push_back(this); } @@ -813,16 +782,16 @@ Anope::string User::Mask() const bool User::BadPassword() { - if (!Config->BadPassLimit) + if (!Config->GetBlock("options")->Get<int>("badpasslimit")) return false; - if (Config->BadPassTimeout > 0 && this->invalid_pw_time > 0 && this->invalid_pw_time < Anope::CurTime - Config->BadPassTimeout) + if (Config->GetBlock("options")->Get<time_t>("badpasstimeout") > 0 && this->invalid_pw_time > 0 && this->invalid_pw_time < Anope::CurTime - Config->GetBlock("options")->Get<time_t>("badpasstimeout")) this->invalid_pw_count = 0; ++this->invalid_pw_count; this->invalid_pw_time = Anope::CurTime; - if (this->invalid_pw_count >= Config->BadPassLimit) + if (this->invalid_pw_count >= Config->GetBlock("options")->Get<int>("badpasslimit")) { - this->Kill(Config->ServerName, "Too many invalid passwords"); + this->Kill(Me->GetName(), "Too many invalid passwords"); return true; } diff --git a/src/xline.cpp b/src/xline.cpp index 67f976d9a..0ba3d6557 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -25,11 +25,11 @@ Serialize::Checker<std::multimap<Anope::string, XLine *, ci::less> > XLineManage void XLine::InitRegex() { - if (!Config->RegexEngine.empty() && this->mask.length() >= 2 && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/') + if (this->mask.length() >= 2 && this->mask[0] == '/' && this->mask[this->mask.length() - 1] == '/' && !Config->GetBlock("options")->Get<const Anope::string &>("regexengine").empty()) { Anope::string stripped_mask = this->mask.substr(1, this->mask.length() - 2); - ServiceReference<RegexProvider> provider("Regex", Config->RegexEngine); + ServiceReference<RegexProvider> provider("Regex", Config->GetBlock("options")->Get<const Anope::string &>("regexengine")); if (provider) { try @@ -44,7 +44,7 @@ void XLine::InitRegex() } } -XLine::XLine(const Anope::string &ma, const Anope::string &r, const Anope::string &uid) : Serializable("XLine"), mask(ma), by(Config->OperServ), created(0), expires(0), reason(r), id(uid) +XLine::XLine(const Anope::string &ma, const Anope::string &r, const Anope::string &uid) : Serializable("XLine"), mask(ma), by(OperServ ? OperServ->nick : ""), created(0), expires(0), reason(r), id(uid) { regex = NULL; manager = NULL; @@ -118,8 +118,6 @@ Anope::string XLine::GetReal() const Anope::string XLine::GetReason() const { Anope::string r = this->reason; - if (Config->AddAkiller && !this->by.empty()) - r = "[" + this->by + "] " + r; if (!this->id.empty()) r += " (ID: " + this->id + ")"; return r; |