// Channel.C -*- C++ -*- // Copyright (c) 1997, 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. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "Macros.H" #include "Utils.H" #include "Channel.H" #include "StringTokenizer.H" #ifdef USESCRIPTS #include "Interp.H" #endif Channel::Channel(ServerConnection *c, String name, String wanted = "") : channelName(name.toLower()), channelTopic(""), lockedTopic(false), channelMode(0), channelLimit(0), channelKey(""), keepModes(DEFAULT_KEEPMODES), wantedModes(wanted), count(0), countOp(0), joined(false), doMode(true), gotWho(false), cnx(c) { #ifdef HAVE_STL_CLEAR channelMemory.clear(); channelBanlist.clear(); #endif 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() { User *u; std::map >::iterator it; while (channelMemory.size() != 0) { it = channelMemory.begin(); u = (*it).second; if (u && u->userListItem && u->userListItem->identified > 0) u->userListItem->identified--; channelMemory.erase(it); delete u; } BanEntry *b; std::vector::iterator it2; while (channelBanlist.size() != 0) { it2 = channelBanlist.begin(); b = *it2; channelBanlist.erase(it2); delete b; } } void Channel::addNick(String n, String uh, int mode, UserList *ul, bool names) { if (User * u = getUser(n.toLower())) { count--; if (u->mode & User::OP_MODE) countOp--; channelMemory.erase(n.toLower()); delete u; } User *u; if (names) u = new User(n, mode); else u = new User(n, uh, channelName, mode, ul); channelMemory[n.toLower()] = u; if (u->userListItem) { if (u->userListItem->identified) u->userListItem->identified++; else { if (u->userListItem->passwd == "") u->userListItem->identified = 1; } } count++; if (u->mode & User::OP_MODE) countOp++; } void Channel::delNick(String n) { n = n.toLower(); User *u = getUser(n); if (!u) return; if (channelMemory[n]!=0) { channelMemory.erase(n); } count--; if (u->mode & User::OP_MODE) countOp--; if (u->userListItem && u->userListItem->identified > 0) u->userListItem->identified--; delete u; } void Channel::changeNick(String on, String nn) { on = on.toLower(); User *u = getUser(on); channelMemory.erase(on); channelMemory[nn.toLower()] = u; } bool Channel::hasNick(String n) { return getUser(n.toLower()) != 0; } User * Channel::getUser(String n) { User *u; n = n.toLower(); if ((u = channelMemory[n]) == 0) { channelMemory.erase(n); return 0; } return u; } void Channel::addBan(String mask, std::time_t expiration) { for (std::vector::iterator it = channelBanlist.begin(); it != channelBanlist.end(); ++it) if ((*it)->getMask() == mask) { if (expiration > (*it)->getExpirationDate()) (*it)->setExpirationDate(expiration); return; } channelBanlist.push_back(new BanEntry(mask, expiration)); } void Channel::delBan(String mask) { for (std::vector::iterator it = channelBanlist.begin(); it != channelBanlist.end(); ++it) if (mask == (*it)->getMask()) { BanEntry *b = *it; channelBanlist.erase(it); delete b; break; } } void Channel::resynchModes() { cnx->queue->sendChannelMode(String("MODE ") + channelName + " +" + cnx->bot->wantedChannels[channelName]->mode); } void Channel::parseMode(Person *from, String mode) { char sign = '-'; StringTokenizer st(mode); String m = st.next_token(), n; User *u = 0; if (from) u = getUser(from->getNick()); // u == 0 if it's a server mode bool doNotObey = !u || (u->getProt() <= User::NO_PROT); 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", String((long)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 : String("")); break; case 'o': n = st.next_token(); u = getUser(n); if (joined) sign == '+' ? countOp++ : countOp--; if (!u) break; sign == '+' ? (u->mode |= User::OP_MODE) : (u->mode &= ~User::OP_MODE); if (sign == '-' && u->getProt() >= User::NO_DEOP) { String fromNick = from->getNick(); User * v = getUser(fromNick); if (u == v) 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 (n.toLower() == cnx->bot->nickName.toLower() && doMode) { doMode = false; resynchModes(); } } break; case 'v': u = getUser(st.next_token()); u->mode = (sign == '+' ? u->mode |= User::VOICE_MODE : u->mode &= ~User::VOICE_MODE); break; case 'b': String m = st.next_token(); sign == '+' ? addBan(m) : delBan(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); } } }