[project @ 2005-06-28 03:16:45 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
fd7440f1 39 QUEUE->sendCTCP (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
170Message
171Commands::Cycle(Bot *bot, String channel)
172{
173 CHECK_CONNECTION;
174
175 if (!CHANNEL(channel))
176 return NotOnChannel(channel);
177
178 QUEUE->sendPart(channel);
179 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
180
181 return Ok;
182}
183
184Message
185Commands::Deban(Bot *bot, String channel, String who)
186{
187 CHECK_CONNECTION;
188
189 Channel *c = CHANNEL(channel);
190
191 if (!c)
192 return NotOnChannel(channel);
193
194 if (!bot->iAmOp(channel))
195 return NotChannelOp(channel);
196
197 String dest;
198
a6339323 199 if (!Utils::wildcard_p(who))
cb21075d 200 dest = bot->getUserhost(channel, who);
201 else
202 dest = who;
203
204 if (dest.length() == 0)
205 return UserNotFound(who, channel);
206
a6339323 207 dest = Utils::make_wildcard(dest);
cb21075d 208 Mask m(dest);
209
210 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
211 it != c->channelBanlist.end(); ++it)
212 if (m.matches((*it)->getMask())) {
213 // Let's see if the ban is in the shitlist
214 ShitEntry *se = bot->shitList->getShit((*it)->getMask(), channel);
215 if (!se || !se->isStillValid() ||
216 se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
217 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask());
218 }
219
220 return Ok;
221}
222
223Message
224Commands::DelServer(Bot *bot, int number)
225{
226 if (number < 0 || number >= bot->serverList->size())
227 return InvalidServerNumber(number);
228
229 bot->serverList->delServer(number);
230
231 return Ok;
232}
233
234Message
235Commands::DelUser(Bot *bot, String who, String maskChannel)
236{
237 if (who.length() == 0 || maskChannel.length() == 0)
238 return InvalidParameters;
239
240 String dest;
241
a6339323 242 if (!Utils::wildcard_p(who)) {
cb21075d 243 dest = bot->getUserhost("", who);
244 if (dest.length() == 0)
245 return NotFound(who);
a6339323 246 dest = Utils::make_wildcard(who);
cb21075d 247 }
248
249 if (!bot->userList->isInUserList(dest, maskChannel))
250 return NotInUserlist(who);
251
252 bot->userList->removeUser(dest, maskChannel);
253 bot->rehash();
254
255 return Ok;
256}
257
258Message
259Commands::DelShit(Bot *bot, String who, String maskChannel)
260{
261 if (who.length() == 0 || maskChannel.length() == 0)
262 return InvalidParameters;
263
264 String dest;
265
a6339323 266 if (!Utils::wildcard_p(who)) {
cb21075d 267 dest = bot->getUserhost("", who);
268 if (dest.length() == 0)
269 return NotFound(who);
a6339323 270 dest = Utils::make_wildcard(who);
cb21075d 271 }
272
273 if (!bot->shitList->getShit(dest, maskChannel))
274 return NotInShitlist(who);
275
276 bot->shitList->delShit(dest, maskChannel);
277
278 return Ok;
279}
280
281Message
282Commands::Deop(Bot *bot, String channel, String who)
283{
284 CHECK_CONNECTION;
285
286 Channel *c = CHANNEL(channel);
287
288 if (!c)
289 return NotOnChannel(channel);
290
291 if (!bot->iAmOp(channel))
292 return NotChannelOp(channel);
293
a6339323 294 if (!Utils::wildcard_p(who)) {
cb21075d 295 User *u = c->getUser(who);
296 if (!u)
297 return UserNotFound(who, channel);
298 if (!(u->mode & User::OP_MODE))
299 return UserNotOp(who, channel);
300 if (u->getProt() >= User::NO_DEOP)
301 return UserProtected(who, channel);
302 QUEUE->sendChannelMode(channel, "-o", who);
303 } else {
304 Mask m(who);
305 for (std::map<String, User *, std::less<String> >::iterator
306 it = c->channelMemory.begin();
307 it != c->channelMemory.end(); ++it) {
308 if (m.matches((*it).second->nick + "!" +
309 (*it).second->userhost) &&
310 (*it).second->getProt() < User::NO_DEOP &&
311 ((*it).second->mode & User::OP_MODE))
312 QUEUE->sendChannelMode(channel, "-o", (*it).second->nick);
313 }
314 }
315
316 return Ok;
317}
318
319Message
320Commands::Die(Bot *bot, String reason)
321{
322 CHECK_CONNECTION;
323
324 QUEUE->sendQuit(reason);
325 bot->stop = true;
326
327 return Ok;
328}
329
330Message
331Commands::Do(Bot *bot, String command)
332{
333 CHECK_CONNECTION;
334
335 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
336 return Ok;
337}
338
339Message
340Commands::Invite(Bot *bot, String channel, String who)
341{
342 CHECK_CONNECTION;
343
344 if (!bot->iAmOp(channel))
345 return NotChannelOp(channel);
346
347 QUEUE->sendInvite(channel, who);
348
349 return Ok;
350}
351
352Message
353Commands::Join(Bot *bot, String channel, String key)
354{
355 CHECK_CONNECTION;
356
a6339323 357 if (!Utils::valid_channel_name_p(channel))
cb21075d 358 return InvalidChannel(channel);
359
360 // We change the key only if we are not on the channel.
361 // We don't trust the user...
362 if (!CHANNEL(channel)) {
363 if (bot->wantedChannels[channel])
364 bot->wantedChannels[channel]->key = key;
365 else {
366 bot->wantedChannels[channel] = new wantedChannel("", "", key);
367 }
368 }
369 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
370
371 return Ok;
372}
373
374Message
375Commands::Keep(Bot *bot, String channel, String modes)
376{
377 CHECK_CONNECTION;
378
379 Channel *c = CHANNEL(channel);
380
381 if (!c)
382 return NotOnChannel(channel);
383
384 c->keepModes = modes;
385
386 return Ok;
387}
388
389Message
390Commands::Kick(Bot *bot, String channel, String who, String reason)
391{
392 CHECK_CONNECTION;
393
394 Channel *c = CHANNEL(channel);
395
396 if (!c)
397 return NotOnChannel(channel);
398
399 if (!bot->iAmOp(channel))
400 return NotChannelOp(channel);
401
a6339323 402 if (Utils::wildcard_p(who)) {
cb21075d 403 Mask m(who);
404 for (std::map<String, User *, std::less<String> >::iterator it =
405 c->channelMemory.begin();
406 it != c->channelMemory.end();
407 ++it)
408 if (m.matches((*it).second->nick + "!" +
409 (*it).second->userhost) &&
410 (*it).second->getProt() < User::NO_KICK)
411 QUEUE->sendKick(channel, (*it).second->nick, reason);
412 } else {
413 User * u = c->getUser(who);
414 if (!u)
415 return UserNotFound(who, channel);
416 if (u->getProt() < User::NO_KICK)
417 QUEUE->sendKick(channel, who, reason);
418 else
419 return UserProtected(who, channel);
420 }
421
422 return Ok;
423}
424
425Message
426Commands::KickBan(Bot *bot, String channel, String who, String reason)
427{
428 CHECK_CONNECTION;
429
430 Message m = Commands::Ban(bot, channel, who);
431
432 if (m.getCode() == 0)
433 m = Commands::Kick(bot, channel, who, reason);
434
435 return m;
436}
437
438Message
439Commands::Lock(Bot *bot, String channel)
440{
441 CHECK_CONNECTION;
442
443 Channel *c = CHANNEL(channel);
444
445 if (!c)
446 return NotOnChannel(channel);
447
448 c->lockedTopic = true;
449
450 return Ok;
451}
452
453Message
454Commands::Mode(Bot *bot, String channel, String mode)
455{
456 CHECK_CONNECTION;
457
458 if (!CHANNEL(channel))
459 return NotOnChannel(channel);
460
461 if (!bot->iAmOp(channel))
462 return NotChannelOp(channel);
463
464 QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode);
465
466 return Ok;
467}
468
469Message
470Commands::Msg(Bot *bot, String who, String message)
471{
472 CHECK_CONNECTION;
473
474 if (who == "")
5c73c60a 475 {
476 return EmptyAddressee;
477 }
cb21075d 478
a6339323 479 if (Utils::channel_p(who))
5c73c60a 480 {
4cc479d8 481 if (!CHANNEL(who))
482 {
483 return NotOnChannel (who);
484 }
5c73c60a 485 }
cb21075d 486
487 if (message == "")
5c73c60a 488 {
489 return EmptyMessage;
490 }
cb21075d 491
6b7614a8 492 // Send multi-line messages as seperate privmsgs
493 StringTokenizer st_message (message);
494
495 while (st_message.more_tokens_p ('\n'))
496 {
497 QUEUE->sendPrivmsg(who, st_message.next_token ('\n'));
498 }
cb21075d 499
500 return Ok;
501}
502
503Message
504Commands::NextServer(Bot *bot)
505{
506 CHECK_CONNECTION;
507
508 if (bot->serverList->size() == 0)
509 return EmptyServerList;
510
511 if (!bot->canChangeServer())
512 return CanNotChangeServer;
513
514 QUEUE->sendQuit("Changing server");
515 bot->nextServer();
516
517 return Ok;
518}
519
520Message
521Commands::Nick(Bot *bot, String nick)
522{
523 CHECK_CONNECTION;
524
6b7614a8 525 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
cb21075d 526 return InvalidNick(nick);
527
528 bot->wantedNickName = nick;
529 QUEUE->sendNick(nick);
530
531 return Ok;
532}
533
534Message
535Commands::Notice(Bot *bot, String who, String message)
536{
537 CHECK_CONNECTION;
538
539 if (who == "")
540 return EmptyAddressee;
541
5aec4622 542 // if (Utils::channel_p(who))
543 // return NotToChannel;
cb21075d 544
545 if (message == "")
546 return EmptyMessage;
547
6b7614a8 548 // Send multiple lines as multiple notices
549 StringTokenizer st_message (message);
550
551 while (st_message.more_tokens_p ('\n'))
552 {
553 QUEUE->sendNotice(who, st_message.next_token ('\n'));
554 }
cb21075d 555
556 return Ok;
557}
558
559Message
560Commands::Op(Bot *bot, String channel, String who)
561{
562 CHECK_CONNECTION;
563
564 Channel *c = CHANNEL(channel);
565
566 if (!c)
567 return NotOnChannel(channel);
568
569 if (!bot->iAmOp(channel))
570 return NotChannelOp(channel);
571
a6339323 572 if (Utils::wildcard_p(who))
cb21075d 573 return MassOpNotAllowed;
574
575 User *u = c->getUser(who);
576 if (!u)
577 return UserNotFound(who, channel);
578
579 ShitEntry *se = bot->shitList->getShit(who, channel);
580 if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
581 return UserOnShitList(who);
582
583 QUEUE->sendChannelMode(channel, "+o", who);
584
585 return Ok;
586}
587
588
589Message
590Commands::Part(Bot *bot, String channel)
591{
592 CHECK_CONNECTION;
593
594 if (!CHANNEL(channel))
595 return NotOnChannel(channel);
596
597 wantedChannel *w = bot->wantedChannels[channel];
598 bot->wantedChannels.erase(channel);
599 delete w;
600 QUEUE->sendPart(channel);
601
602 return Ok;
603}
604
605Message
606Commands::Reconnect(Bot *bot)
607{
608 CHECK_CONNECTION;
609
610 if (!bot->canChangeServer())
611 return CanNotChangeServer;
612
613 QUEUE->sendQuit("Reconnecting");
614 bot->reconnect();
615
616 return Ok;
617}
618
619Message
620Commands::Say(Bot *bot, String channel, String message)
621{
4cc479d8 622 return Commands::Msg (bot, channel, message);
cb21075d 623}
624
625
626Message
627Commands::Server(Bot *bot, int number)
628{
629 CHECK_CONNECTION;
630
631 if (number < 0 || number >= bot->serverList->size())
632 return InvalidServerNumber(number);
633
634 if (!bot->canChangeServer())
635 return CanNotChangeServer;
636
637 QUEUE->sendQuit("Changing server");
638 QUEUE->flush();
639 bot->connect(number);
640
641 return Ok;
642}
643
e171dcce 644Message
645Commands::SetFloodRate(Bot *bot, unsigned int num_messages)
646{
647 if (num_messages > 0)
648 {
649 bot->MAX_MESSAGES = num_messages;
650 return Ok;
651 }
652 return InvalidParameters;
653}
654
cb21075d 655Message
656Commands::SetVersion(Bot *bot, String str)
657{
658 if (str.length() == 0)
659 return InvalidParameters;
660
661 bot->versionString = str;
662 return Ok;
663}
664
665Message
666Commands::TBan(Bot *bot, String channel, String who, int seconds)
667{
668 CHECK_CONNECTION;
669
670 Channel *c = CHANNEL(channel);
cf8ea873 671 String dest;
cb21075d 672
cf8ea873 673 // Make sure all of the inputs are valid
cb21075d 674 if (!c)
cf8ea873 675 {
676 return NotOnChannel(channel);
677 }
cb21075d 678
679 if (!bot->iAmOp(channel))
cf8ea873 680 {
681 return NotChannelOp(channel);
682 }
cb21075d 683
684 if (seconds <= 0)
cf8ea873 685 {
686 return InvalidTime(seconds);
687 }
cb21075d 688
cf8ea873 689 // Look for user
a6339323 690 if (!Utils::wildcard_p(who))
cf8ea873 691 {
692 dest = bot->getUserhost(channel, who);
693 }
cb21075d 694 else
cf8ea873 695 {
696 dest = who;
697 }
cb21075d 698
699 if (dest.length() == 0)
cf8ea873 700 {
701 return UserNotFound(who, channel);
702 }
703
cb21075d 704
a6339323 705 dest = Utils::make_wildcard(dest);
cb21075d 706 Mask m(dest);
707
cf8ea873 708 // Make sure the user isn't protected from bans
cb21075d 709 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
710 it != bot->userList->l.end();
711 it++)
cf8ea873 712 {
713 if (m.matches((*it)->mask) &&
714 (*it)->channelMask.matches(channel) &&
715 (*it)->prot >= User::NO_BAN)
716 {
717 return UserProtected(who, channel);
718 }
719 }
cb21075d 720
cf8ea873 721 // Clear existing bans on the user
cb21075d 722 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
723 it != c->channelBanlist.end(); ++it)
cf8ea873 724 {
725 if (m.matches((*it)->banMask))
726 {
727 QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
728 }
729 }
cb21075d 730
cf8ea873 731 // Ban them
cb21075d 732 CHANNEL(channel)->addBan(dest, seconds);
733 QUEUE->sendChannelMode(channel, "+b", dest);
734 bot->todoList->addDeban(channel, dest, seconds);
cf8ea873 735
736 return Ok;
cb21075d 737}
738
739
740Message
741Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason)
742{
743 CHECK_CONNECTION;
744
745 Message m = Commands::TBan(bot, channel, who, seconds);
746
747 if (m.getCode() == 0)
748 m = Commands::Kick(bot, channel, who, reason);
749
750 return m;
751}
752
753
754Message
755Commands::Topic(Bot *bot, String channel, String topic)
756{
757 CHECK_CONNECTION;
758
759 Channel *c = CHANNEL(channel);
760
761 if (!c)
762 return NotOnChannel(channel);
763
764 if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED))
765 return CanNotChangeTopic(channel);
766
767 if (c->lockedTopic)
768 return TopicLocked(channel);
769
770 QUEUE->sendTopic(channel, topic);
771
772 return Ok;
773}
774
775
776Message
777Commands::Unlock(Bot *bot, String channel)
778{
779 CHECK_CONNECTION;
780
781 Channel *c = CHANNEL(channel);
782
783 if (!c)
784 return NotOnChannel(channel);
785
786 c->lockedTopic = false;
787
788 return Ok;
789}