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