diff options
author | Adam <Adam@anope.org> | 2014-12-29 17:26:20 -0500 |
---|---|---|
committer | Adam <Adam@anope.org> | 2014-12-29 17:26:20 -0500 |
commit | 8ab1c71d7dc7a0d47e5711dc72e3fc9c3ee850bb (patch) | |
tree | d65f46a60e49d51ee1f0192de22c35e3cdd322c9 | |
parent | ed920366d69801bab7fc276fa24296b7f1264ff2 (diff) |
Allow configuring casemaps
-rw-r--r-- | data/CMakeLists.txt | 6 | ||||
-rw-r--r-- | data/ascii.conf | 157 | ||||
-rw-r--r-- | data/example.conf | 34 | ||||
-rw-r--r-- | data/rfc1459.conf | 24 | ||||
-rw-r--r-- | include/config.h | 4 | ||||
-rw-r--r-- | include/hashcomp.h | 48 | ||||
-rw-r--r-- | modules/database/db_flatfile.cpp | 1 | ||||
-rw-r--r-- | src/config.cpp | 70 | ||||
-rw-r--r-- | src/hashcomp.cpp | 38 | ||||
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/main.cpp | 3 |
11 files changed, 272 insertions, 115 deletions
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 8bb635dcf..2515bc082 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -1,6 +1,4 @@ -# Only install example.chk and example.conf from this directory -# NOTE: I would've had this just find all files in the directory, but that would include files not needed (like this file) -set(DATA example.chk botserv.example.conf example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf irc2sql.example.conf stats.standalone.example.conf) -install(FILES ${DATA} +file(GLOB DATA_EXAMPLECONFS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.conf") +install(FILES example.chk ${DATA_EXAMPLECONFS} DESTINATION ${CONF_DIR} ) diff --git a/data/ascii.conf b/data/ascii.conf new file mode 100644 index 000000000..1bfcb33f0 --- /dev/null +++ b/data/ascii.conf @@ -0,0 +1,157 @@ + +casemap +{ + lower = "a" + upper = "A" +} + +casemap +{ + lower = "b" + upper = "B" +} + +casemap +{ + lower = "c" + upper = "C" +} + +casemap +{ + lower = "d" + upper = "D" +} + +casemap +{ + lower = "e" + upper = "E" +} + +casemap +{ + lower = "f" + upper = "F" +} + +casemap +{ + lower = "g" + upper = "G" +} + +casemap +{ + lower = "h" + upper = "H" +} + +casemap +{ + lower = "i" + upper = "I" +} + +casemap +{ + lower = "j" + upper = "J" +} + +casemap +{ + lower = "k" + upper = "K" +} + +casemap +{ + lower = "l" + upper = "L" +} + +casemap +{ + lower = "m" + upper = "M" +} + +casemap +{ + lower = "n" + upper = "N" +} + +casemap +{ + lower = "o" + upper = "O" +} + +casemap +{ + lower = "p" + upper = "P" +} + +casemap +{ + lower = "q" + upper = "Q" +} + +casemap +{ + lower = "r" + upper = "R" +} + +casemap +{ + lower = "s" + upper = "S" +} + +casemap +{ + lower = "t" + upper = "T" +} + +casemap +{ + lower = "u" + upper = "U" +} + +casemap +{ + lower = "v" + upper = "V" +} + +casemap +{ + lower = "w" + upper = "W" +} + +casemap +{ + lower = "x" + upper = "X" +} + +casemap +{ + lower = "y" + upper = "Y" +} + +casemap +{ + lower = "z" + upper = "Z" +} + diff --git a/data/example.conf b/data/example.conf index f10c62fb2..f746a2595 100644 --- a/data/example.conf +++ b/data/example.conf @@ -362,20 +362,6 @@ options #group = "anope" /* - * The case mapping used by services. This must be set to a valid locale name - * installed on your machine. Services use this case map to compare, with - * case insensitivity, things such as nick names, channel names, etc. - * - * We provide two special casemaps shipped with Anope, ascii and rfc1459. - * - * This value should be set to what your IRCd uses, which is probably rfc1459, - * however Anope has always used ascii for comparison, so the default is ascii. - * - * Changing this value once set is not recommended. - */ - casemap = "ascii" - - /* * This key is used to initiate the random number generator. This number * MUST be random as you want your passcodes to be random. Don't give this * key to anyone! Keep it private! @@ -539,6 +525,26 @@ options } /* + * [REQUIRED] Casemapping configuration + * + * Includes the configuration for the casemap services should use. + * Services use this case map to compare, with case insensitivity, + * things such as nick names, channel names, etc. + * + * Two casemaps shipped with Anope are ascii and rfc1459. + * + * This value should be set to what your IRCd uses, which is probably rfc1459, + * however Anope has always used ascii for comparison, so the default is ascii. + * + * Changing this value once set is not recommended. + */ +include +{ + name = "ascii.conf" + #name = "rfc1459.conf" +} + +/* * [OPTIONAL] BotServ * * Includes botserv.example.conf, which is necessary for BotServ functionality. diff --git a/data/rfc1459.conf b/data/rfc1459.conf new file mode 100644 index 000000000..81ced1ac0 --- /dev/null +++ b/data/rfc1459.conf @@ -0,0 +1,24 @@ + +include +{ + name = "ascii.conf" +} + +casemap +{ + lower = "{" + upper = "[" +} + +casemap +{ + lower = "}" + upper = "]" +} + +casemap +{ + lower = "|" + upper = "\"" +} + diff --git a/include/config.h b/include/config.h index fe4a6fded..fdeddf6dc 100644 --- a/include/config.h +++ b/include/config.h @@ -60,9 +60,10 @@ namespace Configuration const item_map* GetItems() const; }; - template<> CoreExport const Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const; + template<> CoreExport Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const; template<> CoreExport time_t Block::Get(const Anope::string &tag, const Anope::string &def) const; template<> CoreExport bool Block::Get(const Anope::string &tag, const Anope::string &def) const; + template<> CoreExport unsigned int Block::Get(const Anope::string &tag, const Anope::string &def) const; /** Represents a configuration file */ @@ -122,6 +123,7 @@ namespace Configuration std::vector<Anope::string> ModulesAutoLoad; /* After how many characters do we wrap lines? */ unsigned int LineWrap; + unsigned char CaseMapUpper[256], CaseMapLower[256]; /* module configuration blocks */ std::map<Anope::string, Block *> modules; diff --git a/include/hashcomp.h b/include/hashcomp.h index 2364975b9..a9a1105ee 100644 --- a/include/hashcomp.h +++ b/include/hashcomp.h @@ -19,56 +19,8 @@ namespace Anope { class string; - /* Casemap in use by Anope. ci::string's comparation functions use this (and thus Anope::string) */ - extern std::locale casemap; - - extern void CaseMapRebuild(); extern unsigned char tolower(unsigned char); extern unsigned char toupper(unsigned char); - - /* ASCII case insensitive ctype. */ - template<typename char_type> - class ascii_ctype : public std::ctype<char_type> - { - public: - char_type do_toupper(char_type c) const override - { - if (c >= 'a' && c <= 'z') - return c - 32; - else - return c; - } - - char_type do_tolower(char_type c) const override - { - if (c >= 'A' && c <= 'Z') - return c + 32; - else - return c; - } - }; - - /* rfc1459 case insensitive ctype, { = [, } = ], and | = \ */ - template<typename char_type> - class rfc1459_ctype : public ascii_ctype<char_type> - { - public: - char_type do_toupper(char_type c) const override - { - if (c == '{' || c == '}' || c == '|') - return c - 32; - else - return ascii_ctype<char_type>::do_toupper(c); - } - - char_type do_tolower(char_type c) const override - { - if (c == '[' || c == ']' || c == '\\') - return c + 32; - else - return ascii_ctype<char_type>::do_tolower(c); - } - }; } /** The ci namespace contains a number of helper classes relevant to case insensitive strings. diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp index 0793269ea..2486a2307 100644 --- a/modules/database/db_flatfile.cpp +++ b/modules/database/db_flatfile.cpp @@ -101,7 +101,6 @@ class DBFlatFile : public Module Serialize::Object *obj = nullptr; for (Anope::string buf; std::getline(fd, buf.str());) { - Log() << buf; if (buf.find("OBJECT ") == 0) { Anope::string t = buf.substr(7); diff --git a/src/config.cpp b/src/config.cpp index 6ac777a98..323a48519 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -72,7 +72,7 @@ const Block::item_map* Block::GetItems() const return NULL; } -template<> const Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const +template<> Anope::string Block::Get(const Anope::string &tag, const Anope::string& def) const { if (!this) return def; @@ -95,6 +95,27 @@ template<> bool Block::Get(const Anope::string &tag, const Anope::string &def) c return !str.empty() && !str.equals_ci("no") && !str.equals_ci("off") && !str.equals_ci("false") && !str.equals_ci("0"); } +template<> unsigned int Block::Get(const Anope::string &tag, const Anope::string &def) const +{ + const Anope::string &str = Get<Anope::string>(tag, def); + std::size_t pos = str.length(); + unsigned long l; + + try + { + l = std::stoul(str.str(), &pos, 0); + } + catch (...) + { + return 0; + } + + if (pos != str.length()) + return 0; + + return l; +} + static void ValidateNotEmpty(const Anope::string &block, const Anope::string &name, const Anope::string &value) { if (value.empty()) @@ -127,6 +148,8 @@ Conf::Conf() : Block("") const Anope::string &type = include->Get<Anope::string>("type"), &file = include->Get<Anope::string>("name"); + ValidateNotEmpty("include", "name", file); + File f(file, type == "executable"); this->LoadConf(f); } @@ -489,6 +512,34 @@ Conf::Conf() : Block("") this->CommandGroups.push_back(gr); } + for (int i = 0; i < this->CountBlock("casemap"); ++i) + { + Block *casemap = this->GetBlock("casemap", i); + + unsigned char upper = casemap->Get<unsigned int>("upper"), + lower = casemap->Get<unsigned int>("lower"); + + if (!upper) + { + Anope::string s = casemap->Get<Anope::string>("upper"); + if (s.length() == 1) + upper = s[0]; + } + + if (!lower) + { + Anope::string s = casemap->Get<Anope::string>("lower"); + if (s.length() == 1) + lower = s[0]; + } + + if (upper && lower) + { + CaseMapUpper[lower] = CaseMapUpper[upper] = upper; + CaseMapLower[lower] = CaseMapLower[upper] = lower; + } + } + /* Below here can't throw */ /* Clear existing conf opers */ @@ -508,23 +559,6 @@ Conf::Conf() : Block("") Log() << "Tied oper " << na->GetAccount()->GetDisplay() << " to type " << o->GetType()->GetName(); } - if (options->Get<Anope::string>("casemap", "ascii") == "ascii") - Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype<char>()); - else if (options->Get<Anope::string>("casemap") == "rfc1459") - Anope::casemap = std::locale(std::locale(), new Anope::rfc1459_ctype<char>()); - else - { - try - { - Anope::casemap = std::locale(options->Get<Anope::string>("casemap").c_str()); - } - catch (const std::runtime_error &) - { - Log() << "Unknown casemap " << options->Get<Anope::string>("casemap") << " - casemap not changed"; - } - } - Anope::CaseMapRebuild(); - /* Check the user keys */ if (!options->Get<unsigned>("seed")) Log() << "Configuration option options:seed should be set. It's for YOUR safety! Remember that!"; diff --git a/src/hashcomp.cpp b/src/hashcomp.cpp index 62bcc404f..e17ae6176 100644 --- a/src/hashcomp.cpp +++ b/src/hashcomp.cpp @@ -10,32 +10,22 @@ #include "services.h" #include "hashcomp.h" #include "anope.h" - -/* Case map in use by Anope */ -std::locale Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype<char>()); -/* Cache of the above case map, forced upper */ -static unsigned char case_map_upper[256], case_map_lower[256]; - -/* called whenever Anope::casemap is modified to rebuild the casemap cache */ -void Anope::CaseMapRebuild() -{ - const std::ctype<char> &ct = std::use_facet<std::ctype<char> >(Anope::casemap); - - for (unsigned i = 0; i < sizeof(case_map_upper); ++i) - { - case_map_upper[i] = ct.toupper(i); - case_map_lower[i] = ct.tolower(i); - } -} +#include "config.h" unsigned char Anope::tolower(unsigned char c) { - return case_map_lower[c]; + if (!Config || !Config->CaseMapLower[c]) + return std::tolower(c); + + return Config->CaseMapLower[c]; } unsigned char Anope::toupper(unsigned char c) { - return case_map_upper[c]; + if (!Config || !Config->CaseMapUpper[c]) + return std::toupper(c); + + return Config->CaseMapUpper[c]; } /* @@ -47,7 +37,7 @@ unsigned char Anope::toupper(unsigned char c) bool ci::ci_char_traits::eq(char c1st, char c2nd) { - return case_map_upper[static_cast<unsigned char>(c1st)] == case_map_upper[static_cast<unsigned char>(c2nd)]; + return Anope::toupper(c1st) == Anope::toupper(c2nd); } bool ci::ci_char_traits::ne(char c1st, char c2nd) @@ -57,15 +47,15 @@ bool ci::ci_char_traits::ne(char c1st, char c2nd) bool ci::ci_char_traits::lt(char c1st, char c2nd) { - return case_map_upper[static_cast<unsigned char>(c1st)] < case_map_upper[static_cast<unsigned char>(c2nd)]; + return Anope::toupper(c1st) < Anope::toupper(c2nd); } int ci::ci_char_traits::compare(const char *str1, const char *str2, size_t n) { for (unsigned i = 0; i < n; ++i) { - unsigned char c1 = case_map_upper[static_cast<unsigned char>(*str1)], - c2 = case_map_upper[static_cast<unsigned char>(*str2)]; + unsigned char c1 = Anope::toupper(*str1), + c2 = Anope::toupper(*str2); if (c1 > c2) return 1; @@ -82,7 +72,7 @@ int ci::ci_char_traits::compare(const char *str1, const char *str2, size_t n) const char *ci::ci_char_traits::find(const char *s1, int n, char c) { - while (n-- > 0 && case_map_upper[static_cast<unsigned char>(*s1)] != case_map_upper[static_cast<unsigned char>(c)]) + while (n-- > 0 && Anope::toupper(*s1) != Anope::toupper(c)) ++s1; return n >= 0 ? s1 : NULL; } diff --git a/src/init.cpp b/src/init.cpp index 853cf7209..0b381cbf6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -290,8 +290,6 @@ void Anope::Init(int ac, char **av) umask(DEFUMASK); #endif - //Serialize::RegisterTypes(); - /* Parse command line arguments */ ParseCommandLineArguments(ac, av); diff --git a/src/main.cpp b/src/main.cpp index 1f4434f18..65fb8d3f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -116,9 +116,6 @@ static Anope::string GetFullProgDir(const Anope::string &argv0) int main(int ac, char **av, char **envp) { - /* String comparisons won't work until we build the case map cache, so do it first */ - Anope::CaseMapRebuild(); - BinaryDir = GetFullProgDir(av[0]); if (BinaryDir[BinaryDir.length() - 1] == '.') BinaryDir = BinaryDir.substr(0, BinaryDir.length() - 2); |