1 // Commands.C -*- C++ -*-
2 // Copyright (c) 1998 Etienne BERNARD
3 // Copyright (C) 2002,2005 Clinton Ebadi
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
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.
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.
23 #include "StringTokenizer.H"
26 #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
29 Commands::Action(Bot *bot, String channel, String message)
33 if (!CHANNEL(channel))
34 return NotOnChannel(channel);
36 if (message.length() == 0)
37 return InvalidParameters;
39 Commands::CTCP (bot, channel, "ACTION", message);
45 Commands::AddUser(Bot *bot, String who, String maskChannel, int level,
46 int prot, bool aop, std::time_t expire, String password)
48 // Gah, fix this (makes bot segfault)
49 if (who.length() == 0 ||
50 maskChannel.length() == 0 ||
52 level > User::FRIEND ||
55 return InvalidParameters;
59 if (!Utils::wildcard_p(who))
61 mask = bot->getUserhost("", who);
62 if (mask.length() == 0)
67 // Aha! This was before the brace...segfault gone
68 mask = Utils::make_wildcard(mask);
70 if (bot->userList->isInUserList(mask, maskChannel))
72 return AlreadyInUserlist(mask, maskChannel);
75 bot->userList->addUser(mask, maskChannel, level, prot, aop,
84 Commands::AddServer(Bot *bot, String servername, int port)
87 return InvalidPort(port);
89 bot->serverList->addServer(new class Server(servername, port));
96 Commands::AddShit(Bot *bot, String mask, String maskChannel,
97 int level, time_t expiration, String reason)
99 if (mask.length() == 0 || maskChannel.length() == 0 ||
100 level < 0 || level > ShitEntry::SHIT_NODEBAN)
101 return InvalidParameters;
104 reason = "You're on my shitlist, lamer";
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);
117 if (bot->userList->getMaxProt(mask, maskChannel) > 0)
118 return UserProtected(who, maskChannel);
120 bot->shitList->addShit(mask, maskChannel, level, expiration, reason);
127 Commands::Ban(Bot *bot, String channel, String who)
131 Channel *c = CHANNEL(channel);
134 return NotOnChannel(channel);
136 if (!bot->iAmOp(channel))
137 return NotChannelOp(channel);
141 if (!Utils::wildcard_p(who))
142 dest = bot->getUserhost(channel, who);
146 if (dest.length() == 0)
147 return NotFound(who);
149 dest = Utils::make_wildcard(dest);
152 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
153 it != bot->userList->l.end();
155 if (m.matches((*it)->mask) &&
156 (*it)->channelMask.matches(channel) &&
157 (*it)->prot >= User::NO_BAN)
158 return UserProtected(who, channel);
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());
165 QUEUE->sendChannelMode(channel, "+b", dest);
171 Commands::CTCP (Bot *bot, std::string target, std::string command,
178 return EmptyAddressee;
183 return InvalidParameters;
191 if (Utils::channel_p (target) && !CHANNEL (target))
193 return NotOnChannel (target);
197 // Send multi-line messages as seperate privmsgs
198 StringTokenizer st_message (message);
200 while (st_message.more_tokens_p ('\n'))
202 QUEUE->sendCTCP (target, command, st_message.next_token ('\n'));
209 Commands::CTCPReply (Bot *bot, std::string target, std::string command,
216 return EmptyAddressee;
221 return InvalidParameters;
229 // CTCP-REPLY cannot go to a channel
230 if (Utils::channel_p (target))
236 // Send multi-line messages as seperate privmsgs
237 StringTokenizer st_message (message);
239 while (st_message.more_tokens_p ('\n'))
241 QUEUE->sendCTCPReply (target, command, st_message.next_token ('\n'));
249 Commands::Cycle(Bot *bot, String channel)
253 if (!CHANNEL(channel))
254 return NotOnChannel(channel);
256 QUEUE->sendPart(channel);
257 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
263 Commands::Deban(Bot *bot, String channel, String who)
267 Channel *c = CHANNEL(channel);
270 return NotOnChannel(channel);
272 if (!bot->iAmOp(channel))
273 return NotChannelOp(channel);
277 if (!Utils::wildcard_p(who))
278 dest = bot->getUserhost(channel, who);
282 if (dest.length() == 0)
283 return UserNotFound(who, channel);
285 dest = Utils::make_wildcard(dest);
288 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
289 it != c->channelBanlist.end(); ++it)
290 if (m.matches((*it)->getMask())) {
291 // Let's see if the ban is in the shitlist
292 ShitEntry *se = bot->shitList->getShit((*it)->getMask(), channel);
293 if (!se || !se->isStillValid() ||
294 se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
295 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask());
302 Commands::DelServer(Bot *bot, int number)
304 if (number < 0 || number >= bot->serverList->size())
305 return InvalidServerNumber(number);
307 bot->serverList->delServer(number);
313 Commands::DelUser(Bot *bot, String who, String maskChannel)
315 if (who.length() == 0 || maskChannel.length() == 0)
316 return InvalidParameters;
320 if (!Utils::wildcard_p(who)) {
321 dest = bot->getUserhost("", who);
322 if (dest.length() == 0)
323 return NotFound(who);
324 dest = Utils::make_wildcard(who);
327 if (!bot->userList->isInUserList(dest, maskChannel))
328 return NotInUserlist(who);
330 bot->userList->removeUser(dest, maskChannel);
337 Commands::DelShit(Bot *bot, String who, String maskChannel)
339 if (who.length() == 0 || maskChannel.length() == 0)
340 return InvalidParameters;
344 if (!Utils::wildcard_p(who)) {
345 dest = bot->getUserhost("", who);
346 if (dest.length() == 0)
347 return NotFound(who);
348 dest = Utils::make_wildcard(who);
351 if (!bot->shitList->getShit(dest, maskChannel))
352 return NotInShitlist(who);
354 bot->shitList->delShit(dest, maskChannel);
360 Commands::Deop(Bot *bot, String channel, String who)
364 Channel *c = CHANNEL(channel);
367 return NotOnChannel(channel);
369 if (!bot->iAmOp(channel))
370 return NotChannelOp(channel);
372 if (!Utils::wildcard_p(who)) {
373 User *u = c->getUser(who);
375 return UserNotFound(who, channel);
376 if (!(u->mode & User::OP_MODE))
377 return UserNotOp(who, channel);
378 if (u->getProt() >= User::NO_DEOP)
379 return UserProtected(who, channel);
380 QUEUE->sendChannelMode(channel, "-o", who);
383 for (std::map<String, User *, std::less<String> >::iterator
384 it = c->channelMemory.begin();
385 it != c->channelMemory.end(); ++it) {
386 if (m.matches((*it).second->nick + "!" +
387 (*it).second->userhost) &&
388 (*it).second->getProt() < User::NO_DEOP &&
389 ((*it).second->mode & User::OP_MODE))
390 QUEUE->sendChannelMode(channel, "-o", (*it).second->nick);
398 Commands::Die(Bot *bot, String reason)
402 QUEUE->sendQuit(reason);
409 Commands::Do(Bot *bot, String command)
413 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
418 Commands::Invite(Bot *bot, String channel, String who)
422 if (!bot->iAmOp(channel))
423 return NotChannelOp(channel);
425 QUEUE->sendInvite(channel, who);
431 Commands::Join(Bot *bot, String channel, String key)
435 if (!Utils::valid_channel_name_p(channel))
436 return InvalidChannel(channel);
438 // We change the key only if we are not on the channel.
439 // We don't trust the user...
440 if (!CHANNEL(channel)) {
441 if (bot->wantedChannels[channel])
442 bot->wantedChannels[channel]->key = key;
444 bot->wantedChannels[channel] = new wantedChannel("", "", key);
447 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
453 Commands::Keep(Bot *bot, String channel, String modes)
457 Channel *c = CHANNEL(channel);
460 return NotOnChannel(channel);
462 c->keepModes = modes;
468 Commands::Kick(Bot *bot, String channel, String who, String reason)
472 Channel *c = CHANNEL(channel);
475 return NotOnChannel(channel);
477 if (!bot->iAmOp(channel))
478 return NotChannelOp(channel);
480 if (Utils::wildcard_p(who)) {
482 for (std::map<String, User *, std::less<String> >::iterator it =
483 c->channelMemory.begin();
484 it != c->channelMemory.end();
486 if (m.matches((*it).second->nick + "!" +
487 (*it).second->userhost) &&
488 (*it).second->getProt() < User::NO_KICK)
489 QUEUE->sendKick(channel, (*it).second->nick, reason);
491 User * u = c->getUser(who);
493 return UserNotFound(who, channel);
494 if (u->getProt() < User::NO_KICK)
495 QUEUE->sendKick(channel, who, reason);
497 return UserProtected(who, channel);
504 Commands::KickBan(Bot *bot, String channel, String who, String reason)
508 Message m = Commands::Ban(bot, channel, who);
510 if (m.getCode() == 0)
511 m = Commands::Kick(bot, channel, who, reason);
517 Commands::Lock(Bot *bot, String channel)
521 Channel *c = CHANNEL(channel);
524 return NotOnChannel(channel);
526 c->lockedTopic = true;
532 Commands::Mode(Bot *bot, String channel, String mode)
536 if (!CHANNEL(channel))
537 return NotOnChannel(channel);
539 if (!bot->iAmOp(channel))
540 return NotChannelOp(channel);
542 QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode);
548 Commands::Msg(Bot *bot, String who, String message)
554 return EmptyAddressee;
557 if (Utils::channel_p(who))
561 return NotOnChannel (who);
570 // Send multi-line messages as seperate privmsgs
571 StringTokenizer st_message (message);
573 while (st_message.more_tokens_p ('\n'))
575 QUEUE->sendPrivmsg(who, st_message.next_token ('\n'));
582 Commands::NextServer(Bot *bot)
586 if (bot->serverList->size() == 0)
587 return EmptyServerList;
589 if (!bot->canChangeServer())
590 return CanNotChangeServer;
593 // Run hooks/disconnect
594 bot->botInterp->RunHooks
596 bot->serverConnection->server->getHostName (),
598 (Utils::str2scm (bot->serverConnection->server->getHostName ()),
602 QUEUE->sendQuit("Changing server");
609 Commands::Nick(Bot *bot, String nick)
613 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
614 return InvalidNick(nick);
616 bot->wantedNickName = nick;
617 QUEUE->sendNick(nick);
623 Commands::Notice(Bot *bot, String who, String message)
628 return EmptyAddressee;
630 // if (Utils::channel_p(who))
631 // return NotToChannel;
636 // Send multiple lines as multiple notices
637 StringTokenizer st_message (message);
639 while (st_message.more_tokens_p ('\n'))
641 QUEUE->sendNotice(who, st_message.next_token ('\n'));
648 Commands::Op(Bot *bot, String channel, String who)
652 Channel *c = CHANNEL(channel);
655 return NotOnChannel(channel);
657 if (!bot->iAmOp(channel))
658 return NotChannelOp(channel);
660 if (Utils::wildcard_p(who))
661 return MassOpNotAllowed;
663 User *u = c->getUser(who);
665 return UserNotFound(who, channel);
667 ShitEntry *se = bot->shitList->getShit(who, channel);
668 if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
669 return UserOnShitList(who);
671 QUEUE->sendChannelMode(channel, "+o", who);
678 Commands::Part(Bot *bot, String channel)
682 if (!CHANNEL(channel))
683 return NotOnChannel(channel);
685 wantedChannel *w = bot->wantedChannels[channel];
686 bot->wantedChannels.erase(channel);
688 QUEUE->sendPart(channel);
694 Commands::Reconnect(Bot *bot)
698 if (!bot->canChangeServer())
699 return CanNotChangeServer;
701 QUEUE->sendQuit("Reconnecting");
708 Commands::Say(Bot *bot, String channel, String message)
710 return Commands::Msg (bot, channel, message);
715 Commands::Server(Bot *bot, int number)
719 if (number < 0 || number >= bot->serverList->size())
720 return InvalidServerNumber(number);
722 if (!bot->canChangeServer())
723 return CanNotChangeServer;
725 QUEUE->sendQuit("Changing server");
727 bot->connect(number);
733 Commands::SetFloodRate(Bot *bot, unsigned int num_messages)
735 if (num_messages > 0)
737 bot->MAX_MESSAGES = num_messages;
740 return InvalidParameters;
744 Commands::SetVersion(Bot *bot, String str)
746 if (str.length() == 0)
747 return InvalidParameters;
749 bot->versionString = str;
754 Commands::TBan(Bot *bot, String channel, String who, int seconds)
758 Channel *c = CHANNEL(channel);
761 // Make sure all of the inputs are valid
764 return NotOnChannel(channel);
767 if (!bot->iAmOp(channel))
769 return NotChannelOp(channel);
774 return InvalidTime(seconds);
778 if (!Utils::wildcard_p(who))
780 dest = bot->getUserhost(channel, who);
787 if (dest.length() == 0)
789 return UserNotFound(who, channel);
793 dest = Utils::make_wildcard(dest);
796 // Make sure the user isn't protected from bans
797 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
798 it != bot->userList->l.end();
801 if (m.matches((*it)->mask) &&
802 (*it)->channelMask.matches(channel) &&
803 (*it)->prot >= User::NO_BAN)
805 return UserProtected(who, channel);
809 // Clear existing bans on the user
810 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
811 it != c->channelBanlist.end(); ++it)
813 if (m.matches((*it)->banMask))
815 QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
820 CHANNEL(channel)->addBan(dest, seconds);
821 QUEUE->sendChannelMode(channel, "+b", dest);
822 bot->todoList->addDeban(channel, dest, seconds);
829 Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason)
833 Message m = Commands::TBan(bot, channel, who, seconds);
835 if (m.getCode() == 0)
836 m = Commands::Kick(bot, channel, who, reason);
843 Commands::Topic(Bot *bot, String channel, String topic)
847 Channel *c = CHANNEL(channel);
850 return NotOnChannel(channel);
852 if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED))
853 return CanNotChangeTopic(channel);
856 return TopicLocked(channel);
858 QUEUE->sendTopic(channel, topic);
865 Commands::Unlock(Bot *bot, String channel)
869 Channel *c = CHANNEL(channel);
872 return NotOnChannel(channel);
874 c->lockedTopic = false;