summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/anope.example.conf60
-rw-r--r--data/chanserv.example.conf6
-rw-r--r--data/modules.example.conf38
-rw-r--r--data/nickserv.example.conf2
-rw-r--r--data/operserv.example.conf2
-rw-r--r--include/anope.h7
-rw-r--r--modules/chanserv/cs_akick.cpp6
-rw-r--r--modules/chanserv/cs_ban.cpp13
-rw-r--r--modules/chanserv/cs_kick.cpp13
-rw-r--r--modules/dnsbl.cpp18
-rw-r--r--modules/ldap_authentication.cpp5
-rw-r--r--modules/ldap_oper.cpp13
-rw-r--r--modules/memoserv/memoserv.cpp24
-rw-r--r--modules/nickserv/nickserv.cpp7
-rw-r--r--modules/nickserv/ns_register.cpp18
-rw-r--r--modules/nickserv/ns_resetpass.cpp23
-rw-r--r--modules/nickserv/ns_set.cpp24
-rw-r--r--modules/operserv/os_defcon.cpp4
-rw-r--r--modules/operserv/os_session.cpp4
-rw-r--r--modules/proxyscan.cpp10
-rw-r--r--src/misc.cpp38
21 files changed, 201 insertions, 134 deletions
diff --git a/data/anope.example.conf b/data/anope.example.conf
index 4474b3175..c21aa343f 100644
--- a/data/anope.example.conf
+++ b/data/anope.example.conf
@@ -975,76 +975,76 @@ mail
* The subject and message of emails sent to users when they register accounts.
*
* Available tokens for this template are:
- * %n - Gets replaced with the nickname
- * %N - Gets replaced with the network name
- * %c - Gets replaced with the confirmation code
+ * {nick} - Gets replaced with the nickname
+ * {network} - Gets replaced with the network name
+ * {code} - Gets replaced with the confirmation code
*/
- registration_subject = "Nickname registration for %n"
+ registration_subject = "Nickname registration for {nick}"
registration_message = "Hi,
- You have requested to register the nickname %n on %N.
- Please type \" /msg NickServ CONFIRM %c \" to complete registration.
+ You have requested to register the nickname {nick} on {network}.
+ Please type \" /msg NickServ CONFIRM {code} \" to complete registration.
If you don't know why this mail was sent to you, please ignore it silently.
- %N administrators."
+ {network} administrators."
/*
* The subject and message of emails sent to users when they request a new password.
*
* Available tokens for this template are:
- * %n - Gets replaced with the nickname
- * %N - Gets replaced with the network name
- * %c - Gets replaced with the confirmation code
+ * {nick} - Gets replaced with the nickname
+ * {network} - Gets replaced with the network name
+ * {code} - Gets replaced with the confirmation code
*/
- reset_subject = "Reset password request for %n"
+ reset_subject = "Reset password request for {nick}"
reset_message = "Hi,
- You have requested to have the password for %n reset.
- To reset your password, type \" /msg NickServ CONFIRM %n %c \"
+ You have requested to have the password for {nick} reset.
+ To reset your password, type \" /msg NickServ CONFIRM {nick} {code} \"
If you don't know why this mail was sent to you, please ignore it silently.
- %N administrators."
+ {network} administrators."
/*
* The subject and message of emails sent to users when they request a new email address.
*
* Available tokens for this template are:
- * %e - Gets replaced with the old email address
- * %E - Gets replaced with the new email address
- * %n - Gets replaced with the nickname
- * %N - Gets replaced with the network name
- * %c - Gets replaced with the confirmation code
+ * {old_email} - Gets replaced with the old email address
+ * {new_email} - Gets replaced with the new email address
+ * {account} - Gets replaced with the nickname
+ * {network} - Gets replaced with the network name
+ * {code} - Gets replaced with the confirmation code
*/
emailchange_subject = "Email confirmation"
emailchange_message = "Hi,
- You have requested to change your email address from %e to %E.
- Please type \" /msg NickServ CONFIRM %c \" to confirm this change.
+ You have requested to change your email address from {old_email} to {new_email}.
+ Please type \" /msg NickServ CONFIRM {code} \" to confirm this change.
If you don't know why this mail was sent to you, please ignore it silently.
- %N administrators."
+ {network} administrators."
/*
* The subject and message of emails sent to users when they receive a new memo.
*
* Available tokens for this template are:
- * %n - Gets replaced with the nickname
- * %s - Gets replaced with the sender's nickname
- * %d - Gets replaced with the memo number
- * %t - Gets replaced with the memo text
- * %N - Gets replaced with the network name
+ * {receiver} - Gets replaced with the receiver's nickname
+ * {sender} - Gets replaced with the sender's nickname
+ * {number} - Gets replaced with the memo number
+ * {text} - Gets replaced with the memo text
+ * {network} - Gets replaced with the network name
*/
memo_subject = "New memo"
- memo_message = "Hi %n,
+ memo_message = "Hi {receiver},
- You've just received a new memo from %s. This is memo number %d.
+ You've just received a new memo from {sender}. This is memo number {number}.
Memo text:
- %t"
+ {text}"
}
/*
diff --git a/data/chanserv.example.conf b/data/chanserv.example.conf
index b6b4c8938..218e42a1f 100644
--- a/data/chanserv.example.conf
+++ b/data/chanserv.example.conf
@@ -163,10 +163,10 @@ module
/*
* The message formatting to use for signed kick messages.
- * %n is the nick of the kicker
- * %m is the message specified
+ * {nick} is the nick of the kicker
+ * {message} is the message specified
*/
- signkickformat = "%m (%n)"
+ signkickformat = "{message} ({nick})"
/*
* If set, prevents channel access entries from containing hostmasks.
diff --git a/data/modules.example.conf b/data/modules.example.conf
index df03e8519..a242c0a6d 100644
--- a/data/modules.example.conf
+++ b/data/modules.example.conf
@@ -119,15 +119,15 @@ module { name = "help" }
time = 4h
/* Reason for akill.
- * %n is the nick of the user
- * %u is the ident/username of the user
- * %g is the realname of the user
- * %h is the hostname of the user
- * %i is the IP of the user
- * %r is the reply reason (configured below). Will be nothing if not configured.
- * %N is the network name set in networkinfo:networkname
+ * {nick} is the nick of the user
+ * {user} is the ident/username of the user
+ * {real} is the realname of the user
+ * {host} is the hostname of the user
+ * {ip} is the IP of the user
+ * {reply} is the reply reason (configured below). Will be nothing if not configured.
+ * {network} is the network name set in networkinfo:networkname
*/
- reason = "You are listed in the EFnet RBL, visit https://rbl.efnetrbl.org/?i=%i for info"
+ reason = "You are listed in the EFnet RBL, visit https://rbl.efnetrbl.org/?i={ip} for info"
/* Replies to ban and their reason. If no replies are configured, all replies get banned. */
reply
@@ -171,7 +171,7 @@ module { name = "help" }
{
name = "dnsbl.dronebl.org"
time = 4h
- reason = "You have a host listed in the DroneBL. For more information, visit https://dronebl.org/lookup_branded?ip=%i&network=%N"
+ reason = "You have a host listed in the DroneBL. For more information, visit https://dronebl.org/lookup?ip={ip}&network={network}"
}
/* Exempt localhost from DNSBL checks */
@@ -270,10 +270,10 @@ module { name = "help" }
/*
* The search filter used to look up users's accounts.
- * %account is replaced with the user's account.
- * %object_class is replaced with the object_class configured below.
+ * {account} is replaced with the user's account.
+ * {object_class} is replaced with the object_class configured below.
*/
- search_filter = "(&(uid=%account)(objectClass=%object_class))"
+ search_filter = "(&(uid={account})(objectClass={object_class}))"
/*
* The object class used by LDAP to store user account information.
@@ -327,7 +327,7 @@ module { name = "help" }
/*
* An optional binddn to use when searching for groups.
- * %a is replaced with the account name of the user.
+ * {account} is replaced with the account name of the user.
*/
#binddn = "cn=Manager,dc=anope,dc=org"
@@ -343,9 +343,9 @@ module { name = "help" }
/*
* The filter to use when searching for users.
- * %a is replaced with the account name of the user.
+ * {account} is replaced with the account name of the user.
*/
- filter = "(member=uid=%a,ou=users,dc=anope,dc=org)"
+ filter = "(member=uid={account},ou=users,dc=anope,dc=org)"
/*
* The attribute of the group that is the name of the opertype.
@@ -550,11 +550,11 @@ module
/*
* The reason to ban the user for.
- * %h is replaced with the type of proxy found.
- * %i is replaced with the IP of proxy found.
- * %p is replaced with the port.
+ * {type} is replaced with the type of proxy found.
+ * {ip} is replaced with the IP of proxy found.
+ * {port} is replaced with the port.
*/
- reason = "You have an open proxy running on your host (%t:%i:%p)"
+ reason = "You have an open proxy running on your host ({type}:{ip}:{port})"
}
}
diff --git a/data/nickserv.example.conf b/data/nickserv.example.conf
index 0b99e3daf..8d2896c8c 100644
--- a/data/nickserv.example.conf
+++ b/data/nickserv.example.conf
@@ -93,7 +93,7 @@ module
#confirmemailchanges = yes
/*
- * A message sent to users on connect if they use an unregistered nick. %n will be replaced with the user's nickname.
+ * A message sent to users on connect if they use an unregistered nick. {nick} will be replaced with the user's nickname.
*
* This directive is optional.
*/
diff --git a/data/operserv.example.conf b/data/operserv.example.conf
index eb85797f2..f5dc935a6 100644
--- a/data/operserv.example.conf
+++ b/data/operserv.example.conf
@@ -580,7 +580,7 @@ module
*
* This directive is optional, if not set, nothing will be sent.
*/
- sessionlimitexceeded = "The session limit for your IP %IP% has been exceeded."
+ sessionlimitexceeded = "The session limit for your IP {ip} has been exceeded."
/*
* Same as above, but should be used to provide a website address where users can find out more
diff --git a/include/anope.h b/include/anope.h
index 08dff4af3..9c109d9ee 100644
--- a/include/anope.h
+++ b/include/anope.h
@@ -608,6 +608,13 @@ namespace Anope
* @return True if the message was a well formed CTCP; otherwise, false.
*/
extern CoreExport bool ParseCTCP(const Anope::string &text, Anope::string &name, Anope::string &body);
+
+ /** Replaces template variables within a string with values from a map.
+ * @param str The string to template from.
+ * @param vars The variables to replace within the string.
+ * @return The specified string with all variables replaced within it.
+ */
+ extern CoreExport Anope::string Template(const Anope::string &str, const Anope::map<Anope::string> &vars);
}
/** sepstream allows for splitting token separated lists.
diff --git a/modules/chanserv/cs_akick.cpp b/modules/chanserv/cs_akick.cpp
index 5453aa5d2..e6672b965 100644
--- a/modules/chanserv/cs_akick.cpp
+++ b/modules/chanserv/cs_akick.cpp
@@ -567,8 +567,10 @@ public:
if (reason.empty())
{
reason = Language::Translate(u, Config->GetModule(this).Get<const Anope::string>("autokickreason").c_str());
- reason = reason.replace_all_cs("%n", u->nick)
- .replace_all_cs("%c", c->name);
+ reason = Anope::Template(reason, {
+ { "channel", c->name },
+ { "nick", u->nick },
+ });
}
if (reason.empty())
reason = Language::Translate(u, _("User has been banned from the channel"));
diff --git a/modules/chanserv/cs_ban.cpp b/modules/chanserv/cs_ban.cpp
index 74dc129f4..8560e4eac 100644
--- a/modules/chanserv/cs_ban.cpp
+++ b/modules/chanserv/cs_ban.cpp
@@ -111,8 +111,7 @@ public:
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
- Anope::string signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "%m (%n)");
- signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
+ auto signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "{message} ({nick})");
User *u = source.GetUser();
User *u2 = User::Find(target, true);
@@ -160,7 +159,10 @@ public:
{
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !source.AccessFor(ci).HasPriv("SIGNKICK")))
{
- signkickformat = signkickformat.replace_all_cs("%m", reason);
+ signkickformat = Anope::Template(signkickformat, {
+ { "message", reason },
+ { "nick", source.GetNick() },
+ });
c->Kick(ci->WhoSends(), u2, signkickformat);
}
else
@@ -215,7 +217,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
reason += " (Matches " + mask + ")";
- signkickformat = signkickformat.replace_all_cs("%m", reason);
+ signkickformat = Anope::Template(signkickformat, {
+ { "message", reason },
+ { "nick", source.GetNick() },
+ });
c->Kick(ci->WhoSends(), uc->user, signkickformat);
}
else
diff --git a/modules/chanserv/cs_kick.cpp b/modules/chanserv/cs_kick.cpp
index 210a5168c..5ba61eaef 100644
--- a/modules/chanserv/cs_kick.cpp
+++ b/modules/chanserv/cs_kick.cpp
@@ -48,8 +48,7 @@ public:
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
- Anope::string signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "%m (%n)");
- signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
+ auto signkickformat = Config->GetModule("chanserv").Get<Anope::string>("signkickformat", "{message} ({nick})");
AccessGroup u_access = source.AccessFor(ci);
@@ -71,7 +70,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
- signkickformat = signkickformat.replace_all_cs("%m", reason);
+ signkickformat = Anope::Template(signkickformat, {
+ { "message", reason },
+ { "nick", source.GetNick() },
+ });
c->Kick(ci->WhoSends(), u2, signkickformat);
}
else
@@ -105,7 +107,10 @@ public:
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
{
reason += " (Matches " + mask + ")";
- signkickformat = signkickformat.replace_all_cs("%m", reason);
+ signkickformat = Anope::Template(signkickformat, {
+ { "message", reason },
+ { "nick", source.GetNick() },
+ });
c->Kick(ci->WhoSends(), uc->user, signkickformat);
}
else
diff --git a/modules/dnsbl.cpp b/modules/dnsbl.cpp
index 6db41ba84..e2e49e410 100644
--- a/modules/dnsbl.cpp
+++ b/modules/dnsbl.cpp
@@ -70,14 +70,16 @@ public:
if (reply && reply->allow_account && user->IsIdentified())
return;
- Anope::string reason = this->blacklist.reason, addr = user->ip.addr();
- reason = reason.replace_all_cs("%n", user->nick);
- reason = reason.replace_all_cs("%u", user->GetIdent());
- reason = reason.replace_all_cs("%g", user->realname);
- reason = reason.replace_all_cs("%h", user->host);
- reason = reason.replace_all_cs("%i", addr);
- reason = reason.replace_all_cs("%r", reply ? reply->reason : "");
- reason = reason.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
+ auto addr = user->ip.addr();
+ auto reason = Anope::Template(this->blacklist.reason, {
+ { "nick", user->nick },
+ { "user", user->GetIdent() },
+ { "real", user->realname },
+ { "host", user->host },
+ { "ip", addr },
+ { "reply", reply ? reply->reason : "" },
+ { "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
+ });
BotInfo *OperServ = Config->GetClient("OperServ");
Log(creator, "dnsbl", OperServ) << user->GetMask() << " (" << addr << ") appears in " << this->blacklist.name;
diff --git a/modules/ldap_authentication.cpp b/modules/ldap_authentication.cpp
index f4e3ddd0a..5ca00bdf9 100644
--- a/modules/ldap_authentication.cpp
+++ b/modules/ldap_authentication.cpp
@@ -85,7 +85,10 @@ public:
{
if (ii->admin_bind)
{
- Anope::string sf = search_filter.replace_all_cs("%account", ii->req->GetAccount()).replace_all_cs("%object_class", object_class);
+ auto sf = Anope::Template(search_filter, {
+ { "account", ii->req->GetAccount() },
+ { "object_class", object_class },
+ });
try
{
Log(LOG_DEBUG) << "ldap_authentication: searching for " << sf;
diff --git a/modules/ldap_oper.cpp b/modules/ldap_oper.cpp
index fa57f7aa9..4d62052cd 100644
--- a/modules/ldap_oper.cpp
+++ b/modules/ldap_oper.cpp
@@ -117,8 +117,17 @@ public:
throw LDAPException("Could not search LDAP for opertype settings, invalid configuration.");
if (!this->binddn.empty())
- this->ldap->Bind(NULL, this->binddn.replace_all_cs("%a", u->Account()->display), this->password.c_str());
- this->ldap->Search(new IdentifyInterface(this, u), this->basedn, this->filter.replace_all_cs("%a", u->Account()->display));
+ {
+ auto bdn = Anope::Template(this->binddn, {
+ { "account", u->Account()->display },
+ });
+ this->ldap->Bind(NULL, bdn, this->password.c_str());
+ }
+
+ auto af = Anope::Template(this->filter, {
+ { "account", u->Account()->display },
+ });
+ this->ldap->Search(new IdentifyInterface(this, u), this->basedn, af);
}
catch (const LDAPException &ex)
{
diff --git a/modules/memoserv/memoserv.cpp b/modules/memoserv/memoserv.cpp
index a95a1fd87..b653e8ade 100644
--- a/modules/memoserv/memoserv.cpp
+++ b/modules/memoserv/memoserv.cpp
@@ -19,20 +19,16 @@ class MemoServCore final
static bool SendMemoMail(NickCore *nc, MemoInfo *mi, Memo *m)
{
- Anope::string subject = Language::Translate(nc, Config->GetBlock("mail").Get<const Anope::string>("memo_subject").c_str()),
- message = Language::Translate(nc, Config->GetBlock("mail").Get<const Anope::string>("memo_message").c_str());
-
- subject = subject.replace_all_cs("%n", nc->display);
- subject = subject.replace_all_cs("%s", m->sender);
- subject = subject.replace_all_cs("%d", Anope::ToString(mi->GetIndex(m) + 1));
- subject = subject.replace_all_cs("%t", m->text);
- subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
-
- message = message.replace_all_cs("%n", nc->display);
- message = message.replace_all_cs("%s", m->sender);
- message = message.replace_all_cs("%d", Anope::ToString(mi->GetIndex(m) + 1));
- message = message.replace_all_cs("%t", m->text);
- message = message.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
+ Anope::map<Anope::string> vars = {
+ { "receiver", nc->display },
+ { "sender", m->sender },
+ { "number", Anope::ToString(mi->GetIndex(m) + 1) },
+ { "text", m->text },
+ { "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
+ };
+
+ auto subject = Anope::Template(Language::Translate(nc, Config->GetBlock("mail").Get<const Anope::string>("memo_subject").c_str()), vars);
+ auto message = Anope::Template(Language::Translate(nc, Config->GetBlock("mail").Get<const Anope::string>("memo_message").c_str()), vars);
return Mail::Send(nc, subject, message);
}
diff --git a/modules/nickserv/nickserv.cpp b/modules/nickserv/nickserv.cpp
index 80ffaf3cc..3358dcbef 100644
--- a/modules/nickserv/nickserv.cpp
+++ b/modules/nickserv/nickserv.cpp
@@ -432,7 +432,12 @@ public:
const Anope::string &unregistered_notice = Config->GetModule(this).Get<const Anope::string>("unregistered_notice");
if (!Config->GetModule("nickserv").Get<bool>("nonicknameownership") && !unregistered_notice.empty() && !na && !u->IsIdentified())
- u->SendMessage(NickServ, unregistered_notice.replace_all_cs("%n", u->nick));
+ {
+ auto msg = Anope::Template(unregistered_notice, {
+ { "nick", u->nick },
+ });
+ u->SendMessage(NickServ, msg);
+ }
else if (na && !u->IsIdentified(true))
this->Validate(u);
}
diff --git a/modules/nickserv/ns_register.cpp b/modules/nickserv/ns_register.cpp
index 1f049e851..2bcb8eac1 100644
--- a/modules/nickserv/ns_register.cpp
+++ b/modules/nickserv/ns_register.cpp
@@ -428,16 +428,14 @@ static bool SendRegmail(User *u, const NickAlias *na, BotInfo *bi)
*code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
}
- Anope::string subject = Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("registration_subject").c_str()),
- message = Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("registration_message").c_str());
-
- subject = subject.replace_all_cs("%n", na->nick);
- subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
- subject = subject.replace_all_cs("%c", *code);
-
- message = message.replace_all_cs("%n", na->nick);
- message = message.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
- message = message.replace_all_cs("%c", *code);
+ Anope::map<Anope::string> vars = {
+ { "nick", na->nick },
+ { "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
+ { "code", *code },
+ };
+
+ auto subject = Anope::Template(Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("registration_subject").c_str()), vars);
+ auto message = Anope::Template(Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("registration_message").c_str()), vars);
return Mail::Send(u, nc, bi, subject, message);
}
diff --git a/modules/nickserv/ns_resetpass.cpp b/modules/nickserv/ns_resetpass.cpp
index 3eeae5052..7425ade66 100644
--- a/modules/nickserv/ns_resetpass.cpp
+++ b/modules/nickserv/ns_resetpass.cpp
@@ -132,21 +132,18 @@ public:
static bool SendResetEmail(User *u, const NickAlias *na, BotInfo *bi)
{
- Anope::string subject = Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("reset_subject").c_str()),
- message = Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("reset_message").c_str()),
- passcode = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
-
- subject = subject.replace_all_cs("%n", na->nick);
- subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
- subject = subject.replace_all_cs("%c", passcode);
+ auto *ri = na->nc->Extend<ResetInfo>("reset");
+ ri->code = Anope::Random(Config->GetBlock("options").Get<size_t>("codelength", 15));
+ ri->time = Anope::CurTime;
- message = message.replace_all_cs("%n", na->nick);
- message = message.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
- message = message.replace_all_cs("%c", passcode);
+ Anope::map<Anope::string> vars = {
+ { "nick", na->nick },
+ { "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
+ { "code", ri->code },
+ };
- ResetInfo *ri = na->nc->Extend<ResetInfo>("reset");
- ri->code = passcode;
- ri->time = Anope::CurTime;
+ auto subject = Anope::Template(Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("reset_subject").c_str()), vars);
+ auto message = Anope::Template(Language::Translate(na->nc, Config->GetBlock("mail").Get<const Anope::string>("reset_message").c_str()), vars);
return Mail::Send(u, na->nc, bi, subject, message);
}
diff --git a/modules/nickserv/ns_set.cpp b/modules/nickserv/ns_set.cpp
index 39da08053..b8f6c257b 100644
--- a/modules/nickserv/ns_set.cpp
+++ b/modules/nickserv/ns_set.cpp
@@ -528,20 +528,16 @@ class CommandNSSetEmail
n->first = new_email;
n->second = code;
- Anope::string subject = Config->GetBlock("mail").Get<const Anope::string>("emailchange_subject"),
- message = Config->GetBlock("mail").Get<const Anope::string>("emailchange_message");
-
- subject = subject.replace_all_cs("%e", nc->email);
- subject = subject.replace_all_cs("%E", new_email);
- subject = subject.replace_all_cs("%n", nc->display);
- subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
- subject = subject.replace_all_cs("%c", code);
-
- message = message.replace_all_cs("%e", nc->email);
- message = message.replace_all_cs("%E", new_email);
- message = message.replace_all_cs("%n", nc->display);
- message = message.replace_all_cs("%N", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname"));
- message = message.replace_all_cs("%c", code);
+ Anope::map<Anope::string> vars = {
+ { "old_email", nc->email },
+ { "new_email", new_email },
+ { "account", nc->display },
+ { "network", Config->GetBlock("networkinfo").Get<const Anope::string>("networkname") },
+ { "code", code },
+ };
+
+ auto subject = Anope::Template(Config->GetBlock("mail").Get<const Anope::string>("emailchange_subject"), vars);
+ auto message = Anope::Template(Config->GetBlock("mail").Get<const Anope::string>("emailchange_message"), vars);
Anope::string old = nc->email;
nc->email = new_email;
diff --git a/modules/operserv/os_defcon.cpp b/modules/operserv/os_defcon.cpp
index 49ba77b0a..53ceef8a3 100644
--- a/modules/operserv/os_defcon.cpp
+++ b/modules/operserv/os_defcon.cpp
@@ -513,7 +513,9 @@ public:
{
if (!DConfig.sle_reason.empty())
{
- Anope::string message = DConfig.sle_reason.replace_all_cs("%IP%", u->ip.addr());
+ auto message = Anope::Template(DConfig.sle_reason, {
+ { "ip", u->ip.addr() },
+ });
u->SendMessage(OperServ, message);
}
if (!DConfig.sle_detailsloc.empty())
diff --git a/modules/operserv/os_session.cpp b/modules/operserv/os_session.cpp
index 3db90f132..858b1b2a9 100644
--- a/modules/operserv/os_session.cpp
+++ b/modules/operserv/os_session.cpp
@@ -696,7 +696,9 @@ public:
{
if (!sle_reason.empty())
{
- Anope::string message = sle_reason.replace_all_cs("%IP%", u->ip.addr());
+ auto message = Anope::Template(sle_reason, {
+ { "ip", u->ip.addr() },
+ });
u->SendMessage(OperServ, message);
}
if (!sle_detailsloc.empty())
diff --git a/modules/proxyscan.cpp b/modules/proxyscan.cpp
index 8b814ec0a..4984034d7 100644
--- a/modules/proxyscan.cpp
+++ b/modules/proxyscan.cpp
@@ -84,11 +84,11 @@ public:
protected:
void Ban()
{
- Anope::string reason = this->proxy.reason;
-
- reason = reason.replace_all_cs("%t", this->GetType());
- reason = reason.replace_all_cs("%i", this->conaddr.addr());
- reason = reason.replace_all_cs("%p", Anope::ToString(this->conaddr.port()));
+ auto reason = Anope::Template(this->proxy.reason, {
+ { "ip", this->conaddr.addr() },
+ { "port", Anope::ToString(this->conaddr.port()) },
+ { "type", this->GetType() },
+ });
BotInfo *OperServ = Config->GetClient("OperServ");
Log(OperServ) << "PROXYSCAN: Open " << this->GetType() << " proxy found on " << this->conaddr.str() << " (" << reason << ")";
diff --git a/src/misc.cpp b/src/misc.cpp
index c1c963f6d..73a6fd9bd 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -856,3 +856,41 @@ bool Anope::ParseCTCP(const Anope::string &text, Anope::string &name, Anope::str
body = text.substr(start_of_body, text.length() - start_of_body - end_of_ctcp);
return true;
}
+
+Anope::string Anope::Template(const Anope::string &str, const Anope::map<Anope::string> &vars)
+{
+ Anope::string out;
+ for (size_t idx = 0; idx < str.length(); ++idx)
+ {
+ if (str[idx] != '{')
+ {
+ out.push_back(str[idx]);
+ continue;
+ }
+
+ for (size_t endidx = idx + 1; endidx < str.length(); ++endidx)
+ {
+ if (str[endidx] == '}')
+ {
+ if (endidx - idx == 1)
+ {
+ // foo{{bar is an escape of foo{bar
+ out.push_back('{');
+ idx = endidx;
+ break;
+ }
+
+ auto var = vars.find(str.substr(idx + 1, endidx - idx - 1));
+ if (var != vars.end())
+ {
+ // We have a variable, replace it in the string.
+ out.append(var->second);
+ }
+
+ idx = endidx;
+ break;
+ }
+ }
+ }
+ return out;
+}