diff options
author | Sadie Powell <sadie@witchery.services> | 2025-04-14 11:31:19 +0100 |
---|---|---|
committer | Sadie Powell <sadie@witchery.services> | 2025-04-14 11:31:19 +0100 |
commit | d04a312d0d1edd1223b55ed89b7fb707ceca3117 (patch) | |
tree | 39b0c165b17d5ff4571423b2bc279b34546c3b72 | |
parent | 099f0ce43a7e34e4a6e74d91aa911c745c262ba8 (diff) |
Add Anope::Templace and switch all template strings to use it.
-rw-r--r-- | data/anope.example.conf | 60 | ||||
-rw-r--r-- | data/chanserv.example.conf | 6 | ||||
-rw-r--r-- | data/modules.example.conf | 38 | ||||
-rw-r--r-- | data/nickserv.example.conf | 2 | ||||
-rw-r--r-- | data/operserv.example.conf | 2 | ||||
-rw-r--r-- | include/anope.h | 7 | ||||
-rw-r--r-- | modules/chanserv/cs_akick.cpp | 6 | ||||
-rw-r--r-- | modules/chanserv/cs_ban.cpp | 13 | ||||
-rw-r--r-- | modules/chanserv/cs_kick.cpp | 13 | ||||
-rw-r--r-- | modules/dnsbl.cpp | 18 | ||||
-rw-r--r-- | modules/ldap_authentication.cpp | 5 | ||||
-rw-r--r-- | modules/ldap_oper.cpp | 13 | ||||
-rw-r--r-- | modules/memoserv/memoserv.cpp | 24 | ||||
-rw-r--r-- | modules/nickserv/nickserv.cpp | 7 | ||||
-rw-r--r-- | modules/nickserv/ns_register.cpp | 18 | ||||
-rw-r--r-- | modules/nickserv/ns_resetpass.cpp | 23 | ||||
-rw-r--r-- | modules/nickserv/ns_set.cpp | 24 | ||||
-rw-r--r-- | modules/operserv/os_defcon.cpp | 4 | ||||
-rw-r--r-- | modules/operserv/os_session.cpp | 4 | ||||
-rw-r--r-- | modules/proxyscan.cpp | 10 | ||||
-rw-r--r-- | src/misc.cpp | 38 |
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; +} |