2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2013-2015 Attila Molnar <attilamolnar@hush.com>
5 * Copyright (C) 2013, 2017-2018, 2020 Sadie Powell <sadie@witchery.services>
6 * Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
7 * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
8 * Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
9 * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
10 * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
11 * Copyright (C) 2006-2007 Craig Edwards <brain@inspircd.org>
13 * This file is part of InspIRCd. InspIRCd is free software: you can
14 * redistribute it and/or modify it under the terms of the GNU General Public
15 * License as published by the Free Software Foundation, version 2.
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "modules/whois.h"
33 RPL_WHOISHELPOP = 310,
36 ERR_HELPNOTFOUND = 524,
42 typedef std::vector<std::string> HelpMessage;
44 typedef std::map<std::string, HelpMessage, irc::insensitive_swo> HelpMap;
46 class CommandHelpop : public Command
49 const std::string startkey;
55 CommandHelpop(Module* Creator)
56 : Command(Creator, "HELPOP", 0)
59 syntax = "<any-text>";
62 CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE
64 const std::string& topic = parameters.empty() ? startkey : parameters[0];
65 HelpMap::const_iterator titer = help.find(topic);
66 if (titer == help.end())
68 user->WriteNumeric(ERR_HELPNOTFOUND, topic, nohelp);
72 user->WriteNumeric(RPL_HELPSTART, topic, InspIRCd::Format("*** Help for %s", topic.c_str()));
73 for (HelpMessage::const_iterator liter = titer->second.begin(); liter != titer->second.end(); ++liter)
74 user->WriteNumeric(RPL_HELPTXT, topic, *liter);
75 user->WriteNumeric(RPL_ENDOFHELP, topic, "*** End of help");
82 , public Whois::EventListener
86 SimpleUserModeHandler ho;
90 : Whois::EventListener(this)
92 , ho(this, "helpop", 'h', true)
96 void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
98 size_t longestkey = 0;
101 ConfigTagList tags = ServerInstance->Config->ConfTags("helpop");
102 if (tags.first == tags.second)
103 throw ModuleException("You have loaded the helpop module but not configured any help topics!");
105 for (ConfigIter i = tags.first; i != tags.second; ++i)
107 ConfigTag* tag = i->second;
109 // Attempt to read the help key.
110 const std::string key = tag->getString("key");
112 throw ModuleException(InspIRCd::Format("<helpop:key> is empty at %s", tag->getTagLocation().c_str()));
113 else if (irc::equals(key, "index"))
114 throw ModuleException(InspIRCd::Format("<helpop:key> is set to \"index\" which is reserved at %s", tag->getTagLocation().c_str()));
115 else if (key.length() > longestkey)
116 longestkey = key.length();
118 // Attempt to read the help value.
120 if (!tag->readString("value", value, true) || value.empty())
121 throw ModuleException(InspIRCd::Format("<helpop:value> is empty at %s", tag->getTagLocation().c_str()));
123 // Parse the help body. Empty lines are replaced with a single
124 // space because some clients are unable to show blank lines.
126 irc::sepstream linestream(value, '\n', true);
127 for (std::string line; linestream.GetToken(line); )
128 helpmsg.push_back(line.empty() ? " " : line);
129 newhelp[key] = helpmsg;
132 // The number of items we can fit on a page.
133 HelpMessage& indexmsg = newhelp["index"];
134 size_t maxcolumns = 80 / (longestkey + 2);
135 for (HelpMap::iterator iter = newhelp.begin(); iter != newhelp.end(); )
137 std::string indexline;
138 for (size_t column = 0; column != maxcolumns; )
140 if (iter == newhelp.end())
143 indexline.append(iter->first);
144 if (++column != maxcolumns)
145 indexline.append(longestkey - iter->first.length() + 2, ' ');
148 indexmsg.push_back(indexline);
150 cmd.help.swap(newhelp);
152 ConfigTag* tag = ServerInstance->Config->ConfValue("helpmsg");
153 cmd.nohelp = tag->getString("nohelp", "There is no help for the topic you searched for. Please try again.", 1);
156 void OnWhois(Whois::Context& whois) CXX11_OVERRIDE
158 if (whois.GetTarget()->IsModeSet(ho))
159 whois.SendLine(RPL_WHOISHELPOP, "is available for help.");
162 Version GetVersion() CXX11_OVERRIDE
164 return Version("Provides help to users via the HELPOP command", VF_VENDOR);
168 MODULE_INIT(ModuleHelpop)