From 148b26f687ce85dc01e852a2358b03d493757ada Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 23 Jun 2014 07:12:41 -0400 Subject: Mostly working language string rewrite with new format strings --- include/anope.h | 66 ++++- include/bots.h | 2 + include/commands.h | 11 +- include/config.h | 2 + include/event.h | 2 +- include/language.h | 64 ---- include/users.h | 13 +- modules/commands/bs_assign.cpp | 114 +++++--- modules/commands/bs_badwords.cpp | 144 +++++---- modules/commands/bs_bot.cpp | 156 ++++++---- modules/commands/bs_botlist.cpp | 25 +- modules/commands/bs_control.cpp | 52 +++- modules/commands/bs_info.cpp | 42 +-- modules/commands/bs_kick.cpp | 335 ++++++++------------- modules/commands/bs_set.cpp | 47 ++- modules/commands/cs_access.cpp | 312 +++++++++++--------- modules/commands/cs_akick.cpp | 157 ++++++---- modules/commands/cs_ban.cpp | 99 ++++--- modules/commands/cs_clone.cpp | 32 +- modules/commands/cs_drop.cpp | 27 +- modules/commands/cs_enforce.cpp | 55 ++-- modules/commands/cs_entrymsg.cpp | 60 ++-- modules/commands/cs_flags.cpp | 83 +++--- modules/commands/cs_getkey.cpp | 17 +- modules/commands/cs_info.cpp | 16 +- modules/commands/cs_invite.cpp | 51 ++-- modules/commands/cs_kick.cpp | 39 +-- modules/commands/cs_list.cpp | 79 +++-- modules/commands/cs_log.cpp | 78 ++--- modules/commands/cs_mode.cpp | 146 +++++---- modules/commands/cs_register.cpp | 51 ++-- modules/commands/cs_seen.cpp | 70 ++--- modules/commands/cs_set.cpp | 439 +++++++++++++--------------- modules/commands/cs_set_misc.cpp | 16 +- modules/commands/cs_status.cpp | 109 +++---- modules/commands/cs_suspend.cpp | 39 +-- modules/commands/cs_sync.cpp | 42 ++- modules/commands/cs_topic.cpp | 66 ++--- modules/commands/cs_unban.cpp | 30 +- modules/commands/cs_updown.cpp | 84 +++--- modules/commands/cs_xop.cpp | 158 +++++----- modules/commands/gl_global.cpp | 6 +- modules/commands/greet.cpp | 56 ++-- modules/commands/help.cpp | 16 +- modules/commands/hs_del.cpp | 32 +- modules/commands/hs_group.cpp | 16 +- modules/commands/hs_list.cpp | 29 +- modules/commands/hs_off.cpp | 10 +- modules/commands/hs_on.cpp | 14 +- modules/commands/hs_request.cpp | 72 ++--- modules/commands/hs_set.cpp | 61 ++-- modules/commands/ms_cancel.cpp | 22 +- modules/commands/ms_check.cpp | 24 +- modules/commands/ms_del.cpp | 50 ++-- modules/commands/ms_ignore.cpp | 34 +-- modules/commands/ms_info.cpp | 85 +++--- modules/commands/ms_list.cpp | 36 +-- modules/commands/ms_read.cpp | 54 ++-- modules/commands/ms_rsend.cpp | 14 +- modules/commands/ms_send.cpp | 19 +- modules/commands/ms_sendall.cpp | 4 +- modules/commands/ms_set.cpp | 130 ++++---- modules/commands/ms_staff.cpp | 2 - modules/commands/ns_access.cpp | 83 +++--- modules/commands/ns_ajoin.cpp | 43 ++- modules/commands/ns_alist.cpp | 16 +- modules/commands/ns_cert.cpp | 67 ++--- modules/commands/ns_drop.cpp | 15 +- modules/commands/ns_getemail.cpp | 14 +- modules/commands/ns_getpass.cpp | 16 +- modules/commands/ns_group.cpp | 106 +++---- modules/commands/ns_identify.cpp | 20 +- modules/commands/ns_info.cpp | 62 ++-- modules/commands/ns_list.cpp | 98 +++---- modules/commands/ns_logout.cpp | 15 +- modules/commands/ns_recover.cpp | 35 +-- modules/commands/ns_register.cpp | 93 ++---- modules/commands/ns_resetpass.cpp | 18 +- modules/commands/ns_set.cpp | 321 +++++++++----------- modules/commands/ns_set_misc.cpp | 10 +- modules/commands/ns_status.cpp | 5 +- modules/commands/ns_suspend.cpp | 34 +-- modules/commands/os_akill.cpp | 142 ++++----- modules/commands/os_chankill.cpp | 11 +- modules/commands/os_config.cpp | 23 +- modules/commands/os_defcon.cpp | 25 +- modules/commands/os_dns.cpp | 149 +++++----- modules/commands/os_forbid.cpp | 40 ++- modules/commands/os_ignore.cpp | 44 ++- modules/commands/os_info.cpp | 32 +- modules/commands/os_jupe.cpp | 18 +- modules/commands/os_kick.cpp | 24 +- modules/commands/os_kill.cpp | 10 +- modules/commands/os_list.cpp | 31 +- modules/commands/os_login.cpp | 18 +- modules/commands/os_logsearch.cpp | 33 +-- modules/commands/os_mode.cpp | 22 +- modules/commands/os_modinfo.cpp | 20 +- modules/commands/os_module.cpp | 39 +-- modules/commands/os_news.cpp | 47 ++- modules/commands/os_noop.cpp | 16 +- modules/commands/os_oline.cpp | 12 +- modules/commands/os_oper.cpp | 43 ++- modules/commands/os_reload.cpp | 9 +- modules/commands/os_session.cpp | 130 +++----- modules/commands/os_set.cpp | 76 ++--- modules/commands/os_shutdown.cpp | 19 +- modules/commands/os_stats.cpp | 84 +++--- modules/commands/os_svs.cpp | 47 ++- modules/commands/os_sxline.cpp | 255 ++++++++-------- modules/commands/os_update.cpp | 5 +- modules/fantasy.cpp | 13 +- modules/ns_maxemail.cpp | 4 +- modules/pseudoclients/chanserv/chanserv.cpp | 2 +- modules/pseudoclients/memoserv/memoserv.cpp | 4 +- modules/pseudoclients/nickserv/nickserv.cpp | 6 +- modules/pseudoclients/operserv.cpp | 2 +- modules/webcpanel/pages/chanserv/modes.cpp | 2 +- src/bots.cpp | 14 + src/channels.cpp | 2 +- src/command.cpp | 32 +- src/config.cpp | 5 + src/misc.cpp | 2 +- src/users.cpp | 51 ++-- 124 files changed, 3234 insertions(+), 3616 deletions(-) diff --git a/include/anope.h b/include/anope.h index 845a2b1fb..839d201cf 100644 --- a/include/anope.h +++ b/include/anope.h @@ -631,7 +631,7 @@ class spacesepstream : public sepstream public: /** Initialize with space seperator */ - spacesepstream(const Anope::string &source) : sepstream(source, ' ') { } + spacesepstream(const Anope::string &source, bool allowempty = false) : sepstream(source, ' ', allowempty) { } }; /** This class can be used on its own to represent an exception, or derived to represent a module-specific exception. @@ -775,3 +775,67 @@ template inline T anope_dynamic_static_cast(O ptr) return static_cast(ptr); } #endif + +struct kwarg +{ + Anope::string name, value; + + template + kwarg& operator=(const T& rhs) + { + value = stringify(rhs); + return *this; + } +}; + +inline kwarg operator"" _kw(const char *literal, size_t n) +{ + return kwarg{ literal }; +} + +struct FormatInfo +{ + Anope::string format; + std::vector parameters; + unsigned int pos = 0; + + FormatInfo(const Anope::string &fmt, size_t size) : format(fmt), parameters(size) { } + + template + void Add(T& arg) + { + parameters[pos] = kwarg{ stringify(pos).c_str() } = stringify(arg); + ++pos; + } + + template + void Format(Arg &&arg, Args&&... args) + { + Add(arg); + Format(std::forward(args)...); + } + + void Format() + { + for (kwarg& arg : parameters) + format = format.replace_all_cs("{" + arg.name + "}", arg.value); + } +}; + +template<> +inline void FormatInfo::Add(kwarg &arg) +{ + parameters[pos++] = arg; +} + +namespace Anope +{ + template + inline Anope::string Format(const Anope::string &format, Args&&... args) + { + FormatInfo fi(format, sizeof...(Args)); + fi.Format(std::forward(args)...); + return fi.format; + } +} + diff --git a/include/bots.h b/include/bots.h index 9a2c5d237..ef57d31f3 100644 --- a/include/bots.h +++ b/include/bots.h @@ -124,6 +124,8 @@ class CoreExport BotInfo : public User, public Serializable */ CommandInfo *GetCommand(const Anope::string &cname); + CommandInfo *FindCommand(const Anope::string &service); + /** Find a bot by nick * @param nick The nick * @param nick_only True to only look by nick, and not by UID diff --git a/include/commands.h b/include/commands.h index 359995f8f..6f29aa135 100644 --- a/include/commands.h +++ b/include/commands.h @@ -14,6 +14,7 @@ #include "service.h" #include "anope.h" #include "channels.h" +#include "language.h" struct CommandGroup { @@ -29,6 +30,8 @@ struct CommandInfo /* Service name of the command */ Anope::string name; + /* User visible name */ + Anope::string cname; /* Permission required to execute the command */ Anope::string permission; /* Group this command is in */ @@ -77,7 +80,13 @@ class CoreExport CommandSource ChanServ::AccessGroup AccessFor(ChanServ::Channel *ci); bool IsFounder(ChanServ::Channel *ci); - void Reply(const char *message, ...); + template + void Reply(const char *message, Args&&... args) + { + const char *translated_message = Language::Translate(this->nc, message); + Reply(Anope::Format(translated_message, std::forward(args)...)); + } + void Reply(const Anope::string &message); bool HasCommand(const Anope::string &cmd); diff --git a/include/config.h b/include/config.h index 585c681fb..ccb7bcdf1 100644 --- a/include/config.h +++ b/include/config.h @@ -122,6 +122,8 @@ namespace Configuration std::vector CommandGroups; /* List of modules to autoload */ std::vector ModulesAutoLoad; + /* After how many characters do we wrap lines? */ + unsigned int LineWrap; /* module configuration blocks */ std::map modules; diff --git a/include/event.h b/include/event.h index 83d5a79e1..381db967b 100644 --- a/include/event.h +++ b/include/event.h @@ -123,7 +123,7 @@ class EventHook : public EventHandler } priority; - EventHook(const Anope::string &name, Priority p = Priority::LAST) : handlers(this, name) + EventHook(const Anope::string &name, Priority p = Priority::LAST) : handlers(this, name), priority(p) { handlers.Check(); } diff --git a/include/language.h b/include/language.h index 0aaa5ac9c..3bb732ddf 100644 --- a/include/language.h +++ b/include/language.h @@ -63,67 +63,3 @@ namespace Language } // namespace Language -/* Commonly used language strings */ -#define MORE_INFO _("\002%s%s HELP %s\002 for more information.") -#define BAD_USERHOST_MASK _("Mask must be in the form \037user\037@\037host\037.") -#define BAD_EXPIRY_TIME _("Invalid expiry time.") -#define USERHOST_MASK_TOO_WIDE _("%s coverage is too wide; Please use a more specific mask.") -#define READ_ONLY_MODE _("Services are in read-only mode!") -#define PASSWORD_INCORRECT _("Password incorrect.") -#define ACCESS_DENIED _("Access denied.") -#define MORE_OBSCURE_PASSWORD _("Please try again with a more obscure password. Passwords should be at least\n" \ - "five characters long, should not be something easily guessed\n" \ - "(e.g. your real name or your nick), and cannot contain the space or tab characters.") -#define PASSWORD_TOO_LONG _("Your password is too long. Please try again with a shorter password.") -#define NICK_NOT_REGISTERED _("Your nick isn't registered.") -#define NICK_X_NOT_REGISTERED _("Nick \002%s\002 isn't registered.") -#define NICK_X_NOT_IN_USE _("Nick \002%s\002 isn't currently in use.") -#define NICK_X_NOT_ON_CHAN _("\002%s\002 is not currently on channel %s.") -#define NICK_X_SUSPENDED _("Nick %s is currently suspended.") -#define CHAN_X_SUSPENDED _("Channel %s is currently suspended.") -#define CHAN_X_NOT_REGISTERED _("Channel \002%s\002 isn't registered.") -#define CHAN_X_NOT_IN_USE _("Channel \002%s\002 doesn't exist.") -#define NICK_IDENTIFY_REQUIRED _("Password authentication required for that command.") -#define MAIL_X_INVALID _("\002%s\002 is not a valid e-mail address.") -#define UNKNOWN _("") -#define NO_EXPIRE _("does not expire") -#define LIST_INCORRECT_RANGE _("Incorrect range specified. The correct syntax is \002#\037from\037-\037to\037\002.") -#define NICK_IS_REGISTERED _("This nick is owned by someone else. Please choose another.\n" \ - "(If this is your nick, type \002%s%s IDENTIFY \037password\037\002.)") -#define NICK_IS_SECURE _("This nickname is registered and protected. If it is your\n" \ - "nick, type \002%s%s IDENTIFY \037password\037\002. Otherwise,\n" \ - "please choose a different nick.") -#define FORCENICKCHANGE_NOW _("This nickname has been registered; you may not use it.") -#define NICK_CANNOT_BE_REGISTERED _("Nickname \002%s\002 may not be registered.") -#define NICK_ALREADY_REGISTERED _("Nickname \002%s\002 is already registered!") -#define NICK_SET_DISPLAY_CHANGED _("The new display is now \002%s\002.") -#define NICK_CONFIRM_INVALID _("Invalid passcode has been entered, please check the e-mail again, and retry.") -#define CHAN_NOT_ALLOWED_TO_JOIN _("You are not permitted to be on this channel.") -#define CHAN_X_INVALID _("Channel %s is not a valid channel.") -#define CHAN_REACHED_CHANNEL_LIMIT _("Sorry, you have already reached your limit of \002%d\002 channels.") -#define CHAN_EXCEEDED_CHANNEL_LIMIT _("Sorry, you have already exceeded your limit of \002%d\002 channels.") -#define CHAN_SYMBOL_REQUIRED _("Please use the symbol of \002#\002 when attempting to register.") -#define CHAN_SETTING_CHANGED _("%s for %s set to %s.") -#define CHAN_SETTING_UNSET _("%s for %s unset.") -#define CHAN_ACCESS_LEVEL_RANGE _("Access level must be between %d and %d inclusive.") -#define CHAN_INFO_HEADER _("Information for channel \002%s\002:") -#define CHAN_EXCEPTED _("\002%s\002 matches an except on %s and cannot be banned until the except has been removed.") -#define MEMO_NEW_X_MEMO_ARRIVED _("There is a new memo on channel %s.\n" \ - "Type \002%s%s READ %s %d\002 to read it.") -#define MEMO_NEW_MEMO_ARRIVED _("You have a new memo from %s.\n" \ - "Type \002%s%s READ %d\002 to read it.") -#define MEMO_HAVE_NO_MEMOS _("You have no memos.") -#define MEMO_X_HAS_NO_MEMOS _("%s has no memos.") -#define MEMO_SEND_DISABLED _("Sorry, memo sending is temporarily disabled.") -#define MEMO_HAVE_NO_NEW_MEMOS _("You have no new memos.") -#define MEMO_X_HAS_NO_NEW_MEMOS _("%s has no new memos.") -#define BOT_DOES_NOT_EXIST _("Bot \002%s\002 does not exist.") -#define BOT_NOT_ASSIGNED _("You must assign a bot to the channel before using this command.") -#define BOT_NOT_ON_CHANNEL _("Bot is not on channel \002%s\002.") -#define HOST_SET_ERROR _("A vHost must be in the format of a valid hostname.") -#define HOST_SET_IDENT_ERROR _("A vHost ident must be in the format of a valid ident.") -#define HOST_SET_TOOLONG _("Error! The vHost is too long, please use a hostname shorter than %d characters.") -#define HOST_SET_IDENTTOOLONG _("Error! The vHost ident is too long, please use an ident shorter than %d characters.") -#define HOST_NOT_ASSIGNED _("Please contact an Operator to get a vHost assigned to this nick.") -#define HOST_NO_VIDENT _("Your IRCd does not support vIdent's, if this is incorrect, please report this as a possible bug") - diff --git a/include/users.h b/include/users.h index e89d7c8af..972fa2ac0 100644 --- a/include/users.h +++ b/include/users.h @@ -185,10 +185,15 @@ class CoreExport User : public virtual Base, public Extensible, public CommandRe /** * Send a message (notice or privmsg, depending on settings) to a user * @param source Sender - * @param fmt Format of the Message - * @param ... any number of parameters - */ - void SendMessage(const MessageSource &, const char *fmt, ...); + * @param message Format of the Message + * @param args any number of parameters + */ + template + void SendMessage(const MessageSource &source, const char *message, Args&&... args) + { + const char *translated_message = Language::Translate(this->Account(), message); + SendMessage(source, Anope::Format(translated_message, std::forward(args)...)); + } void SendMessage(const MessageSource &, const Anope::string &msg) override; /** Identify the user to a nick. diff --git a/modules/commands/bs_assign.cpp b/modules/commands/bs_assign.cpp index fe7938fc8..6fc66f43c 100644 --- a/modules/commands/bs_assign.cpp +++ b/modules/commands/bs_assign.cpp @@ -18,7 +18,7 @@ class CommandBSAssign : public Command CommandBSAssign(Module *creator) : Command(creator, "botserv/assign", 2, 2) { this->SetDesc(_("Assigns a bot to a channel")); - this->SetSyntax(_("\037channel\037 \037nick\037")); + this->SetSyntax(_("\037channel\037 \037nickname\037")); } void Execute(CommandSource &source, const std::vector ¶ms) override @@ -32,36 +32,42 @@ class CommandBSAssign : public Command return; } - ChanServ::Channel *ci = ChanServ::Find(params[0]); + ChanServ::Channel *ci = ChanServ::Find(chan); if (ci == NULL) { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + source.Reply(_("Channel \002{0}\002 isn't registered."), chan); return; } BotInfo *bi = BotInfo::Find(nick, true); if (!bi) { - source.Reply(BOT_DOES_NOT_EXIST, nick.c_str()); + source.Reply(_("Bot \002{0}\002 does not exist."), nick); return; } ChanServ::AccessGroup access = source.AccessFor(ci); - if (ci->HasExt("BS_NOBOT") || (!access.HasPriv("ASSIGN") && !source.HasPriv("botserv/administration"))) + if (!access.HasPriv("ASSIGN") && !source.HasPriv("botserv/administration")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "ASSIGN", ci->name); + return; + } + + if (ci->HasExt("BS_NOBOT")) + { + source.Reply(_("Access denied. \002{0}\002 may not have a bot assigned to it because a Services Operator has disallowed it."), ci->name); return; } if (bi->oper_only && !source.HasPriv("botserv/administration")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. Bot \002{0}\002 is for operators only."), bi->nick); return; } if (ci->bi == bi) { - source.Reply(_("Bot \002%s\002 is already assigned to channel \002%s\002."), ci->bi->nick.c_str(), chan.c_str()); + source.Reply(_("Bot \002{0}\002 is already assigned to \002{1}\002."), ci->bi->nick, ci->name); return; } @@ -69,16 +75,20 @@ class CommandBSAssign : public Command Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << bi->nick; bi->Assign(source.GetUser(), ci); - source.Reply(_("Bot \002%s\002 has been assigned to %s."), bi->nick.c_str(), ci->name.c_str()); + source.Reply(_("Bot \002{0}\002 has been assigned to \002{1}\002."), bi->nick, ci->name); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Assigns a bot pointed out by nick to a channel. You\n" - "can then configure the bot for the channel so it fits\n" - "your needs.")); + source.Reply(_("Assigns the bot \037nickname\037 to \037channel\037." + " You can then configure the bot for the channel so it fits your needs.\n" + "\n" + "Use of this command requires the \002{0}\002 privilege on \037channel\037." + "\n" + "Example:\n" + " {command} #anope Botox\n" + " Assigns the bot Botox to #anope.\n"), + "ASSIGN", "command"_kw = source.command); return true; } }; @@ -94,29 +104,31 @@ class CommandBSUnassign : public Command void Execute(CommandSource &source, const std::vector ¶ms) override { + const Anope::string &chan = params[0]; + if (Anope::ReadOnly) { source.Reply(_("Sorry, bot assignment is temporarily disabled.")); return; } - ChanServ::Channel *ci = ChanServ::Find(params[0]); + ChanServ::Channel *ci = ChanServ::Find(chan); if (ci == NULL) { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + source.Reply(_("Channel \002{0}\002 isn't registered."), chan); return; } ChanServ::AccessGroup access = source.AccessFor(ci); if (!source.HasPriv("botserv/administration") && !access.HasPriv("ASSIGN")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "ASSIGN", ci->name); return; } if (!ci->bi) { - source.Reply(BOT_NOT_ASSIGNED); + source.Reply(_("There is no bot assigned to \002{0}\002."), ci->name); return; } @@ -129,19 +141,22 @@ class CommandBSUnassign : public Command bool override = !access.HasPriv("ASSIGN"); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << ci->bi->nick; + BotInfo *bi = ci->bi; ci->bi->UnAssign(source.GetUser(), ci); - source.Reply(_("There is no bot assigned to %s anymore."), ci->name.c_str()); + source.Reply(_("Bot \002{0}\002 has been unassigned from \002{1}\002."), bi->nick, ci->name); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Unassigns a bot from a channel. When you use this command,\n" - "the bot won't join the channel anymore. However, bot\n" - "configuration for the channel is kept, so you will always\n" - "be able to reassign a bot later without having to reconfigure\n" - "it entirely.")); + source.Reply(_("Unassigns a bot from \037channel\037." + "Bot configuration is kept, so you will always be able to reassign a bot later without losing your settings.\n" + "\n" + "Use of this command requires the \002{0}\002 privilege on \037channel\037." + "\n" + "Example:\n" + " {command} #anope\n" + " Unassigns the current bot from #anope.\n"), + "ASSIGN", "command"_kw = source.command); return true; } }; @@ -157,18 +172,13 @@ class CommandBSSetNoBot : public Command void Execute(CommandSource &source, const std::vector ¶ms) override { - ChanServ::Channel *ci = ChanServ::Find(params[0]); + const Anope::string &chan = params[0]; const Anope::string &value = params[1]; - if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot modification is temporarily disabled.")); - return; - } - + ChanServ::Channel *ci = ChanServ::Find(chan); if (ci == NULL) { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + source.Reply(_("Channel \002{0}\002 isn't registered."), chan); return; } @@ -179,14 +189,14 @@ class CommandBSSetNoBot : public Command ci->Extend("BS_NOBOT"); if (ci->bi) ci->bi->UnAssign(source.GetUser(), ci); - source.Reply(_("No-bot mode is now \002on\002 on channel %s."), ci->name.c_str()); + source.Reply(_("No-bot mode is now \002on\002 for \002{0}\002."), ci->name); } else if (value.equals_ci("OFF")) { Log(LOG_ADMIN, source, this, ci) << "to disable nobot"; ci->Shrink("BS_NOBOT"); - source.Reply(_("No-bot mode is now \002off\002 on channel %s."), ci->name.c_str()); + source.Reply(_("No-bot mode is now \002off\002 for \002{0}\002."), ci->name); } else this->OnSyntaxError(source, source.command); @@ -194,11 +204,13 @@ class CommandBSSetNoBot : public Command bool OnHelp(CommandSource &source, const Anope::string &) override { - this->SendSyntax(source); - source.Reply(_(" \n" - "This option makes a channel be unassignable. If a bot\n" - "is already assigned to the channel, it is unassigned\n" - "automatically when you enable the option.")); + source.Reply(_("If no-bot is set on a channel, then the channel will be unabled to have a bot assigned to it." + " If a bot is already assigned to the channel, it is unassigned automatically when no-bot is enabled." + "\n" + "Example:\n" + " {command} #anope on\n" + " Prevents a service bot from being assigned to #anope.\n"), + "command"_kw = source.command); return true; } }; @@ -217,7 +229,9 @@ class BSAssign : public Module BSAssign(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR) , EventHook("OnInvite") , EventHook("OnBotInfoEvent") + , nobot(this, "BS_NOBOT") + , commandbsassign(this) , commandbsunassign(this) , commandbssetnobot(this) @@ -227,30 +241,36 @@ class BSAssign : public Module void OnInvite(User *source, Channel *c, User *targ) override { BotInfo *bi; - if (Anope::ReadOnly || !c->ci || targ->server != Me || !(bi = dynamic_cast(targ))) + if (Anope::ReadOnly || !c->ci || targ->server != Me || !(bi = BotInfo::Find(targ->nick, true))) return; ChanServ::AccessGroup access = c->ci->AccessFor(source); - if (nobot.HasExt(c->ci) || (!access.HasPriv("ASSIGN") && !source->HasPriv("botserv/administration"))) + if (!access.HasPriv("ASSIGN") && !source->HasPriv("botserv/administration")) + { + targ->SendMessage(bi, _("Access denied. You do not have privilege \002ASSIGN\002 on \002{0}\002."), c->ci->name); + return; + } + + if (nobot.HasExt(c->ci)) { - targ->SendMessage(bi, ACCESS_DENIED); + targ->SendMessage(bi, _("Access denied. \002{0}\002 may not have a bot assigned to it because a Services Operator has disallowed it."), c->ci->name); return; } if (bi->oper_only && !source->HasPriv("botserv/administration")) { - targ->SendMessage(bi, ACCESS_DENIED); + targ->SendMessage(bi, _("Access denied. Bot \002{0}\002 is for operators only."), bi->nick); return; } if (c->ci->bi == bi) { - targ->SendMessage(bi, _("Bot \002%s\002 is already assigned to channel \002%s\002."), c->ci->bi->nick.c_str(), c->name.c_str()); + targ->SendMessage(bi, _("Bot \002{0}\002 is already assigned to \002{1}\002."), bi->nick, c->ci->name); return; } bi->Assign(source, c->ci); - targ->SendMessage(bi, _("Bot \002%s\002 has been assigned to %s."), bi->nick.c_str(), c->name.c_str()); + targ->SendMessage(bi, _("Bot \002{0}\002 has been assigned to \002{1}\002."), bi->nick, c->ci->name); } void OnBotInfo(CommandSource &source, BotInfo *bi, ChanServ::Channel *ci, InfoFormatter &info) override diff --git a/modules/commands/bs_badwords.cpp b/modules/commands/bs_badwords.cpp index b410aced2..5e9dd363a 100644 --- a/modules/commands/bs_badwords.cpp +++ b/modules/commands/bs_badwords.cpp @@ -164,11 +164,11 @@ class BadwordsDelCallback : public NumberList ~BadwordsDelCallback() { if (!deleted) - source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str()); + source.Reply(_("No matching entries on the bad word list of \002{0}\002."), ci->name); else if (deleted == 1) - source.Reply(_("Deleted 1 entry from %s bad words list."), ci->name.c_str()); + source.Reply(_("Deleted \0021\002 entry from bad word list of \002{0}\002."), ci->name); else - source.Reply(_("Deleted %d entries from %s bad words list."), deleted, ci->name.c_str()); + source.Reply(_("Deleted \002{0}\002 entries from the bad word list of \002{1}\002."), deleted, ci->name); } void HandleNumber(unsigned Number) override @@ -196,10 +196,11 @@ class CommandBSBadwords : public Command if (!bw || !bw->GetBadWordCount()) { - source.Reply(_("%s bad words list is empty."), ci->name.c_str()); + source.Reply(_("The bad word list of \002{0}\002 is empty."), ci->name); return; } - else if (!word.empty() && word.find_first_not_of("1234567890,-") == Anope::string::npos) + + if (!word.empty() && word.find_first_not_of("1234567890,-") == Anope::string::npos) { class BadwordsListCallback : public NumberList { @@ -244,13 +245,13 @@ class CommandBSBadwords : public Command } if (list.IsEmpty()) - source.Reply(_("No matching entries on %s bad words list."), ci->name.c_str()); + source.Reply(_("No matching entries on the bad word list of \002{0}\002."), ci->name); else { std::vector replies; list.Process(replies); - source.Reply(_("Bad words list for %s:"), ci->name.c_str()); + source.Reply(_("Bad words list for \002{0}\002:"), ci->name); for (unsigned i = 0; i < replies.size(); ++i) source.Reply(replies[i]); @@ -284,7 +285,7 @@ class CommandBSBadwords : public Command unsigned badwordsmax = Config->GetModule(this->module)->Get("badwordsmax"); if (badwords->GetBadWordCount() >= badwordsmax) { - source.Reply(_("Sorry, you can only have %d bad words entries on a channel."), badwordsmax); + source.Reply(_("Sorry, you can only have \002{0}\002 bad words entries on a channel."), badwordsmax); return; } @@ -296,7 +297,7 @@ class CommandBSBadwords : public Command if ((casesensitive && realword.equals_cs(bw->word)) || (!casesensitive && realword.equals_ci(bw->word))) { - source.Reply(_("\002%s\002 already exists in %s bad words list."), bw->word.c_str(), ci->name.c_str()); + source.Reply(_("\002{0}\002 already exists in \002{1}\002 bad words list."), bw->word, ci->name); return; } } @@ -305,7 +306,7 @@ class CommandBSBadwords : public Command Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "ADD " << realword; badwords->AddBadWord(realword, bwtype); - source.Reply(_("\002%s\002 added to %s bad words list."), realword.c_str(), ci->name.c_str()); + source.Reply(_("\002{0}\002 added to \002{1}\002 bad words list."), realword, ci->name); } void DoDelete(CommandSource &source, ChanServ::Channel *ci, const Anope::string &word) @@ -314,7 +315,7 @@ class CommandBSBadwords : public Command if (!badwords || !badwords->GetBadWordCount()) { - source.Reply(_("%s bad words list is empty."), ci->name.c_str()); + source.Reply(_("Bad word list for \002{0}\002 is empty."), ci->name); return; } @@ -339,14 +340,14 @@ class CommandBSBadwords : public Command if (i == end) { - source.Reply(_("\002%s\002 not found on %s bad words list."), word.c_str(), ci->name.c_str()); + source.Reply(_("\002{0}\002 was not found on the bad word list of \002{1}\002."), word, ci->name); return; } bool override = !source.AccessFor(ci).HasPriv("BADWORDS"); Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "DEL " << badword->word; - source.Reply(_("\002%s\002 deleted from %s bad words list."), badword->word.c_str(), ci->name.c_str()); + source.Reply(_("\002{0}\002 deleted from \002{1}\002 bad words list."), badword->word, ci->name); badwords->EraseBadWord(i); } @@ -377,6 +378,7 @@ class CommandBSBadwords : public Command void Execute(CommandSource &source, const std::vector ¶ms) override { + const Anope::string &chan = params[0]; const Anope::string &cmd = params[1]; const Anope::string &word = params.size() > 2 ? params[2] : ""; bool need_args = cmd.equals_ci("LIST") || cmd.equals_ci("CLEAR"); @@ -387,16 +389,16 @@ class CommandBSBadwords : public Command return; } - ChanServ::Channel *ci = ChanServ::Find(params[0]); + ChanServ::Channel *ci = ChanServ::Find(chan); if (ci == NULL) { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + source.Reply(_("Channel \002{0}\002 isn't registered."), chan); return; } if (!source.AccessFor(ci).HasPriv("BADWORDS") && (!need_args || !source.HasPriv("botserv/administration"))) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "BADWORDS", ci->name); return; } @@ -407,49 +409,91 @@ class CommandBSBadwords : public Command } if (cmd.equals_ci("ADD")) - return this->DoAdd(source, ci, word); + this->DoAdd(source, ci, word); else if (cmd.equals_ci("DEL")) - return this->DoDelete(source, ci, word); + this->DoDelete(source, ci, word); else if (cmd.equals_ci("LIST")) - return this->DoList(source, ci, word); + this->DoList(source, ci, word); else if (cmd.equals_ci("CLEAR")) - return this->DoClear(source, ci); + this->DoClear(source, ci); else this->OnSyntaxError(source, ""); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Maintains the \002bad words list\002 for a channel. The bad\n" - "words list determines which words are to be kicked\n" - "when the bad words kicker is enabled. For more information,\n" - "type \002%s%s HELP KICK %s\002.\n" - " \n" - "The \002ADD\002 command adds the given word to the\n" - "bad words list. If SINGLE is specified, a kick will be\n" - "done only if a user says the entire word. If START is\n" - "specified, a kick will be done if a user says a word\n" - "that starts with \037word\037. If END is specified, a kick\n" - "will be done if a user says a word that ends with\n" - "\037word\037. If you don't specify anything, a kick will\n" - "be issued every time \037word\037 is said by a user.\n" - " \n"), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), source.command.c_str()); - source.Reply(_("The \002DEL\002 command removes the given word from the\n" - "bad words list. If a list of entry numbers is given, those\n" - "entries are deleted. (See the example for LIST below.)\n" - " \n" - "The \002LIST\002 command displays the bad words list. If\n" - "a wildcard mask is given, only those entries matching the\n" - "mask are displayed. If a list of entry numbers is given,\n" - "only those entries are shown; for example:\n" - " \002#channel LIST 2-5,7-9\002\n" - " Lists bad words entries numbered 2 through 5 and\n" - " 7 through 9.\n" - " \n" - "The \002CLEAR\002 command clears all entries of the\n" - "bad words list.")); + if (subcommand.equals_ci("ADD")) + { + source.Reply(_("Adds \037word\037 to the bad words list for \037channel\037. If \002SINGLE\002 is specified then the user must say the enire word for it to be considered a match." + " If \002START\002 is specified then the user only must say a word that starts with \037word\037." + " Likewise if \002END\002 is specified then the user must only say a word that ends with \037word\037." + " If no argument is specified, then any word which contains \037word\037 will be considered a match.\n" + "\n" + "Examples:\n" + " {command} #anope ADD raw SINGLE\n" + " Adds the bad word \"raw\" to the bad word list of #anope."), + "command"_kw = source.command); + } + else if (subcommand.equals_ci("DEL")) + { + source.Reply(_("Removes \037word\037 from the bad words list for \037channel\037. If a number or list of numbers is given, those entries are deleted.\n" + "\n" + "Examples:\n" + " {command} #anope DEL raw\n" + " Removes the bad word \"raw\" from the bad word list of #anope.\n" + "\n" + " {command} #anope DEL 2-5,7-9\n" + " Removes bad words entries numbered 2 through 5 and 7 through 9 on #anope."), + "command"_kw = source.command); + + } + else if (subcommand.equals_ci("LIST")) + { + source.Reply(_("Lists the badwords for \037channel\037." + " If a wildcard mask is given, only those entries matching the mask are displayed." + " If a list of entry numbers is given, only those entries are shown.\n" + "\n" + "Examples:\n" + " {command} #anope LIST\n" + " Lists the bad words for #anope.\n" + "\n" + " {command} #anope LIST 2-5,7-9\n" + " Lists bad words entries numbered 2 thorough 5 and 7 through 9 on #anope."), + "command"_kw = source.command); + } + else if (subcommand.equals_ci("CLEAR")) + { + source.Reply(_("Clears the bad words for \037channel\037." + "\n" + "\n" + "Example:\n" + " {command} #anope CLEAR\n" + " Clears the bad word list for #anope."), + "command"_kw = source.command); + } + else + { + source.Reply(_("Maintains the bad words list for a channel." + " When a word on the bad words list is said, action may be taken against the offending user.\n" + "\n" + "Use of this command requires the \002{0}\002 privilege on \037channel\037."), + "BADWORDS"); + + CommandInfo *help = source.service->FindCommand("generic/help"); + if (help) + source.Reply(_("\n" + "For help configuring the bad word kicker use \002{msg}{service} HELP KICK BADWORDS\002.\n"//XXX + "\n" + "The \002ADD\002 command adds \037word\037 to the badwords list.\n" + "\002{msg}{service} {help} {command} ADD\002 for more information.\n" + "\n" + "The \002DEL\002 command removes \037word\037 from the badwords list.\n" + "\002{msg}{service} {help} {command} DEL\002 for more information.\n" + "\n" + "The \002LIST\002 and \002CLEAR\002 commands show and clear the bad words list, respectively.\n" + "\002{msg}{service} {help} {command} LIST\002 and \002{msg}{service} {help} {command} CLEAR\002 for more information.\n"), + "msg"_kw = Config->StrictPrivmsg, "service"_kw = source.service->nick, "command"_kw = source.command, "help"_kw = help->cname); + } return true; } }; diff --git a/modules/commands/bs_bot.cpp b/modules/commands/bs_bot.cpp index 977d4b72f..2413e6b6d 100644 --- a/modules/commands/bs_bot.cpp +++ b/modules/commands/bs_bot.cpp @@ -27,7 +27,7 @@ class CommandBSBot : public Command if (BotInfo::Find(nick, true)) { - source.Reply(_("Bot \002%s\002 already exists."), nick.c_str()); + source.Reply(_("Bot \002{0}\002 already exists."), nick); return; } @@ -35,19 +35,19 @@ class CommandBSBot : public Command if (nick.length() > networkinfo->Get("nicklen")) { - source.Reply(_("Bot nicks may only be %d characters long."), networkinfo->Get("nicklen")); + source.Reply(_("Bot nicks may only be \002{0}\002 characters long."), networkinfo->Get("nicklen")); return; } if (user.length() > networkinfo->Get("userlen")) { - source.Reply(_("Bot idents may only be %d characters long."), networkinfo->Get("userlen")); + source.Reply(_("Bot idents may only be \002{0}\002 characters long."), networkinfo->Get("userlen")); return; } if (host.length() > networkinfo->Get("hostlen")) { - source.Reply(_("Bot hosts may only be %d characters long."), networkinfo->Get("hostlen")); + source.Reply(_("Bot hosts may only be \002{0}\002 characters long."), networkinfo->Get("hostlen")); return; } @@ -73,17 +73,22 @@ class CommandBSBot : public Command * if so. You need to drop the nick manually before you can use * it as a bot nick from now on -GD */ - if (NickServ::FindNick(nick)) + NickServ::Nick *na = NickServ::FindNick(nick); + if (na) { - source.Reply(NICK_ALREADY_REGISTERED, nick.c_str()); + source.Reply(_("Nickname \002{0}\002 is already registered!"), na->nick); return; } + User *targ = User::Find(nick, true); + if (targ) + targ->Kill(Me, "Nickname is reserved for services"); + BotInfo *bi = new BotInfo(nick, user, host, real); Log(LOG_ADMIN, source, this) << "ADD " << bi->GetMask() << " " << bi->realname; - source.Reply(_("%s!%s@%s (%s) added to the bot list."), bi->nick.c_str(), bi->GetIdent().c_str(), bi->host.c_str(), bi->realname.c_str()); + source.Reply(_("\002{0}!{1}@{2}\002 (\002{3}\002) added to the bot list."), bi->nick, bi->GetIdent(), bi->host, bi->realname); this->OnBotCreate(&Event::BotCreate::OnBotCreate, bi); } @@ -105,13 +110,13 @@ class CommandBSBot : public Command BotInfo *bi = BotInfo::Find(oldnick, true); if (!bi) { - source.Reply(BOT_DOES_NOT_EXIST, oldnick.c_str()); + source.Reply(_("Bot \002{0}\002 does not exist."), oldnick); return; } if (bi->conf) { - source.Reply(_("Bot %s is not changeable."), bi->nick.c_str()); + source.Reply(_("Bot \002{0}\002 is not changeable because it is configured in services configuration."), bi->nick.c_str()); return; } @@ -119,19 +124,19 @@ class CommandBSBot : public Command if (nick.length() > networkinfo->Get("nicklen")) { - source.Reply(_("Bot nicks may only be %d characters long."), networkinfo->Get("nicklen")); + source.Reply(_("Bot nicknames may only be \002{0}\002 characters long."), networkinfo->Get("nicklen")); return; } if (user.length() > networkinfo->Get("userlen")) { - source.Reply(_("Bot idents may only be %d characters long."), networkinfo->Get("userlen")); + source.Reply(_("Bot usernames may only be \002{0}\002 characters long."), networkinfo->Get("userlen")); return; } if (host.length() > networkinfo->Get("hostlen")) { - source.Reply(_("Bot hosts may only be %d characters long."), networkinfo->Get("hostlen")); + source.Reply(_("Bot hostnames may only be \002{0}\002 characters long."), networkinfo->Get("hostlen")); return; } @@ -140,33 +145,37 @@ class CommandBSBot : public Command * And we must finally check that the nick is not already * taken by another bot. */ - if (nick.equals_cs(bi->nick) && (!user.empty() ? user.equals_cs(bi->GetIdent()) : 1) && (!host.empty() ? host.equals_cs(bi->host) : 1) && (!real.empty() ? real.equals_cs(bi->realname) : 1)) + if (nick.equals_cs(bi->nick) + && (user.empty() || user.equals_cs(bi->GetIdent())) + && (host.empty() || host.equals_cs(bi->host)) + && (real.empty() || real.equals_cs(bi->realname))) { - source.Reply(_("Old info is equal to the new one.")); + source.Reply(_("There is no difference between the current settings and the new settings.")); return; } if (!IRCD->IsNickValid(nick)) { - source.Reply(_("Bot nicks may only contain valid nick characters.")); + source.Reply(_("Bot nicknames may only contain valid nickname characters.")); return; } if (!user.empty() && !IRCD->IsIdentValid(user)) { - source.Reply(_("Bot idents may only contain valid ident characters.")); + source.Reply(_("Bot uesrnames may only contain valid username characters.")); return; } if (!host.empty() && !IRCD->IsHostValid(host)) { - source.Reply(_("Bot hosts may only contain valid host characters.")); + source.Reply(_("Bot hostnames may only contain valid hostname characters.")); return; } - if (!nick.equals_ci(bi->nick) && BotInfo::Find(nick, true)) + BotInfo *newbi = BotInfo::Find(nick, true); + if (newbi && bi != newbi) { - source.Reply(_("Bot \002%s\002 already exists."), nick.c_str()); + source.Reply(_("Bot \002{0}\002 already exists."), newbi->nick); return; } @@ -176,9 +185,10 @@ class CommandBSBot : public Command * if so. You need to drop the nick manually before you can use * it as a bot nick from now on -GD */ - if (NickServ::FindNick(nick)) + NickServ::Nick *na = NickServ::FindNick(nick); + if (na) { - source.Reply(NICK_ALREADY_REGISTERED, nick.c_str()); + source.Reply(_("Nickname \002{0}\002 is already registered."), na->nick); return; } @@ -199,11 +209,11 @@ class CommandBSBot : public Command if (!nick.equals_cs(bi->nick)) bi->SetNewNick(nick); - if (!user.empty() && !user.equals_cs(bi->GetIdent())) + if (!user.equals_cs(bi->GetIdent())) bi->SetIdent(user); - if (!host.empty() && !host.equals_cs(bi->host)) + if (!host.equals_cs(bi->host)) bi->host = host; - if (!real.empty() && !real.equals_cs(bi->realname)) + if (real.equals_cs(bi->realname)) bi->realname = real; if (!user.empty()) @@ -220,7 +230,7 @@ class CommandBSBot : public Command } } - source.Reply(_("Bot \002%s\002 has been changed to %s!%s@%s (%s)."), oldnick.c_str(), bi->nick.c_str(), bi->GetIdent().c_str(), bi->host.c_str(), bi->realname.c_str()); + source.Reply(_("Bot \002{0}\002 has been changed to \002{1}!{2}@{3}\002 (\002{4}\002)."), oldnick, bi->nick, bi->GetIdent(), bi->host, bi->realname); Log(LOG_ADMIN, source, this) << "CHANGE " << oldnick << " to " << bi->GetMask() << " " << bi->realname; this->OnBotChange(&Event::BotChange::OnBotChange, bi); @@ -239,13 +249,13 @@ class CommandBSBot : public Command BotInfo *bi = BotInfo::Find(nick, true); if (!bi) { - source.Reply(BOT_DOES_NOT_EXIST, nick.c_str()); + source.Reply(_("Bot \002{0}\002 does not exist."), nick); return; } if (bi->conf) { - source.Reply(_("Bot %s is not deletable."), bi->nick.c_str()); + source.Reply(_("Bot \002{0}\002 is can not be deleted because it is configured in services configuration."), bi->nick); return; } @@ -253,7 +263,7 @@ class CommandBSBot : public Command Log(LOG_ADMIN, source, this) << "DEL " << bi->nick; - source.Reply(_("Bot \002%s\002 has been deleted."), nick.c_str()); + source.Reply(_("Bot \002{0}\002 has been deleted."), bi->nick); delete bi; } @@ -261,9 +271,9 @@ class CommandBSBot : public Command CommandBSBot(Module *creator) : Command(creator, "botserv/bot", 1, 6), OnBotCreate(creator, "OnBotCreate"), OnBotChange(creator, "OnBotChange"), OnBotDelete(creator, "OnBotDelete") { this->SetDesc(_("Maintains network bot list")); - this->SetSyntax(_("\002ADD \037nick\037 \037user\037 \037host\037 \037real\037\002")); - this->SetSyntax(_("\002CHANGE \037oldnick\037 \037newnick\037 [\037user\037 [\037host\037 [\037real\037]]]\002")); - this->SetSyntax(_("\002DEL \037nick\037\002")); + this->SetSyntax(_("\002ADD \037nicknae\037 \037username\037 \037hostname\037 \037realname\037\002")); + this->SetSyntax(_("\002CHANGE \037oldnickname\037 \037newnickname\037 [\037username\037 [\037hostname\037 [\037realname\037]]]\002")); + this->SetSyntax(_("\002DEL \037nickname\037\002")); } void Execute(CommandSource &source, const std::vector ¶ms) override @@ -271,20 +281,17 @@ class CommandBSBot : public Command const Anope::string &cmd = params[0]; if (Anope::ReadOnly) - { - source.Reply(_("Sorry, bot modification is temporarily disabled.")); - return; - } + source.Reply(_("Services are in read-only mode. Any changes made may not persist.")); if (cmd.equals_ci("ADD")) { - // ADD nick user host real - 5 if (!source.HasCommand("botserv/bot/add")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have access to the operator command \002{0}\002."), "botserv/bot/add"); return; } + // ADD nick user host real - 5 if (params.size() < 5) { this->OnSyntaxError(source, "ADD"); @@ -296,7 +303,7 @@ class CommandBSBot : public Command if (tempparams.size() >= 6) tempparams[4] = tempparams[4] + " " + tempparams[5]; - return this->DoAdd(source, tempparams); + this->DoAdd(source, tempparams); } else if (cmd.equals_ci("CHANGE")) { @@ -304,7 +311,7 @@ class CommandBSBot : public Command // but only oldn and newn are required if (!source.HasCommand("botserv/bot/change")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have access to the operator command \002{0}\002."), "botserv/bot/change"); return; } @@ -314,14 +321,14 @@ class CommandBSBot : public Command return; } - return this->DoChange(source, params); + this->DoChange(source, params); } else if (cmd.equals_ci("DEL")) { // DEL nick if (!source.HasCommand("botserv/bot/del")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have access to the operator command \002{0}\002."), "botserv/bot/del"); return; } @@ -331,35 +338,58 @@ class CommandBSBot : public Command return; } - return this->DoDel(source, params); + this->DoDel(source, params); } else this->OnSyntaxError(source, ""); - - return; } bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Allows Services Operators to create, modify, and delete\n" - "bots that users will be able to use on their own\n" - "channels.\n" - " \n" - "\002BOT ADD\002 adds a bot with the given nickname, username,\n" - "hostname and realname. Since no integrity checks are done\n" - "for these settings, be really careful.\n" - " \n" - "\002BOT CHANGE\002 allows to change the nickname, username, hostname\n" - "or realname of a bot without actually having to delete it (and\n" - "all the data associated with it).\n" - " \n" - "\002BOT DEL\002 removes the given bot from the bot list.\n" - " \n" - "\002Note\002: you cannot create a bot that has a nick that is\n" - "currently registered. If an unregistered user is currently\n" - "using the nick, they will be killed.")); + if (subcommand.equals_ci("ADD")) + source.Reply(_("\002{command} ADD\002 adds a bot with the given \037nickname\037, \037username\037, \037hostname\037 and \037realname\037." + " You can not create a bot with a nickname that is currently registered. If an unregistered user is currently using the nick, they will be killed.\n" + " Once a bot is created, users will be able to assign the bot to their channels. This command requires the opererator privilege for command \002{0}\002." + "\n" + "Example:\n" + " {command} ADD Botox Botox services.anope.org Botox\n" + " Adds a service bot with nickname \"Botox\", username \"Botox\", hostname \"services.anope.org\", and realname \"Botox\" to the bot list."), + "botserv/bot/add", "command"_kw = source.command); + else if (subcommand.equals_ci("CHANGE")) + source.Reply(_("\002{command} CHANGE\002 allows changing the \037nickname\037, \037username\037, \037hostname\037 and \037realname\037 of bot \037oldnickname\037." + " If a new username, hostname, or realname is specified, then the bot \037nickname\037 will quit and rejoin all of its channels using the new mask." + " Otherwise, the bot simply change nick to \037newnickname\037. All settings on the bot, such as channels and no-bot, are retained." + " This command requires the operator privilege for command \002{0}\002." + "\n" + "Example:\n" + " {command} CHANGE Botox peer connection reset.by peer\n" + " Renames the bot \"Botox\" to \"peer\" with the given username, hostname, and realname."), + "botserv/bot/change", "command"_kw = source.command); + else if (subcommand.equals_ci("DEL")) + source.Reply(_("\002{command} DEL\002 removes the bot \037nickname\037 from the bot list. The bot will quit from any channels it is in, and will not be replaced." + " This command requires the operator privilege for command \002{0}\002.\n" + "\n" + "Example:\n" + " {command} DEL peer\n" + " Removes the bot \"peer\" from the bot list."), + "botserv/bot/del", "command"_kw = source.command); + else + { + source.Reply(_("Allows Services Operators to create, modify, and delete bots that users will be able to use on their channels.")); + + CommandInfo *help = source.service->FindCommand("generic/help"); + if (help) + source.Reply(_("\n" + "The \002ADD\002 command adds a bot with the given \037nickname\037, \037username\037, \037hostname\037 and \037realname\037 to the bot list.\n" + "\002{msg}{service} {help} {command} ADD\002 for more information.\n" + "\n" + "The \002CHANGE\002 command allows changing the \037nickname\037, \037username\037, \037hostname\037 and \037realname\037 of bot \037oldnickname\037.\n" + "\002{msg}{service} {help} {command} CHANGE\002 for more information.\n" + "\n" + "The \002{command} DEL\002 removes the bot \037nickname\037 from the bot list.\n" + "\002{msg}{service} {help} {command} DEL\002 for more information."), + "msg"_kw = Config->StrictPrivmsg, "help"_kw = help->cname, "command"_kw = source.command); + } return true; } }; diff --git a/modules/commands/bs_botlist.cpp b/modules/commands/bs_botlist.cpp index 2ee130aba..85855bb82 100644 --- a/modules/commands/bs_botlist.cpp +++ b/modules/commands/bs_botlist.cpp @@ -44,8 +44,7 @@ class CommandBSBotList : public Command list.Process(replies); if (!count) - source.Reply(_("There are no bots available at this time.\n" - "Ask a Services Operator to create one!")); + source.Reply(_("There are no bots available at this time.")); else { source.Reply(_("Bot list:")); @@ -53,16 +52,28 @@ class CommandBSBotList : public Command for (unsigned i = 0; i < replies.size(); ++i) source.Reply(replies[i]); - source.Reply(_("%d bots available."), count); + source.Reply(_("{0} bots available."), count); } } bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Lists all available bots on this network.\n" - "Bots prefixed by a * are reserved for IRC Operators.")); + BotInfo *bi; + Anope::string name; + Command::FindCommandFromService("botserv/assign", bi, name); + if (!bi) + return false; + + source.Reply(_("Lists all available bots. You may use the \002{msg}{service} {assign}\002 command to assign a bot to your channel." + "The bot names are vanity; they all proviate the same commands and features."), + "msg"_kw = Config->StrictPrivmsg, "service"_kw = bi->nick, "assign"_kw = name); + if (source.HasPriv("botserv/administration")) + source.Reply(_("Bots prefixed by a * are reserved for Services Operators with the privilege \002{0}\002."), + "botserv/administration"); + source.Reply(_("\n" + "Example:\n" + " {command} BOTLIST"), + "command"_kw = source.command); return true; } }; diff --git a/modules/commands/bs_control.cpp b/modules/commands/bs_control.cpp index 0311a9df2..74e978404 100644 --- a/modules/commands/bs_control.cpp +++ b/modules/commands/bs_control.cpp @@ -22,30 +22,38 @@ class CommandBSSay : public Command void Execute(CommandSource &source, const std::vector ¶ms) override { + const Anope::string &chan = params[0]; const Anope::string &text = params[1]; - ChanServ::Channel *ci = ChanServ::Find(params[0]); + ChanServ::Channel *ci = ChanServ::Find(chan); if (ci == NULL) { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + source.Reply(_("Channel \002{0}\002 isn't registered."), chan); return; } if (!source.AccessFor(ci).HasPriv("SAY") && !source.HasPriv("botserv/administration")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "SAY", ci->name); return; } if (!ci->bi) { - source.Reply(BOT_NOT_ASSIGNED); + source.Reply(_("There is no bot assigned to \002{0}\002. One must be assigned to the channel before this command can be used."), ci->name); + BotInfo *bi; + Anope::string name; + Command::FindCommandFromService("botserv/assign", bi, name); + CommandInfo *help = source.service->FindCommand("generic/help"); + if (bi && help) + source.Reply(_("See \002{msg}{service} {help} {command}\002 for information on assigning bots."), + "msg"_kw = Config->StrictPrivmsg, "service"_kw = bi->nick, "help"_kw = help->cname, "command"_kw = name); return; } if (!ci->c || !ci->c->FindUser(ci->bi)) { - source.Reply(BOT_NOT_ON_CHANNEL, ci->name.c_str()); + source.Reply(_("Bot \002{0}\002 is not on channel \002{1}\002."), ci->bi->nick, ci->name); return; } @@ -66,7 +74,11 @@ class CommandBSSay : public Command { this->SendSyntax(source); source.Reply(" "); - source.Reply(_("Makes the bot say the given text on the given channel.")); + source.Reply(_("Makes the bot say the given \037text\037 on \037channel\037.\n" + "\n" + "Example:\n" + " {command} #anope mmm pie\n" + " Makes the assigned service bot say \"mmm pie\".")); return true; } }; @@ -82,30 +94,38 @@ class CommandBSAct : public Command void Execute(CommandSource &source, const std::vector ¶ms) override { + const Anope::string &chan = params[0]; Anope::string message = params[1]; - ChanServ::Channel *ci = ChanServ::Find(params[0]); + ChanServ::Channel *ci = ChanServ::Find(chan); if (ci == NULL) { - source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str()); + source.Reply(_("Channel \002{0}\002 isn't registered."), chan); return; } if (!source.AccessFor(ci).HasPriv("SAY") && !source.HasPriv("botserv/administration")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "SAY", ci->name); return; } if (!ci->bi) { - source.Reply(BOT_NOT_ASSIGNED); + source.Reply(_("There is no bot assigned to \002{0}\002. One must be assigned to the channel before this command can be used."), ci->name); + BotInfo *bi; + Anope::string name; + Command::FindCommandFromService("botserv/assign", bi, name); + CommandInfo *help = source.service->FindCommand("generic/help"); + if (bi && help) + source.Reply(_("See \002{msg}{service} {help} {command}\002 for information on assigning bots."), + "msg"_kw = Config->StrictPrivmsg, "service"_kw = bi->nick, "help"_kw = help->cname, "command"_kw = name); return; } if (!ci->c || !ci->c->FindUser(ci->bi)) { - source.Reply(BOT_NOT_ON_CHANNEL, ci->name.c_str()); + source.Reply(_("Bot \002{0}\002 is not on channel \002{1}\002."), ci->bi->nick, ci->name); return; } @@ -122,10 +142,12 @@ class CommandBSAct : public Command bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Makes the bot do the equivalent of a \"/me\" command\n" - "on the given channel using the given text.")); + source.Reply(_("Makes the assigned bot do the equivalent of a \"/me\" command on \037channel\037 using the given \037text\037.\n" + "\n" + "Example:\n" + " {command} #anope slaps Cronus\n" + " Shows the assigned service bot \"slapping\" Cronus."), + "command"_kw = source.command); return true; } }; diff --git a/modules/commands/bs_info.cpp b/modules/commands/bs_info.cpp index 88ac15a48..677dfaaf6 100644 --- a/modules/commands/bs_info.cpp +++ b/modules/commands/bs_info.cpp @@ -16,23 +16,6 @@ class CommandBSInfo : public Command { - private: - void send_bot_channels(std::vector &buffers, const BotInfo *bi) - { - Anope::string buf; - for (ChanServ::Channel *ci : bi->GetChannels()) - { - buf += " " + ci->name + " "; - if (buf.length() > 300) - { - buffers.push_back(buf); - buf.clear(); - } - } - if (!buf.empty()) - buffers.push_back(buf); - } - EventHandlers &onbotinfo; public: @@ -68,10 +51,10 @@ class CommandBSInfo : public Command if (source.HasPriv("botserv/administration")) { - std::vector buf; - this->send_bot_channels(buf, bi); - for (unsigned i = 0; i < buf.size(); ++i) - source.Reply(buf[i]); + Anope::string buf; + for (ChanServ::Channel *ci : bi->GetChannels()) + buf += " " + ci->name; + source.Reply(buf); } } @@ -79,11 +62,11 @@ class CommandBSInfo : public Command { if (!source.AccessFor(ci).HasPriv("INFO") && !source.HasPriv("botserv/administration")) { - source.Reply(ACCESS_DENIED); + source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "INFO", ci->name); return; } - source.Reply(CHAN_INFO_HEADER, ci->name.c_str()); + source.Reply(_("Information for channel \002{0}\002:"), ci->name); info[_("Bot nick")] = ci->bi ? ci->bi->nick : _("not assigned yet"); Anope::string enabled = Language::Translate(source.nc, _("Enabled")); @@ -98,18 +81,15 @@ class CommandBSInfo : public Command source.Reply(replies[i]); } else - source.Reply(_("\002%s\002 is not a valid bot or registered channel."), query.c_str()); + source.Reply(_("\002{0}\002 is not a valid bot or registered channel."), query.c_str()); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Allows you to see %s information about a channel or a bot.\n" - "If the parameter is a channel, then you'll get information\n" - "such as enabled kickers. If the parameter is a nick,\n" - "you'll get information about a bot, such as creation\n" - "time or number of channels it is on."), source.service->nick.c_str()); + source.Reply(_("Allows you to see {0} information about a channel or a bot." + " If the parameter is a channel, then you'll get information such as enabled kickers." + " If the parameter is a bot nickname, you'll get information about a bot, such as creation time and number of channels it is on."), + source.service->nick); return true; } diff --git a/modules/commands/bs_kick.cpp b/modules/commands/bs_kick.cpp index 7ffd9d353..c0ea685c5 100644 --- a/modules/commands/bs_kick.cpp +++ b/modules/commands/bs_kick.cpp @@ -130,9 +130,10 @@ class CommandBSKick : public Command bool OnHelp(CommandSource &source, const Anope::string &subcommand) override { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("Configures bot kickers. \037option\037 can be one of:")); + source.Reply(_("Configures bot kickers." + " Use of this command requires the \002SET\002 privilege on \037channel\037.\n" + "\n" + "Available kickers:")); Anope::string this_name = source.command; for (CommandInfo::map::const_iterator it = source.service->commands.begin(), it_end = source.service->commands.end(); it != it_end; ++it) @@ -151,11