// Commands.C -*- C++ -*- // Copyright (c) 1998 Etienne BERNARD // Copyright (C) 2002,2005 Clinton Ebadi // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "Macros.H" #include "Message.H" #include "Commands.H" #include "Utils.H" #include "StringTokenizer.H" #define CHECK_CONNECTION if (!bot->serverConnection) return NotConnected Message Commands::Action(Bot *bot, String channel, String message) { CHECK_CONNECTION; if (!CHANNEL(channel)) return NotOnChannel(channel); if (message.length() == 0) return InvalidParameters; Commands::CTCP (bot, channel, "ACTION", message); return Ok; } Message Commands::AddUser(Bot *bot, String who, String maskChannel, int level, int prot, bool aop, std::time_t expire, String password) { // Gah, fix this (makes bot segfault) if (who.length() == 0 || maskChannel.length() == 0 || level < 0 || level > User::FRIEND || prot < 0 || prot > User::NO_DEOP) return InvalidParameters; String mask; if (!Utils::wildcard_p(who)) { mask = bot->getUserhost("", who); if (mask.length() == 0) { return NotFound(who); } } // Aha! This was before the brace...segfault gone mask = Utils::make_wildcard(mask); if (bot->userList->isInUserList(mask, maskChannel)) { return AlreadyInUserlist(mask, maskChannel); } bot->userList->addUser(mask, maskChannel, level, prot, aop, expire, password); bot->rehash(); return Ok; } Message Commands::AddServer(Bot *bot, String servername, int port) { if (port <= 0) return InvalidPort(port); bot->serverList->addServer(new class Server(servername, port)); return Ok; } Message Commands::AddShit(Bot *bot, String mask, String maskChannel, int level, time_t expiration, String reason) { if (mask.length() == 0 || maskChannel.length() == 0 || level < 0 || level > ShitEntry::SHIT_NODEBAN) return InvalidParameters; if (reason == "") reason = "You're on my shitlist, lamer"; String who = mask; if (!Utils::wildcard_p(mask)) { mask = bot->getUserhost("", who); if (mask.length() == 0) return NotFound(who); mask = Utils::make_wildcard(mask); if (bot->shitList->getShit(mask, maskChannel)) return AlreadyInShitlist(mask, maskChannel); } if (bot->userList->getMaxProt(mask, maskChannel) > 0) return UserProtected(who, maskChannel); bot->shitList->addShit(mask, maskChannel, level, expiration, reason); return Ok; } Message Commands::Ban(Bot *bot, String channel, String who) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); if (!bot->iAmOp(channel)) return NotChannelOp(channel); String dest; if (!Utils::wildcard_p(who)) dest = bot->getUserhost(channel, who); else dest = who; if (dest.length() == 0) return NotFound(who); dest = Utils::make_wildcard(dest); Mask m(dest); for (std::list::iterator it = bot->userList->l.begin(); it != bot->userList->l.end(); it++) if (m.matches((*it)->mask) && (*it)->channelMask.matches(channel) && (*it)->prot >= User::NO_BAN) return UserProtected(who, channel); for (std::vector::iterator it = c->channelBanlist.begin(); it != c->channelBanlist.end(); ++it) if (m.matches((*it)->banMask) && (*it)->banMask.getMask() != m.getMask()) QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask()); QUEUE->sendChannelMode(channel, "+b", dest); return Ok; } Message Commands::CTCP (Bot *bot, std::string target, std::string command, std::string message) { CHECK_CONNECTION; if (target == "") { return EmptyAddressee; } if (command == "") { return InvalidParameters; } if (message == "") { return EmptyMessage; } if (Utils::channel_p (target) && !CHANNEL (target)) { return NotOnChannel (target); } // Send multi-line messages as seperate privmsgs StringTokenizer st_message (message); while (st_message.more_tokens_p ('\n')) { QUEUE->sendCTCP (target, command, st_message.next_token ('\n')); } return Ok; } Message Commands::CTCPReply (Bot *bot, std::string target, std::string command, std::string message) { CHECK_CONNECTION; if (target == "") { return EmptyAddressee; } if (command == "") { return InvalidParameters; } if (message == "") { return EmptyMessage; } // CTCP-REPLY cannot go to a channel if (Utils::channel_p (target)) { return NotToChannel; } // Send multi-line messages as seperate privmsgs StringTokenizer st_message (message); while (st_message.more_tokens_p ('\n')) { QUEUE->sendCTCPReply (target, command, st_message.next_token ('\n')); } return Ok; } Message Commands::Cycle(Bot *bot, String channel) { CHECK_CONNECTION; if (!CHANNEL(channel)) return NotOnChannel(channel); QUEUE->sendPart(channel); QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key); return Ok; } Message Commands::Deban(Bot *bot, String channel, String who) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); if (!bot->iAmOp(channel)) return NotChannelOp(channel); String dest; if (!Utils::wildcard_p(who)) dest = bot->getUserhost(channel, who); else dest = who; if (dest.length() == 0) return UserNotFound(who, channel); dest = Utils::make_wildcard(dest); Mask m(dest); for (std::vector::iterator it = c->channelBanlist.begin(); it != c->channelBanlist.end(); ++it) if (m.matches((*it)->getMask())) { // Let's see if the ban is in the shitlist ShitEntry *se = bot->shitList->getShit((*it)->getMask(), channel); if (!se || !se->isStillValid() || se->getShitLevel() < ShitEntry::SHIT_NODEBAN) QUEUE->sendChannelMode(channel, "-b", (*it)->getMask()); } return Ok; } Message Commands::DelServer(Bot *bot, int number) { if (number < 0 || number >= bot->serverList->size()) return InvalidServerNumber(number); bot->serverList->delServer(number); return Ok; } Message Commands::DelUser(Bot *bot, String who, String maskChannel) { if (who.length() == 0 || maskChannel.length() == 0) return InvalidParameters; String dest; if (!Utils::wildcard_p(who)) { dest = bot->getUserhost("", who); if (dest.length() == 0) return NotFound(who); dest = Utils::make_wildcard(who); } if (!bot->userList->isInUserList(dest, maskChannel)) return NotInUserlist(who); bot->userList->removeUser(dest, maskChannel); bot->rehash(); return Ok; } Message Commands::DelShit(Bot *bot, String who, String maskChannel) { if (who.length() == 0 || maskChannel.length() == 0) return InvalidParameters; String dest; if (!Utils::wildcard_p(who)) { dest = bot->getUserhost("", who); if (dest.length() == 0) return NotFound(who); dest = Utils::make_wildcard(who); } if (!bot->shitList->getShit(dest, maskChannel)) return NotInShitlist(who); bot->shitList->delShit(dest, maskChannel); return Ok; } Message Commands::Deop(Bot *bot, String channel, String who) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); if (!bot->iAmOp(channel)) return NotChannelOp(channel); if (!Utils::wildcard_p(who)) { User *u = c->getUser(who); if (!u) return UserNotFound(who, channel); if (!(u->mode & User::OP_MODE)) return UserNotOp(who, channel); if (u->getProt() >= User::NO_DEOP) return UserProtected(who, channel); QUEUE->sendChannelMode(channel, "-o", who); } else { Mask m(who); for (std::map >::iterator it = c->channelMemory.begin(); it != c->channelMemory.end(); ++it) { if (m.matches((*it).second->nick + "!" + (*it).second->userhost) && (*it).second->getProt() < User::NO_DEOP && ((*it).second->mode & User::OP_MODE)) QUEUE->sendChannelMode(channel, "-o", (*it).second->nick); } } return Ok; } Message Commands::Die(Bot *bot, String reason) { CHECK_CONNECTION; QUEUE->sendQuit(reason); bot->stop = true; return Ok; } Message Commands::Do(Bot *bot, String command) { CHECK_CONNECTION; QUEUE->addLine(command, 0, 0, ServerQueueItem::OTHER); return Ok; } Message Commands::Invite(Bot *bot, String channel, String who) { CHECK_CONNECTION; if (!bot->iAmOp(channel)) return NotChannelOp(channel); QUEUE->sendInvite(channel, who); return Ok; } Message Commands::Join(Bot *bot, String channel, String key) { CHECK_CONNECTION; if (!Utils::valid_channel_name_p(channel)) return InvalidChannel(channel); // We change the key only if we are not on the channel. // We don't trust the user... if (!CHANNEL(channel)) { if (bot->wantedChannels[channel]) bot->wantedChannels[channel]->key = key; else { bot->wantedChannels[channel] = new wantedChannel("", "", key); } } QUEUE->sendJoin(channel, bot->wantedChannels[channel]->key); return Ok; } Message Commands::Keep(Bot *bot, String channel, String modes) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); c->keepModes = modes; return Ok; } Message Commands::Kick(Bot *bot, String channel, String who, String reason) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); if (!bot->iAmOp(channel)) return NotChannelOp(channel); if (Utils::wildcard_p(who)) { Mask m(who); for (std::map >::iterator it = c->channelMemory.begin(); it != c->channelMemory.end(); ++it) if (m.matches((*it).second->nick + "!" + (*it).second->userhost) && (*it).second->getProt() < User::NO_KICK) QUEUE->sendKick(channel, (*it).second->nick, reason); } else { User * u = c->getUser(who); if (!u) return UserNotFound(who, channel); if (u->getProt() < User::NO_KICK) QUEUE->sendKick(channel, who, reason); else return UserProtected(who, channel); } return Ok; } Message Commands::KickBan(Bot *bot, String channel, String who, String reason) { CHECK_CONNECTION; Message m = Commands::Ban(bot, channel, who); if (m.getCode() == 0) m = Commands::Kick(bot, channel, who, reason); return m; } Message Commands::Lock(Bot *bot, String channel) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); c->lockedTopic = true; return Ok; } Message Commands::Mode(Bot *bot, String channel, String mode) { CHECK_CONNECTION; if (!CHANNEL(channel)) return NotOnChannel(channel); if (!bot->iAmOp(channel)) return NotChannelOp(channel); QUEUE->sendChannelMode(String("MODE ") + channel + " " + mode); return Ok; } Message Commands::Msg(Bot *bot, String who, String message) { CHECK_CONNECTION; if (who == "") { return EmptyAddressee; } if (Utils::channel_p(who)) { if (!CHANNEL(who)) { return NotOnChannel (who); } } if (message == "") { return EmptyMessage; } // Send multi-line messages as seperate privmsgs StringTokenizer st_message (message); while (st_message.more_tokens_p ('\n')) { QUEUE->sendPrivmsg(who, st_message.next_token ('\n')); } return Ok; } Message Commands::NextServer(Bot *bot) { CHECK_CONNECTION; if (bot->serverList->size() == 0) return EmptyServerList; if (!bot->canChangeServer()) return CanNotChangeServer; #ifdef USESCRIPTS // Run hooks/disconnect bot->botInterp->RunHooks (Hook::DISCONNECT, bot->serverConnection->server->getHostName (), scm_list_n (Utils::str2scm (bot->serverConnection->server->getHostName ()), SCM_BOOL_T)); #endif QUEUE->sendQuit("Changing server"); bot->nextServer(); return Ok; } Message Commands::Nick(Bot *bot, String nick) { CHECK_CONNECTION; if (nick == "" || !Utils::valid_nickname_p(bot, nick)) return InvalidNick(nick); bot->wantedNickName = nick; QUEUE->sendNick(nick); return Ok; } Message Commands::Notice(Bot *bot, String who, String message) { CHECK_CONNECTION; if (who == "") return EmptyAddressee; // if (Utils::channel_p(who)) // return NotToChannel; if (message == "") return EmptyMessage; // Send multiple lines as multiple notices StringTokenizer st_message (message); while (st_message.more_tokens_p ('\n')) { QUEUE->sendNotice(who, st_message.next_token ('\n')); } return Ok; } Message Commands::Op(Bot *bot, String channel, String who) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); if (!bot->iAmOp(channel)) return NotChannelOp(channel); if (Utils::wildcard_p(who)) return MassOpNotAllowed; User *u = c->getUser(who); if (!u) return UserNotFound(who, channel); ShitEntry *se = bot->shitList->getShit(who, channel); if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP) return UserOnShitList(who); QUEUE->sendChannelMode(channel, "+o", who); return Ok; } Message Commands::Part(Bot *bot, String channel) { CHECK_CONNECTION; if (!CHANNEL(channel)) return NotOnChannel(channel); wantedChannel *w = bot->wantedChannels[channel]; bot->wantedChannels.erase(channel); delete w; QUEUE->sendPart(channel); return Ok; } Message Commands::Reconnect(Bot *bot) { CHECK_CONNECTION; if (!bot->canChangeServer()) return CanNotChangeServer; QUEUE->sendQuit("Reconnecting"); bot->reconnect(); return Ok; } Message Commands::Say(Bot *bot, String channel, String message) { return Commands::Msg (bot, channel, message); } Message Commands::Server(Bot *bot, int number) { CHECK_CONNECTION; if (number < 0 || number >= bot->serverList->size()) return InvalidServerNumber(number); if (!bot->canChangeServer()) return CanNotChangeServer; QUEUE->sendQuit("Changing server"); QUEUE->flush(); bot->connect(number); return Ok; } Message Commands::SetFloodRate(Bot *bot, unsigned int num_messages) { if (num_messages > 0) { bot->MAX_MESSAGES = num_messages; return Ok; } return InvalidParameters; } Message Commands::SetVersion(Bot *bot, String str) { if (str.length() == 0) return InvalidParameters; bot->versionString = str; return Ok; } Message Commands::TBan(Bot *bot, String channel, String who, int seconds) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); String dest; // Make sure all of the inputs are valid if (!c) { return NotOnChannel(channel); } if (!bot->iAmOp(channel)) { return NotChannelOp(channel); } if (seconds <= 0) { return InvalidTime(seconds); } // Look for user if (!Utils::wildcard_p(who)) { dest = bot->getUserhost(channel, who); } else { dest = who; } if (dest.length() == 0) { return UserNotFound(who, channel); } dest = Utils::make_wildcard(dest); Mask m(dest); // Make sure the user isn't protected from bans for (std::list::iterator it = bot->userList->l.begin(); it != bot->userList->l.end(); it++) { if (m.matches((*it)->mask) && (*it)->channelMask.matches(channel) && (*it)->prot >= User::NO_BAN) { return UserProtected(who, channel); } } // Clear existing bans on the user for (std::vector::iterator it = c->channelBanlist.begin(); it != c->channelBanlist.end(); ++it) { if (m.matches((*it)->banMask)) { QUEUE->sendChannelMode(channel, "-b", (*it)->banMask.getMask()); } } // Ban them CHANNEL(channel)->addBan(dest, seconds); QUEUE->sendChannelMode(channel, "+b", dest); bot->todoList->addDeban(channel, dest, seconds); return Ok; } Message Commands::TKBan(Bot *bot, String channel, String who, int seconds, String reason) { CHECK_CONNECTION; Message m = Commands::TBan(bot, channel, who, seconds); if (m.getCode() == 0) m = Commands::Kick(bot, channel, who, reason); return m; } Message Commands::Topic(Bot *bot, String channel, String topic) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); if (!bot->iAmOp(channel) && !(c->channelMode & Channel::TOPIC_RESTRICTED)) return CanNotChangeTopic(channel); if (c->lockedTopic) return TopicLocked(channel); QUEUE->sendTopic(channel, topic); return Ok; } Message Commands::Unlock(Bot *bot, String channel) { CHECK_CONNECTION; Channel *c = CHANNEL(channel); if (!c) return NotOnChannel(channel); c->lockedTopic = false; return Ok; }