// Channel.C -*- C++ -*- // Copyright (c) 1997, 1998 Etienne BERNARD // Copyright (C) 2002,2005,2008,2009 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. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "Channel.H" #include #include "BanEntry.H" #include "Bot.H" #include "Macros.H" #include "Mask.H" #include "Person.H" #include "ServerConnection.H" #include "ShitEntry.H" #include "ShitList.H" #include "StringTokenizer.H" #include "User.H" #include "Utils.H" #ifdef USESCRIPTS #include "Interp.H" #endif Channel::Channel(ServerConnection *c, std::string name, std::string wanted = "") : channelName(Utils::to_lower(name)), channelTopic(""), lockedTopic(false), channelMode(0), channelLimit(0), channelKey(""), keepModes(DEFAULT_KEEPMODES), wantedModes(wanted), channelUserlist (name), joined(false), doMode(true), gotWho(false), cnx(c) { if (c->bot->wantedChannels[channelName]) { if (c->bot->wantedChannels[channelName]->keep != "") keepModes = c->bot->wantedChannels[channelName]->keep; if (c->bot->wantedChannels[channelName]->mode != "") wantedModes = c->bot->wantedChannels[channelName]->mode; } } Channel::~Channel() { } void Channel::addNick(std::string n, std::string uh, int mode, UserList *ul, bool names) { channelUserlist.add (n, uh, mode, ul, names); } void Channel::delNick(std::string n) { channelUserlist.del (n); } void Channel::changeNick(std::string on, std::string nn) { channelUserlist.change_nickname (on, nn); } bool Channel::hasNick(const std::string &n) const { return channelUserlist.in_channel_p (n); } const User Channel::getUser(const std::string &n) const { return channelUserlist.get (n); } void Channel::change_user_key (std::string name, std::string key) { channelUserlist.change_user_key (name, key); } unsigned int Channel::user_count () const throw () { return channelUserlist.user_count (); } unsigned int Channel::operator_count () const throw () { return channelUserlist.operator_count (); } void Channel::addBan(const Mask & mask, std::time_t expiration) { if (channelBanlist.add (mask, expiration)) cnx->queue->sendChannelMode (channelName, "+b", mask.getMask ()); } void Channel::delBan(const Mask & mask) { BanList::MatchList matches = channelBanlist.find_matches (mask); for (BanList::MatchList::const_iterator it = matches.begin (); it != matches.end (); ++it) { if (channelBanlist.del (*it)) cnx->queue->sendChannelMode (channelName, "-b", mask.getMask ()); } } void Channel::purge_expired_bans () { BanList::MatchList expired = channelBanlist.delete_expired_x (); for (BanList::MatchList::const_iterator it = expired.begin (); it != expired.end (); ++it) cnx->queue->sendChannelMode (channelName, "-b", (*it).getMask ()); } void Channel::resynchModes() { cnx->queue->sendChannelMode(std::string("MODE ") + channelName + " +" + cnx->bot->wantedChannels[channelName]->mode); } void Channel::parseMode(Person *from, std::string mode) { char sign = '-'; StringTokenizer st(mode); std::string m = st.next_token(), n; bool doNotObey = true; // disobey mode if server or target is protected if (from) try { doNotObey = getUser(from->getNick()).getProt () <= User::NO_PROT; } catch (ChannelUserList::user_not_found&) { } if (!gotWho) doNotObey = false; for (int i = 0; i < m.length(); i++) switch(m[i]) { case '+': case '-': sign = m[i]; break; case 'p': sign =='+' ? channelMode |= PRIVATE : channelMode &= ~PRIVATE; if (keepModes.find('p') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('p') != -1) cnx->queue->sendChannelMode(channelName, "+p", ""); else cnx->queue->sendChannelMode(channelName, "-p", ""); } break; case 's': sign =='+' ? channelMode |= SECRET : channelMode &= ~SECRET; if (keepModes.find('s') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('s') != -1) cnx->queue->sendChannelMode(channelName, "+s", ""); else cnx->queue->sendChannelMode(channelName, "-s", ""); } break; case 'i': sign =='+' ? channelMode |= INVITE_ONLY : channelMode &= ~INVITE_ONLY; if (keepModes.find('i') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('i') != -1) cnx->queue->sendChannelMode(channelName, "+i", ""); else cnx->queue->sendChannelMode(channelName, "-i", ""); } break; case 't': sign =='+' ? channelMode |= TOPIC_RESTRICTED : channelMode &= ~TOPIC_RESTRICTED; if (keepModes.find('t') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('t') != -1) cnx->queue->sendChannelMode(channelName, "+t", ""); else cnx->queue->sendChannelMode(channelName, "-t", ""); } break; case 'n': sign =='+' ? channelMode |= EXTMSG_RESTRICTED : channelMode &= ~EXTMSG_RESTRICTED; if (keepModes.find('n') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('n') != -1) cnx->queue->sendChannelMode(channelName, "+n", ""); else cnx->queue->sendChannelMode(channelName, "-n", ""); } break; case 'm': sign =='+' ? channelMode |= MODERATED : channelMode &= ~MODERATED; if (keepModes.find('m') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('m') != -1) cnx->queue->sendChannelMode(channelName, "+m", ""); else cnx->queue->sendChannelMode(channelName, "-m", ""); } break; case 'l': if (keepModes.find('l') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('l') != -1) cnx->queue->sendChannelMode(channelName, "+l", Utils::long2str(channelLimit)); else cnx->queue->sendChannelMode(channelName, "-l", ""); } channelLimit = (sign == '+' ? std::atoi(st.next_token().c_str()) : channelLimit = 0); break; case 'k': channelKey = st.next_token(); if (keepModes.find('k') != -1 && doNotObey) { if (sign == '-' && wantedModes.find('k') != -1) cnx->queue->sendChannelMode(channelName, "+k", channelKey); else cnx->queue->sendChannelMode(channelName, "-k", channelKey); } cnx->bot->wantedChannels[channelName]->key = (sign == '+' ? channelKey : std::string("")); break; case 'o': try { n = st.next_token(); User u = getUser(n); // if (joined) // sign == '+' ? countOp++ : countOp--; channelUserlist.change_user_mode (n, User::OP_MODE, sign != '+'); if (sign == '-' && u.getProt() >= User::NO_DEOP) { std::string fromNick = from->getNick(); User v = getUser(fromNick); if (n == fromNick) return; if (v.getProt() < User::NO_DEOP) cnx->queue->sendChannelMode(channelName, "-o", fromNick); cnx->queue->sendChannelMode(channelName, "+o", n); } if (sign == '+') { if (doNotObey && !from && u.getProt() < User::NO_DEOP && !u.getAop()) cnx->queue->sendChannelMode(channelName, "-o", n); ShitEntry * se = cnx->bot->shitList->getShit(n+"!"+cnx->bot->getUserhost(channelName, n), channelName); if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NOOP) cnx->queue->sendChannelMode(channelName, "-o", n); if (Utils::to_lower (n) == cnx->bot->nickName.toLower() && doMode) { doMode = false; resynchModes(); } } break; } catch (ChannelUserList::user_not_found &) { break; } case 'v': channelUserlist.change_user_mode (st.next_token (), User::VOICE_MODE, sign != '+'); break; case 'b': std::string m = st.next_token(); if (sign == '+') channelBanlist.add (Mask(m)); if (sign == '-') { ShitEntry * se = cnx->bot->shitList->getShit(m, channelName); if (se && se->isStillValid() && se->getShitLevel() >= ShitEntry::SHIT_NODEBAN) cnx->queue->sendChannelMode(channelName, "+b", m); else channelBanlist.del (Mask(m)); } } }