2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5 * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
6 * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
8 * This file is part of InspIRCd. InspIRCd is free software: you can
9 * redistribute it and/or modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation, version 2.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 class WhoisContextImpl : public Whois::Context
26 Events::ModuleEventProvider& lineevprov;
29 WhoisContextImpl(LocalUser* src, User* targ, Events::ModuleEventProvider& evprov)
30 : Whois::Context(src, targ)
35 using Whois::Context::SendLine;
36 void SendLine(unsigned int numeric, const std::string& text) CXX11_OVERRIDE;
39 void WhoisContextImpl::SendLine(unsigned int numeric, const std::string& text)
41 std::string copy_text = target->nick;
42 copy_text.push_back(' ');
43 copy_text.append(text);
46 FIRST_MOD_RESULT_CUSTOM(lineevprov, Whois::LineEventListener, OnWhoisLine, MOD_RESULT, (*this, numeric, copy_text));
48 if (MOD_RESULT != MOD_RES_DENY)
49 source->WriteNumeric(numeric, copy_text);
54 class CommandWhois : public SplitCommand
56 ChanModeReference secretmode;
57 ChanModeReference privatemode;
58 UserModeReference snomaskmode;
59 Events::ModuleEventProvider evprov;
60 Events::ModuleEventProvider lineevprov;
62 void DoWhois(LocalUser* user, User* dest, unsigned long signon, unsigned long idle);
63 void SendChanList(WhoisContextImpl& whois);
66 /** Constructor for whois.
68 CommandWhois(Module* parent)
69 : SplitCommand(parent, "WHOIS", 1)
70 , secretmode(parent, "secret")
71 , privatemode(parent, "private")
72 , snomaskmode(parent, "snomask")
73 , evprov(parent, "event/whois")
74 , lineevprov(parent, "event/whoisline")
77 syntax = "<nick>{,<nick>}";
81 * @param parameters The parameters to the command
82 * @param user The user issuing the command
83 * @return A value from CmdResult to indicate command success or failure.
85 CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user);
86 CmdResult HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target);
89 class WhoisNumericSink
91 WhoisContextImpl& whois;
93 WhoisNumericSink(WhoisContextImpl& whoisref)
98 void operator()(unsigned int numeric, const std::string& text) const
100 whois.SendLine(numeric, text);
104 class WhoisChanListNumericBuilder : public Numeric::GenericBuilder<' ', false, WhoisNumericSink>
107 WhoisChanListNumericBuilder(WhoisContextImpl& whois)
108 : GenericBuilder<' ', false, WhoisNumericSink>(WhoisNumericSink(whois), 319, true, whois.GetSource()->nick.size() + whois.GetTarget()->nick.size() + 1)
115 const ServerConfig::OperSpyWhoisState spywhois;
116 WhoisChanListNumericBuilder num;
117 WhoisChanListNumericBuilder spynum;
118 std::string prefixstr;
120 void AddMember(Membership* memb, WhoisChanListNumericBuilder& out)
123 const char prefix = memb->GetPrefixChar();
125 prefixstr.push_back(prefix);
126 out.Add(prefixstr, memb->chan->name);
130 WhoisChanList(WhoisContextImpl& whois)
131 : spywhois(whois.GetSource()->HasPrivPermission("users/auspex") ? ServerInstance->Config->OperSpyWhois : ServerConfig::SPYWHOIS_NONE)
137 void AddVisible(Membership* memb)
139 AddMember(memb, num);
142 void AddHidden(Membership* memb)
144 if (spywhois == ServerConfig::SPYWHOIS_NONE)
146 AddMember(memb, (spywhois == ServerConfig::SPYWHOIS_SPLITMSG ? spynum : num));
149 void Flush(WhoisContextImpl& whois)
152 if (!spynum.IsEmpty())
153 whois.SendLine(336, ":is on private/secret channels:");
158 void CommandWhois::SendChanList(WhoisContextImpl& whois)
160 WhoisChanList chanlist(whois);
162 User* const target = whois.GetTarget();
163 for (User::ChanList::iterator i = target->chans.begin(); i != target->chans.end(); ++i)
165 Membership* memb = *i;
166 Channel* c = memb->chan;
167 /* If the target is the sender, neither +p nor +s is set, or
168 * the channel contains the user, it is not a spy channel
170 if ((whois.IsSelfWhois()) || ((!c->IsModeSet(privatemode)) && (!c->IsModeSet(secretmode))) || (c->HasUser(whois.GetSource())))
171 chanlist.AddVisible(memb);
173 chanlist.AddHidden(memb);
176 chanlist.Flush(whois);
179 void CommandWhois::DoWhois(LocalUser* user, User* dest, unsigned long signon, unsigned long idle)
181 WhoisContextImpl whois(user, dest, lineevprov);
183 whois.SendLine(311, "%s %s * :%s", dest->ident.c_str(), dest->dhost.c_str(), dest->fullname.c_str());
184 if (whois.IsSelfWhois() || user->HasPrivPermission("users/auspex"))
186 whois.SendLine(378, ":is connecting from %s@%s %s", dest->ident.c_str(), dest->host.c_str(), dest->GetIPString().c_str());
191 if (!whois.IsSelfWhois() && !ServerInstance->Config->HideWhoisServer.empty() && !user->HasPrivPermission("servers/auspex"))
193 whois.SendLine(312, "%s :%s", ServerInstance->Config->HideWhoisServer.c_str(), ServerInstance->Config->Network.c_str());
197 whois.SendLine(312, "%s :%s", dest->server->GetName().c_str(), dest->server->GetDesc().c_str());
202 whois.SendLine(301, ":%s", dest->awaymsg.c_str());
207 if (ServerInstance->Config->GenericOper)
208 whois.SendLine(313, ":is an IRC operator");
210 whois.SendLine(313, ":is %s %s on %s", (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"),dest->oper->name.c_str(), ServerInstance->Config->Network.c_str());
213 if (whois.IsSelfWhois() || user->HasPrivPermission("users/auspex"))
215 if (dest->IsModeSet(snomaskmode))
217 whois.SendLine(379, ":is using modes +%s %s", dest->FormatModes(), snomaskmode->GetUserParameter(dest).c_str());
221 whois.SendLine(379, ":is using modes +%s", dest->FormatModes());
225 FOREACH_MOD_CUSTOM(evprov, Whois::EventListener, OnWhois, (whois));
228 * We only send these if we've been provided them. That is, if hidewhois is turned off, and user is local, or
229 * if remote whois is queried, too. This is to keep the user hidden, and also since you can't reliably tell remote time. -- w00t
231 if ((idle) || (signon))
233 whois.SendLine(317, "%lu %lu :seconds idle, signon time", idle, signon);
236 whois.SendLine(318, ":End of /WHOIS list.");
239 CmdResult CommandWhois::HandleRemote(const std::vector<std::string>& parameters, RemoteUser* target)
241 if (parameters.size() < 2)
244 User* user = ServerInstance->FindUUID(parameters[0]);
248 // User doing the whois must be on this server
249 LocalUser* localuser = IS_LOCAL(user);
253 unsigned long idle = ConvToInt(parameters.back());
254 DoWhois(localuser, target, target->signon, idle);
259 CmdResult CommandWhois::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
263 unsigned long idle = 0, signon = 0;
265 if (CommandParser::LoopCall(user, this, parameters, 0))
269 * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree
270 * does, and use the second one, otherwise, use the only paramter. -- djGrrr
272 if (parameters.size() > 1)
275 dest = ServerInstance->FindNickOnly(parameters[userindex]);
277 if ((dest) && (dest->registered == REG_ALL))
280 * Okay. Umpteenth attempt at doing this, so let's re-comment...
281 * For local users (/w localuser), we show idletime if hidewhois is disabled
282 * For local users (/w localuser localuser), we always show idletime, hence parameters.size() > 1 check.
283 * For remote users (/w remoteuser), we do NOT show idletime
284 * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case.
285 * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t
287 LocalUser* localuser = IS_LOCAL(dest);
288 if (localuser && (ServerInstance->Config->HideWhoisServer.empty() || parameters.size() > 1))
290 idle = labs((long)((localuser->idle_lastmsg)-ServerInstance->Time()));
291 signon = dest->signon;
294 DoWhois(user,dest,signon,idle);
298 /* no such nick/channel */
299 user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", !parameters[userindex].empty() ? parameters[userindex].c_str() : "*");
300 user->WriteNumeric(RPL_ENDOFWHOIS, "%s :End of /WHOIS list.", !parameters[userindex].empty() ? parameters[userindex].c_str() : "*");
307 COMMAND_INIT(CommandWhois)