411 lines
9.7 KiB
C++
411 lines
9.7 KiB
C++
/**
|
|
* PURGECommand.cc
|
|
*
|
|
* 24/01/2001 - Greg Sikorski <gte@atomicrevs.demon.co.uk>
|
|
* 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 <string>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
|
|
#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.
|