diff options
author | Sadie Powell <sadie@witchery.services> | 2020-01-13 14:32:49 +0000 |
---|---|---|
committer | Sadie Powell <sadie@witchery.services> | 2020-01-13 14:32:49 +0000 |
commit | 88d1811905675c84b5ef96ff157d304e0e5f4e9a (patch) | |
tree | 83aac27f4d5aa9a80165502c3ece7b3f5247d9ad | |
parent | a0176191c9e2a32d898857f2a7e6a4016f894f2f (diff) |
Various improvements for the helpop module.
- Ensure that the config is actually valid. This found an invalid
entry in the default helpop configs.
- Columize the index page and build it whilst reading the config
instead of at request time.
-rw-r--r-- | docs/conf/helpop.conf.example | 2 | ||||
-rw-r--r-- | src/modules/m_helpop.cpp | 110 |
2 files changed, 58 insertions, 54 deletions
diff --git a/docs/conf/helpop.conf.example b/docs/conf/helpop.conf.example index a0e90b6cb..437f30499 100644 --- a/docs/conf/helpop.conf.example +++ b/docs/conf/helpop.conf.example @@ -621,7 +621,7 @@ Sets your host to the specified host."> Sets your ident to the specified ident."> -<helpop key="swhois" line="/SWHOIS <nick> :<swhois> +<helpop key="swhois" value="/SWHOIS <nick> :<swhois> Sets the user's swhois field to the given swhois message. This will be visible in their /WHOIS. diff --git a/src/modules/m_helpop.cpp b/src/modules/m_helpop.cpp index bb2acfd6a..a34e3ff94 100644 --- a/src/modules/m_helpop.cpp +++ b/src/modules/m_helpop.cpp @@ -39,17 +39,17 @@ enum RPL_ENDOFHELP = 706 }; -typedef std::map<std::string, std::string, irc::insensitive_swo> HelpopMap; -static HelpopMap helpop_map; +typedef std::vector<std::string> HelpMessage; + +typedef std::map<std::string, HelpMessage, irc::insensitive_swo> HelpMap; -/** Handles /HELPOP - */ class CommandHelpop : public Command { private: const std::string startkey; public: + HelpMap help; std::string nohelp; CommandHelpop(Module* Creator) @@ -61,40 +61,18 @@ class CommandHelpop : public Command CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE { - const std::string& parameter = (!parameters.empty() ? parameters[0] : startkey); - - if (parameter == "index") + const std::string& topic = parameters.empty() ? startkey : parameters[0]; + HelpMap::const_iterator titer = help.find(topic); + if (titer == help.end()) { - /* iterate over all helpop items */ - user->WriteNumeric(RPL_HELPSTART, parameter, "HELPOP topic index"); - for (HelpopMap::const_iterator iter = helpop_map.begin(); iter != helpop_map.end(); iter++) - user->WriteNumeric(RPL_HELPTXT, parameter, InspIRCd::Format(" %s", iter->first.c_str())); - user->WriteNumeric(RPL_ENDOFHELP, parameter, "*** End of HELPOP topic index"); + user->WriteNumeric(ERR_HELPNOTFOUND, topic, nohelp); + return CMD_FAILURE; } - else - { - HelpopMap::const_iterator iter = helpop_map.find(parameter); - if (iter == helpop_map.end()) - { - user->WriteNumeric(ERR_HELPNOTFOUND, parameter, nohelp); - return CMD_FAILURE; - } - const std::string& value = iter->second; - irc::sepstream stream(value, '\n', true); - std::string token = "*"; - - user->WriteNumeric(RPL_HELPSTART, parameter, InspIRCd::Format("*** HELPOP for %s", parameter.c_str())); - while (stream.GetToken(token)) - { - // Writing a blank line will not work with some clients - if (token.empty()) - user->WriteNumeric(RPL_HELPTXT, parameter, ' '); - else - user->WriteNumeric(RPL_HELPTXT, parameter, token); - } - user->WriteNumeric(RPL_ENDOFHELP, parameter, "*** End of HELPOP"); - } + user->WriteNumeric(RPL_HELPSTART, topic, InspIRCd::Format("*** Help for %s", topic.c_str())); + for (HelpMessage::const_iterator liter = titer->second.begin(); liter != titer->second.end(); ++liter) + user->WriteNumeric(RPL_HELPTXT, topic, *liter); + user->WriteNumeric(RPL_ENDOFHELP, topic, "*** End of help"); return CMD_SUCCESS; } }; @@ -117,31 +95,59 @@ class ModuleHelpop void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { - HelpopMap help; + size_t longestkey = 0; + HelpMap newhelp; ConfigTagList tags = ServerInstance->Config->ConfTags("helpop"); - for(ConfigIter i = tags.first; i != tags.second; ++i) + if (tags.first == tags.second) + throw ModuleException("You have loaded the helpop module but not configured any help topics!"); + + for (ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; - std::string key = tag->getString("key"); - std::string value; - tag->readString("value", value, true); /* Linefeeds allowed */ - if (key == "index") - { - throw ModuleException("m_helpop: The key 'index' is reserved for internal purposes. Please remove it."); - } + // Attempt to read the help key. + const std::string key = tag->getString("key"); + if (key.empty()) + throw ModuleException(InspIRCd::Format("<helpop:key> is empty at %s", tag->getTagLocation().c_str())); + else if (irc::equals(key, "index")) + throw ModuleException(InspIRCd::Format("<helpop:key> is set to \"index\" which is reserved at %s", tag->getTagLocation().c_str())); + else if (key.length() > longestkey) + longestkey = key.length(); - help[key] = value; + // Attempt to read the help value. + std::string value; + if (!tag->readString("value", value, true) || value.empty()) + throw ModuleException(InspIRCd::Format("<helpop:value> is empty at %s", tag->getTagLocation().c_str())); + + // Parse the help body. Empty lines are replaced with a single + // space because some clients are unable to show blank lines. + HelpMessage helpmsg; + irc::sepstream linestream(value, '\n', true); + for (std::string line; linestream.GetToken(line); ) + helpmsg.push_back(line.empty() ? " " : line); + newhelp[key] = helpmsg; } - if (help.find("start") == help.end()) + // The number of items we can fit on a page. + HelpMessage& indexmsg = newhelp["index"]; + size_t maxcolumns = 80 / (longestkey + 2); + for (HelpMap::iterator iter = newhelp.begin(); iter != newhelp.end(); ) { - // error! - throw ModuleException("m_helpop: Helpop file is missing important entry 'start'. Please check the example conf."); - } + std::string indexline; + for (size_t column = 0; column != maxcolumns; ) + { + if (iter == newhelp.end()) + break; - helpop_map.swap(help); + indexline.append(iter->first); + if (++column != maxcolumns) + indexline.append(longestkey - iter->first.length() + 2, ' '); + iter++; + } + indexmsg.push_back(indexline); + } + cmd.help.swap(newhelp); ConfigTag* tag = ServerInstance->Config->ConfValue("helpmsg"); cmd.nohelp = tag->getString("nohelp", "There is no help for the topic you searched for. Please try again.", 1); @@ -150,14 +156,12 @@ class ModuleHelpop void OnWhois(Whois::Context& whois) CXX11_OVERRIDE { if (whois.GetTarget()->IsModeSet(ho)) - { whois.SendLine(RPL_WHOISHELPOP, "is available for help."); - } } Version GetVersion() CXX11_OVERRIDE { - return Version("Provides the HELPOP command for useful information", VF_VENDOR); + return Version("Provides help to users via the HELPOP command", VF_VENDOR); } }; |