diff options
-rw-r--r-- | data/example.conf | 22 | ||||
-rw-r--r-- | docs/Changes | 1 | ||||
-rw-r--r-- | docs/Changes.conf | 1 | ||||
-rw-r--r-- | include/config.h | 218 | ||||
-rw-r--r-- | include/extern.h | 4 | ||||
-rw-r--r-- | include/language.h | 2 | ||||
-rw-r--r-- | include/services.h | 1 | ||||
-rw-r--r-- | modules/core/ns_identify.cpp | 2 | ||||
-rw-r--r-- | modules/core/ns_recover.cpp | 6 | ||||
-rw-r--r-- | modules/core/ns_register.cpp | 2 | ||||
-rw-r--r-- | modules/core/ns_release.cpp | 3 | ||||
-rw-r--r-- | modules/core/os_akill.cpp | 2 | ||||
-rw-r--r-- | modules/core/os_config.cpp | 231 | ||||
-rw-r--r-- | modules/core/os_reload.cpp | 3 | ||||
-rw-r--r-- | modules/core/os_snline.cpp | 2 | ||||
-rw-r--r-- | modules/core/os_sqline.cpp | 2 | ||||
-rw-r--r-- | modules/core/os_stats.cpp | 40 | ||||
-rw-r--r-- | modules/core/os_szline.cpp | 2 | ||||
-rw-r--r-- | src/bots.cpp | 2 | ||||
-rw-r--r-- | src/config.cpp | 936 | ||||
-rw-r--r-- | src/init.cpp | 6 | ||||
-rw-r--r-- | src/misc.cpp | 7 |
22 files changed, 859 insertions, 636 deletions
diff --git a/data/example.conf b/data/example.conf index c797a2f84..783c1fb14 100644 --- a/data/example.conf +++ b/data/example.conf @@ -724,7 +724,7 @@ log * operserv/global operserv/news operserv/stats operserv/kick * operserv/mode operserv/session operserv/modlist operserv/ignore * operserv/chankill operserv/akill operserv/sqline operserv/snline - * operserv/szline operserv/staff operserv/defcon + * operserv/szline operserv/staff operserv/defcon operserv/config * operserv/modload operserv/jupe operserv/set operserv/noop * operserv/quit operserv/update operserv/reload operserv/restart * operserv/shutdown operserv/svsnick operserv/oline @@ -1493,7 +1493,7 @@ operserv * * This directive is optional, but highly recommended. */ - modules = "os_help os_global os_stats os_staff os_mode os_kick os_akill os_snline os_sqline os_szline os_chanlist os_userlist os_news os_session os_noop os_jupe os_ignore os_set os_reload os_update os_restart os_quit os_shutdown os_defcon os_chankill os_svsnick os_oline os_modload os_modunload os_modreload os_modlist os_modinfo" + modules = "os_help os_global os_stats os_staff os_mode os_kick os_akill os_snline os_sqline os_szline os_chanlist os_userlist os_news os_session os_noop os_jupe os_ignore os_set os_reload os_update os_restart os_quit os_shutdown os_defcon os_chankill os_svsnick os_oline os_modload os_modunload os_modreload os_modlist os_modinfo os_config" /* * If set, Services Admins will be able to use SUPERADMIN [ON|OFF] which will temporarily grant @@ -1773,6 +1773,24 @@ defcon } /* + * [OPTIONAL] Additional includes + * + * You can include additional configuration files here. + * You may also include executable files, which will be executed and + * the output from it will be included into your configuration. + */ +include +{ + #type = "file" + #name = "some_other.conf" +} +include +{ + #type = "executable" + #name = "/usr/bin/wget -q -O - http://some.miconfigured.network.com/services.conf" +} + +/* * [OPTIONAL] Non-Core Modules * * The following blocks are used to load all non-core modules, including 3rd-party modules. diff --git a/docs/Changes b/docs/Changes index 9125a6258..9d9b8be36 100644 --- a/docs/Changes +++ b/docs/Changes @@ -13,6 +13,7 @@ A Added support for learning tracking/storing/locking all modes at runtime A Added m_alias A Added support for XMLRPC queries A Added /botserv set msg +A Added /operserv config F Changed the GHOST command to not allow ghosting unidentified users if the RECOVER command exists F Some failed logic in /operserv exception that prevents proper exceptions from being added F Fixed the anope_os_sxlines MySQL table and code to work after restarting diff --git a/docs/Changes.conf b/docs/Changes.conf index 70e97bb46..eaf99cdd4 100644 --- a/docs/Changes.conf +++ b/docs/Changes.conf @@ -10,6 +10,7 @@ nickserv:modules added ns_ajoin options:nomlock added log:target added globops nickserv:confirmemailchanges added +operserv:modules added os_config ** MODIFIED CONFIGURATION DIRECTIVES ** operserv:notifications removed osglobal, osmode, oskick, osakill, ossnline, ossqline, osszline, osnoop, osjupe, getpass, setpass, forbid, drop diff --git a/include/config.h b/include/config.h index f4844ded3..4a8d8411f 100644 --- a/include/config.h +++ b/include/config.h @@ -34,8 +34,6 @@ enum ConfigDataType DT_UINTEGER, // Unsigned Integer DT_LUINTEGER, // Long Unsigned Integer DT_CHARPTR, // Char pointer - DT_CSSTRING, // std::string - DT_CISTRING, // ci::string DT_STRING, // Anope::string DT_BOOLEAN, // Boolean DT_HOSTNAME, // Hostname syntax @@ -89,11 +87,7 @@ class ValueItem int GetInteger() const; /** Get value as a string */ const char *GetString() const; - /** Get value as an std::string */ - inline const std::string GetCSValue() const { return v.str(); } - /** Get value as a ci::string */ - inline const ci::string GetCIValue() const { return v.ci_str(); } - /** Get value as a ci::string */ + /** Get value as an Anope::string */ inline const Anope::string &GetValue() const { return v; } /** Get value as a bool */ bool GetBool() const; @@ -177,78 +171,6 @@ template<> class ValueContainer<char **> : public ValueContainerBase } }; -/** This a specific version of ValueContainer to handle std::string specially - */ -template<> class ValueContainer<std::string *> : public ValueContainerBase -{ - private: - /** Contained item */ - std::string *val; - public: - /** Initialize with nothing */ - ValueContainer() : ValueContainerBase(), val(NULL) { } - /** Initialize with an std::string */ - ValueContainer(std::string *Val) : ValueContainerBase(), val(Val) { } - /** Initialize with a copy */ - ValueContainer(const ValueContainer &Val) : ValueContainerBase(), val(Val.val) { } - ValueContainer &operator=(const ValueContainer &Val) - { - val = Val.val; - return *this; - } - /** Change value to given std::string */ - void Set(const std::string &newval) - { - *val = newval; - } - /** Change value to given ci::string */ - void Set(const ci::string &newval) - { - *val = newval.c_str(); - } - /** Change value to given char pointer */ - void Set(const char *newval) - { - *val = newval; - } -}; - -/** This a specific version of ValueContainer to handle ci::string specially - */ -template<> class ValueContainer<ci::string *> : public ValueContainerBase -{ - private: - /** Contained item */ - ci::string *val; - public: - /** Initialize with nothing */ - ValueContainer() : ValueContainerBase(), val(NULL) { } - /** Initialize with an std::string */ - ValueContainer(ci::string *Val) : ValueContainerBase(), val(Val) { } - /** Initialize with a copy */ - ValueContainer(const ValueContainer &Val) : ValueContainerBase(), val(Val.val) { } - ValueContainer &operator=(const ValueContainer &Val) - { - val = Val.val; - return *this; - } - /** Change value to given std::string */ - void Set(const std::string &newval) - { - *val = newval.c_str(); - } - /** Change value to given ci::string */ - void Set(const ci::string &newval) - { - *val = newval; - } - /** Change value to given char pointer */ - void Set(const char *newval) - { - *val = newval; - } -}; - /** This a specific version of ValueContainer to handle Anope::string specially */ template<> class ValueContainer<Anope::string *> : public ValueContainerBase @@ -268,16 +190,7 @@ template<> class ValueContainer<Anope::string *> : public ValueContainerBase val = Val.val; return *this; } - /** Change value to given std::string */ - void Set(const std::string &newval) - { - *val = newval; - } - /** Change value to given ci::string */ - void Set(const ci::string &newval) - { - *val = newval; - } + /** Change value to given Anope::string */ void Set(const Anope::string &newval) { @@ -320,16 +233,6 @@ typedef ValueContainer<int *> ValueContainerInt; typedef ValueContainer<time_t *> ValueContainerTime; /** A specialization of ValueContainer to hold a pointer to - * an std::string - */ -typedef ValueContainer<std::string *> ValueContainerCSString; - -/** A specialization of ValueContainer to hold a pointer to - * an ci::string - */ -typedef ValueContainer<ci::string *> ValueContainerCIString; - -/** A specialization of ValueContainer to hold a pointer to * an Anope::string */ typedef ValueContainer<Anope::string *> ValueContainerString; @@ -348,43 +251,89 @@ typedef bool (*MultiValidator)(ServerConfig *, const Anope::string &, const Anop */ typedef bool (*MultiNotify)(ServerConfig *, const Anope::string &); -/** Holds a core configuration item and its callbacks +bool ValidateNotEmpty(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateNotZero(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateEmailReg(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidatePort(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateGuestPrefix(ServerConfig *conf, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateBantype(ServerConfig *, const Anope::string &, const Anope::string &, ValueItem &data); +bool ValidateChanServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateMemoServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateBotServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateHostServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateLimitSessions(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateOperServ(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateGlobal(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateDefCon(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateNickLen(ServerConfig *, const Anope::string &, const Anope::string &, ValueItem &data); +bool ValidateMail(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); +bool ValidateGlobalOnCycle(ServerConfig *config, const Anope::string &tag, const Anope::string &value, ValueItem &data); + +/** Represents a configuration file */ -struct InitialConfig +class ConfigurationFile { - /** Tag name */ - const Anope::string tag; - /** Value name */ - const Anope::string value; - /** Default, if not defined */ - const Anope::string default_value; - /** Value containers */ - ValueContainerBase *val; - /** Data types */ - int datatype; - /** Validation function */ - Validator validation_function; + Anope::string name; + bool executable; + FILE *fp; + public: + ConfigurationFile(const Anope::string &, bool); + ~ConfigurationFile(); + const Anope::string &GetName() const; + + bool IsOpen() const; + bool Open(); + void Close(); + bool End() const; + Anope::string Read(); }; -/** Holds a core configuration item and its callbacks - * where there may be more than one item +/** Holds all of the core configuration items */ -struct MultiConfig +class ConfigItems { - /** Tag name */ - const Anope::string tag; - /** One or more items within tag */ - const Anope::string items[17]; - /** One or more defaults for items within tags */ - const Anope::string items_default[17]; - /** One or more data types */ - int datatype[17]; - /** Initialization function */ - MultiNotify init_function; - /** Validation function */ - MultiValidator validation_function; - /** Completion function */ - MultiNotify finish_function; + public: + /** Holds a core configuration item and its callbacks + */ + struct Item + { + /** Tag name */ + Anope::string tag; + /** Value name */ + Anope::string value; + /** Default, if not defined */ + Anope::string default_value; + /** Value containers */ + ValueContainerBase *val; + /** Data types */ + int datatype; + /** Validation function */ + Validator validation_function; + } *Values; + + /** Holds a core configuration item and its callbacks + * where there may be more than one item + */ + struct MultiItem + { + /** Tag name */ + Anope::string tag; + /** One or more items within tag */ + Anope::string items[17]; + /** One or more defaults for items within tags */ + Anope::string items_default[17]; + /** One or more data types */ + int datatype[17]; + /** Initialization function */ + MultiNotify init_function; + /** Validation function */ + MultiValidator validation_function; + /** Completion function */ + MultiNotify finish_function; + } *MultiValues; + + ConfigItems(ServerConfig *conf); + ~ConfigItems(); }; /** This class holds the bulk of the runtime configuration for Anope. @@ -398,8 +347,6 @@ class CoreExport ServerConfig */ bool CheckOnce(const Anope::string &); public: - /* Error from the config */ - std::ostringstream errstr; /** This holds all the information in the config file, * it's indexed by tag name to a vector of key/values. */ @@ -407,15 +354,16 @@ class CoreExport ServerConfig /** Construct a new ServerConfig */ ServerConfig(); + /** Read the entire configuration into memory * and initialize this class. All other methods * should be used only by the core. */ void Read(); - /** Load 'filename' into 'target', with the new config parser everything is parsed into + /** Load the configuration file into 'this'. With the new config parser everything is parsed into * tag/key/value at load-time rather than at read-value time. */ - bool LoadConf(ConfigDataHash &, const Anope::string &); + void LoadConf(ConfigurationFile &file); // Both these return true if the value existed or false otherwise /** Writes 'length' chars into 'result' as a string */ @@ -857,7 +805,7 @@ class CoreExport ConfigReader long error; public: /** Default constructor. - * This constructor initialises the ConfigReader class to read services.conf. + * This constructor initialises the ConfigReader class to read the configuration file(s). */ ConfigReader(); /** Overloaded constructor. diff --git a/include/extern.h b/include/extern.h index c158c6381..8c351eecf 100644 --- a/include/extern.h +++ b/include/extern.h @@ -108,7 +108,7 @@ E Anope::string get_mlock_modes(ChannelInfo *ci, int complete); /**** config.c ****/ -E Anope::string services_conf; +E ConfigurationFile services_conf; E ServerConfig *Config; /* hostserv.c */ @@ -234,7 +234,7 @@ E size_t strlcat(char *, const char *, size_t); #endif E time_t dotime(const Anope::string &s); -E Anope::string duration(NickCore *nc, time_t seconds); +E Anope::string duration(time_t seconds); E Anope::string expire_left(NickCore *nc, time_t expires); E Anope::string do_strftime(const time_t &t); E bool doValidHost(const Anope::string &host, int type); diff --git a/include/language.h b/include/language.h index 5e2cdf9e8..2653fce4c 100644 --- a/include/language.h +++ b/include/language.h @@ -10,7 +10,7 @@ #define BAD_USERHOST_MASK "Mask must be in the form \037user\037@\037host\037." #define BAD_EXPIRY_TIME "Invalid expiry time." #define USERHOST_MASK_TOO_WIDE "%s coverage is too wide; Please use a more specific mask." -#define READ_ONLY_MODE "\002Notice:\002 Services is in read-only mode; changes will not be saved!" +#define READ_ONLY_MODE "Services are in read-only mode!" #define PASSWORD_INCORRECT "Password incorrect." #define ACCESS_DENIED "Access denied." #define MORE_OBSCURE_PASSWORD "Please try again with a more obscure password. Passwords should be at least five characters long, should not be something easily guessed (e.g. your real name or your nick), and cannot contain the space or tab characters." diff --git a/include/services.h b/include/services.h index a0beabf2a..3500e532f 100644 --- a/include/services.h +++ b/include/services.h @@ -942,6 +942,7 @@ class IRCDProto; class IRCdMessage; struct Uplink; class ServerConfig; +class ConfigurationFile; #include "extern.h" #include "language.h" diff --git a/modules/core/ns_identify.cpp b/modules/core/ns_identify.cpp index 074adbb76..db7ad563b 100644 --- a/modules/core/ns_identify.cpp +++ b/modules/core/ns_identify.cpp @@ -95,7 +95,7 @@ class CommandNSIdentify : public Command source.Reply(_("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you when you registered.")); time_t time_registered = Anope::CurTime - na->time_registered; if (Config->NSUnconfirmedExpire > time_registered) - source.Reply(_("Your account will expire, if not confirmed, in %s"), duration(u->Account(), Config->NSUnconfirmedExpire - time_registered).c_str()); + source.Reply(_("Your account will expire, if not confirmed, in %s"), duration(Config->NSUnconfirmedExpire - time_registered).c_str()); } check_memos(u); diff --git a/modules/core/ns_recover.cpp b/modules/core/ns_recover.cpp index af50ed573..5e7e8c175 100644 --- a/modules/core/ns_recover.cpp +++ b/modules/core/ns_recover.cpp @@ -51,7 +51,7 @@ class CommandNSRecover : public Command u2->Collide(na); /* Convert Config->NSReleaseTimeout seconds to string format */ - Anope::string relstr = duration(na->nc, Config->NSReleaseTimeout); + Anope::string relstr = duration(Config->NSReleaseTimeout); source.Reply(_(NICK_RECOVERED), Config->s_NickServ.c_str(), nick.c_str(), relstr.c_str()); } @@ -74,7 +74,7 @@ class CommandNSRecover : public Command u2->Collide(na); /* Convert Config->NSReleaseTimeout seconds to string format */ - Anope::string relstr = duration(na->nc, Config->NSReleaseTimeout); + Anope::string relstr = duration(Config->NSReleaseTimeout); source.Reply(_(NICK_RECOVERED), Config->s_NickServ.c_str(), nick.c_str(), relstr.c_str()); } @@ -87,7 +87,7 @@ class CommandNSRecover : public Command bool OnHelp(CommandSource &source, const Anope::string &subcommand) { /* Convert Config->NSReleaseTimeout seconds to string format */ - Anope::string relstr = duration(source.u->Account(), Config->NSReleaseTimeout); + Anope::string relstr = duration(Config->NSReleaseTimeout); source.Reply(_("Syntax: \002RECOVER \037nickname\037 [\037password\037]\002\n" " \n" diff --git a/modules/core/ns_register.cpp b/modules/core/ns_register.cpp index d336f1f4d..c71bcea9c 100644 --- a/modules/core/ns_register.cpp +++ b/modules/core/ns_register.cpp @@ -200,7 +200,7 @@ class CommandNSRegister : public Command if (SendRegmail(u, na)) { source.Reply(_("A passcode has been sent to %s, please type %R%s confirm <passcode> to confirm your email address."), email.c_str(), NickServ->nick.c_str()); - source.Reply(_("If you do not confirm your email address within %s your account will expire."), duration(na->nc, Config->NSUnconfirmedExpire).c_str()); + source.Reply(_("If you do not confirm your email address within %s your account will expire."), duration(Config->NSUnconfirmedExpire).c_str()); } } diff --git a/modules/core/ns_release.cpp b/modules/core/ns_release.cpp index 1a0319b78..d77bd113b 100644 --- a/modules/core/ns_release.cpp +++ b/modules/core/ns_release.cpp @@ -72,8 +72,7 @@ class CommandNSRelease : public Command bool OnHelp(CommandSource &source, const Anope::string &subcommand) { /* Convert Config->NSReleaseTimeout seconds to string format */ - User *u = source.u; - Anope::string relstr = duration(u->Account(), Config->NSReleaseTimeout); + Anope::string relstr = duration(Config->NSReleaseTimeout); source.Reply(_("Syntax: \002RELEASE \037nickname\037 [\037password\037]\002\n" " \n" diff --git a/modules/core/os_akill.cpp b/modules/core/os_akill.cpp index dd07e2abc..f9083e2c6 100644 --- a/modules/core/os_akill.cpp +++ b/modules/core/os_akill.cpp @@ -195,7 +195,7 @@ class CommandOSAKill : public Command source.Reply(_("\002%s\002 added to the AKILL list."), mask.c_str()); - Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(NULL, expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; + Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; if (readonly) source.Reply(_(READ_ONLY_MODE)); diff --git a/modules/core/os_config.cpp b/modules/core/os_config.cpp new file mode 100644 index 000000000..b7335527c --- /dev/null +++ b/modules/core/os_config.cpp @@ -0,0 +1,231 @@ +/* OperServ core functions + * + * (C) 2003-2011 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +/*************************************************************************/ + +#include "module.h" + +class CommandOSConfig : public Command +{ + void ChangeHash(ConfigDataHash &hash, const Anope::string &block, const Anope::string &iname, const Anope::string &value) + { + ConfigDataHash::iterator it = hash.find(block); + + KeyValList &list = it->second; + for (unsigned i = 0; i < list.size(); ++i) + { + const Anope::string &item = list[i].first; + if (item == iname) + { + list[i] = std::make_pair(item, value); + break; + } + } + } + + public: + CommandOSConfig() : Command("CONFIG", 1, 4, "operserv/config") + { + this->SetDesc("View and change configuration file settings"); + } + + CommandReturn Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + const Anope::string &what = params[0]; + + if (what.equals_ci("MODIFY") && params.size() > 3) + { + ConfigItems configitems(Config); + + for (unsigned i = 0; !configitems.Values[i].tag.empty(); ++i) + { + ConfigItems::Item *v = &configitems.Values[i]; + if (v->tag.equals_cs(params[1]) && v->value.equals_cs(params[2])) + { + try + { + ValueItem vi(params[3]); + if (!v->validation_function(Config, v->tag, v->value, vi)) + throw ConfigException("Parameter failed to validate."); + + int dt = v->datatype; + + if (dt & DT_NORELOAD) + throw ConfigException("This item can not be changed while Anope is running."); + bool allow_wild = dt & DT_ALLOW_WILD; + dt &= ~(DT_ALLOW_NEWLINE | DT_ALLOW_WILD); + + /* Yay for *massive* copypaste from config.cpp */ + switch (dt) + { + case DT_NOSPACES: + { + ValueContainerString *vcs = debug_cast<ValueContainerString *>(v->val); + Config->ValidateNoSpaces(vi.GetValue(), v->tag, v->value); + vcs->Set(vi.GetValue()); + break; + } + case DT_HOSTNAME: + { + ValueContainerString *vcs = debug_cast<ValueContainerString *>(v->val); + Config->ValidateHostname(vi.GetValue(), v->tag, v->value); + vcs->Set(vi.GetValue()); + break; + } + case DT_IPADDRESS: + { + ValueContainerString *vcs = debug_cast<ValueContainerString *>(v->val); + Config->ValidateIP(vi.GetValue(), v->tag, v->value, allow_wild); + vcs->Set(vi.GetValue()); + break; + } + case DT_CHARPTR: + { + ValueContainerChar *vcc = debug_cast<ValueContainerChar *>(v->val); + // Make sure we also copy the null terminator + vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); + break; + } + case DT_STRING: + { + ValueContainerString *vcs = debug_cast<ValueContainerString *>(v->val); + vcs->Set(vi.GetValue()); + break; + } + case DT_INTEGER: + { + int val = vi.GetInteger(); + ValueContainerInt *vci = debug_cast<ValueContainerInt *>(v->val); + vci->Set(&val, sizeof(int)); + break; + } + case DT_UINTEGER: + { + unsigned val = vi.GetInteger(); + ValueContainerUInt *vci = debug_cast<ValueContainerUInt *>(v->val); + vci->Set(&val, sizeof(unsigned)); + break; + } + case DT_LUINTEGER: + { + unsigned long val = vi.GetInteger(); + ValueContainerLUInt *vci = debug_cast<ValueContainerLUInt *>(v->val); + vci->Set(&val, sizeof(unsigned long)); + break; + } + case DT_TIME: + { + time_t time = dotime(vi.GetValue()); + ValueContainerTime *vci = debug_cast<ValueContainerTime *>(v->val); + vci->Set(&time, sizeof(time_t)); + break; + } + case DT_BOOLEAN: + { + bool val = vi.GetBool(); + ValueContainerBool *vcb = debug_cast<ValueContainerBool *>(v->val); + vcb->Set(&val, sizeof(bool)); + break; + } + default: + break; + } + } + catch (const ConfigException &ex) + { + source.Reply(_("Error changing configuration value: ") + ex.GetReason()); + return MOD_CONT; + } + + ChangeHash(Config->config_data, params[1], params[2], params[3]); + + Log(LOG_ADMIN, source.u, this) << "to change the configuration value of " << params[1] << ":" << params[2] << " to " << params[3]; + source.Reply(_("Value of %s:%s changed to %s"), params[1].c_str(), params[2].c_str(), params[3].c_str()); + return MOD_CONT; + } + } + + source.Reply("There is no configuration value named %s:%s", params[1].c_str(), params[2].c_str()); + } + else if (what.equals_ci("VIEW")) + { + /* Blocks we should show */ + const Anope::string show_blocks[] = { "botserv", "chanserv", "defcon", "global", "memoserv", "nickserv", "networkinfo", "operserv", "options", "" }; + + Log(LOG_ADMIN, source.u, this); + + for (ConfigDataHash::const_iterator it = Config->config_data.begin(), it_end = Config->config_data.end(); it != it_end; ++it) + { + const Anope::string &bname = it->first; + const KeyValList &list = it->second; + + bool ok = false; + for (unsigned i = 0; !show_blocks[i].empty(); ++i) + if (bname == show_blocks[i]) + ok = true; + if (ok == false) + continue; + + source.Reply(_("%s settings:"), bname.c_str()); + for (unsigned i = 0; i < list.size(); ++i) + { + const Anope::string &first = list[i].first, second = list[i].second; + + if (first == "modules") + continue; // Modules list isn't important + + source.Reply(_(" Name: %-15s Value: %s"), first.c_str(), second.c_str()); + } + } + + source.Reply(_("End of configuration.")); + } + else + this->OnSyntaxError(source, what); + + return MOD_CONT; + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) + { + source.Reply(_("Syntax: \002CONFIG {\037MODIFY\037|\037VIEW\037} [\037block name\037 \037item name\037 \037item value\037]\002\n" + "\n" + "\002CONFIG\002 allows you to change and view configuration settings.\n" + "Settings changed by this command are temporary and will not be reflected\n" + "back into the configuration file, and will be lost if Anope is shut down,\n" + "restarted, or the RELOAD command is used.\n" + " \n" + "Example:\n" + " \002CONFIG MODIFY nickserv forcemail no\002")); + return true; + } + + void OnSyntaxError(CommandSource &source, const Anope::string &subcommand) + { + SyntaxError(source, "CONFIG", _("CONFIG {\037MODIFY\037|\037VIEW\037} [\037block name\037 \037item name\037 \037item value\037]")); + } +}; + +class OSConfig : public Module +{ + CommandOSConfig commandosconfig; + + public: + OSConfig(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator) + { + this->SetAuthor("Anope"); + this->SetType(CORE); + + this->AddCommand(OperServ, &commandosconfig); + } +}; + +MODULE_INIT(OSConfig) diff --git a/modules/core/os_reload.cpp b/modules/core/os_reload.cpp index 0a3e26ccc..46e3686a2 100644 --- a/modules/core/os_reload.cpp +++ b/modules/core/os_reload.cpp @@ -29,13 +29,14 @@ class CommandOSReload : public Command delete Config; Config = newconfig; FOREACH_MOD(I_OnReload, OnReload(false)); + source.Reply(_("Services' configuration file has been reloaded.")); } catch (const ConfigException &ex) { Log() << "Error reloading configuration file: " << ex.GetReason(); + source.Reply(_("Error reloading confguration file: ") + ex.GetReason()); } - source.Reply(_("Services' configuration file has been reloaded.")); return MOD_CONT; } diff --git a/modules/core/os_snline.cpp b/modules/core/os_snline.cpp index f9697a98f..6758b98b6 100644 --- a/modules/core/os_snline.cpp +++ b/modules/core/os_snline.cpp @@ -208,7 +208,7 @@ class CommandOSSNLine : public Command return MOD_CONT; source.Reply(_("\002%s\002 added to the SNLINE list."), mask.c_str()); - Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(NULL, expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; + Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; if (readonly) source.Reply(_(READ_ONLY_MODE)); diff --git a/modules/core/os_sqline.cpp b/modules/core/os_sqline.cpp index 56a1aed9d..c9599f0e0 100644 --- a/modules/core/os_sqline.cpp +++ b/modules/core/os_sqline.cpp @@ -188,7 +188,7 @@ class CommandOSSQLine : public Command return MOD_CONT; source.Reply(_("\002%s\002 added to the SQLINE list."), mask.c_str()); - Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(NULL, expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; + Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; if (readonly) source.Reply(_(READ_ONLY_MODE)); diff --git a/modules/core/os_stats.cpp b/modules/core/os_stats.cpp index a3898949f..8dedee571 100644 --- a/modules/core/os_stats.cpp +++ b/modules/core/os_stats.cpp @@ -130,47 +130,9 @@ class CommandOSStats : public Command CommandReturn DoStatsUptime(CommandSource &source) { time_t uptime = Anope::CurTime - start_time; - int days = uptime / 86400, hours = (uptime / 3600) % 24, mins = (uptime / 60) % 60, secs = uptime % 60; source.Reply(_("Current users: \002%d\002 (\002%d\002 ops)"), usercnt, opcnt); source.Reply(_("Maximum users: \002%d\002 (%s)"), maxusercnt, do_strftime(maxusertime).c_str()); - if (days > 1) - source.Reply(_("Services up \002%d\002 days, \002%02d:%02d\002"), days, hours, mins, secs); - else if (days == 1) - source.Reply(_("Services up OPER_STATS_UPTIME_1\002%dOPER_STATS_UPTIME_1\002 day, OPER_STATS_UPTIME_1\002%02d:%02dOPER_STATS_UPTIME_1\002"), days, hours, mins, secs); - else - { - if (hours > 1) - { - if (mins != 1) - source.Reply(_("Services up \002%d\002 hours, \002%d\002 minutes"), hours, mins); - else - source.Reply(_("Services up OPER_STATS_UPTIME_H1\002%dOPER_STATS_UPTIME_H1\002 hours, OPER_STATS_UPTIME_H1\002%dOPER_STATS_UPTIME_H1\002 minute"), hours, mins, secs); - } - else if (hours == 1) - { - if (mins != 1) - source.Reply(_("Services up OPER_STATS_UPTIME_1\002%dOPER_STATS_UPTIME_1\002 hour, OPER_STATS_UPTIME_1\002%dOPER_STATS_UPTIME_1\002 minutes"), hours, mins, secs); - else - source.Reply(_("Services up OPER_STATS_UPTIME_1H1\002%dOPER_STATS_UPTIME_1H1\002 hour, OPER_STATS_UPTIME_1H1\002%dOPER_STATS_UPTIME_1H1\002 minute"), hours, mins, secs); - } - else - { - if (mins != 1) - { - if (secs != 1) - source.Reply(_("Services up \002%d\002 minutes, \002%d\002 seconds"), mins, secs); - else - source.Reply(_("Services up OPER_STATS_UPTIME_M1\002%dOPER_STATS_UPTIME_M1\002 minutes, OPER_STATS_UPTIME_M1\002%dOPER_STATS_UPTIME_M1\002 second"), mins, secs); - } - else - { - if (secs != 1) - source.Reply(_("Services up OPER_STATS_UPTIME_1\002%dOPER_STATS_UPTIME_1\002 minute, OPER_STATS_UPTIME_1\002%dOPER_STATS_UPTIME_1\002 seconds"), mins, secs); - else - source.Reply(_("Services up OPER_STATS_UPTIME_1M1\002%dOPER_STATS_UPTIME_1M1\002 minute, OPER_STATS_UPTIME_1M1\002%dOPER_STATS_UPTIME_1M1\002 second"), mins, secs); - } - } - } + source.Reply(_("Services up %s"), duration(uptime).c_str()); return MOD_CONT; } diff --git a/modules/core/os_szline.cpp b/modules/core/os_szline.cpp index 3225aab39..30a339263 100644 --- a/modules/core/os_szline.cpp +++ b/modules/core/os_szline.cpp @@ -192,7 +192,7 @@ class CommandOSSZLine : public Command return MOD_CONT; source.Reply(_("\002%s\002 added to the SZLINE list."), mask.c_str()); - Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(NULL, expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; + Log(LOG_ADMIN, u, this) << "on " << mask << " (" << reason << ") expires in " << duration(expires - Anope::CurTime) << " [affects " << affected << " user(s) (" << percent << "%)]"; if (readonly) source.Reply(_(READ_ONLY_MODE)); diff --git a/src/bots.cpp b/src/bots.cpp index f8d692d74..85fcf8055 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -147,7 +147,7 @@ void BotInfo::Assign(User *u, ChannelInfo *ci) ci->bi = this; if (ci->c && ci->c->users.size() >= Config->BSMinUsers) - this->Join(ci->c); + this->Join(ci->c, &Config->BotModeList); } void BotInfo::UnAssign(User *u, ChannelInfo *ci) diff --git a/src/config.cpp b/src/config.cpp index ae8ccfc8c..86ef446bc 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -11,11 +11,10 @@ #include "services.h" #include "config.h" -#include "hashcomp.h" // If this gets added to services.h or someplace else later, remove it from here -- CyberBotX /*************************************************************************/ -Anope::string services_conf = "services.conf"; // Services configuration file name +ConfigurationFile services_conf("services.conf", false); // Services configuration file name ServerConfig *Config = NULL; static Anope::string Modules; @@ -40,7 +39,7 @@ static Anope::string NSDefaults; /*************************************************************************/ -ServerConfig::ServerConfig() : errstr(""), config_data(), NSDefFlags(NickCoreFlagStrings), CSDefFlags(ChannelInfoFlagStrings), BSDefFlags(BotServFlagStrings) +ServerConfig::ServerConfig() : config_data(), NSDefFlags(NickCoreFlagStrings), CSDefFlags(ChannelInfoFlagStrings), BSDefFlags(BotServFlagStrings) { this->Read(); @@ -225,7 +224,7 @@ ServerConfig::ServerConfig() : errstr(""), config_data(), NSDefFlags(NickCoreFla if (this->BSFantasyCharacter.empty()) this->BSFantasyCharacter = "!"; if (this->BSFantasyCharacter.length() > 1) - printf("*** this->BSFantasyCharacter is more than 1 character long. Only the first\n*** character ('%c') will be used. The others will be ignored.\n", this->BSFantasyCharacter[0]); + Log() << "*** " << this->BSFantasyCharacter << " is more than 1 character long. Only the first character will be used. The others will be ignored."; } /* Check the user keys */ @@ -471,7 +470,7 @@ bool ValidateNotEmpty(ServerConfig *, const Anope::string &tag, const Anope::str bool ValidateNotZero(ServerConfig *, const Anope::string &tag, const Anope::string &value, ValueItem &data) { - if (!data.GetInteger() && !dotime(data.GetValue())) + if (!data.GetInteger() && dotime(data.GetValue()) <= 0) throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero!"); return true; } @@ -482,7 +481,7 @@ bool ValidateEmailReg(ServerConfig *config, const Anope::string &tag, const Anop { if (value.equals_ci("unconfirmedexpire")) { - if (!data.GetInteger() && !dotime(data.GetValue())) + if (!data.GetInteger() && dotime(data.GetValue()) <= 0) throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero when e-mail registration are enabled!"); } else @@ -558,7 +557,7 @@ bool ValidateBotServ(ServerConfig *config, const Anope::string &tag, const Anope } else if (value.equals_ci("badwordsmax") || value.equals_ci("keepdata")) { - if (!data.GetInteger() && !dotime(data.GetValue())) + if (!data.GetInteger() && 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")) @@ -586,7 +585,7 @@ bool ValidateLimitSessions(ServerConfig *config, const Anope::string &tag, const { if (value.equals_ci("maxsessionlimit") || value.equals_ci("exceptionexpiry")) { - if (!data.GetInteger() && !dotime(data.GetValue())) + if (!data.GetInteger() && dotime(data.GetValue()) <= 0) throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero when session limiting is enabled!"); } } @@ -641,7 +640,7 @@ bool ValidateDefCon(ServerConfig *config, const Anope::string &tag, const Anope: } else if (value.equals_ci("sessionlimit") || value.equals_ci("akillexpire")) { - if (!data.GetInteger() && !dotime(data.GetValue())) + if (!data.GetInteger() && dotime(data.GetValue()) <= 0) throw ConfigException("The value for <" + tag + ":" + value + "> must be non-zero when DefCon is enabled!"); } } @@ -846,6 +845,32 @@ static bool DoneOpers(ServerConfig *config, const Anope::string &) /*************************************************************************/ +static bool InitInclude(ServerConfig *config, const Anope::string &) +{ + return true; +} + +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 (type != "file" && type != "executable") + throw ConfigException("include:type must be either \"file\" or \"executable\""); + + ConfigurationFile f(file, type == "executable"); + config->LoadConf(f); + + return true; +} + +static bool DoneInclude(ServerConfig *config, const Anope::string &) +{ + return true; +} + +/*************************************************************************/ + bool InitModules(ServerConfig *, const Anope::string &) { Modules.clear(); @@ -957,13 +982,75 @@ bool DoneLogs(ServerConfig *config, const Anope::string &) return true; } -void ServerConfig::Read() +ConfigurationFile::ConfigurationFile(const Anope::string &n, bool e) : name(n), executable(e), fp(NULL) +{ +} + +ConfigurationFile::~ConfigurationFile() +{ + this->Close(); +} + +const Anope::string &ConfigurationFile::GetName() const +{ + return this->name; +} + +bool ConfigurationFile::IsOpen() const +{ + return this->fp != NULL; +} + +bool ConfigurationFile::Open() +{ + this->Close(); + this->fp = (this->executable ? popen(this->name.c_str(), "r") : fopen(this->name.c_str(), "r")); + return this->fp != NULL; +} + +void ConfigurationFile::Close() +{ + if (this->fp != NULL) + { + if (this->executable) + pclose(this->fp); + else + fclose(this->fp); + this->fp = NULL; + } +} + +bool ConfigurationFile::End() const +{ + return !this->IsOpen() || feof(this->fp); +} + +Anope::string ConfigurationFile::Read() +{ + Anope::string ret; + char buf[BUFSIZE]; + while (fgets(buf, sizeof(buf), this->fp) != NULL) + { + char *nl = strchr(buf, '\n'); + if (nl != NULL) + *nl = 0; + else if (!this->End()) + { + ret += buf; + continue; + } + + ret = buf; + break; + } + + return ret; +} + +ConfigItems::ConfigItems(ServerConfig *conf) { - errstr.clear(); - // These tags MUST occur and must ONLY occur once in the config file - static const Anope::string Once[] = {"serverinfo", "networkinfo", "options", "nickserv", ""}; // These tags can occur ONCE or not at all - InitialConfig Values[] = { + 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: @@ -972,43 +1059,39 @@ void ServerConfig::Read() * * If you want to create a directive using an integer: * int blarg; - * {"tag", "value", "0", new ValueContainerInt(&blarg), DT_INTEGER, <validation>}, + * {"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(&blarg), DT_UINTEGER, <validation>}, + * {"tag", "value", "0", new ValueContainerUInt(&conf->blarg), DT_UINTEGER, <validation>}, * * If you want to create a directive using a character pointer without additional validation (see below for hostnames, fields with no spaces, and IP addresses): * char *blarg; - * {"tag", "value", "", new ValueContainerChar(&blarg), DT_CHARPTR, <validation>}, + * {"tag", "value", "", new ValueContainerChar(&conf->blarg), DT_CHARPTR, <validation>}, * * If you want to create a directive using a string: - * std::string blarg; - * {"tag", "value", "", new ValueContainerString(&blarg), DT_STRING, <validation>}, - * - * If you want to create a directive using a case-insensitive string: - * std::string blarg; - * {"tag", "value", "", new ValueContainerCIString(&blarg), DT_CISTRING, <validation>}, + * 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(&blarg), DT_BOOLEAN, <validation>}, + * {"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(&blarg), DT_HOSTNAME, <validation>}, + * {"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(&blarg), DT_NOSPACES, <validation>}, + * {"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(&blarg), DT_IPADDRESS, <validation>}, + * {"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(&blarg), DT_TIME, <validation>}, + * {"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 @@ -1017,173 +1100,180 @@ void ServerConfig::Read() * * 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(&this->ServerName), DT_HOSTNAME | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "description", "", new ValueContainerString(&this->ServerDesc), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "localhost", "", new ValueContainerString(&this->LocalHost), DT_HOSTNAME | DT_NORELOAD, NoValidation}, - {"serverinfo", "type", "", new ValueContainerString(&this->IRCDModule), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "id", "", new ValueContainerString(&this->Numeric), DT_NOSPACES | DT_NORELOAD, NoValidation}, - {"serverinfo", "ident", "", new ValueContainerString(&this->ServiceUser), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "hostname", "", new ValueContainerString(&this->ServiceHost), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "pid", "services.pid", new ValueContainerString(&this->PIDFilename), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"serverinfo", "motd", "services.motd", new ValueContainerString(&this->MOTDFilename), DT_STRING, ValidateNotEmpty}, - {"networkinfo", "networkname", "", new ValueContainerString(&this->NetworkName), DT_STRING, ValidateNotEmpty}, - {"networkinfo", "nicklen", "0", new ValueContainerUInt(&this->NickLen), DT_UINTEGER | DT_NORELOAD, ValidateNickLen}, - {"networkinfo", "userlen", "10", new ValueContainerUInt(&this->UserLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, - {"networkinfo", "hostlen", "64", new ValueContainerUInt(&this->HostLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, + {"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", "type", "", new ValueContainerString(&conf->IRCDModule), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, + {"serverinfo", "id", "", new ValueContainerString(&conf->Numeric), DT_NOSPACES | DT_NORELOAD, NoValidation}, + {"serverinfo", "ident", "", new ValueContainerString(&conf->ServiceUser), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, + {"serverinfo", "hostname", "", new ValueContainerString(&conf->ServiceHost), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, + {"serverinfo", "pid", "services.pid", new ValueContainerString(&conf->PIDFilename), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, + {"serverinfo", "motd", "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}, {"options", "encryption", "", new ValueContainerString(&EncModules), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"options", "passlen", "32", new ValueContainerUInt(&this->PassLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, + {"options", "passlen", "32", new ValueContainerUInt(&conf->PassLen), DT_UINTEGER | DT_NORELOAD, NoValidation}, {"options", "database", "", new ValueContainerString(&DBModules), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"options", "socketengine", "", new ValueContainerString(&this->SocketEngine), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"options", "userkey1", "0", new ValueContainerLUInt(&this->UserKey1), DT_LUINTEGER, NoValidation}, - {"options", "userkey2", "0", new ValueContainerLUInt(&this->UserKey2), DT_LUINTEGER, NoValidation}, - {"options", "userkey3", "0", new ValueContainerLUInt(&this->UserKey3), DT_LUINTEGER, NoValidation}, - {"options", "nobackupokay", "no", new ValueContainerBool(&this->NoBackupOkay), DT_BOOLEAN, NoValidation}, - {"options", "strictpasswords", "no", new ValueContainerBool(&this->StrictPasswords), DT_BOOLEAN, NoValidation}, - {"options", "badpasslimit", "0", new ValueContainerUInt(&this->BadPassLimit), DT_UINTEGER, NoValidation}, - {"options", "badpasstimeout", "0", new ValueContainerTime(&this->BadPassTimeout), DT_TIME, NoValidation}, - {"options", "updatetimeout", "0", new ValueContainerTime(&this->UpdateTimeout), DT_TIME, ValidateNotZero}, - {"options", "expiretimeout", "0", new ValueContainerTime(&this->ExpireTimeout), DT_TIME, ValidateNotZero}, - {"options", "readtimeout", "0", new ValueContainerTime(&this->ReadTimeout), DT_TIME, ValidateNotZero}, - {"options", "warningtimeout", "0", new ValueContainerTime(&this->WarningTimeout), DT_TIME, ValidateNotZero}, - {"options", "timeoutcheck", "0", new ValueContainerTime(&this->TimeoutCheck), DT_TIME, NoValidation}, - {"options", "keepbackups", "0", new ValueContainerInt(&this->KeepBackups), DT_INTEGER, NoValidation}, - {"options", "forceforbidreason", "no", new ValueContainerBool(&this->ForceForbidReason), DT_BOOLEAN, NoValidation}, - {"options", "useprivmsg", "no", new ValueContainerBool(&this->UsePrivmsg), DT_BOOLEAN, NoValidation}, - {"options", "usestrictprivmsg", "no", new ValueContainerBool(&this->UseStrictPrivMsg), DT_BOOLEAN, NoValidation}, - {"options", "hidestatso", "no", new ValueContainerBool(&this->HideStatsO), DT_BOOLEAN, NoValidation}, - {"options", "globaloncycle", "no", new ValueContainerBool(&this->GlobalOnCycle), DT_BOOLEAN, NoValidation}, - {"options", "globaloncycledown", "", new ValueContainerString(&this->GlobalOnCycleMessage), DT_STRING, ValidateGlobalOnCycle}, - {"options", "globaloncycleup", "", new ValueContainerString(&this->GlobalOnCycleUP), DT_STRING, ValidateGlobalOnCycle}, - {"options", "anonymousglobal", "no", new ValueContainerBool(&this->AnonymousGlobal), DT_BOOLEAN, NoValidation}, - {"options", "nickregdelay", "0", new ValueContainerUInt(&this->NickRegDelay), DT_UINTEGER, NoValidation}, - {"options", "restrictopernicks", "no", new ValueContainerBool(&this->RestrictOperNicks), DT_BOOLEAN, NoValidation}, - {"options", "newscount", "3", new ValueContainerUInt(&this->NewsCount), DT_UINTEGER, NoValidation}, + {"options", "socketengine", "", new ValueContainerString(&conf->SocketEngine), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, + {"options", "userkey1", "0", new ValueContainerLUInt(&conf->UserKey1), DT_LUINTEGER, NoValidation}, + {"options", "userkey2", "0", new ValueContainerLUInt(&conf->UserKey2), DT_LUINTEGER, NoValidation}, + {"options", "userkey3", "0", new ValueContainerLUInt(&conf->UserKey3), 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", "globaloncycle", "no", new ValueContainerBool(&conf->GlobalOnCycle), DT_BOOLEAN, NoValidation}, + {"options", "globaloncycledown", "", new ValueContainerString(&conf->GlobalOnCycleMessage), DT_STRING, ValidateGlobalOnCycle}, + {"options", "globaloncycleup", "", new ValueContainerString(&conf->GlobalOnCycleUP), DT_STRING, ValidateGlobalOnCycle}, + {"options", "anonymousglobal", "no", new ValueContainerBool(&conf->AnonymousGlobal), 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", "mlock", "+nrt", new ValueContainerString(&this->MLock), DT_STRING, NoValidation}, - {"options", "nomlock", "", new ValueContainerString(&this->NoMLock), DT_STRING, NoValidation}, - {"options", "botmodes", "", new ValueContainerString(&this->BotModes), DT_STRING, NoValidation}, - {"options", "maxretries", "10", new ValueContainerUInt(&this->MaxRetries), DT_UINTEGER, NoValidation}, - {"options", "retrywait", "60", new ValueContainerInt(&this->RetryWait), DT_INTEGER, ValidateNotZero}, - {"options", "hideprivilegedcommands", "no", new ValueContainerBool(&this->HidePrivilegedCommands), DT_BOOLEAN, NoValidation}, - {"nickserv", "nick", "NickServ", new ValueContainerString(&this->s_NickServ), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"nickserv", "description", "Nickname Registration Service", new ValueContainerString(&this->desc_NickServ), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, - {"nickserv", "emailregistration", "no", new ValueContainerBool(&this->NSEmailReg), DT_BOOLEAN, NoValidation}, + {"options", "mlock", "+nrt", new ValueContainerString(&conf->MLock), DT_STRING, NoValidation}, + {"options", "nomlock", "", new ValueContainerString(&conf->NoMLock), DT_STRING, NoValidation}, + {"options", "botmodes", "", new ValueContainerString(&conf->BotModes), DT_STRING, NoValidation}, + {"options", "maxretries", "10", new ValueContainerUInt(&conf->MaxRetries), DT_UINTEGER, NoValidation}, + {"options", "retrywait", "60", new ValueContainerInt(&conf->RetryWait), DT_INTEGER, ValidateNotZero}, + {"options", "hideprivilegedcommands", "no", new ValueContainerBool(&conf->HidePrivilegedCommands), DT_BOOLEAN, NoValidation}, + {"nickserv", "nick", "NickServ", new ValueContainerString(&conf->s_NickServ), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, + {"nickserv", "description", "Nickname Registration Service", new ValueContainerString(&conf->desc_NickServ), DT_STRING | DT_NORELOAD, ValidateNotEmpty}, + {"nickserv", "emailregistration", "no", new ValueContainerBool(&conf->NSEmailReg), DT_BOOLEAN, NoValidation}, {"nickserv", "modules", "", new ValueContainerString(&NickCoreModules), DT_STRING, NoValidation}, - {"nickserv", "forceemail", "no", new ValueContainerBool(&this->NSForceEmail), DT_BOOLEAN, ValidateEmailReg}, - {"nickserv", "confirmemailchanges", "no", new ValueContainerBool(&this->NSConfirmEmailChanges), DT_BOOLEAN, NoValidation}, + {"nickserv", "forceemail", "no", new ValueContainerBool(&conf->NSForceEmail), DT_BOOLEAN, ValidateEmailReg}, + {"nickserv", "confirmemailchanges", "no", new ValueContainerBool(&conf->NSConfirmEmailChanges), DT_BOOLEAN, NoValidation}, {"nickserv", "defaults", "secure memosignon memoreceive", new ValueContainerString(&NSDefaults), DT_STRING, NoValidation}, - {"nickserv", "languages", "", new ValueContainerString(&this->Languages), DT_STRING, NoValidation}, - {"nickserv", "defaultlanguage", "0", new ValueContainerString(&this->NSDefLanguage), DT_STRING, NoValidation}, - {"nickserv", "regdelay", "0", new ValueContainerTime(&this->NSRegDelay), DT_TIME, NoValidation}, - {"nickserv", "resenddelay", "0", new ValueContainerTime(&this->NSResendDelay), DT_TIME, NoValidation}, - {"nickserv", "expire", "21d", new ValueContainerTime(&this->NSExpire), DT_TIME, NoValidation}, - {"nickserv", "suspendexpire", "0", new ValueContainerTime(&this->NSSuspendExpire), DT_TIME, NoValidation}, - {"nickserv", "forbidexpire", "0", new ValueContainerTime(&this->NSForbidExpire), DT_TIME, NoValidation}, - {"nickserv", "unconfirmedexpire", "0", new ValueContainerTime(&this->NSUnconfirmedExpire), DT_TIME, ValidateEmailReg}, - {"nickserv", "maxaliases", "0", new ValueContainerUInt(&this->NSMaxAliases), DT_UINTEGER, NoValidation}, - {"nickserv", "accessmax", "0", new ValueContainerUInt(&this->NSAccessMax), DT_UINTEGER, ValidateNotZero}, + {"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", "forbidexpire", "0", new ValueContainerTime(&conf->NSForbidExpire), 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, ValidateNotZero}, {"nickserv", "enforceruser", "", new ValueContainerString(&temp_nsuserhost), DT_STRING, ValidateNotEmpty}, - {"nickserv", "releasetimeout", "0", new ValueContainerTime(&this->NSReleaseTimeout), DT_TIME, ValidateNotZero}, - {"nickserv", "allowkillimmed", "no", new ValueContainerBool(&this->NSAllowKillImmed), DT_BOOLEAN | DT_NORELOAD, NoValidation}, - {"nickserv", "nogroupchange", "no", new ValueContainerBool(&this->NSNoGroupChange), DT_BOOLEAN, NoValidation}, - {"nickserv", "listopersonly", "no", new ValueContainerBool(&this->NSListOpersOnly), DT_BOOLEAN, NoValidation}, - {"nickserv", "listmax", "0", new ValueContainerUInt(&this->NSListMax), DT_UINTEGER, ValidateNotZero}, - {"nickserv", "guestnickprefix", "", new ValueContainerString(&this->NSGuestNickPrefix), DT_STRING, ValidateGuestPrefix}, - {"nickserv", "secureadmins", "no", new ValueContainerBool(&this->NSSecureAdmins), DT_BOOLEAN, NoValidation}, - {"nickserv", "strictprivileges", "no", new ValueContainerBool(&this->NSStrictPrivileges), DT_BOOLEAN, NoValidation}, - {"nickserv", "modeonid", "no", new ValueContainerBool(&this->NSModeOnID), DT_BOOLEAN, NoValidation}, - {"nickserv", "addaccessonreg", "no", new ValueContainerBool(&this->NSAddAccessOnReg), DT_BOOLEAN, NoValidation}, - {"nickserv", "ajoinmax", "10", new ValueContainerUInt(&this->AJoinMax), DT_UINTEGER, NoValidation}, - {"mail", "usemail", "no", new ValueContainerBool(&this->UseMail), DT_BOOLEAN, ValidateEmailReg}, - {"mail", "sendmailpath", "", new ValueContainerString(&this->SendMailPath), DT_STRING, ValidateMail}, - {"mail", "sendfrom", "", new ValueContainerString(&this->SendFrom), DT_STRING, ValidateMail}, - {"mail", "restrict", "no", new ValueContainerBool(&this->RestrictMail), DT_BOOLEAN, NoValidation}, - {"mail", "delay", "0", new ValueContainerTime(&this->MailDelay), DT_TIME, NoValidation}, - {"mail", "dontquoteaddresses", "no", new ValueContainerBool(&this->DontQuoteAddresses), DT_BOOLEAN, NoValidation}, - {"dns", "nameserver", "127.0.0.1", new ValueContainerString(&this->NameServer), DT_STRING, NoValidation}, - {"dns", "timeout", "5", new ValueContainerTime(&this->DNSTimeout), DT_TIME, NoValidation}, - {"chanserv", "nick", "", new ValueContainerString(&this->s_ChanServ), DT_STRING | DT_NORELOAD, NoValidation}, - {"chanserv", "description", "Channel Registration Service", new ValueContainerString(&this->desc_ChanServ), DT_STRING | DT_NORELOAD, ValidateChanServ}, + {"nickserv", "releasetimeout", "0", new ValueContainerTime(&conf->NSReleaseTimeout), DT_TIME, ValidateNotZero}, + {"nickserv", "allowkillimmed", "no", new ValueContainerBool(&conf->NSAllowKillImmed), DT_BOOLEAN | DT_NORELOAD, NoValidation}, + {"nickserv", "nogroupchange", "no", new ValueContainerBool(&conf->NSNoGroupChange), DT_BOOLEAN, NoValidation}, + {"nickserv", "listopersonly", "no", new ValueContainerBool(&conf->NSListOpersOnly), DT_BOOLEAN, NoValidation}, + {"nickserv", "listmax", "0", new ValueContainerUInt(&conf->NSListMax), DT_UINTEGER, ValidateNotZero}, + {"nickserv", "guestnickprefix", "", new ValueContainerString(&conf->NSGuestNickPrefix), DT_STRING, ValidateGuestPrefix}, + {"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}, + {"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}, + {"dns", "nameserver", "127.0.0.1", new ValueContainerString(&conf->NameServer), DT_STRING, NoValidation}, + {"dns", "timeout", "5", new ValueContainerTime(&conf->DNSTimeout), DT_TIME, NoValidation}, + {"chanserv", "nick", "", new ValueContainerString(&conf->s_ChanServ), DT_STRING | DT_NORELOAD, NoValidation}, + {"chanserv", "description", "Channel Registration Service", new ValueContainerString(&conf->desc_ChanServ), DT_STRING | DT_NORELOAD, ValidateChanServ}, {"chanserv", "modules", "", new ValueContainerString(&ChanCoreModules), DT_STRING, ValidateChanServ}, {"chanserv", "defaults", "keeptopic secure securefounder signkick", new ValueContainerString(&CSDefaults), DT_STRING, ValidateChanServ}, - {"chanserv", "maxregistered", "0", new ValueContainerUInt(&this->CSMaxReg), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "expire", "14d", new ValueContainerTime(&this->CSExpire), DT_TIME, ValidateChanServ}, - {"chanserv", "suspendexpire", "0", new ValueContainerTime(&this->CSSuspendExpire), DT_TIME, NoValidation}, - {"chanserv", "forbidexpire", "0", new ValueContainerTime(&this->CSForbidExpire), DT_TIME, NoValidation}, - {"chanserv", "defbantype", "2", new ValueContainerInt(&this->CSDefBantype), DT_INTEGER, ValidateChanServ}, - {"chanserv", "accessmax", "0", new ValueContainerUInt(&this->CSAccessMax), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "autokickmax", "0", new ValueContainerUInt(&this->CSAutokickMax), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "autokickreason", "User has been banned from the channel", new ValueContainerString(&this->CSAutokickReason), DT_STRING, ValidateChanServ}, - {"chanserv", "inhabit", "0", new ValueContainerTime(&this->CSInhabit), DT_TIME, ValidateChanServ}, - {"chanserv", "listopersonly", "no", new ValueContainerBool(&this->CSListOpersOnly), DT_BOOLEAN, ValidateChanServ}, - {"chanserv", "listmax", "0", new ValueContainerUInt(&this->CSListMax), DT_UINTEGER, ValidateChanServ}, - {"chanserv", "opersonly", "no", new ValueContainerBool(&this->CSOpersOnly), DT_BOOLEAN, ValidateChanServ}, - {"memoserv", "nick", "", new ValueContainerString(&this->s_MemoServ), DT_STRING | DT_NORELOAD, NoValidation}, - {"memoserv", "description", "Memo Service", new ValueContainerString(&this->desc_MemoServ), DT_STRING | DT_NORELOAD, ValidateMemoServ}, + {"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", "listopersonly", "no", new ValueContainerBool(&conf->CSListOpersOnly), DT_BOOLEAN, ValidateChanServ}, + {"chanserv", "listmax", "0", new ValueContainerUInt(&conf->CSListMax), DT_UINTEGER, ValidateChanServ}, + {"chanserv", "opersonly", "no", new ValueContainerBool(&conf->CSOpersOnly), DT_BOOLEAN, ValidateChanServ}, + {"memoserv", "nick", "", new ValueContainerString(&conf->s_MemoServ), DT_STRING | DT_NORELOAD, NoValidation}, + {"memoserv", "description", "Memo Service", new ValueContainerString(&conf->desc_MemoServ), DT_STRING | DT_NORELOAD, ValidateMemoServ}, {"memoserv", "modules", "", new ValueContainerString(&MemoCoreModules), DT_STRING, NoValidation}, - {"memoserv", "maxmemos", "0", new ValueContainerUInt(&this->MSMaxMemos), DT_UINTEGER, NoValidation}, - {"memoserv", "senddelay", "0", new ValueContainerTime(&this->MSSendDelay), DT_TIME, NoValidation}, - {"memoserv", "notifyall", "no", new ValueContainerBool(&this->MSNotifyAll), DT_BOOLEAN, NoValidation}, - {"memoserv", "memoreceipt", "0", new ValueContainerUInt(&this->MSMemoReceipt), DT_UINTEGER, NoValidation}, - {"botserv", "nick", "", new ValueContainerString(&this->s_BotServ), DT_STRING | DT_NORELOAD, NoValidation}, - {"botserv", "description", "Bot Service", new ValueContainerString(&this->desc_BotServ), DT_STRING | DT_NORELOAD, ValidateBotServ}, + {"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}, + {"botserv", "nick", "", new ValueContainerString(&conf->s_BotServ), DT_STRING | DT_NORELOAD, NoValidation}, + {"botserv", "description", "Bot Service", new ValueContainerString(&conf->desc_BotServ), DT_STRING | DT_NORELOAD, ValidateBotServ}, {"botserv", "modules", "", new ValueContainerString(&BotCoreModules), DT_STRING, NoValidation}, {"botserv", "defaults", "", new ValueContainerString(&BSDefaults), DT_STRING, NoValidation}, - {"botserv", "minusers", "0", new ValueContainerUInt(&this->BSMinUsers), DT_UINTEGER, ValidateBotServ}, - {"botserv", "badwordsmax", "0", new ValueContainerUInt(&this->BSBadWordsMax), DT_UINTEGER, ValidateBotServ}, - {"botserv", "keepdata", "0", new ValueContainerTime(&this->BSKeepData), DT_TIME, ValidateBotServ}, - {"botserv", "smartjoin", "no", new ValueContainerBool(&this->BSSmartJoin), DT_BOOLEAN, NoValidation}, - {"botserv", "gentlebadwordreason", "no", new ValueContainerBool(&this->BSGentleBWReason), DT_BOOLEAN, NoValidation}, - {"botserv", "casesensitive", "no", new ValueContainerBool(&this->BSCaseSensitive), DT_BOOLEAN, NoValidation}, - {"botserv", "fantasycharacter", "!", new ValueContainerString(&this->BSFantasyCharacter), DT_STRING, NoValidation}, - {"hostserv", "nick", "", new ValueContainerString(&this->s_HostServ), DT_STRING | DT_NORELOAD, NoValidation}, - {"hostserv", "description", "vHost Service", new ValueContainerString(&this->desc_HostServ), DT_STRING | DT_NORELOAD, ValidateHostServ}, + {"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, NoValidation}, + {"hostserv", "nick", "", new ValueContainerString(&conf->s_HostServ), DT_STRING | DT_NORELOAD, NoValidation}, + {"hostserv", "description", "vHost Service", new ValueContainerString(&conf->desc_HostServ), DT_STRING | DT_NORELOAD, ValidateHostServ}, {"hostserv", "modules", "", new ValueContainerString(&HostCoreModules), DT_STRING, NoValidation}, - {"operserv", "nick", "", new ValueContainerString(&this->s_OperServ), DT_STRING | DT_NORELOAD, NoValidation}, - {"operserv", "description", "Operator Service", new ValueContainerString(&this->desc_OperServ), DT_STRING | DT_NORELOAD, ValidateOperServ}, + {"operserv", "nick", "", new ValueContainerString(&conf->s_OperServ), DT_STRING | DT_NORELOAD, NoValidation}, + {"operserv", "description", "Operator Service", new ValueContainerString(&conf->desc_OperServ), DT_STRING | DT_NORELOAD, ValidateOperServ}, {"operserv", "modules", "", new ValueContainerString(&OperCoreModules), DT_STRING, NoValidation}, - {"operserv", "superadmin", "no", new ValueContainerBool(&this->SuperAdmin), DT_BOOLEAN, NoValidation}, - {"operserv", "autokillexpiry", "0", new ValueContainerTime(&this->AutokillExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "chankillexpiry", "0", new ValueContainerTime(&this->ChankillExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "snlineexpiry", "0", new ValueContainerTime(&this->SNLineExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "sqlineexpiry", "0", new ValueContainerTime(&this->SQLineExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "szlineexpiry", "0", new ValueContainerTime(&this->SZLineExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "akillonadd", "no", new ValueContainerBool(&this->AkillOnAdd), DT_BOOLEAN, NoValidation}, - {"operserv", "killonsnline", "no", new ValueContainerBool(&this->KillonSNline), DT_BOOLEAN, NoValidation}, - {"operserv", "killonsqline", "no", new ValueContainerBool(&this->KillonSQline), DT_BOOLEAN, 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", "szlineexpiry", "0", new ValueContainerTime(&conf->SZLineExpiry), 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", "notifications", "", new ValueContainerString(&OSNotifications), DT_STRING, NoValidation}, - {"operserv", "limitsessions", "no", new ValueContainerBool(&this->LimitSessions), DT_BOOLEAN, NoValidation}, - {"operserv", "defaultsessionlimit", "0", new ValueContainerUInt(&this->DefSessionLimit), DT_UINTEGER, NoValidation}, - {"operserv", "maxsessionlimit", "0", new ValueContainerUInt(&this->MaxSessionLimit), DT_UINTEGER, ValidateOperServ}, - {"operserv", "exceptionexpiry", "0", new ValueContainerTime(&this->ExceptionExpiry), DT_TIME, ValidateOperServ}, - {"operserv", "sessionlimitexceeded", "", new ValueContainerString(&this->SessionLimitExceeded), DT_STRING, NoValidation}, - {"operserv", "sessionlimitdetailsloc", "", new ValueContainerString(&this->SessionLimitDetailsLoc), DT_STRING, NoValidation}, - {"operserv", "maxsessionkill", "0", new ValueContainerUInt(&this->MaxSessionKill), DT_UINTEGER, NoValidation}, - {"operserv", "sessionautokillexpiry", "0", new ValueContainerTime(&this->SessionAutoKillExpiry), DT_TIME, NoValidation}, - {"operserv", "addakiller", "no", new ValueContainerBool(&this->AddAkiller), DT_BOOLEAN, NoValidation}, - {"operserv", "opersonly", "no", new ValueContainerBool(&this->OSOpersOnly), DT_BOOLEAN, NoValidation}, - {"global", "nick", "", new ValueContainerString(&this->s_GlobalNoticer), DT_STRING | DT_NORELOAD, NoValidation}, - {"global", "description", "Global Noticer", new ValueContainerString(&this->desc_GlobalNoticer), DT_STRING | DT_NORELOAD, ValidateGlobal}, - {"defcon", "defaultlevel", "0", new ValueContainerInt(&DefConLevel), DT_INTEGER, ValidateDefCon}, + {"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", "addakiller", "no", new ValueContainerBool(&conf->AddAkiller), DT_BOOLEAN, NoValidation}, + {"operserv", "opersonly", "no", new ValueContainerBool(&conf->OSOpersOnly), DT_BOOLEAN, NoValidation}, + {"global", "nick", "", new ValueContainerString(&conf->s_GlobalNoticer), DT_STRING | DT_NORELOAD, NoValidation}, + {"global", "description", "Global Noticer", new ValueContainerString(&conf->desc_GlobalNoticer), DT_STRING | DT_NORELOAD, ValidateGlobal}, + {"defcon", "defaultlevel", "0", new ValueContainerInt(&conf->DefConLevel), DT_INTEGER, ValidateDefCon}, {"defcon", "level4", "", new ValueContainerString(&DefCon4), DT_STRING, ValidateDefCon}, {"defcon", "level3", "", new ValueContainerString(&DefCon3), DT_STRING, ValidateDefCon}, {"defcon", "level2", "", new ValueContainerString(&DefCon2), DT_STRING, ValidateDefCon}, {"defcon", "level1", "", new ValueContainerString(&DefCon1), DT_STRING, ValidateDefCon}, - {"defcon", "sessionlimit", "0", new ValueContainerUInt(&this->DefConSessionLimit), DT_UINTEGER, ValidateDefCon}, - {"defcon", "akillexpire", "0", new ValueContainerTime(&this->DefConAKILL), DT_TIME, ValidateDefCon}, - {"defcon", "chanmodes", "", new ValueContainerString(&this->DefConChanModes), DT_STRING, ValidateDefCon}, - {"defcon", "timeout", "0", new ValueContainerTime(&this->DefConTimeOut), DT_TIME, NoValidation}, - {"defcon", "globalondefcon", "no", new ValueContainerBool(&this->GlobalOnDefcon), DT_BOOLEAN, NoValidation}, - {"defcon", "globalondefconmore", "no", new ValueContainerBool(&this->GlobalOnDefconMore), DT_BOOLEAN, NoValidation}, - {"defcon", "message", "", new ValueContainerString(&this->DefconMessage), DT_STRING, ValidateDefCon}, - {"defcon", "offmessage", "", new ValueContainerString(&this->DefConOffMessage), DT_STRING, NoValidation}, - {"defcon", "akillreason", "", new ValueContainerString(&this->DefConAkillReason), DT_STRING, ValidateDefCon}, + {"defcon", "sessionlimit", "0", new ValueContainerUInt(&conf->DefConSessionLimit), DT_UINTEGER, ValidateDefCon}, + {"defcon", "akillexpire", "0", new ValueContainerTime(&conf->DefConAKILL), DT_TIME, ValidateDefCon}, + {"defcon", "chanmodes", "", new ValueContainerString(&conf->DefConChanModes), DT_STRING, ValidateDefCon}, + {"defcon", "timeout", "0", new ValueContainerTime(&conf->DefConTimeOut), DT_TIME, NoValidation}, + {"defcon", "globalondefcon", "no", new ValueContainerBool(&conf->GlobalOnDefcon), DT_BOOLEAN, NoValidation}, + {"defcon", "globalondefconmore", "no", new ValueContainerBool(&conf->GlobalOnDefconMore), DT_BOOLEAN, NoValidation}, + {"defcon", "message", "", new ValueContainerString(&conf->DefconMessage), DT_STRING, ValidateDefCon}, + {"defcon", "offmessage", "", new ValueContainerString(&conf->DefConOffMessage), DT_STRING, NoValidation}, + {"defcon", "akillreason", "", new ValueContainerString(&conf->DefConAkillReason), DT_STRING, ValidateDefCon}, {"", "", "", 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. */ - MultiConfig MultiValues[] = { + MultiItem MultiItems[] = { + /* Include must be first so we can pull in the extra files before processing + * anything else! */ + {"include", + {"type", "name", ""}, + {"", "", ""}, + {DT_CHARPTR, DT_CHARPTR}, + InitInclude, DoInclude, DoneInclude}, {"uplink", {"host", "ipv6", "port", "password", ""}, {"", "no", "0", "", ""}, @@ -1216,284 +1306,255 @@ void ServerConfig::Read() NULL, NULL, NULL} }; - if (!LoadConf(this->config_data, services_conf)) - throw ConfigException(this->errstr.str()); - /* This boolean is set to true when the Values array is completely iterated through, to avoid needing - * to do so inside the catch block to clean up the new'd values from the array. */ - bool CheckedAllValues = false; - // The stuff in here may throw ConfigException, be sure we're in a position to catch it. - try - { - // Read the values of all the tags which occur once or not at all, and call their callbacks. - for (int Index = 0; !Values[Index].tag.empty(); ++Index) - { - Anope::string item; - int dt = Values[Index].datatype; - bool allow_newlines = dt & DT_ALLOW_NEWLINE, allow_wild = dt & DT_ALLOW_WILD, noreload = dt & DT_NORELOAD; - dt &= ~DT_ALLOW_NEWLINE; - dt &= ~DT_ALLOW_WILD; - dt &= ~DT_NORELOAD; + this->Values = new Item[sizeof(Items) / sizeof(Item)]; + for (unsigned i = 0; i < sizeof(Items) / sizeof(Item); ++i) + this->Values[i] = Items[i]; - ConfigDataHash &hash = (noreload && Config ? Config->config_data : this->config_data); - ConfValue(hash, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, allow_newlines); - ValueItem vi(item); + this->MultiValues = new MultiItem[sizeof(MultiItems) / sizeof(MultiItem)]; + for (unsigned i = 0; i < sizeof(MultiItems) / sizeof(MultiItem); ++i) + this->MultiValues[i] = MultiItems[i]; +} - if (!Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi)) - throw ConfigException("One or more values in your configuration file failed to validate. Please see your logfiles for more information."); +ConfigItems::~ConfigItems() +{ + for (unsigned i = 0; !this->Values[i].tag.empty(); ++i) + delete this->Values[i].val; + delete [] this->Values; + delete [] this->MultiValues; +} - switch (dt) +void ServerConfig::Read() +{ + // These tags MUST occur and must ONLY occur once in the config file + static const Anope::string Once[] = {"serverinfo", "networkinfo", "options", "nickserv", ""}; + + this->LoadConf(services_conf); + + 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) { - case DT_NOSPACES: - { - ValueContainerString *vcs = debug_cast<ValueContainerString *>(Values[Index].val); - ValidateNoSpaces(vi.GetValue(), Values[Index].tag, Values[Index].value); - vcs->Set(vi.GetValue()); - } - break; - case DT_HOSTNAME: - { - ValueContainerString *vcs = debug_cast<ValueContainerString *>(Values[Index].val); - ValidateHostname(vi.GetValue(), Values[Index].tag, Values[Index].value); - vcs->Set(vi.GetValue()); - } - break; - case DT_IPADDRESS: - { - ValueContainerString *vcs = debug_cast<ValueContainerString *>(Values[Index].val); - ValidateIP(vi.GetValue(), Values[Index].tag, Values[Index].value, allow_wild); - vcs->Set(vi.GetValue()); - } - break; - case DT_CHARPTR: - { - ValueContainerChar *vcc = debug_cast<ValueContainerChar *>(Values[Index].val); - // Make sure we also copy the null terminator - vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); - } - break; - case DT_CSSTRING: + int dt = configitems.MultiValues[Index].datatype[valuenum]; + bool allow_newlines = dt & DT_ALLOW_NEWLINE, allow_wild = dt & DT_ALLOW_WILD, noreload = dt & DT_NORELOAD; + dt &= ~DT_ALLOW_NEWLINE; + dt &= ~DT_ALLOW_WILD; + dt &= ~DT_NORELOAD; + + ConfigDataHash &hash = (noreload && Config ? Config->config_data : this->config_data); + switch (dt) + { + case DT_NOSPACES: { - ValueContainerCSString *vcs = debug_cast<ValueContainerCSString *>(Values[Index].val); - vcs->Set(vi.GetCSValue()); + Anope::string item; + if (ConfValue(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) + 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; } - break; - case DT_CISTRING: + case DT_HOSTNAME: { - ValueContainerCIString *vcs = debug_cast<ValueContainerCIString *>(Values[Index].val); - vcs->Set(vi.GetCIValue()); - } - break; - case DT_STRING: - { - ValueContainerString *vcs = debug_cast<ValueContainerString *>(Values[Index].val); - vcs->Set(vi.GetValue()); + Anope::string item; + if (ConfValue(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) + 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; } - break; - case DT_INTEGER: + case DT_IPADDRESS: { - int val = vi.GetInteger(); - ValueContainerInt *vci = debug_cast<ValueContainerInt *>(Values[Index].val); - vci->Set(&val, sizeof(int)); + Anope::string item; + if (ConfValue(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) + 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; } - break; - case DT_UINTEGER: + case DT_CHARPTR: { - unsigned val = vi.GetInteger(); - ValueContainerUInt *vci = debug_cast<ValueContainerUInt *>(Values[Index].val); - vci->Set(&val, sizeof(unsigned)); + Anope::string item; + if (ConfValue(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) + vl.push_back(ValueItem(item.c_str())); + else + vl.push_back(ValueItem("")); + break; } - break; - case DT_LUINTEGER: + case DT_STRING: { - unsigned long val = vi.GetInteger(); - ValueContainerLUInt *vci = debug_cast<ValueContainerLUInt *>(Values[Index].val); - vci->Set(&val, sizeof(unsigned long)); + Anope::string item; + if (ConfValue(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem("")); + break; } - break; - case DT_TIME: + case DT_INTEGER: + case DT_UINTEGER: + case DT_LUINTEGER: { - time_t time = dotime(vi.GetValue()); - ValueContainerTime *vci = debug_cast<ValueContainerTime *>(Values[Index].val); - vci->Set(&time, sizeof(time_t)); + int item = 0; + if (ConfValueInteger(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem(0)); + break; } - break; - case DT_BOOLEAN: + case DT_TIME: { - bool val = vi.GetBool(); - ValueContainerBool *vcb = debug_cast<ValueContainerBool *>(Values[Index].val); - vcb->Set(&val, sizeof(bool)); - } - break; - default: - break; - } - // We're done with this now - delete Values[Index].val; - Values[Index].val = NULL; - } - CheckedAllValues = true; - /* 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; !MultiValues[Index].tag.empty(); ++Index) - { - MultiValues[Index].init_function(this, MultiValues[Index].tag); - int number_of_tags = ConfValueEnum(config_data, MultiValues[Index].tag); - for (int tagnum = 0; tagnum < number_of_tags; ++tagnum) - { - ValueList vl; - vl.clear(); - for (int valuenum = 0; !MultiValues[Index].items[valuenum].empty(); ++valuenum) - { - int dt = MultiValues[Index].datatype[valuenum]; - bool allow_newlines = dt & DT_ALLOW_NEWLINE, allow_wild = dt & DT_ALLOW_WILD, noreload = dt & DT_NORELOAD; - dt &= ~DT_ALLOW_NEWLINE; - dt &= ~DT_ALLOW_WILD; - dt &= ~DT_NORELOAD; - - ConfigDataHash &hash = (noreload && Config ? Config->config_data : this->config_data); - switch (dt) - { - case DT_NOSPACES: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - ValidateNoSpaces(vl[vl.size() - 1].GetValue(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); - } - break; - case DT_HOSTNAME: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - ValidateHostname(vl[vl.size() - 1].GetValue(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); - } - break; - case DT_IPADDRESS: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - ValidateIP(vl[vl.size() - 1].GetValue(), MultiValues[Index].tag, MultiValues[Index].items[valuenum], allow_wild); - } - break; - case DT_CHARPTR: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - vl.push_back(ValueItem(item.c_str())); - else - vl.push_back(ValueItem("")); - } - break; - case DT_CSSTRING: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - } - break; - case DT_CISTRING: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - } - break; - case DT_STRING: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - } - break; - case DT_INTEGER: - case DT_UINTEGER: - case DT_LUINTEGER: - { - int item = 0; - if (ConfValueInteger(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem(0)); - } - break; - case DT_TIME: - { - Anope::string item; - if (ConfValue(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) - { + Anope::string item; + if (ConfValue(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum, item, allow_newlines)) + { #ifdef _WIN32 - long time = static_cast<long>(dotime(item)); + long time = static_cast<long>(dotime(item)); #else - time_t time = dotime(item); + time_t time = dotime(item); #endif - vl.push_back(ValueItem(time)); - } - else - vl.push_back(ValueItem(0)); - } - break; - case DT_BOOLEAN: - { - bool item = ConfValueBool(hash, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum); - vl.push_back(ValueItem(item)); - } + vl.push_back(ValueItem(time)); + } + else + vl.push_back(ValueItem(0)); + break; + } + case DT_BOOLEAN: + { + bool item = ConfValueBool(hash, configitems.MultiValues[Index].tag, configitems.MultiValues[Index].items[valuenum], configitems.MultiValues[Index].items_default[valuenum], tagnum); + vl.push_back(ValueItem(item)); } } - MultiValues[Index].validation_function(this, MultiValues[Index].tag, MultiValues[Index].items, vl, MultiValues[Index].datatype); } - MultiValues[Index].finish_function(this, MultiValues[Index].tag); + 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); } - catch (const ConfigException &ce) + + // 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) { - if (!CheckedAllValues) + 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; + dt &= ~DT_ALLOW_NEWLINE; + dt &= ~DT_ALLOW_WILD; + dt &= ~DT_NORELOAD; + + ConfigDataHash &hash = (noreload && Config ? Config->config_data : this->config_data); + ConfValue(hash, configitems.Values[Index].tag, configitems.Values[Index].value, configitems.Values[Index].default_value, 0, item, allow_newlines); + 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) { - for (int Index = 0; !Values[Index].tag.empty(); ++Index) + case DT_NOSPACES: + { + ValueContainerString *vcs = debug_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: { - if (Values[Index].val) - delete Values[Index].val; + ValueContainerString *vcs = debug_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 = debug_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_CHARPTR: + { + ValueContainerChar *vcc = debug_cast<ValueContainerChar *>(configitems.Values[Index].val); + // Make sure we also copy the null terminator + vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); + break; + } + case DT_STRING: + { + ValueContainerString *vcs = debug_cast<ValueContainerString *>(configitems.Values[Index].val); + vcs->Set(vi.GetValue()); + break; + } + case DT_INTEGER: + { + int val = vi.GetInteger(); + ValueContainerInt *vci = debug_cast<ValueContainerInt *>(configitems.Values[Index].val); + vci->Set(&val, sizeof(int)); + break; + } + case DT_UINTEGER: + { + unsigned val = vi.GetInteger(); + ValueContainerUInt *vci = debug_cast<ValueContainerUInt *>(configitems.Values[Index].val); + vci->Set(&val, sizeof(unsigned)); + break; + } + case DT_LUINTEGER: + { + unsigned long val = vi.GetInteger(); + ValueContainerLUInt *vci = debug_cast<ValueContainerLUInt *>(configitems.Values[Index].val); + vci->Set(&val, sizeof(unsigned long)); + break; + } + case DT_TIME: + { + time_t time = dotime(vi.GetValue()); + ValueContainerTime *vci = debug_cast<ValueContainerTime *>(configitems.Values[Index].val); + vci->Set(&time, sizeof(time_t)); + break; + } + case DT_BOOLEAN: + { + bool val = vi.GetBool(); + ValueContainerBool *vcb = debug_cast<ValueContainerBool *>(configitems.Values[Index].val); + vcb->Set(&val, sizeof(bool)); + break; + } + default: + break; } - throw ConfigException(ce); } - Log(LOG_DEBUG) << "End config"; + + Log(LOG_DEBUG) << "End config " << services_conf.GetName(); for (int Index = 0; !Once[Index].empty(); ++Index) CheckOnce(Once[Index]); - Log() << "Done reading configuration file."; + Log() << "Done reading configuration file " << services_conf.GetName(); } -bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filename) +void ServerConfig::LoadConf(ConfigurationFile &file) { - Anope::string line; Anope::string section, wordbuffer, itemname; - std::ifstream conf(filename.c_str()); int linenumber = 0; bool in_word = false, in_quote = false, in_ml_comment = false; KeyValList sectiondata; - if (conf.fail()) + if (!file.Open()) { - errstr << "File " << filename << " could not be opened." << std::endl; - return false; + throw ConfigException("File " + file.GetName() + " could not be opened."); } - Log(LOG_DEBUG) << "Start to read conf " << filename; + Log(LOG_DEBUG) << "Start to read conf " << file.GetName(); // Start reading characters... - while (getline(conf, line.str())) - { + while (!file.End()) + { + Anope::string line = file.Read(); ++linenumber; unsigned c = 0, len = line.length(); for (; c < len; ++c) @@ -1532,13 +1593,13 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam // Quotes are valid only in the value position if (section.empty() || itemname.empty()) { - errstr << "Unexpected quoted string: " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Unexpected quoted string: " + file.GetName() + ":" + stringify(linenumber)); } if (in_word || !wordbuffer.empty()) { - errstr << "Unexpected quoted string (prior unhandled words): " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Unexpected quoted string (prior unhandled words): " + file.GetName() + ":" + stringify(linenumber)); } in_quote = in_word = true; continue; @@ -1547,13 +1608,13 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam { if (section.empty()) { - errstr << "Config item outside of section (or stray '='): " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Config item outside of section (or stray '='): " + file.GetName() + ":" + stringify(linenumber)); } if (!itemname.empty()) { - errstr << "Stray '=' sign or item without value: " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Stray '=' sign or item without value: " + file.GetName() + ":" + stringify(linenumber)); } if (in_word) in_word = false; @@ -1564,13 +1625,13 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam { if (!section.empty()) { - errstr << "Section inside another section: " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Section inside another section: " + file.GetName() + ":" + stringify(linenumber)); } if (wordbuffer.empty()) { - errstr << "Section without a name or unexpected '{': " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Section without a name or unexpected '{': " + file.GetName() + ":" + stringify(linenumber)); } if (in_word) in_word = false; @@ -1581,8 +1642,8 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam { if (section.empty()) { - errstr << "Stray '}': " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Stray '}': " + file.GetName() + ":" + stringify(linenumber)); } if (!wordbuffer.empty() || !itemname.empty()) { @@ -1590,8 +1651,8 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam // but will not allow for anything else, such as: section { key = value; key = value } if (!sectiondata.empty()) { - errstr << "Unexpected end of section: " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Unexpected end of section: " + file.GetName() + ":" + stringify(linenumber)); } // this is the same as the below section for testing if itemname is non-empty after the loop, but done inside it to allow the above construct Log(LOG_DEBUG) << "ln "<< linenumber << " EOL: s='" << section << "' '" << itemname << "' set to '" << wordbuffer << "'"; @@ -1599,7 +1660,7 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam wordbuffer.clear(); itemname.clear(); } - target.insert(std::pair<Anope::string, KeyValList>(section, sectiondata)); + this->config_data.insert(std::pair<Anope::string, KeyValList>(section, sectiondata)); section.clear(); sectiondata.clear(); } @@ -1615,8 +1676,8 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam { if (!in_word && !wordbuffer.empty()) { - errstr << "Unexpected word: " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Unexpected word: " + file.GetName() + ":" + stringify(linenumber)); } wordbuffer += ch; in_word = true; @@ -1633,8 +1694,8 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam { if (wordbuffer.empty()) { - errstr << "Item without value: " << filename << ":" << linenumber << std::endl; - return false; + file.Close(); + throw ConfigException("Item without value: " + file.GetName() + ":" + stringify(linenumber)); } Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << section << "' '" << itemname << "' set to '" << wordbuffer << "'"; sectiondata.push_back(KeyVal(itemname, wordbuffer)); @@ -1644,25 +1705,26 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const Anope::string &filenam } if (in_ml_comment) { - errstr << "Unterminated multiline comment at end of file: " << filename << std::endl; - return false; + file.Close(); + throw ConfigException("Unterminated multiline comment at end of file: " + file.GetName()); } if (in_quote) { - errstr << "Unterminated quote at end of file: " << filename << std::endl; - return false; + file.Close(); + throw ConfigException("Unterminated quote at end of file: " + file.GetName()); } if (!itemname.empty() || !wordbuffer.empty()) { - errstr << "Unexpected garbage at end of file: " << filename << std::endl; - return false; + file.Close(); + throw ConfigException("Unexpected garbage at end of file: " + file.GetName()); } if (!section.empty()) { - errstr << "Unterminated section at end of file: " << filename << std::endl; - return false; + file.Close(); + throw ConfigException("Unterminated section at end of file: " + file.GetName()); } - return true; + + file.Close(); } bool ServerConfig::ConfValue(ConfigDataHash &target, const Anope::string &tag, const Anope::string &var, int index, Anope::string &result, bool allow_linefeeds) diff --git a/src/init.cpp b/src/init.cpp index 7b520808b..71ef4b638 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -295,7 +295,7 @@ void Init(int ac, char **av) { if (Arg.empty()) throw FatalException("The --config option requires a file name"); - services_conf = Arg; + services_conf = ConfigurationFile(Arg, false); } if (GetCommandLineArgument("dir", 0, Arg)) @@ -315,9 +315,9 @@ void Init(int ac, char **av) Log(LOG_TERMINAL) << "Anope " << Anope::Version() << ", " << Anope::Build(); #ifdef _WIN32 - Log(LOG_TERMINAL) << "Using configuration file " << services_dir << "\\" << services_conf; + Log(LOG_TERMINAL) << "Using configuration file " << services_dir << "\\" << services_conf.GetName(); #else - Log(LOG_TERMINAL) << "Using configuration file " << services_dir << "/" << services_conf; + Log(LOG_TERMINAL) << "Using configuration file " << services_dir << "/" << services_conf.GetName(); #endif /* Read configuration file; exit if there are problems. */ diff --git a/src/misc.cpp b/src/misc.cpp index 431f6bc03..3fce523aa 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -201,11 +201,10 @@ time_t dotime(const Anope::string &s) /** * Expresses in a string the period of time represented by a given amount * of seconds (with days/hours/minutes). - * @param na Nick Alias * @param seconds time in seconds * @return buffer */ -Anope::string duration(NickCore *nc, time_t seconds) +Anope::string duration(time_t seconds) { /* We first calculate everything */ time_t days = seconds / 86400; @@ -248,9 +247,9 @@ Anope::string do_strftime(const time_t &t) char buf[BUFSIZE]; strftime(buf, sizeof(buf), "%b %d %H:%M:%S %Y %Z", &tm); if (t < Anope::CurTime) - return Anope::string(buf) + " (" + duration(NULL, Anope::CurTime - t) + " ago)"; + return Anope::string(buf) + " (" + duration(Anope::CurTime - t) + " ago)"; else - return Anope::string(buf) + " (" + duration(NULL, t - Anope::CurTime) + " from now)"; + return Anope::string(buf) + " (" + duration(t - Anope::CurTime) + " from now)"; } /*************************************************************************/ |