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
24 #include "ChannelList.H"
28 #include "ServerConnection.H"
29 #include "ServerList.H"
30 #include "ServerQueueItem.H"
31 #include "ShitEntry.H"
33 #include "StringTokenizer.H"
40 #include "BotInterp.H"
44 #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
47 Commands::Action(Bot *bot, String channel, String message)
51 if (!CHANNEL(channel))
52 return NotOnChannel(channel);
54 if (message.length() == 0)
55 return InvalidParameters;
57 Commands::CTCP (bot, channel, "ACTION", message);
63 Commands::AddUser(Bot *bot, String who, String maskChannel, int level,
64 int prot, bool aop, std::time_t expire, String password)
66 // Gah, fix this (makes bot segfault)
67 if (who.length() == 0 ||
68 maskChannel.length() == 0 ||
70 level > User::FRIEND ||
73 return InvalidParameters;
77 if (!Utils::wildcard_p(who))
79 mask = bot->getUserhost("", who);
80 if (mask.length() == 0)
85 // Aha! This was before the brace...segfault gone
86 mask = Utils::make_wildcard(mask);
88 if (bot->userList->isInUserList(mask, maskChannel))
90 return AlreadyInUserlist(mask, maskChannel);
93 bot->userList->addUser(mask, maskChannel, level, prot, aop,
102 Commands::AddServer(Bot *bot, String servername, int port)
105 return InvalidPort(port);
107 bot->serverList->addServer(new class Server(servername, port));
114 Commands::AddShit(Bot *bot, String mask, String maskChannel,
115 int level, time_t expiration, String reason)
117 if (mask.length() == 0 || maskChannel.length() == 0 ||
118 level < 0 || level > ShitEntry::SHIT_NODEBAN)
119 return InvalidParameters;
122 reason = "You're on my shitlist, lamer";
126 if (!Utils::wildcard_p(mask)) {
127 mask = bot->getUserhost("", who);
128 if (mask.length() == 0)
129 return NotFound(who);
130 mask = Utils::make_wildcard(mask);
131 if (bot->shitList->getShit(mask, maskChannel))
132 return AlreadyInShitlist(mask, maskChannel);
135 if (bot->userList->getMaxProt(mask, maskChannel) > 0)
136 return UserProtected(who, maskChannel);
138 bot->shitList->addShit(mask, maskChannel, level, expiration, reason);
145 Commands::Ban(Bot *bot, String channel, String who)
149 Channel *c = CHANNEL(channel);
152 return NotOnChannel(channel);
154 if (!bot->iAmOp(channel))
155 return NotChannelOp(channel);
159 if (!Utils::wildcard_p(who))
160 dest = bot->getUserhost(channel, who);
164 if (dest.length() == 0)
165 return NotFound(who);
167 dest = Utils::make_wildcard(dest);
170 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
171 it != bot->userList->l.end();
173 if (m.matches((*it)->mask) &&
174 (*it)->channelMask.matches(channel) &&
175 (*it)->prot >= User::NO_BAN)
176 return UserProtected(who, channel);
178 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
179 it != c->channelBanlist.end(); ++it)
180 if (m.matches((*it)->getMask ()) && (*it)->getMask().getMask() != m.getMask())
181 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask().getMask());
183 QUEUE->sendChannelMode(channel, "+b", dest);
189 Commands::CTCP (Bot *bot, std::string target, std::string command,
196 return EmptyAddressee;
201 return InvalidParameters;
209 if (Utils::channel_p (target) && !CHANNEL (target))
211 return NotOnChannel (target);
215 // Send multi-line messages as seperate privmsgs
216 StringTokenizer st_message (message);
218 while (st_message.more_tokens_p ('\n'))
220 QUEUE->sendCTCP (target, command, st_message.next_token ('\n'));
227 Commands::CTCPReply (Bot *bot, std::string target, std::string command,
234 return EmptyAddressee;
239 return InvalidParameters;
247 // CTCP-REPLY cannot go to a channel
248 if (Utils::channel_p (target))
254 // Send multi-line messages as seperate privmsgs
255 StringTokenizer st_message (message);
257 while (st_message.more_tokens_p ('\n'))
259 QUEUE->sendCTCPReply (target, command, st_message.next_token ('\n'));
267 Commands::Cycle(Bot *bot, String channel)
271 if (!CHANNEL(channel))
272 return NotOnChannel(channel);
274 QUEUE->sendPart(channel);
275 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
281 Commands::Deban(Bot *bot, String channel, String who)
285 Channel *c = CHANNEL(channel);
288 return NotOnChannel(channel);
290 if (!bot->iAmOp(channel))
291 return NotChannelOp(channel);
295 if (!Utils::wildcard_p(who))
296 dest = bot->getUserhost(channel, who);
300 if (dest.length() == 0)
301 return UserNotFound(who, channel);
303 dest = Utils::make_wildcard(dest);
306 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
307 it != c->channelBanlist.end(); ++it)
308 if (m.matches((*it)->getMask())) {
309 // Let's see if the ban is in the shitlist
310 ShitEntry *se = bot->shitList->getShit((*it)->getMask().getMask(), channel);
311 if (!se || !se->isStillValid() ||
312 se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
313 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask().getMask());
320 Commands::DelServer(Bot *bot, int number)
322 if (number < 0 || number >= bot->serverList->size())
323 return InvalidServerNumber(number);
325 bot->serverList->delServer(number);
331 Commands::DelUser(Bot *bot, String who, String maskChannel)
333 if (who.length() == 0 || maskChannel.length() == 0)
334 return InvalidParameters;
338 if (!Utils::wildcard_p(who)) {
339 dest = bot->getUserhost("", who);
340 if (dest.length() == 0)
341 return NotFound(who);
342 dest = Utils::make_wildcard(who);
345 if (!bot->userList->isInUserList(dest, maskChannel))
346 return NotInUserlist(who);
348 bot->userList->removeUser(dest, maskChannel);
355 Commands::DelShit(Bot *bot, String who, String maskChannel)
357 if (who.length() == 0 || maskChannel.length() == 0)
358 return InvalidParameters;
362 if (!Utils::wildcard_p(who)) {
363 dest = bot->getUserhost("", who);
364 if (dest.length() == 0)
365 return NotFound(who);
366 dest = Utils::make_wildcard(who);
369 if (!bot->shitList->getShit(dest, maskChannel))
370 return NotInShitlist(who);
372 bot->shitList->delShit(dest, maskChannel);
378 Commands::Deop(Bot *bot, String channel, String who)
382 Channel *c = CHANNEL(channel);
385 return NotOnChannel(channel);
387 if (!bot->iAmOp(channel))
388 return NotChannelOp(channel);
390 if (!Utils::wildcard_p(who)) {
391 User *u = c->getUser(who);
393 return UserNotFound(who, channel);
394 if (!(u->mode & User::OP_MODE))
395 return UserNotOp(who, channel);
396 if (u->getProt() >= User::NO_DEOP)
397 return UserProtected(who, channel);
398 QUEUE->sendChannelMode(channel, "-o", who);
401 for (std::map<String, User *, std::less<String> >::iterator
402 it = c->channelMemory.begin();
403 it != c->channelMemory.end(); ++it) {
404 if (m.matches((*it).second->nick + "!" +
405 (*it).second->userhost) &&
406 (*it).second->getProt() < User::NO_DEOP &&
407 ((*it).second->mode & User::OP_MODE))
408 QUEUE->sendChannelMode(channel, "-o", (*it).second->nick);
416 Commands::Die(Bot *bot, String reason)
420 QUEUE->sendQuit(reason);
427 Commands::Do(Bot *bot, String command)
431 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
436 Commands::Invite(Bot *bot, String channel, String who)
440 if (!bot->iAmOp(channel))
441 return NotChannelOp(channel);
443 QUEUE->sendInvite(channel, who);
449 Commands::Join(Bot *bot, String channel, String key)
453 if (!Utils::valid_channel_name_p(channel))
454 return InvalidChannel(channel);
456 // We change the key only if we are not on the channel.
457 // We don't trust the user...
458 if (!CHANNEL(channel)) {
459 if (bot->wantedChannels[channel])
460 bot->wantedChannels[channel]->key = key;
462 bot->wantedChannels[channel] = new wantedChannel("", "", key);
465 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
471 Commands::Keep(Bot *bot, String channel, String modes)
475 Channel *c = CHANNEL(channel);
478 return NotOnChannel(channel);
480 c->keepModes = modes;
486 Commands::Kick(Bot *bot, String channel, String who, String reason)
490 Channel *c = CHANNEL(channel);
493 return NotOnChannel(channel);
495 if (!bot->iAmOp(channel))
496 return NotChannelOp(channel);
498 if (Utils::wildcard_p(who)) {
500 for (std::map<String, User *, std::less<String> >::iterator it =
501 c->channelMemory.begin();
502 it != c->channelMemory.end();
504 if (m.matches((*it).second->nick + "!" +
505 (*it).second->userhost) &&
506 (*it).second->getProt() < User::NO_KICK)
507 QUEUE->sendKick(channel, (*it).second->nick, reason);
509 User * u = c->getUser(who);
511 return UserNotFound(who, channel);
512 if (u->getProt() < User::NO_KICK)
513 QUEUE->sendKick(channel, who, reason);
515 return UserProtected(who, channel);
522 Commands::KickBan(Bot *bot, String channel, String who, String reason)
526 Message m = Commands::Ban(bot, channel, who);
528 if (m.getCode() == 0)
529 m = Commands::Kick(bot, channel, who, reason);
535 Commands::Lock(Bot *bot, String channel)
539 Channel *c = CHANNEL(channel);
542 return NotOnChannel(channel);
544 c->lockedTopic = true;
550 Commands::Mode(Bot *bot, String channel, String mode)
554 if (!CHANNEL(channel))
555 return NotOnChannel(channel);
557 if (!bot->iAmOp(channel))
558 return NotChannelOp(channel);
560 QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode);
566 Commands::Msg(Bot *bot, String who, String message)
572 return EmptyAddressee;
575 if (Utils::channel_p(who))
579 return NotOnChannel (who);
588 // Send multi-line messages as seperate privmsgs
589 StringTokenizer st_message (message);
591 while (st_message.more_tokens_p ('\n'))
593 QUEUE->sendPrivmsg(who, st_message.next_token ('\n'));
600 Commands::NextServer(Bot *bot)
604 if (bot->serverList->size() == 0)
605 return EmptyServerList;
607 if (!bot->canChangeServer())
608 return CanNotChangeServer;
611 // Run hooks/disconnect
612 bot->botInterp->RunHooks
614 bot->serverConnection->server->getHostName (),
616 (Utils::str2scm (bot->serverConnection->server->getHostName ()),
620 QUEUE->sendQuit("Changing server");
627 Commands::Nick(Bot *bot, String nick)
631 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
632 return InvalidNick(nick);
634 bot->wantedNickName = nick;
635 QUEUE->sendNick(nick);
641 Commands::Notice(Bot *bot, String who, String message)
646 return EmptyAddressee;
648 // if (Utils::channel_p(who))
649 // return NotToChannel;
654 // Send multiple lines as multiple notices
655 StringTokenizer st_message (message);
657 while (st_message.more_tokens_p ('\n'))
659 QUEUE->sendNotice(who, st_message.next_token ('\n'));
666 Commands::Op(Bot *bot, String channel, String who)
670 Channel *c = CHANNEL(channel);
673 return NotOnChannel(channel);
675 if (!bot->iAmOp(channel))
676 return NotChannelOp(channel);
678 if (Utils::wildcard_p(who))
679 return MassOpNotAllowed;
681 User *u = c->getUser(who);
683 return UserNotFound(who, channel);
685 ShitEntry *se = bot->shitList->getShit(who, channel);
686 if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
687 return UserOnShitList(who);
689 QUEUE->sendChannelMode(channel, "+o", who);
696 Commands::Part(Bot *bot, String channel)
700 if (!CHANNEL(channel))
701 return NotOnChannel(channel);
703 wantedChannel *w = bot->wantedChannels[channel];
704 bot->wantedChannels.erase(channel);
706 QUEUE->sendPart(channel);
712 Commands::Reconnect(Bot *bot)
716 if (!bot->canChangeServer())
717 return CanNotChangeServer;
719 QUEUE->sendQuit("Reconnecting");
726 Commands::Say(Bot *bot, String channel, String message)
728 return Commands::Msg (bot, channel, message);
733 Commands::Server(Bot *bot, int number)
737 if (number < 0 || number >= bot->serverList->size())
738 return InvalidServerNumber(number);
740 if (!bot->canChangeServer())
741 return CanNotChangeServer;
743 QUEUE->sendQuit("Changing server");
745 bot->connect(number);
751 Commands::SetFloodRate(Bot *bot, unsigned int num_messages)
753 if (num_messages > 0)
755 bot->MAX_MESSAGES = num_messages;
758 return InvalidParameters;
762 Commands::SetVersion(Bot *bot, String str)
764 if (str.length() == 0)
765 return InvalidParameters;
767 bot->versionString = str;
772 Commands::TBan(Bot *bot, String channel, String who, int seconds)
776 Channel *c = CHANNEL(channel);
779 // Make sure all of the inputs are valid
782 return NotOnChannel(channel);
785 if (!bot->iAmOp(channel))
787 return NotChannelOp(channel);
792 return InvalidTime(seconds);
796 if (!Utils::wildcard_p(who))
798 dest = bot->getUserhost(channel, who);
805 if (dest.length() == 0)
807 return UserNotFound(who, channel);
811 dest = Utils::make_wildcard(dest);
814 // Make sure the user isn't protected from bans
815 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
816 it != bot->userList->l.end();
819 if (m.matches((*it)->mask) &&
820 (*it)->channelMask.matches(channel) &&
821 (*it)->prot >= User::NO_BAN)
823 return UserProtected(who, channel);
827 // Clear existing bans on the user
828 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
829 it != c->channelBanlist.end(); ++it)
831 if (m.matches((*it)->getMask ()))
833 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask().getMask());
838 CHANNEL(channel)->addBan(dest, seconds);
839 QUEUE->sendChannelMode(channel, "+b", dest);
840 bot->todoList->addDeban(channel, dest, seconds);
847 Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason)
851 Message m = Commands::TBan(bot, channel, who, seconds);
853 if (m.getCode() == 0)
854 m = Commands::Kick(bot, channel, who, reason);
861 Commands::Topic(Bot *bot, String channel, String topic)
865 Channel *c = CHANNEL(channel);
868 return NotOnChannel(channel);
870 if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED))
871 return CanNotChangeTopic(channel);
874 return TopicLocked(channel);
876 QUEUE->sendTopic(channel, topic);
883 Commands::Unlock(Bot *bot, String channel)
887 Channel *c = CHANNEL(channel);
890 return NotOnChannel(channel);
892 c->lockedTopic = false;
898 Commands::Who (Bot *bot, String target)
902 QUEUE->sendWho (target);
908 Commands::Whois (Bot *bot, String nick)
912 if (!Utils::valid_nickname_p (bot, nick))
914 return InvalidNick (nick);
918 QUEUE->sendWhois (nick);