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