/** * PURGECommand.cc * * 24/01/2001 - Greg Sikorski * Initial Version. * * Purges a channel. * * Caveats: None * * 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 (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * $Id: PURGECommand.cc,v 1.22 2008/04/16 20:34:40 danielaustin Exp $ */ #include #include #include #include "StringTokenizer.h" #include "ELog.h" #include "cservice.h" #include "levels.h" #include "dbHandle.h" #include "Network.h" #include "responses.h" #include "cservice_config.h" const char PURGECommand_cc_rcsId[] = "$Id: PURGECommand.cc,v 1.22 2008/04/16 20:34:40 danielaustin Exp $" ; namespace gnuworld { using std::endl ; using std::ends ; using std::string ; using std::stringstream ; bool PURGECommand::Exec( iClient* theClient, const string& Message ) { bot->incStat("COMMANDS.PURGE"); StringTokenizer st( Message ) ; if( st.size() < 2 ) { Usage(theClient); return true; } /* * Fetch the sqlUser record attached to this client. If there isn't one, * they aren't logged in - tell them they should be. */ sqlUser* theUser = bot->isAuthed(theClient, true); if (!theUser) { return false; } /* * Are we purging a user or a channel? */ // Did we find a '#' ? if( string::npos == st[ 1 ].find_first_of( '#' ) ) { // Nope, look by user then. sqlUser* tmpUser = bot->getUserRecord(st[1]); if (!tmpUser) { bot->Notice(theClient, bot->getResponse(theUser, language::not_registered, string("The user %s doesn't appear to be registered.")).c_str(), st[1].c_str()); return true; } int level = bot->getAdminAccessLevel(theUser); if (!theUser->getFlag(sqlUser::F_POWER)) if (level < level::userpurge) { bot->Notice(theClient, bot->getResponse(theUser, language::insuf_access, string("You have insufficient access to perform that command"))); return false; } int admLevel = bot->getAdminAccessLevel(tmpUser); /* * Why I did these ?? * if (admLevel) { bot->Notice(theClient, "Cannot purge any user with '*' access. Try to remove it's '*' access first."); return false; } if (tmpUser->getFlag(sqlUser::F_NOPURGE)) { bot->Notice(theClient, "User %s has NOPURGE flag. Remove it first.", tmpUser->getUserName().c_str()); return false; } */ if (!theUser->getFlag(sqlUser::F_POWER)) if ((level <= admLevel)/* && (tmpUser != theUser)*/) //<- reactivate this if admin can purge it's own user { bot->Notice(theClient, "Cannot purge a user with equal or higher access than your own"); return false; } string userToDel = tmpUser->getUserName(); if (bot->wipeUser(tmpUser->getID(), false)) { bot->logAdminMessage("%s (%s) purged user %s", theClient->getNickName().c_str(), theUser->getUserName().c_str(), userToDel.c_str()); bot->Notice(theClient, "Successfully purged user %s", userToDel.c_str()); } else { bot->logDebugMessage("An error occured at a user purge command."); bot->Notice(theClient, "An error occured while purged user. Contact coders."); return false; } return true; } //End of user purge if (st.size() < 3) { Usage(theClient); return true; } /* * First, check the channel isn't already registered. */ sqlChannel* theChan = bot->getChannelRecord(st[1]); if ((!theChan) || (st[1] == "*")) { bot->Notice(theClient, bot->getResponse(theUser, language::chan_not_reg, string("%s isn't registered with me")).c_str(), st[1].c_str()); return false; } /* * Check the user has sufficient access for this command.. */ int level = bot->getAdminAccessLevel(theUser); if (!theUser->getFlag(sqlUser::F_POWER)) if (level < level::chanpurge) { bot->Notice(theClient, bot->getResponse(theUser, language::insuf_access, string("You have insufficient access to perform that command"))); return false; } /* * Don't purge the channel if NOPURGE is set. */ if (!theUser->getFlag(sqlUser::F_POWER)) if (theChan->getFlag(sqlChannel::F_NOPURGE)) { bot->Notice(theClient, "%s has NOPURGE set, so I'm not purging it.", theChan->getName().c_str()); return false; } bool reop; string reason; if (!strcasecmp(st[2],"-noop")) { reason = st.assemble(3); reop = false; } else { reason = st.assemble(2); reop = true; } /* * Fetch some information about the owner of this channel, so we can * 'freeze' it for future investigation in the log. */ stringstream managerQuery; managerQuery << "SELECT users.user_name,users.email " << "FROM users,levels " << "WHERE levels.user_id = users.id " << "AND levels.access = 500 " << "AND levels.channel_id = " << theChan->getID() << " LIMIT 1" << ends; #ifdef LOG_SQL elog << "sqlQuery> " << managerQuery.str().c_str() << endl; #endif string manager = "No Manager"; string managerEmail = "No Email Address"; if( !bot->SQLDb->Exec(managerQuery, true ) ) //if( status != PGRES_TUPLES_OK ) { elog << "PURGE> SQL Error: " << bot->SQLDb->ErrorMessage() << endl ; return false ; } else { if (bot->SQLDb->Tuples() != 0) { manager = bot->SQLDb->GetValue(0,0); managerEmail = bot->SQLDb->GetValue(0,1); } } /* If we need to reop, do it here */ if (reop) { /* iterate over the channel userlist */ vector< iClient* > opList; Channel* tmpChan = Network->findChannel(theChan->getName()); /* only parse the following if the channel exists on the network * if there is nobody in the channel, there is nobody to op. */ if (tmpChan) { for (Channel::userIterator chanUsers = tmpChan->userList_begin(); chanUsers != tmpChan->userList_end(); ++chanUsers) { ChannelUser* tmpUser = chanUsers->second; iClient* tmpClient = tmpUser->getClient(); sqlUser* tUser = bot->isAuthed(tmpClient, false); if (!tUser) continue; /* are they globally suspended? */ if (tUser->getFlag(sqlUser::F_GLOBAL_SUSPEND)) continue; sqlLevel* theLevel = bot->getLevelRecord(tUser, theChan); /* check if they have access (and not suspended) */ if (theLevel) { if (theLevel->getSuspendExpire() > bot->currentTime()) continue; if (theLevel->getAccess() >= 100) { /* they're 100+, op them */ opList.push_back(tmpClient); } } } /* actually do the ops */ if (!opList.empty()) { /* check we are in the channel, and opped */ ChannelUser* tmpBotUser = tmpChan->findUser(bot->getInstance()); if (tmpBotUser) { if (!tmpBotUser->getMode(ChannelUser::MODE_O)) { /* op ourselves so that we can do the reops */ stringstream s; s << bot->getCharYY() << " M " << theChan->getName() << " +o " << bot->getCharYYXXX() << ends; bot->Write( s ); /* update the channel state */ tmpBotUser->setMode(ChannelUser::MODE_O); } } /* do the ops - if we were not in the channel before, this will * auto-join and op the bot anyway. */ bot->Op(tmpChan, opList); } } } /* * Reset everything back to nice default values. */ theChan->clearFlags(); theChan->setMassDeopPro(3); theChan->setFloodPro(0); theChan->setNoTake(0); theChan->setURL(""); theChan->setDescription(""); theChan->setComment(""); theChan->setKeywords(""); theChan->setRegisteredTS(0); theChan->setChannelMode("+tn"); theChan->commit(); /* * Permanently delete all associated Level records for this channel. */ stringstream theQuery ; theQuery << "DELETE FROM levels WHERE channel_id = " << theChan->getID() << ends; #ifdef LOG_SQL elog << "sqlQuery> " << theQuery.str().c_str() << endl; #endif if( !bot->SQLDb->Exec(theQuery ) ) //if( status != PGRES_COMMAND_OK ) { elog << "PURGE> SQL Error: " << bot->SQLDb->ErrorMessage() << endl ; return false ; } /* * Bin 'em all. */ cservice::sqlLevelHashType::const_iterator ptr = bot->sqlLevelCache.begin(); cservice::sqlLevelHashType::key_type thePair; while(ptr != bot->sqlLevelCache.end()) { sqlLevel* tmpLevel = ptr->second; unsigned int channel_id = ptr->first.second; if (channel_id == theChan->getID()) { thePair = ptr->first; #ifdef LOG_DEBUG elog << "Purging Level Record for: " << thePair.second << " (UID: " << thePair.first << ")" << endl; #endif ++ptr; bot->sqlLevelCache.erase(thePair); delete(tmpLevel); } else { ++ptr; } } bot->logAdminMessage("%s (%s) has purged %s (%s)", theClient->getNickName().c_str(), theUser->getUserName().c_str(), theChan->getName().c_str(), reason.c_str()); bot->Notice(theClient, bot->getResponse(theUser, language::purged_chan, string("Purged channel %s")).c_str(), st[1].c_str()); bot->writeChannelLog(theChan, theClient, sqlChannel::EV_PURGE, "has purged " + theChan->getName() + " (" + reason + "), " + "Manager was " + manager + " (" + managerEmail + ")" ); /* Remove from cache.. part channel. */ bot->sqlChannelCache.erase(theChan->getName()); bot->sqlChannelIDCache.erase(theChan->getID()); /* no longer interested in this channel */ bot->getUplink()->UnRegisterChannelEvent( theChan->getName(), bot ) ; /* remove mode 'R' (no longer registered) */ Channel* tmpChan = Network->findChannel(theChan->getName()); if (tmpChan) bot->getUplink()->Mode(NULL, tmpChan, string("-R"), string() ); bot->Part(theChan->getName()); bot->joinCount--; delete(theChan); return true ; } } // namespace gnuworld.