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
26 #include "ChannelList.H"
30 #include "ServerConnection.H"
31 #include "ServerList.H"
32 #include "ServerQueueItem.H"
33 #include "ShitEntry.H"
35 #include "StringTokenizer.H"
41 #include "BotInterp.H"
45 #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
48 Commands::Action(Bot *bot, String channel, String message)
52 if (!CHANNEL(channel))
53 return NotOnChannel(channel);
55 if (message.length() == 0)
56 return InvalidParameters;
58 Commands::CTCP (bot, channel, "ACTION", message);
64 Commands::AddUser(Bot *bot, String who, String maskChannel, int level,
65 int prot, bool aop, std::time_t expire, String password)
67 // Gah, fix this (makes bot segfault)
68 if (who.length() == 0 ||
69 maskChannel.length() == 0 ||
71 level > User::FRIEND ||
74 return InvalidParameters;
78 if (!Utils::wildcard_p(who))
80 mask = bot->getUserhost("", who);
81 if (mask.length() == 0)
86 // Aha! This was before the brace...segfault gone
87 mask = Utils::make_wildcard(mask);
89 if (bot->userList->isInUserList(mask, maskChannel))
91 return AlreadyInUserlist(mask, maskChannel);
94 bot->userList->addUser(mask, maskChannel, level, prot, aop,
103 Commands::AddServer(Bot *bot, String servername, int port)
106 return InvalidPort(port);
108 bot->serverList->addServer(new class Server(servername, port));
115 Commands::AddShit(Bot *bot, String mask, String maskChannel,
116 int level, time_t expiration, String reason)
118 if (mask.length() == 0 || maskChannel.length() == 0 ||
119 level < 0 || level > ShitEntry::SHIT_NODEBAN)
120 return InvalidParameters;
123 reason = "You're on my shitlist, lamer";
127 if (!Utils::wildcard_p(mask)) {
128 mask = bot->getUserhost("", who);
129 if (mask.length() == 0)
130 return NotFound(who);
131 mask = Utils::make_wildcard(mask);
132 if (bot->shitList->getShit(mask, maskChannel))
133 return AlreadyInShitlist(mask, maskChannel);
136 if (bot->userList->getMaxProt(mask, maskChannel) > 0)
137 return UserProtected(who, maskChannel);
139 bot->shitList->addShit(mask, maskChannel, level, expiration, reason);
146 Commands::Ban(Bot *bot, String channel, String who)
150 Channel *c = CHANNEL(channel);
153 return NotOnChannel(channel);
155 if (!bot->iAmOp(channel))
156 return NotChannelOp(channel);
160 if (!Utils::wildcard_p(who))
161 dest = bot->getUserhost(channel, who);
165 if (dest.length() == 0)
166 return NotFound(who);
168 dest = Utils::make_wildcard(dest);
171 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
172 it != bot->userList->l.end();
174 if (m.matches((*it)->mask) &&
175 (*it)->channelMask.matches(channel) &&
176 (*it)->prot >= User::NO_BAN)
177 return UserProtected(who, channel);
186 Commands::CTCP (Bot *bot, std::string target, std::string command,
193 return EmptyAddressee;
198 return InvalidParameters;
206 if (Utils::channel_p (target) && !CHANNEL (target))
208 return NotOnChannel (target);
212 // Send multi-line messages as seperate privmsgs
213 StringTokenizer st_message (message);
215 while (st_message.more_tokens_p ('\n'))
217 QUEUE->sendCTCP (target, command, st_message.next_token ('\n'));
224 Commands::CTCPReply (Bot *bot, std::string target, std::string command,
231 return EmptyAddressee;
236 return InvalidParameters;
244 // CTCP-REPLY cannot go to a channel
245 if (Utils::channel_p (target))
251 // Send multi-line messages as seperate privmsgs
252 StringTokenizer st_message (message);
254 while (st_message.more_tokens_p ('\n'))
256 QUEUE->sendCTCPReply (target, command, st_message.next_token ('\n'));
264 Commands::Cycle(Bot *bot, String channel)
268 if (!CHANNEL(channel))
269 return NotOnChannel(channel);
271 QUEUE->sendPart(channel);
272 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
278 Commands::Deban(Bot *bot, String channel, String who)
282 Channel *c = CHANNEL(channel);
285 return NotOnChannel(channel);
287 if (!bot->iAmOp(channel))
288 return NotChannelOp(channel);
292 if (!Utils::wildcard_p(who))
293 dest = bot->getUserhost(channel, who);
297 if (dest.length() == 0)
298 return UserNotFound(who, channel);
300 dest = Utils::make_wildcard(dest);
303 BanList::MatchList matches = c->channelBanlist.find_matches (m);
305 for (BanList::MatchList::iterator it = matches.begin ();
310 // Let's see if the ban is in the shitlist
311 ShitEntry *se = bot->shitList->getShit(it->getMask(), channel);
312 if (!se || !se->isStillValid() ||
313 se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
321 Commands::DelServer(Bot *bot, int number)
323 if (number < 0 || number >= bot->serverList->size())
324 return InvalidServerNumber(number);
326 bot->serverList->delServer(number);
332 Commands::DelUser(Bot *bot, String who, String maskChannel)
334 if (who.length() == 0 || maskChannel.length() == 0)
335 return InvalidParameters;
339 if (!Utils::wildcard_p(who)) {
340 dest = bot->getUserhost("", who);
341 if (dest.length() == 0)
342 return NotFound(who);
343 dest = Utils::make_wildcard(who);
346 if (!bot->userList->isInUserList(dest, maskChannel))
347 return NotInUserlist(who);
349 bot->userList->removeUser(dest, maskChannel);
356 Commands::DelShit(Bot *bot, String who, String maskChannel)
358 if (who.length() == 0 || maskChannel.length() == 0)
359 return InvalidParameters;
363 if (!Utils::wildcard_p(who)) {
364 dest = bot->getUserhost("", who);
365 if (dest.length() == 0)
366 return NotFound(who);
367 dest = Utils::make_wildcard(who);
370 if (!bot->shitList->getShit(dest, maskChannel))
371 return NotInShitlist(who);
373 bot->shitList->delShit(dest, maskChannel);
378 Commands::deop_wildcard::deop_wildcard
379 (Bot *b, Mask &m, String &c)
380 : bot (b), mask (m), channel (c)
384 Commands::deop_wildcard::operator() (const User &user)
386 if (mask.matches(user.nick + "!" + user.userhost)
387 && user.getProt() < User::NO_DEOP
388 && (user.mode & User::OP_MODE))
389 QUEUE->sendChannelMode(channel, "-o", user.nick);
393 Commands::Deop(Bot *bot, String channel, String who)
397 Channel *c = CHANNEL(channel);
400 return NotOnChannel(channel);
402 if (!bot->iAmOp(channel))
403 return NotChannelOp(channel);
405 if (!Utils::wildcard_p(who)) {
408 User u = c->getUser(who);
410 if (!(u.mode & User::OP_MODE))
411 return UserNotOp(who, channel);
412 if (u.getProt() >= User::NO_DEOP)
413 return UserProtected(who, channel);
414 QUEUE->sendChannelMode(channel, "-o", who);
416 catch (const ChannelUserList::user_not_found &e)
418 return UserNotFound(e.name, channel);
422 deop_wildcard f (bot, m, channel);
423 c->for_each_channel_users (f);
429 Commands::Die(Bot *bot, String reason)
433 QUEUE->sendQuit(reason);
440 Commands::Do(Bot *bot, String command)
444 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
449 Commands::Invite(Bot *bot, String channel, String who)
453 if (!bot->iAmOp(channel))
454 return NotChannelOp(channel);
456 QUEUE->sendInvite(channel, who);
462 Commands::Join(Bot *bot, String channel, String key)
466 if (!Utils::valid_channel_name_p(channel))
467 return InvalidChannel(channel);
469 // We change the key only if we are not on the channel.
470 // We don't trust the user...
471 if (!CHANNEL(channel)) {
472 if (bot->wantedChannels[channel])
473 bot->wantedChannels[channel]->key = static_cast<std::string> (key);
475 bot->wantedChannels[channel] = new wantedChannel("", "", key);
478 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
484 Commands::Keep(Bot *bot, String channel, String modes)
488 Channel *c = CHANNEL(channel);
491 return NotOnChannel(channel);
493 c->keepModes = modes;
498 Commands::kick_wildcard::kick_wildcard
499 (Bot *b, Mask &m, String &c, String &r)
500 : bot (b), mask (m), channel (c), reason (r)
504 Commands::kick_wildcard::operator() (const User &user)
506 if (mask.matches(user.nick + "!" + user.userhost) &&
507 user.getProt() < User::NO_KICK)
508 QUEUE->sendKick(channel, user.nick, reason);
512 Commands::Kick(Bot *bot, String channel, String who, String reason)
516 Channel *c = CHANNEL(channel);
519 return NotOnChannel(channel);
521 if (!bot->iAmOp(channel))
522 return NotChannelOp(channel);
524 if (Utils::wildcard_p(who)) {
526 kick_wildcard f (bot, m, channel, reason);
527 c->for_each_channel_users (f);
531 User u = c->getUser(who);
533 if (u.getProt() < User::NO_KICK)
534 QUEUE->sendKick(channel, who, reason);
536 return UserProtected(who, channel);
538 catch (const ChannelUserList::user_not_found &e)
540 return UserNotFound(e.name, channel);
548 Commands::KickBan(Bot *bot, String channel, String who, String reason)
552 Message m = Commands::Ban(bot, channel, who);
554 if (m.getCode() == 0)
555 m = Commands::Kick(bot, channel, who, reason);
561 Commands::Lock(Bot *bot, String channel)
565 Channel *c = CHANNEL(channel);
568 return NotOnChannel(channel);
570 c->lockedTopic = true;
576 Commands::Mode(Bot *bot, String channel, String mode)
580 if (!CHANNEL(channel))
581 return NotOnChannel(channel);
583 if (!bot->iAmOp(channel))
584 return NotChannelOp(channel);
586 QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode);
592 Commands::Msg(Bot *bot, String who, String message)
598 return EmptyAddressee;
601 if (Utils::channel_p(who))
605 return NotOnChannel (who);
614 // Send multi-line messages as seperate privmsgs
615 StringTokenizer st_message (message);
617 while (st_message.more_tokens_p ('\n'))
619 QUEUE->sendPrivmsg(who, st_message.next_token ('\n'));
626 Commands::NextServer(Bot *bot)
630 if (bot->serverList->size() == 0)
631 return EmptyServerList;
633 if (!bot->canChangeServer())
634 return CanNotChangeServer;
637 // Run hooks/disconnect
638 bot->botInterp->RunHooks
640 bot->serverConnection->server->getHostName (),
642 (Utils::str2scm (bot->serverConnection->server->getHostName ()),
646 QUEUE->sendQuit("Changing server");
653 Commands::Nick(Bot *bot, String nick)
657 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
658 return InvalidNick(nick);
660 bot->wantedNickName = nick;
661 QUEUE->sendNick(nick);
667 Commands::Notice(Bot *bot, String who, String message)
672 return EmptyAddressee;
674 // if (Utils::channel_p(who))
675 // return NotToChannel;
680 // Send multiple lines as multiple notices
681 StringTokenizer st_message (message);
683 while (st_message.more_tokens_p ('\n'))
685 QUEUE->sendNotice(who, st_message.next_token ('\n'));
692 Commands::Op(Bot *bot, String channel, String who)
696 Channel *c = CHANNEL(channel);
699 return NotOnChannel(channel);
701 if (!bot->iAmOp(channel))
702 return NotChannelOp(channel);
704 if (Utils::wildcard_p(who))
705 return MassOpNotAllowed;
709 User u = c->getUser(who);
711 ShitEntry *se = bot->shitList->getShit(who, channel);
712 if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
713 return UserOnShitList(who);
715 QUEUE->sendChannelMode(channel, "+o", who);
717 catch (const ChannelUserList::user_not_found &e)
719 return UserNotFound(e.name, channel);
727 Commands::Part(Bot *bot, String channel)
731 if (!CHANNEL(channel))
732 return NotOnChannel(channel);
734 wantedChannel *w = bot->wantedChannels[channel];
735 bot->wantedChannels.erase(channel);
737 QUEUE->sendPart(channel);
743 Commands::Reconnect(Bot *bot)
747 if (!bot->canChangeServer())
748 return CanNotChangeServer;
750 QUEUE->sendQuit("Reconnecting");
757 Commands::Say(Bot *bot, String channel, String message)
759 return Commands::Msg (bot, channel, message);
764 Commands::Server(Bot *bot, int number)
768 if (number < 0 || number >= bot->serverList->size())
769 return InvalidServerNumber(number);
771 if (!bot->canChangeServer())
772 return CanNotChangeServer;
774 QUEUE->sendQuit("Changing server");
776 bot->connect(number);
782 Commands::SetFloodRate(Bot *bot, unsigned int num_messages)
784 if (num_messages > 0)
786 bot->MAX_MESSAGES = num_messages;
789 return InvalidParameters;
793 Commands::SetVersion(Bot *bot, String str)
795 if (str.length() == 0)
796 return InvalidParameters;
798 bot->versionString = str;
803 Commands::TBan(Bot *bot, String channel, String who, int seconds)
807 Channel *c = CHANNEL(channel);
810 // Make sure all of the inputs are valid
812 return NotOnChannel(channel);
813 if (!bot->iAmOp(channel))
814 return NotChannelOp(channel);
816 return InvalidTime(seconds);
819 if (!Utils::wildcard_p(who))
820 dest = bot->getUserhost(channel, who);
824 if (dest.length() == 0)
825 return UserNotFound(who, channel);
827 dest = Utils::make_wildcard(dest);
830 // Make sure the user isn't protected from bans
831 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
832 it != bot->userList->l.end();
835 if (m.matches((*it)->mask) &&
836 (*it)->channelMask.matches(channel) &&
837 (*it)->prot >= User::NO_BAN)
839 return UserProtected(who, channel);
845 c->addBan(dest, seconds);
852 Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason)
856 Message m = Commands::TBan(bot, channel, who, seconds);
858 if (m.getCode() == 0)
859 m = Commands::Kick(bot, channel, who, reason);
866 Commands::Topic(Bot *bot, String channel, String topic)
870 Channel *c = CHANNEL(channel);
873 return NotOnChannel(channel);
875 if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED))
876 return CanNotChangeTopic(channel);
879 return TopicLocked(channel);
881 QUEUE->sendTopic(channel, topic);
888 Commands::Unlock(Bot *bot, String channel)
892 Channel *c = CHANNEL(channel);
895 return NotOnChannel(channel);
897 c->lockedTopic = false;
903 Commands::Who (Bot *bot, String target)
907 QUEUE->sendWho (target);
913 Commands::Whois (Bot *bot, String nick)
917 if (!Utils::valid_nickname_p (bot, nick))
919 return InvalidNick (nick);
923 QUEUE->sendWhois (nick);