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