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