[project @ 2005-07-05 07:24:59 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 02110-1301, USA.
18
19 #include "Macros.H"
20 #include "Message.H"
21 #include "Commands.H"
22 #include "Utils.H"
23 #include "StringTokenizer.H"
24
25
26 #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
27
28 Message
29 Commands::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
39 Commands::CTCP (bot, channel, "ACTION", message);
40
41 return Ok;
42 }
43
44 Message
45 Commands::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
59 if (!Utils::wildcard_p(who))
60 {
61 mask = bot->getUserhost("", who);
62 if (mask.length() == 0)
63 {
64 return NotFound(who);
65 }
66 }
67 // Aha! This was before the brace...segfault gone
68 mask = Utils::make_wildcard(mask);
69
70 if (bot->userList->isInUserList(mask, maskChannel))
71 {
72 return AlreadyInUserlist(mask, maskChannel);
73 }
74
75 bot->userList->addUser(mask, maskChannel, level, prot, aop,
76 expire, password);
77 bot->rehash();
78
79 return Ok;
80 }
81
82
83 Message
84 Commands::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
95 Message
96 Commands::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
108 if (!Utils::wildcard_p(mask)) {
109 mask = bot->getUserhost("", who);
110 if (mask.length() == 0)
111 return NotFound(who);
112 mask = Utils::make_wildcard(mask);
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
126 Message
127 Commands::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
141 if (!Utils::wildcard_p(who))
142 dest = bot->getUserhost(channel, who);
143 else
144 dest = who;
145
146 if (dest.length() == 0)
147 return NotFound(who);
148
149 dest = Utils::make_wildcard(dest);
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
170 Message
171 Commands::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
208 Message
209 Commands::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
248 Message
249 Commands::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
262 Message
263 Commands::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
277 if (!Utils::wildcard_p(who))
278 dest = bot->getUserhost(channel, who);
279 else
280 dest = who;
281
282 if (dest.length() == 0)
283 return UserNotFound(who, channel);
284
285 dest = Utils::make_wildcard(dest);
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
301 Message
302 Commands::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
312 Message
313 Commands::DelUser(Bot *bot, String who, String maskChannel)
314 {
315 if (who.length() == 0 || maskChannel.length() == 0)
316 return InvalidParameters;
317
318 String dest;
319
320 if (!Utils::wildcard_p(who)) {
321 dest = bot->getUserhost("", who);
322 if (dest.length() == 0)
323 return NotFound(who);
324 dest = Utils::make_wildcard(who);
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
336 Message
337 Commands::DelShit(Bot *bot, String who, String maskChannel)
338 {
339 if (who.length() == 0 || maskChannel.length() == 0)
340 return InvalidParameters;
341
342 String dest;
343
344 if (!Utils::wildcard_p(who)) {
345 dest = bot->getUserhost("", who);
346 if (dest.length() == 0)
347 return NotFound(who);
348 dest = Utils::make_wildcard(who);
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
359 Message
360 Commands::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
372 if (!Utils::wildcard_p(who)) {
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
397 Message
398 Commands::Die(Bot *bot, String reason)
399 {
400 CHECK_CONNECTION;
401
402 QUEUE->sendQuit(reason);
403 bot->stop = true;
404
405 return Ok;
406 }
407
408 Message
409 Commands::Do(Bot *bot, String command)
410 {
411 CHECK_CONNECTION;
412
413 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
414 return Ok;
415 }
416
417 Message
418 Commands::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
430 Message
431 Commands::Join(Bot *bot, String channel, String key)
432 {
433 CHECK_CONNECTION;
434
435 if (!Utils::valid_channel_name_p(channel))
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
452 Message
453 Commands::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
467 Message
468 Commands::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
480 if (Utils::wildcard_p(who)) {
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
503 Message
504 Commands::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
516 Message
517 Commands::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
531 Message
532 Commands::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
547 Message
548 Commands::Msg(Bot *bot, String who, String message)
549 {
550 CHECK_CONNECTION;
551
552 if (who == "")
553 {
554 return EmptyAddressee;
555 }
556
557 if (Utils::channel_p(who))
558 {
559 if (!CHANNEL(who))
560 {
561 return NotOnChannel (who);
562 }
563 }
564
565 if (message == "")
566 {
567 return EmptyMessage;
568 }
569
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 }
577
578 return Ok;
579 }
580
581 Message
582 Commands::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;
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
601
602 QUEUE->sendQuit("Changing server");
603 bot->nextServer();
604
605 return Ok;
606 }
607
608 Message
609 Commands::Nick(Bot *bot, String nick)
610 {
611 CHECK_CONNECTION;
612
613 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
614 return InvalidNick(nick);
615
616 bot->wantedNickName = nick;
617 QUEUE->sendNick(nick);
618
619 return Ok;
620 }
621
622 Message
623 Commands::Notice(Bot *bot, String who, String message)
624 {
625 CHECK_CONNECTION;
626
627 if (who == "")
628 return EmptyAddressee;
629
630 // if (Utils::channel_p(who))
631 // return NotToChannel;
632
633 if (message == "")
634 return EmptyMessage;
635
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 }
643
644 return Ok;
645 }
646
647 Message
648 Commands::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
660 if (Utils::wildcard_p(who))
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
677 Message
678 Commands::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
693 Message
694 Commands::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
707 Message
708 Commands::Say(Bot *bot, String channel, String message)
709 {
710 return Commands::Msg (bot, channel, message);
711 }
712
713
714 Message
715 Commands::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
732 Message
733 Commands::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
743 Message
744 Commands::SetVersion(Bot *bot, String str)
745 {
746 if (str.length() == 0)
747 return InvalidParameters;
748
749 bot->versionString = str;
750 return Ok;
751 }
752
753 Message
754 Commands::TBan(Bot *bot, String channel, String who, int seconds)
755 {
756 CHECK_CONNECTION;
757
758 Channel *c = CHANNEL(channel);
759 String dest;
760
761 // Make sure all of the inputs are valid
762 if (!c)
763 {
764 return NotOnChannel(channel);
765 }
766
767 if (!bot->iAmOp(channel))
768 {
769 return NotChannelOp(channel);
770 }
771
772 if (seconds <= 0)
773 {
774 return InvalidTime(seconds);
775 }
776
777 // Look for user
778 if (!Utils::wildcard_p(who))
779 {
780 dest = bot->getUserhost(channel, who);
781 }
782 else
783 {
784 dest = who;
785 }
786
787 if (dest.length() == 0)
788 {
789 return UserNotFound(who, channel);
790 }
791
792
793 dest = Utils::make_wildcard(dest);
794 Mask m(dest);
795
796 // Make sure the user isn't protected from bans
797 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
798 it != bot->userList->l.end();
799 it++)
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 }
808
809 // Clear existing bans on the user
810 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
811 it != c->channelBanlist.end(); ++it)
812 {
813 if (m.matches((*it)->banMask))
814 {
815 QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
816 }
817 }
818
819 // Ban them
820 CHANNEL(channel)->addBan(dest, seconds);
821 QUEUE->sendChannelMode(channel, "+b", dest);
822 bot->todoList->addDeban(channel, dest, seconds);
823
824 return Ok;
825 }
826
827
828 Message
829 Commands::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
842 Message
843 Commands::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
864 Message
865 Commands::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 }