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 "StringTokenizer.H"
27 #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected
30 Commands::Action(Bot *bot, String channel, String message)
34 if (!CHANNEL(channel))
35 return NotOnChannel(channel);
37 if (message.length() == 0)
38 return InvalidParameters;
40 Commands::CTCP (bot, channel, "ACTION", message);
46 Commands::AddUser(Bot *bot, String who, String maskChannel, int level,
47 int prot, bool aop, std::time_t expire, String password)
49 // Gah, fix this (makes bot segfault)
50 if (who.length() == 0 ||
51 maskChannel.length() == 0 ||
53 level > User::FRIEND ||
56 return InvalidParameters;
60 if (!Utils::wildcard_p(who))
62 mask = bot->getUserhost("", who);
63 if (mask.length() == 0)
68 // Aha! This was before the brace...segfault gone
69 mask = Utils::make_wildcard(mask);
71 if (bot->userList->isInUserList(mask, maskChannel))
73 return AlreadyInUserlist(mask, maskChannel);
76 bot->userList->addUser(mask, maskChannel, level, prot, aop,
85 Commands::AddServer(Bot *bot, String servername, int port)
88 return InvalidPort(port);
90 bot->serverList->addServer(new class Server(servername, port));
97 Commands::AddShit(Bot *bot, String mask, String maskChannel,
98 int level, time_t expiration, String reason)
100 if (mask.length() == 0 || maskChannel.length() == 0 ||
101 level < 0 || level > ShitEntry::SHIT_NODEBAN)
102 return InvalidParameters;
105 reason = "You're on my shitlist, lamer";
109 if (!Utils::wildcard_p(mask)) {
110 mask = bot->getUserhost("", who);
111 if (mask.length() == 0)
112 return NotFound(who);
113 mask = Utils::make_wildcard(mask);
114 if (bot->shitList->getShit(mask, maskChannel))
115 return AlreadyInShitlist(mask, maskChannel);
118 if (bot->userList->getMaxProt(mask, maskChannel) > 0)
119 return UserProtected(who, maskChannel);
121 bot->shitList->addShit(mask, maskChannel, level, expiration, reason);
128 Commands::Ban(Bot *bot, String channel, String who)
132 Channel *c = CHANNEL(channel);
135 return NotOnChannel(channel);
137 if (!bot->iAmOp(channel))
138 return NotChannelOp(channel);
142 if (!Utils::wildcard_p(who))
143 dest = bot->getUserhost(channel, who);
147 if (dest.length() == 0)
148 return NotFound(who);
150 dest = Utils::make_wildcard(dest);
153 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
154 it != bot->userList->l.end();
156 if (m.matches((*it)->mask) &&
157 (*it)->channelMask.matches(channel) &&
158 (*it)->prot >= User::NO_BAN)
159 return UserProtected(who, channel);
161 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
162 it != c->channelBanlist.end(); ++it)
163 if (m.matches((*it)->banMask) && (*it)->banMask.getMask() != m.getMask())
164 QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
166 QUEUE->sendChannelMode(channel, "+b", dest);
172 Commands::CTCP (Bot *bot, std::string target, std::string command,
179 return EmptyAddressee;
184 return InvalidParameters;
192 if (Utils::channel_p (target) && !CHANNEL (target))
194 return NotOnChannel (target);
198 // Send multi-line messages as seperate privmsgs
199 StringTokenizer st_message (message);
201 while (st_message.more_tokens_p ('\n'))
203 QUEUE->sendCTCP (target, command, st_message.next_token ('\n'));
210 Commands::CTCPReply (Bot *bot, std::string target, std::string command,
217 return EmptyAddressee;
222 return InvalidParameters;
230 // CTCP-REPLY cannot go to a channel
231 if (Utils::channel_p (target))
237 // Send multi-line messages as seperate privmsgs
238 StringTokenizer st_message (message);
240 while (st_message.more_tokens_p ('\n'))
242 QUEUE->sendCTCPReply (target, command, st_message.next_token ('\n'));
250 Commands::Cycle(Bot *bot, String channel)
254 if (!CHANNEL(channel))
255 return NotOnChannel(channel);
257 QUEUE->sendPart(channel);
258 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
264 Commands::Deban(Bot *bot, String channel, String who)
268 Channel *c = CHANNEL(channel);
271 return NotOnChannel(channel);
273 if (!bot->iAmOp(channel))
274 return NotChannelOp(channel);
278 if (!Utils::wildcard_p(who))
279 dest = bot->getUserhost(channel, who);
283 if (dest.length() == 0)
284 return UserNotFound(who, channel);
286 dest = Utils::make_wildcard(dest);
289 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
290 it != c->channelBanlist.end(); ++it)
291 if (m.matches((*it)->getMask())) {
292 // Let's see if the ban is in the shitlist
293 ShitEntry *se = bot->shitList->getShit((*it)->getMask(), channel);
294 if (!se || !se->isStillValid() ||
295 se->getShitLevel() < ShitEntry::SHIT_NODEBAN)
296 QUEUE->sendChannelMode(channel, "-b", (*it)->getMask());
303 Commands::DelServer(Bot *bot, int number)
305 if (number < 0 || number >= bot->serverList->size())
306 return InvalidServerNumber(number);
308 bot->serverList->delServer(number);
314 Commands::DelUser(Bot *bot, String who, String maskChannel)
316 if (who.length() == 0 || maskChannel.length() == 0)
317 return InvalidParameters;
321 if (!Utils::wildcard_p(who)) {
322 dest = bot->getUserhost("", who);
323 if (dest.length() == 0)
324 return NotFound(who);
325 dest = Utils::make_wildcard(who);
328 if (!bot->userList->isInUserList(dest, maskChannel))
329 return NotInUserlist(who);
331 bot->userList->removeUser(dest, maskChannel);
338 Commands::DelShit(Bot *bot, String who, String maskChannel)
340 if (who.length() == 0 || maskChannel.length() == 0)
341 return InvalidParameters;
345 if (!Utils::wildcard_p(who)) {
346 dest = bot->getUserhost("", who);
347 if (dest.length() == 0)
348 return NotFound(who);
349 dest = Utils::make_wildcard(who);
352 if (!bot->shitList->getShit(dest, maskChannel))
353 return NotInShitlist(who);
355 bot->shitList->delShit(dest, maskChannel);
361 Commands::Deop(Bot *bot, String channel, String who)
365 Channel *c = CHANNEL(channel);
368 return NotOnChannel(channel);
370 if (!bot->iAmOp(channel))
371 return NotChannelOp(channel);
373 if (!Utils::wildcard_p(who)) {
374 User *u = c->getUser(who);
376 return UserNotFound(who, channel);
377 if (!(u->mode & User::OP_MODE))
378 return UserNotOp(who, channel);
379 if (u->getProt() >= User::NO_DEOP)
380 return UserProtected(who, channel);
381 QUEUE->sendChannelMode(channel, "-o", who);
384 for (std::map<String, User *, std::less<String> >::iterator
385 it = c->channelMemory.begin();
386 it != c->channelMemory.end(); ++it) {
387 if (m.matches((*it).second->nick + "!" +
388 (*it).second->userhost) &&
389 (*it).second->getProt() < User::NO_DEOP &&
390 ((*it).second->mode & User::OP_MODE))
391 QUEUE->sendChannelMode(channel, "-o", (*it).second->nick);
399 Commands::Die(Bot *bot, String reason)
403 QUEUE->sendQuit(reason);
410 Commands::Do(Bot *bot, String command)
414 QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER);
419 Commands::Invite(Bot *bot, String channel, String who)
423 if (!bot->iAmOp(channel))
424 return NotChannelOp(channel);
426 QUEUE->sendInvite(channel, who);
432 Commands::Join(Bot *bot, String channel, String key)
436 if (!Utils::valid_channel_name_p(channel))
437 return InvalidChannel(channel);
439 // We change the key only if we are not on the channel.
440 // We don't trust the user...
441 if (!CHANNEL(channel)) {
442 if (bot->wantedChannels[channel])
443 bot->wantedChannels[channel]->key = key;
445 bot->wantedChannels[channel] = new wantedChannel("", "", key);
448 QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key);
454 Commands::Keep(Bot *bot, String channel, String modes)
458 Channel *c = CHANNEL(channel);
461 return NotOnChannel(channel);
463 c->keepModes = modes;
469 Commands::Kick(Bot *bot, String channel, String who, String reason)
473 Channel *c = CHANNEL(channel);
476 return NotOnChannel(channel);
478 if (!bot->iAmOp(channel))
479 return NotChannelOp(channel);
481 if (Utils::wildcard_p(who)) {
483 for (std::map<String, User *, std::less<String> >::iterator it =
484 c->channelMemory.begin();
485 it != c->channelMemory.end();
487 if (m.matches((*it).second->nick + "!" +
488 (*it).second->userhost) &&
489 (*it).second->getProt() < User::NO_KICK)
490 QUEUE->sendKick(channel, (*it).second->nick, reason);
492 User * u = c->getUser(who);
494 return UserNotFound(who, channel);
495 if (u->getProt() < User::NO_KICK)
496 QUEUE->sendKick(channel, who, reason);
498 return UserProtected(who, channel);
505 Commands::KickBan(Bot *bot, String channel, String who, String reason)
509 Message m = Commands::Ban(bot, channel, who);
511 if (m.getCode() == 0)
512 m = Commands::Kick(bot, channel, who, reason);
518 Commands::Lock(Bot *bot, String channel)
522 Channel *c = CHANNEL(channel);
525 return NotOnChannel(channel);
527 c->lockedTopic = true;
533 Commands::Mode(Bot *bot, String channel, String mode)
537 if (!CHANNEL(channel))
538 return NotOnChannel(channel);
540 if (!bot->iAmOp(channel))
541 return NotChannelOp(channel);
543 QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode);
549 Commands::Msg(Bot *bot, String who, String message)
555 return EmptyAddressee;
558 if (Utils::channel_p(who))
562 return NotOnChannel (who);
571 // Send multi-line messages as seperate privmsgs
572 StringTokenizer st_message (message);
574 while (st_message.more_tokens_p ('\n'))
576 QUEUE->sendPrivmsg(who, st_message.next_token ('\n'));
583 Commands::NextServer(Bot *bot)
587 if (bot->serverList->size() == 0)
588 return EmptyServerList;
590 if (!bot->canChangeServer())
591 return CanNotChangeServer;
594 // Run hooks/disconnect
595 bot->botInterp->RunHooks
597 bot->serverConnection->server->getHostName (),
599 (Utils::str2scm (bot->serverConnection->server->getHostName ()),
603 QUEUE->sendQuit("Changing server");
610 Commands::Nick(Bot *bot, String nick)
614 if (nick == "" || !Utils::valid_nickname_p(bot, nick))
615 return InvalidNick(nick);
617 bot->wantedNickName = nick;
618 QUEUE->sendNick(nick);
624 Commands::Notice(Bot *bot, String who, String message)
629 return EmptyAddressee;
631 // if (Utils::channel_p(who))
632 // return NotToChannel;
637 // Send multiple lines as multiple notices
638 StringTokenizer st_message (message);
640 while (st_message.more_tokens_p ('\n'))
642 QUEUE->sendNotice(who, st_message.next_token ('\n'));
649 Commands::Op(Bot *bot, String channel, String who)
653 Channel *c = CHANNEL(channel);
656 return NotOnChannel(channel);
658 if (!bot->iAmOp(channel))
659 return NotChannelOp(channel);
661 if (Utils::wildcard_p(who))
662 return MassOpNotAllowed;
664 User *u = c->getUser(who);
666 return UserNotFound(who, channel);
668 ShitEntry *se = bot->shitList->getShit(who, channel);
669 if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP)
670 return UserOnShitList(who);
672 QUEUE->sendChannelMode(channel, "+o", who);
679 Commands::Part(Bot *bot, String channel)
683 if (!CHANNEL(channel))
684 return NotOnChannel(channel);
686 wantedChannel *w = bot->wantedChannels[channel];
687 bot->wantedChannels.erase(channel);
689 QUEUE->sendPart(channel);
695 Commands::Reconnect(Bot *bot)
699 if (!bot->canChangeServer())
700 return CanNotChangeServer;
702 QUEUE->sendQuit("Reconnecting");
709 Commands::Say(Bot *bot, String channel, String message)
711 return Commands::Msg (bot, channel, message);
716 Commands::Server(Bot *bot, int number)
720 if (number < 0 || number >= bot->serverList->size())
721 return InvalidServerNumber(number);
723 if (!bot->canChangeServer())
724 return CanNotChangeServer;
726 QUEUE->sendQuit("Changing server");
728 bot->connect(number);
734 Commands::SetFloodRate(Bot *bot, unsigned int num_messages)
736 if (num_messages > 0)
738 bot->MAX_MESSAGES = num_messages;
741 return InvalidParameters;
745 Commands::SetVersion(Bot *bot, String str)
747 if (str.length() == 0)
748 return InvalidParameters;
750 bot->versionString = str;
755 Commands::TBan(Bot *bot, String channel, String who, int seconds)
759 Channel *c = CHANNEL(channel);
762 // Make sure all of the inputs are valid
765 return NotOnChannel(channel);
768 if (!bot->iAmOp(channel))
770 return NotChannelOp(channel);
775 return InvalidTime(seconds);
779 if (!Utils::wildcard_p(who))
781 dest = bot->getUserhost(channel, who);
788 if (dest.length() == 0)
790 return UserNotFound(who, channel);
794 dest = Utils::make_wildcard(dest);
797 // Make sure the user isn't protected from bans
798 for (std::list<UserListItem *>::iterator it = bot->userList->l.begin();
799 it != bot->userList->l.end();
802 if (m.matches((*it)->mask) &&
803 (*it)->channelMask.matches(channel) &&
804 (*it)->prot >= User::NO_BAN)
806 return UserProtected(who, channel);
810 // Clear existing bans on the user
811 for (std::vector<BanEntry *>::iterator it = c->channelBanlist.begin();
812 it != c->channelBanlist.end(); ++it)
814 if (m.matches((*it)->banMask))
816 QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask());
821 CHANNEL(channel)->addBan(dest, seconds);
822 QUEUE->sendChannelMode(channel, "+b", dest);
823 bot->todoList->addDeban(channel, dest, seconds);
830 Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason)
834 Message m = Commands::TBan(bot, channel, who, seconds);
836 if (m.getCode() == 0)
837 m = Commands::Kick(bot, channel, who, reason);
844 Commands::Topic(Bot *bot, String channel, String topic)
848 Channel *c = CHANNEL(channel);
851 return NotOnChannel(channel);
853 if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED))
854 return CanNotChangeTopic(channel);
857 return TopicLocked(channel);
859 QUEUE->sendTopic(channel, topic);
866 Commands::Unlock(Bot *bot, String channel)
870 Channel *c = CHANNEL(channel);
873 return NotOnChannel(channel);
875 c->lockedTopic = false;
881 Commands::Who (Bot *bot, String target)
885 QUEUE->sendWho (target);
891 Commands::Whois (Bot *bot, String nick)
895 if (!Utils::valid_nickname_p (bot, nick))
897 return InvalidNick (nick);
901 QUEUE->sendWhois (nick);