summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadie Powell <sadie@witchery.services>2025-03-09 13:57:20 +0000
committerSadie Powell <sadie@witchery.services>2025-03-09 14:20:34 +0000
commitbadcf31499d8dd4023d10d623c7a7dadef254f95 (patch)
tree60b5520cb773f40b099f99f30c8cb02aba3a2971
parentc98602bf19c3b3fa4966dd4fe4f990e5977e163a (diff)
Make config variables a lot more useful.
- Config variables now no longer conflict with regular values. - Config variables can now be read from the environment. (e.g. ${env.USER}). - Config variables can now be used as partial values (e.g. support@${network.domain})
-rw-r--r--data/anope.example.conf11
-rw-r--r--data/botserv.example.conf2
-rw-r--r--data/chanserv.example.conf2
-rw-r--r--data/global.example.conf2
-rw-r--r--data/hostserv.example.conf2
-rw-r--r--data/irc2sql.example.conf2
-rw-r--r--data/memoserv.example.conf2
-rw-r--r--data/nickserv.example.conf4
-rw-r--r--data/operserv.example.conf2
-rw-r--r--data/stats.standalone.example.conf15
-rw-r--r--include/config.h9
-rw-r--r--src/config.cpp65
12 files changed, 83 insertions, 35 deletions
diff --git a/data/anope.example.conf b/data/anope.example.conf
index ad85cd364..8c6a96c50 100644
--- a/data/anope.example.conf
+++ b/data/anope.example.conf
@@ -79,13 +79,16 @@
/*
* [OPTIONAL] Defines
*
- * You can define values to other values, which can be used to easily change
- * many values in the configuration at once.
+ * You can use defines for repeated information, which can be used to easily change many
+ * values in the configuration at once.
+ *
+ * To use a define called foo.bar you use ${foo.bar} in your config file. You can also use
+ * environment variables by prefixing their name with "env." like ${env.USER}.
*/
/*
* The services.host define is used in multiple different locations throughout the
- * configuration for services clients hostnames.
+ * configuration for the server name and pseudoclient hostnames.
*/
define
{
@@ -211,7 +214,7 @@ serverinfo
* other server names on the rest of your IRC network. Note that it does not have
* to be an existing hostname, just one that isn't on your network already.
*/
- name = "services.example.com"
+ name = "${services.host}"
/*
* The text which should appear as the server's information in /WHOIS and similar
diff --git a/data/botserv.example.conf b/data/botserv.example.conf
index 8e7346bd1..034b6de40 100644
--- a/data/botserv.example.conf
+++ b/data/botserv.example.conf
@@ -31,7 +31,7 @@ service
/*
* The hostname of the BotServ client.
*/
- host = "services.host"
+ host = "${services.host}"
/*
* The realname of the BotServ client.
diff --git a/data/chanserv.example.conf b/data/chanserv.example.conf
index 1d742ee7b..a666e43ac 100644
--- a/data/chanserv.example.conf
+++ b/data/chanserv.example.conf
@@ -21,7 +21,7 @@ service
/*
* The hostname of the ChanServ client.
*/
- host = "services.host"
+ host = "${services.host}"
/*
* The realname of the ChanServ client.
diff --git a/data/global.example.conf b/data/global.example.conf
index 15b6347e6..6f207a692 100644
--- a/data/global.example.conf
+++ b/data/global.example.conf
@@ -21,7 +21,7 @@ service
/*
* The hostname of the Global client.
*/
- host = "services.host"
+ host = "${services.host}"
/*
* The realname of the Global client.
diff --git a/data/hostserv.example.conf b/data/hostserv.example.conf
index 4a8354a02..4c15e04a1 100644
--- a/data/hostserv.example.conf
+++ b/data/hostserv.example.conf
@@ -21,7 +21,7 @@ service
/*
* The hostname of the HostServ client.
*/
- host = "services.host"
+ host = "${services.host}"
/*
* The realname of the HostServ client.
diff --git a/data/irc2sql.example.conf b/data/irc2sql.example.conf
index f23044dab..5e090d4f2 100644
--- a/data/irc2sql.example.conf
+++ b/data/irc2sql.example.conf
@@ -18,7 +18,7 @@ service
/*
* The hostname of the StatServ client.
*/
- host = "stats.host"
+ host = "${services.host}"
/*
* The realname of the StatServ client.
diff --git a/data/memoserv.example.conf b/data/memoserv.example.conf
index e05e1c14a..7906bc14a 100644
--- a/data/memoserv.example.conf
+++ b/data/memoserv.example.conf
@@ -21,7 +21,7 @@ service
/*
* The hostname of the MemoServ client.
*/
- host = "services.host"
+ host = "${services.host}"
/*
* The realname of the MemoServ client.
diff --git a/data/nickserv.example.conf b/data/nickserv.example.conf
index d4e5c28fe..6ee4d8b15 100644
--- a/data/nickserv.example.conf
+++ b/data/nickserv.example.conf
@@ -21,7 +21,7 @@ service
/*
* The hostname of the NickServ client.
*/
- host = "services.host"
+ host = "${services.host}"
/*
* The realname of the NickServ client.
@@ -210,7 +210,7 @@ module
* hold a nickname.
*/
enforceruser = "enforcer"
- enforcerhost = "services.host"
+ enforcerhost = "${services.host}"
/*
* The length of time Anope should hold nicknames for.
diff --git a/data/operserv.example.conf b/data/operserv.example.conf
index fd7ae6c95..eb85797f2 100644
--- a/data/operserv.example.conf
+++ b/data/operserv.example.conf
@@ -21,7 +21,7 @@ service
/*
* The hostname of the OperServ client.
*/
- host = "services.host"
+ host = "${services.host}"
/*
* The realname of the OperServ client.
diff --git a/data/stats.standalone.example.conf b/data/stats.standalone.example.conf
index 27af0e182..a85099529 100644
--- a/data/stats.standalone.example.conf
+++ b/data/stats.standalone.example.conf
@@ -79,17 +79,20 @@
/*
* [OPTIONAL] Defines
*
- * You can define values to other values, which can be used to easily change
- * many values in the configuration at once.
+ * You can use defines for repeated information, which can be used to easily change many
+ * values in the configuration at once.
+ *
+ * To use a define called foo.bar you use ${foo.bar} in your config file. You can also use
+ * environment variables by prefixing their name with "env." like ${env.USER}.
*/
/*
- * The stats.host define is used in multiple different locations throughout the
- * configuration for the stats client hostname.
+ * The services.host define is used in multiple different locations throughout the
+ * configuration for the server name and pseudoclient hostnames.
*/
define
{
- name = "stats.host"
+ name = "services.host"
value = "stats.example.com"
}
@@ -208,7 +211,7 @@ serverinfo
* other server names on the rest of your IRC network. Note that it does not have
* to be an existing hostname, just one that isn't on your network already.
*/
- name = "stats.example.com"
+ name = "${services.host}"
/*
* The text which should appear as the server's information in /WHOIS and similar
diff --git a/include/config.h b/include/config.h
index 7d12d602d..d5fb9b91d 100644
--- a/include/config.h
+++ b/include/config.h
@@ -83,9 +83,14 @@ namespace Configuration
struct Uplink;
- struct CoreExport Conf final
- : Block
+ class CoreExport Conf final
+ : public Block
{
+ private:
+ /** Replaces defined variables within a string. */
+ Anope::string ReplaceVars(const Anope::string &str, const File &file, int linenumber);
+
+ public:
/* options:readtimeout */
time_t ReadTimeout;
/* If we should default to privmsging clients */
diff --git a/src/config.cpp b/src/config.cpp
index e9096599c..94dd8d222 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -939,24 +939,12 @@ void Conf::LoadConf(File &file)
}
Block *b = block_stack.top();
-
if (b)
- Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'";
-
- /* Check defines */
- for (int i = 0; i < this->CountBlock("define"); ++i)
{
- const Block &define = this->GetBlock("define", i);
-
- const Anope::string &dname = define.Get<const Anope::string>("name");
-
- if (dname == wordbuffer && &define != b)
- wordbuffer = define.Get<const Anope::string>("value");
+ Log(LOG_DEBUG) << "ln " << linenumber << " EOL: s='" << b->name << "' '" << itemname << "' set to '" << wordbuffer << "'";
+ b->items[itemname] = ReplaceVars(wordbuffer, file, linenumber);
}
- if (b)
- b->items[itemname] = wordbuffer;
-
wordbuffer.clear();
itemname.clear();
}
@@ -991,3 +979,52 @@ void Conf::LoadConf(File &file)
throw ConfigException("Unterminated commented block at end of file: " + file.GetName());
}
}
+
+Anope::string Conf::ReplaceVars(const Anope::string &str, const File &file, int linenumber)
+{
+ Anope::string ret;
+ for (auto it = str.begin(); it != str.end(); )
+ {
+ if (*it != '$')
+ {
+ ret.push_back(*it++);
+ continue;
+ }
+
+ if (++it == str.end() || *it != '{')
+ continue;
+
+ it++;
+ Anope::string var;
+ while (it != str.end() && *it != '}')
+ var.push_back(*it++);
+
+ if (it == str.end())
+ throw ConfigException("Unterminated variable: " + file.GetName() + ":" + Anope::ToString(linenumber));
+
+ it++;
+ if (var.compare(0, 4, "env.", 4) == 0)
+ {
+ // This is an environment variable rather than a defined variable
+ const char* envstr = getenv(var.c_str() + 4);
+ if (envstr && envstr)
+ ret.append(envstr);
+ continue;
+ }
+
+ for (int i = 0; i < this->CountBlock("define"); ++i)
+ {
+ const auto &define = this->GetBlock("define", i);
+ const auto defname = define.Get<const Anope::string>("name");
+ if (defname == var)
+ {
+ ret.append(define.Get<const Anope::string>("value"));
+ break;
+ }
+ }
+ }
+
+ if (!str.equals_cs(ret))
+ Log(LOG_DEBUG) << "Expanded \"" << str << "\" to \"" << ret << "\"";
+ return ret;
+}