diff --git a/data/anope.example.conf b/data/anope.example.conf index 14ec55a4b..f49d3ecce 100644 --- a/data/anope.example.conf +++ b/data/anope.example.conf @@ -747,6 +747,7 @@ log * nickserv/drop/display - Allows dropping display nicks when preservedisplay is enabled * nickserv/drop/override - Allows dropping nicks without using a confirmation code * nickserv/recover - Can recover other users nicks + * nickserv/resend - Can resend confirmation codes via email * operserv/config - Can modify services's configuration * operserv/oper/modify - Can add and remove operators with at most the same privileges * protected - Can not be kicked from channels by services @@ -811,7 +812,7 @@ opertype inherits = "Helper, Another Helper" /* What commands (see above) this opertype may use */ - commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline" + commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/resend nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline" /* What privs (see above) this opertype has */ privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm/*" diff --git a/language/anope.en_US.po b/language/anope.en_US.po index 57e8c4d51..28fb08795 100644 --- a/language/anope.en_US.po +++ b/language/anope.en_US.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Anope\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-07-12 16:32+0100\n" +"POT-Creation-Date: 2025-07-25 12:27+0100\n" "PO-Revision-Date: 2025-07-12 16:32+0100\n" "Last-Translator: Sadie Powell \n" "Language-Team: English\n" @@ -1341,6 +1341,9 @@ msgstr "" msgid "Additionally, Services Operators with the nickserv/drop/override permission can replace code with OVERRIDE to drop without a confirmation code." msgstr "" +msgid "Additionally, Services Operators with the nickserv/resend permission can specify a nickname to resend a confirmation email for another account." +msgstr "" + #, c-format msgid "Additionally, if fantasy is enabled fantasy commands can be executed by prefixing the command name with one of the following characters: %s" msgstr "" @@ -3673,6 +3676,10 @@ msgstr "" msgid "Nick %s is already an operator." msgstr "" +#, c-format +msgid "Nick %s is already confirmed." +msgstr "" + #, c-format msgid "Nick %s is an illegal nickname and cannot be used." msgstr "" @@ -5161,6 +5168,10 @@ msgstr "" msgid "The Defcon level is now at: %d" msgstr "" +#, c-format +msgid "The confirmation code for %s has been re-sent to %s." +msgstr "" + msgid "The defcon system can be used to implement a pre-defined set of restrictions to services useful during an attempted attack on the network." msgstr "" @@ -5449,7 +5460,7 @@ msgstr "" msgid "This command unloads the module named modname." msgstr "" -msgid "This command will resend you the registration confirmation email." +msgid "This command will resend a registration confirmation email." msgstr "" #, c-format @@ -6167,9 +6178,6 @@ msgstr "" msgid "Your account %s has been successfully created." msgstr "" -msgid "Your account is already confirmed." -msgstr "" - msgid "Your account is not confirmed. To confirm it, follow the instructions that were emailed to you." msgstr "" @@ -6181,10 +6189,6 @@ msgstr "" msgid "Your account will expire, if not confirmed, in %s." msgstr "" -#, c-format -msgid "Your confirmation code has been re-sent to %s." -msgstr "" - #, c-format msgid "Your email address has been updated to %s" msgstr "" diff --git a/modules/nickserv/ns_register.cpp b/modules/nickserv/ns_register.cpp index 9bd8ecfc1..c78e5b6bc 100644 --- a/modules/nickserv/ns_register.cpp +++ b/modules/nickserv/ns_register.cpp @@ -351,9 +351,12 @@ class CommandNSResend final : public Command { public: - CommandNSResend(Module *creator) : Command(creator, "nickserv/resend", 0, 0) + CommandNSResend(Module *creator) + : Command(creator, "nickserv/resend", 0, 1) { this->SetDesc(_("Resend registration confirmation email")); + this->SetSyntax(_("[\037nickname\037]"), [](auto &source) { return source.HasCommand("nickserv/resend"); }); + this->AllowUnregistered(true); } void Execute(CommandSource &source, const std::vector ¶ms) override @@ -364,27 +367,49 @@ public: return; } - const NickAlias *na = NickAlias::Find(source.GetNick()); - - if (na == NULL) - source.Reply(NICK_X_NOT_REGISTERED, source.GetNick().c_str()); - else if (na->nc != source.GetAccount() || !source.nc->HasExt("UNCONFIRMED")) - source.Reply(_("Your account is already confirmed.")); - else + auto is_oper = false; + Anope::string nick; + if (!params.empty() && source.HasCommand("nickserv/resend")) { - if (Anope::CurTime < source.nc->lastmail + Config->GetModule(this->owner).Get("resenddelay")) - source.Reply(_("Cannot send mail now; please retry a little later.")); - else if (SendRegmail(source.GetUser(), na, source.service)) - { - na->nc->lastmail = Anope::CurTime; - source.Reply(_("Your confirmation code has been re-sent to %s."), na->nc->email.c_str()); - Log(LOG_COMMAND, source, this) << "to resend registration confirmation code"; - } - else - Log(this->owner) << "Unable to resend registration confirmation code for " << source.GetNick(); + nick = params[0]; + is_oper = true; + } + else if (source.nc) + nick = source.GetAccount()->display; + else + nick = source.GetNick(); + + const auto *na = NickAlias::Find(nick); + if (!na) + { + source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); + return; } - return; + NickCore *nc = na->nc; + if (!nc->HasExt("UNCONFIRMED")) + { + source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str()); + return; + } + + if (!is_oper && Anope::CurTime < nc->lastmail + Config->GetModule(this->owner).Get("resenddelay")) + { + source.Reply(_("Cannot send mail now; please retry a little later.")); + return; + } + + if (!SendRegmail(source.GetUser(), na, source.service)) + { + Log(this->owner) << "Unable to resend registration confirmation code for " << na->nick; + return; + } + + nc->lastmail = Anope::CurTime; + source.Reply(_("The confirmation code for \002%s\002 has been re-sent to %s."), + na->nick.c_str(), nc->email.c_str()); + + Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to resend the registration confirmation code for " << na->nick; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) override @@ -394,7 +419,16 @@ public: this->SendSyntax(source); source.Reply(" "); - source.Reply(_("This command will resend you the registration confirmation email.")); + source.Reply(_("This command will resend a registration confirmation email.")); + + if (source.HasCommand("nickserv/resend")) + { + source.Reply(" "); + source.Reply(_( + "Additionally, Services Operators with the \037nickserv/resend\037 permission " + "can specify a nickname to resend a confirmation email for another account." + )); + } return true; }