[project @ 2005-06-28 03:16:45 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 QUEUE->sendCTCP (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::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
184 Message
185 Commands::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
199 if (!Utils::wildcard_p(who))
200 dest = bot->getUserhost(channel, who);
201 else
202 dest = who;
203
204 if (dest.length() == 0)
205 return UserNotFound(who, channel);
206
207 dest = Utils::make_wildcard(dest);
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
223 Message
224 Commands::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
234 Message
235 Commands::DelUser(Bot *bot, String who, String maskChannel)
236 {
237 if (who.length() == 0 || maskChannel.length() == 0)
238 return InvalidParameters;
239
240 String dest;
241
242 if (!Utils::wildcard_p(who)) {
243 dest = bot->getUserhost("", who);
244 if (dest.length() == 0)
245 return NotFound(who);
246 dest = Utils::make_wildcard(who);
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
258 Message
259 Commands::DelShit(Bot *bot, String who, String maskChannel)
260 {
261 if (who.length() == 0 || maskChannel.length() == 0)
262 return InvalidParameters;
263
264 String dest;
265
266 if (!Utils::wildcard_p(who)) {
267 dest = bot->getUserhost("", who);
268 if (dest.length() == 0)
269 return NotFound(who);
270 dest = Utils::make_wildcard(who);
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
281 Message
282 Commands::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
294 if (!Utils::wildcard_p(who)) {
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
319 Message
320 Commands::Die(Bot *bot, String reason)
321 {
322 CHECK_CONNECTION;
323
324 QUEUE->sendQuit(reason);
325 bot->stop = true;
326
327 return Ok;
328 }
329
330 Message
331 Commands::Do(Bot *bot, String command)
332 {
333 CHECK_CONNECTION;
334
335 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
336 return Ok;
337 }
338
339 Message
340 Commands::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
352 Message
353 Commands::Join(Bot *bot, String channel, String key)
354 {
355 CHECK_CONNECTION;
356
357 if (!Utils::valid_channel_name_p(channel))
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
374 Message
375 Commands::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
389 Message
390 Commands::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
402 if (Utils::wildcard_p(who)) {
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
425 Message
426 Commands::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
438 Message
439 Commands::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
453 Message
454 Commands::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
469 Message
470 Commands::Msg(Bot *bot, String who, String message)
471 {
472 CHECK_CONNECTION;
473
474 if (who == "")
475 {
476 return EmptyAddressee;
477 }
478
479 if (Utils::channel_p(who))
480 {
481 if (!CHANNEL(who))
482 {
483 return NotOnChannel (who);
484 }
485 }
486
487 if (message == "")
488 {
489 return EmptyMessage;
490 }
491
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 }
499
500 return Ok;
501 }
502
503 Message
504 Commands::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
520 Message
521 Commands::Nick(Bot *bot, String nick)
522 {
523 CHECK_CONNECTION;
524
525 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
526 return InvalidNick(nick);
527
528 bot->wantedNickName = nick;
529 QUEUE->sendNick(nick);
530
531 return Ok;
532 }
533
534 Message
535 Commands::Notice(Bot *bot, String who, String message)
536 {
537 CHECK_CONNECTION;
538
539 if (who == "")
540 return EmptyAddressee;
541
542 // if (Utils::channel_p(who))
543 // return NotToChannel;
544
545 if (message == "")
546 return EmptyMessage;
547
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 }
555
556 return Ok;
557 }
558
559 Message
560 Commands::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
572 if (Utils::wildcard_p(who))
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
589 Message
590 Commands::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
605 Message
606 Commands::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
619 Message
620 Commands::Say(Bot *bot, String channel, String message)
621 {
622 return Commands::Msg (bot, channel, message);
623 }
624
625
626 Message
627 Commands::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
644 Message
645 Commands::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
655 Message
656 Commands::SetVersion(Bot *bot, String str)
657 {
658 if (str.length() == 0)
659 return InvalidParameters;
660
661 bot->versionString = str;
662 return Ok;
663 }
664
665 Message
666 Commands::TBan(Bot *bot, String channel, String who, int seconds)
667 {
668 CHECK_CONNECTION;
669
670 Channel *c = CHANNEL(channel);
671 String dest;
672
673 // Make sure all of the inputs are valid
674 if (!c)
675 {
676 return NotOnChannel(channel);
677 }
678
679 if (!bot->iAmOp(channel))
680 {
681 return NotChannelOp(channel);
682 }
683
684 if (seconds <= 0)
685 {
686 return InvalidTime(seconds);
687 }
688
689 // Look for user
690 if (!Utils::wildcard_p(who))
691 {
692 dest = bot->getUserhost(channel, who);
693 }
694 else
695 {
696 dest = who;
697 }
698
699 if (dest.length() == 0)
700 {
701 return UserNotFound(who, channel);
702 }
703
704
705 dest = Utils::make_wildcard(dest);
706 Mask m(dest);
707
708 // Make sure the user isn't protected from bans
709 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
710 it != bot->userList->l.end();
711 it++)
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 }
720
721 // Clear existing bans on the user
722 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
723 it != c->channelBanlist.end(); ++it)
724 {
725 if (m.matches((*it)->banMask))
726 {
727 QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
728 }
729 }
730
731 // Ban them
732 CHANNEL(channel)->addBan(dest, seconds);
733 QUEUE->sendChannelMode(channel, "+b", dest);
734 bot->todoList->addDeban(channel, dest, seconds);
735
736 return Ok;
737 }
738
739
740 Message
741 Commands::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
754 Message
755 Commands::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
776 Message
777 Commands::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 }