Improve BanEntry
[clinton/bobotpp.git] / source / Commands.C
CommitLineData
cb21075d 1// Commands.C -*- C++ -*-
2// Copyright (c) 1998 Etienne BERNARD
a6339323 3// Copyright (C) 2002,2005 Clinton Ebadi
cb21075d 4
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// any later version.
9
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
c6e7af05 17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18// 02110-1301, USA.
cb21075d 19
cfa82921 20#include "Commands.H"
21
22#include "BanEntry.H"
23#include "Bot.H"
24#include "ChannelList.H"
cb21075d 25#include "Macros.H"
26#include "Message.H"
cfa82921 27#include "Server.H"
28#include "ServerConnection.H"
29#include "ServerList.H"
30#include "ServerQueueItem.H"
31#include "ShitEntry.H"
32#include "ShitList.H"
6b7614a8 33#include "StringTokenizer.H"
cfa82921 34#include "TodoList.H"
35#include "User.H"
36#include "UserList.H"
37#include "Utils.H"
38
39#ifdef USESCRIPTS
40#include "BotInterp.H"
41#endif
cb21075d 42
cb21075d 43
44#define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
45
46Message
47Commands::Action(Bot *bot, String channel, String message)
48{
49 CHECK_CONNECTION;
50
51 if (!CHANNEL(channel))
52 return NotOnChannel(channel);
53
54 if (message.length() == 0)
55 return InvalidParameters;
56
672b7d4e 57 Commands::CTCP (bot, channel, "ACTION", message);
cb21075d 58
59 return Ok;
60}
61
62Message
63Commands::AddUser(Bot *bot, String who, String maskChannel, int level,
64 int prot, bool aop, std::time_t expire, String password)
65{
66 // Gah, fix this (makes bot segfault)
67 if (who.length() == 0 ||
68 maskChannel.length() == 0 ||
69 level < 0 ||
70 level > User::FRIEND ||
71 prot < 0 ||
72 prot > User::NO_DEOP)
73 return InvalidParameters;
74
75 String mask;
76
a6339323 77 if (!Utils::wildcard_p(who))
cb21075d 78 {
0316e2c1 79 mask = bot->getUserhost("", who);
80 if (mask.length() == 0)
81 {
82 return NotFound(who);
83 }
84 }
cb21075d 85 // Aha! This was before the brace...segfault gone
a6339323 86 mask = Utils::make_wildcard(mask);
cb21075d 87
88 if (bot->userList->isInUserList(mask, maskChannel))
0316e2c1 89 {
90 return AlreadyInUserlist(mask, maskChannel);
91 }
cb21075d 92
93 bot->userList->addUser(mask, maskChannel, level, prot, aop,
94 expire, password);
95 bot->rehash();
96
97 return Ok;
98}
99
100
101Message
102Commands::AddServer(Bot *bot, String servername, int port)
103{
104 if (port <= 0)
105 return InvalidPort(port);
106
107 bot->serverList->addServer(new class Server(servername, port));
108
109 return Ok;
110}
111
112
113Message
114Commands::AddShit(Bot *bot, String mask, String maskChannel,
115 int level, time_t expiration, String reason)
116{
117 if (mask.length() == 0 || maskChannel.length() == 0 ||
118 level < 0 || level > ShitEntry::SHIT_NODEBAN)
119 return InvalidParameters;
120
121 if (reason == "")
122 reason = "You're on my shitlist, lamer";
123
124 String who = mask;
125
a6339323 126 if (!Utils::wildcard_p(mask)) {
cb21075d 127 mask = bot->getUserhost("", who);
128 if (mask.length() == 0)
129 return NotFound(who);
a6339323 130 mask = Utils::make_wildcard(mask);
cb21075d 131 if (bot->shitList->getShit(mask, maskChannel))
132 return AlreadyInShitlist(mask, maskChannel);
133 }
134
135 if (bot->userList->getMaxProt(mask, maskChannel) > 0)
136 return UserProtected(who, maskChannel);
137
138 bot->shitList->addShit(mask, maskChannel, level, expiration, reason);
139
140 return Ok;
141}
142
143
144Message
145Commands::Ban(Bot *bot, String channel, String who)
146{
147 CHECK_CONNECTION;
148
149 Channel *c = CHANNEL(channel);
150
151 if (!c)
152 return NotOnChannel(channel);
153
154 if (!bot->iAmOp(channel))
155 return NotChannelOp(channel);
156
157 String dest;
158
a6339323 159 if (!Utils::wildcard_p(who))
cb21075d 160 dest = bot->getUserhost(channel, who);
161 else
162 dest = who;
163
164 if (dest.length() == 0)
165 return NotFound(who);
166
a6339323 167 dest = Utils::make_wildcard(dest);
cb21075d 168 Mask m(dest);
169
170 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
171 it != bot->userList->l.end();
172 it++)
173 if (m.matches((*it)->mask) &&
174 (*it)->channelMask.matches(channel) &&
175 (*it)->prot >= User::NO_BAN)
176 return UserProtected(who, channel);
177
178 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
179 it != c->channelBanlist.end(); ++it)
952376e7 180 if (m.matches((*it)->getMask ()) && (*it)->getMask().getMask() != m.getMask())
181 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask().getMask());
cb21075d 182
183 QUEUE->sendChannelMode(channel, "+b", dest);
184
185 return Ok;
186}
187
672b7d4e 188Message
189Commands::CTCP (Bot *bot, std::string target, std::string command,
190 std::string message)
191{
192 CHECK_CONNECTION;
193
194 if (target == "")
195 {
196 return EmptyAddressee;
197 }
198
199 if (command == "")
200 {
201 return InvalidParameters;
202 }
203
204 if (message == "")
205 {
206 return EmptyMessage;
207 }
208
209 if (Utils::channel_p (target) && !CHANNEL (target))
210 {
211 return NotOnChannel (target);
212 }
213
214
215 // Send multi-line messages as seperate privmsgs
216 StringTokenizer st_message (message);
217
218 while (st_message.more_tokens_p ('\n'))
219 {
220 QUEUE->sendCTCP (target, command, st_message.next_token ('\n'));
221 }
222
223 return Ok;
224}
225
226Message
227Commands::CTCPReply (Bot *bot, std::string target, std::string command,
228 std::string message)
229{
230 CHECK_CONNECTION;
231
232 if (target == "")
233 {
234 return EmptyAddressee;
235 }
236
237 if (command == "")
238 {
239 return InvalidParameters;
240 }
241
242 if (message == "")
243 {
244 return EmptyMessage;
245 }
246
247 // CTCP-REPLY cannot go to a channel
248 if (Utils::channel_p (target))
249 {
250 return NotToChannel;
251 }
252
253
254 // Send multi-line messages as seperate privmsgs
255 StringTokenizer st_message (message);
256
257 while (st_message.more_tokens_p ('\n'))
258 {
259 QUEUE->sendCTCPReply (target, command, st_message.next_token ('\n'));
260 }
261
262 return Ok;
263}
264
265
cb21075d 266Message
267Commands::Cycle(Bot *bot, String channel)
268{
269 CHECK_CONNECTION;
270
271 if (!CHANNEL(channel))
272 return NotOnChannel(channel);
273
274 QUEUE->sendPart(channel);
275 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
276
277 return Ok;
278}
279
280Message
281Commands::Deban(Bot *bot, String channel, String who)
282{
283 CHECK_CONNECTION;
284
285 Channel *c = CHANNEL(channel);
286
287 if (!c)
288 return NotOnChannel(channel);
289
290 if (!bot->iAmOp(channel))
291 return NotChannelOp(channel);
292
293 String dest;
294
a6339323 295 if (!Utils::wildcard_p(who))
cb21075d 296 dest = bot->getUserhost(channel, who);
297 else
298 dest = who;
299
300 if (dest.length() == 0)
301 return UserNotFound(who, channel);
302
a6339323 303 dest = Utils::make_wildcard(dest);
cb21075d 304 Mask m(dest);
305
306 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
307 it != c->channelBanlist.end(); ++it)
308 if (m.matches((*it)->getMask())) {
309 // Let's see if the ban is in the shitlist
952376e7 310 ShitEntry *se = bot->shitList->getShit((*it)->getMask().getMask(), channel);
cb21075d 311 if (!se || !se->isStillValid() ||
312 se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
952376e7 313 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask().getMask());
cb21075d 314 }
315
316 return Ok;
317}
318
319Message
320Commands::DelServer(Bot *bot, int number)
321{
322 if (number < 0 || number >= bot->serverList->size())
323 return InvalidServerNumber(number);
324
325 bot->serverList->delServer(number);
326
327 return Ok;
328}
329
330Message
331Commands::DelUser(Bot *bot, String who, String maskChannel)
332{
333 if (who.length() == 0 || maskChannel.length() == 0)
334 return InvalidParameters;
335
336 String dest;
337
a6339323 338 if (!Utils::wildcard_p(who)) {
cb21075d 339 dest = bot->getUserhost("", who);
340 if (dest.length() == 0)
341 return NotFound(who);
a6339323 342 dest = Utils::make_wildcard(who);
cb21075d 343 }
344
345 if (!bot->userList->isInUserList(dest, maskChannel))
346 return NotInUserlist(who);
347
348 bot->userList->removeUser(dest, maskChannel);
349 bot->rehash();
350
351 return Ok;
352}
353
354Message
355Commands::DelShit(Bot *bot, String who, String maskChannel)
356{
357 if (who.length() == 0 || maskChannel.length() == 0)
358 return InvalidParameters;
359
360 String dest;
361
a6339323 362 if (!Utils::wildcard_p(who)) {
cb21075d 363 dest = bot->getUserhost("", who);
364 if (dest.length() == 0)
365 return NotFound(who);
a6339323 366 dest = Utils::make_wildcard(who);
cb21075d 367 }
368
369 if (!bot->shitList->getShit(dest, maskChannel))
370 return NotInShitlist(who);
371
372 bot->shitList->delShit(dest, maskChannel);
373
374 return Ok;
375}
376
377Message
378Commands::Deop(Bot *bot, String channel, String who)
379{
380 CHECK_CONNECTION;
381
382 Channel *c = CHANNEL(channel);
383
384 if (!c)
385 return NotOnChannel(channel);
386
387 if (!bot->iAmOp(channel))
388 return NotChannelOp(channel);
389
a6339323 390 if (!Utils::wildcard_p(who)) {
cb21075d 391 User *u = c->getUser(who);
392 if (!u)
393 return UserNotFound(who, channel);
394 if (!(u->mode & User::OP_MODE))
395 return UserNotOp(who, channel);
396 if (u->getProt() >= User::NO_DEOP)
397 return UserProtected(who, channel);
398 QUEUE->sendChannelMode(channel, "-o", who);
399 } else {
400 Mask m(who);
401 for (std::map<String, User *, std::less<String> >::iterator
402 it = c->channelMemory.begin();
403 it != c->channelMemory.end(); ++it) {
404 if (m.matches((*it).second->nick + "!" +
405 (*it).second->userhost) &&
406 (*it).second->getProt() < User::NO_DEOP &&
407 ((*it).second->mode & User::OP_MODE))
408 QUEUE->sendChannelMode(channel, "-o", (*it).second->nick);
409 }
410 }
411
412 return Ok;
413}
414
415Message
416Commands::Die(Bot *bot, String reason)
417{
418 CHECK_CONNECTION;
419
420 QUEUE->sendQuit(reason);
421 bot->stop = true;
422
423 return Ok;
424}
425
426Message
427Commands::Do(Bot *bot, String command)
428{
429 CHECK_CONNECTION;
430
431 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
432 return Ok;
433}
434
435Message
436Commands::Invite(Bot *bot, String channel, String who)
437{
438 CHECK_CONNECTION;
439
440 if (!bot->iAmOp(channel))
441 return NotChannelOp(channel);
442
443 QUEUE->sendInvite(channel, who);
444
445 return Ok;
446}
447
448Message
449Commands::Join(Bot *bot, String channel, String key)
450{
451 CHECK_CONNECTION;
452
a6339323 453 if (!Utils::valid_channel_name_p(channel))
cb21075d 454 return InvalidChannel(channel);
455
456 // We change the key only if we are not on the channel.
457 // We don't trust the user...
458 if (!CHANNEL(channel)) {
459 if (bot->wantedChannels[channel])
460 bot->wantedChannels[channel]->key = key;
461 else {
462 bot->wantedChannels[channel] = new wantedChannel("", "", key);
463 }
464 }
465 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
466
467 return Ok;
468}
469
470Message
471Commands::Keep(Bot *bot, String channel, String modes)
472{
473 CHECK_CONNECTION;
474
475 Channel *c = CHANNEL(channel);
476
477 if (!c)
478 return NotOnChannel(channel);
479
480 c->keepModes = modes;
481
482 return Ok;
483}
484
485Message
486Commands::Kick(Bot *bot, String channel, String who, String reason)
487{
488 CHECK_CONNECTION;
489
490 Channel *c = CHANNEL(channel);
491
492 if (!c)
493 return NotOnChannel(channel);
494
495 if (!bot->iAmOp(channel))
496 return NotChannelOp(channel);
497
a6339323 498 if (Utils::wildcard_p(who)) {
cb21075d 499 Mask m(who);
500 for (std::map<String, User *, std::less<String> >::iterator it =
501 c->channelMemory.begin();
502 it != c->channelMemory.end();
503 ++it)
504 if (m.matches((*it).second->nick + "!" +
505 (*it).second->userhost) &&
506 (*it).second->getProt() < User::NO_KICK)
507 QUEUE->sendKick(channel, (*it).second->nick, reason);
508 } else {
509 User * u = c->getUser(who);
510 if (!u)
511 return UserNotFound(who, channel);
512 if (u->getProt() < User::NO_KICK)
513 QUEUE->sendKick(channel, who, reason);
514 else
515 return UserProtected(who, channel);
516 }
517
518 return Ok;
519}
520
521Message
522Commands::KickBan(Bot *bot, String channel, String who, String reason)
523{
524 CHECK_CONNECTION;
525
526 Message m = Commands::Ban(bot, channel, who);
527
528 if (m.getCode() == 0)
529 m = Commands::Kick(bot, channel, who, reason);
530
531 return m;
532}
533
534Message
535Commands::Lock(Bot *bot, String channel)
536{
537 CHECK_CONNECTION;
538
539 Channel *c = CHANNEL(channel);
540
541 if (!c)
542 return NotOnChannel(channel);
543
544 c->lockedTopic = true;
545
546 return Ok;
547}
548
549Message
550Commands::Mode(Bot *bot, String channel, String mode)
551{
552 CHECK_CONNECTION;
553
554 if (!CHANNEL(channel))
555 return NotOnChannel(channel);
556
557 if (!bot->iAmOp(channel))
558 return NotChannelOp(channel);
559
560 QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode);
561
562 return Ok;
563}
564
565Message
566Commands::Msg(Bot *bot, String who, String message)
567{
568 CHECK_CONNECTION;
569
570 if (who == "")
5c73c60a 571 {
572 return EmptyAddressee;
573 }
cb21075d 574
a6339323 575 if (Utils::channel_p(who))
5c73c60a 576 {
4cc479d8 577 if (!CHANNEL(who))
578 {
579 return NotOnChannel (who);
580 }
5c73c60a 581 }
cb21075d 582
583 if (message == "")
5c73c60a 584 {
585 return EmptyMessage;
586 }
cb21075d 587
6b7614a8 588 // Send multi-line messages as seperate privmsgs
589 StringTokenizer st_message (message);
590
591 while (st_message.more_tokens_p ('\n'))
592 {
593 QUEUE->sendPrivmsg(who, st_message.next_token ('\n'));
594 }
cb21075d 595
596 return Ok;
597}
598
599Message
600Commands::NextServer(Bot *bot)
601{
602 CHECK_CONNECTION;
603
604 if (bot->serverList->size() == 0)
605 return EmptyServerList;
606
607 if (!bot->canChangeServer())
608 return CanNotChangeServer;
ae97d6ec 609
610#ifdef USESCRIPTS
611 // Run hooks/disconnect
612 bot->botInterp->RunHooks
613 (Hook::DISCONNECT,
614 bot->serverConnection->server->getHostName (),
615 scm_list_n
616 (Utils::str2scm (bot->serverConnection->server->getHostName ()),
617 SCM_BOOL_T));
618#endif
cb21075d 619
620 QUEUE->sendQuit("Changing server");
621 bot->nextServer();
622
623 return Ok;
624}
625
626Message
627Commands::Nick(Bot *bot, String nick)
628{
629 CHECK_CONNECTION;
630
6b7614a8 631 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
cb21075d 632 return InvalidNick(nick);
633
634 bot->wantedNickName = nick;
635 QUEUE->sendNick(nick);
636
637 return Ok;
638}
639
640Message
641Commands::Notice(Bot *bot, String who, String message)
642{
643 CHECK_CONNECTION;
644
645 if (who == "")
646 return EmptyAddressee;
647
5aec4622 648 // if (Utils::channel_p(who))
649 // return NotToChannel;
cb21075d 650
651 if (message == "")
652 return EmptyMessage;
653
6b7614a8 654 // Send multiple lines as multiple notices
655 StringTokenizer st_message (message);
656
657 while (st_message.more_tokens_p ('\n'))
658 {
659 QUEUE->sendNotice(who, st_message.next_token ('\n'));
660 }
cb21075d 661
662 return Ok;
663}
664
665Message
666Commands::Op(Bot *bot, String channel, String who)
667{
668 CHECK_CONNECTION;
669
670 Channel *c = CHANNEL(channel);
671
672 if (!c)
673 return NotOnChannel(channel);
674
675 if (!bot->iAmOp(channel))
676 return NotChannelOp(channel);
677
a6339323 678 if (Utils::wildcard_p(who))
cb21075d 679 return MassOpNotAllowed;
680
681 User *u = c->getUser(who);
682 if (!u)
683 return UserNotFound(who, channel);
684
685 ShitEntry *se = bot->shitList->getShit(who, channel);
686 if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
687 return UserOnShitList(who);
688
689 QUEUE->sendChannelMode(channel, "+o", who);
690
691 return Ok;
692}
693
694
695Message
696Commands::Part(Bot *bot, String channel)
697{
698 CHECK_CONNECTION;
699
700 if (!CHANNEL(channel))
701 return NotOnChannel(channel);
702
703 wantedChannel *w = bot->wantedChannels[channel];
704 bot->wantedChannels.erase(channel);
705 delete w;
706 QUEUE->sendPart(channel);
707
708 return Ok;
709}
710
711Message
712Commands::Reconnect(Bot *bot)
713{
714 CHECK_CONNECTION;
715
716 if (!bot->canChangeServer())
717 return CanNotChangeServer;
718
719 QUEUE->sendQuit("Reconnecting");
720 bot->reconnect();
721
722 return Ok;
723}
724
725Message
726Commands::Say(Bot *bot, String channel, String message)
727{
4cc479d8 728 return Commands::Msg (bot, channel, message);
cb21075d 729}
730
731
732Message
733Commands::Server(Bot *bot, int number)
734{
735 CHECK_CONNECTION;
736
737 if (number < 0 || number >= bot->serverList->size())
738 return InvalidServerNumber(number);
739
740 if (!bot->canChangeServer())
741 return CanNotChangeServer;
742
743 QUEUE->sendQuit("Changing server");
744 QUEUE->flush();
745 bot->connect(number);
746
747 return Ok;
748}
749
e171dcce 750Message
751Commands::SetFloodRate(Bot *bot, unsigned int num_messages)
752{
753 if (num_messages > 0)
754 {
755 bot->MAX_MESSAGES = num_messages;
756 return Ok;
757 }
758 return InvalidParameters;
759}
760
cb21075d 761Message
762Commands::SetVersion(Bot *bot, String str)
763{
764 if (str.length() == 0)
765 return InvalidParameters;
766
767 bot->versionString = str;
768 return Ok;
769}
770
771Message
772Commands::TBan(Bot *bot, String channel, String who, int seconds)
773{
774 CHECK_CONNECTION;
775
776 Channel *c = CHANNEL(channel);
cf8ea873 777 String dest;
cb21075d 778
cf8ea873 779 // Make sure all of the inputs are valid
cb21075d 780 if (!c)
cf8ea873 781 {
782 return NotOnChannel(channel);
783 }
cb21075d 784
785 if (!bot->iAmOp(channel))
cf8ea873 786 {
787 return NotChannelOp(channel);
788 }
cb21075d 789
790 if (seconds <= 0)
cf8ea873 791 {
792 return InvalidTime(seconds);
793 }
cb21075d 794
cf8ea873 795 // Look for user
a6339323 796 if (!Utils::wildcard_p(who))
cf8ea873 797 {
798 dest = bot->getUserhost(channel, who);
799 }
cb21075d 800 else
cf8ea873 801 {
802 dest = who;
803 }
cb21075d 804
805 if (dest.length() == 0)
cf8ea873 806 {
807 return UserNotFound(who, channel);
808 }
809
cb21075d 810
a6339323 811 dest = Utils::make_wildcard(dest);
cb21075d 812 Mask m(dest);
813
cf8ea873 814 // Make sure the user isn't protected from bans
cb21075d 815 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
816 it != bot->userList->l.end();
817 it++)
cf8ea873 818 {
819 if (m.matches((*it)->mask) &&
820 (*it)->channelMask.matches(channel) &&
821 (*it)->prot >= User::NO_BAN)
822 {
823 return UserProtected(who, channel);
824 }
825 }
cb21075d 826
cf8ea873 827 // Clear existing bans on the user
cb21075d 828 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
829 it != c->channelBanlist.end(); ++it)
cf8ea873 830 {
952376e7 831 if (m.matches((*it)->getMask ()))
cf8ea873 832 {
952376e7 833 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask().getMask());
cf8ea873 834 }
835 }
cb21075d 836
cf8ea873 837 // Ban them
cb21075d 838 CHANNEL(channel)->addBan(dest, seconds);
839 QUEUE->sendChannelMode(channel, "+b", dest);
840 bot->todoList->addDeban(channel, dest, seconds);
cf8ea873 841
842 return Ok;
cb21075d 843}
844
845
846Message
847Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason)
848{
849 CHECK_CONNECTION;
850
851 Message m = Commands::TBan(bot, channel, who, seconds);
852
853 if (m.getCode() == 0)
854 m = Commands::Kick(bot, channel, who, reason);
855
856 return m;
857}
858
859
860Message
861Commands::Topic(Bot *bot, String channel, String topic)
862{
863 CHECK_CONNECTION;
864
865 Channel *c = CHANNEL(channel);
866
867 if (!c)
868 return NotOnChannel(channel);
869
870 if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED))
871 return CanNotChangeTopic(channel);
872
873 if (c->lockedTopic)
874 return TopicLocked(channel);
875
876 QUEUE->sendTopic(channel, topic);
877
878 return Ok;
879}
880
881
882Message
883Commands::Unlock(Bot *bot, String channel)
884{
885 CHECK_CONNECTION;
886
887 Channel *c = CHANNEL(channel);
888
889 if (!c)
890 return NotOnChannel(channel);
891
892 c->lockedTopic = false;
893
894 return Ok;
895}
c6e7af05 896
897Message
898Commands::Who (Bot *bot, String target)
899{
900 CHECK_CONNECTION;
901
902 QUEUE->sendWho (target);
903
904 return Ok;
905}
906
907Message
908Commands::Whois (Bot *bot, String nick)
909{
910 CHECK_CONNECTION;
911
912 if (!Utils::valid_nickname_p (bot, nick))
913 {
914 return InvalidNick (nick);
915 }
916 else
917 {
918 QUEUE->sendWhois (nick);
919 return Ok;
920 }
921}
922
923