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