/*
* RAM $Id: ban.c 84 2009-01-17 23:19:56Z ghasatta $
*/
/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************/
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string>
#include "merc.h"
#include "strings.h"
#include "db.h"
#include "interp.h"
#include "ban.h"
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <iomanip>
ban_manager *ban_manager::pInstance = NULL;
ban_manager *ban_manager::Instance()
{
if(ban_manager::pInstance == NULL)
ban_manager::pInstance = new ban_manager;
return ban_manager::pInstance;
}
ban_manager::ban_manager()
{
}
ban_manager::~ban_manager()
{
}
bool ban_manager::add_ban(int _level, std::string _name, int _type, bool _perm)
{
std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
// remove existing ban for _name, if any.
if(this->remove_ban(_level, _name, false) == true)
{
ban_data new_ban(_level, _name, _type, _perm);
this->bans.push_back(new_ban);
this->save_bans();
return true;
}
else
return false;
}
bool ban_manager::remove_ban(int _level, std::string _name, bool should_save /* = true */)
{
std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
// remove any asterisks.
if(_name.empty() == false)
{
if(_name.at(0) == '*')
_name.erase(0,1);
if(_name.at(_name.size() - 1) == '*')
_name.erase(_name.size() - 1, 1);
}
std::vector<ban_data>::iterator existing_iter = this->find_ban(_name, true);
// if we already have a ban for _name, verify that _level is sufficient to change the ban. If so, remove the existing ban.
if(existing_iter != this->bans.end())
{
if(_level < existing_iter->level)
return false;
else
this->bans.erase(existing_iter);
}
if(should_save == true)
this->save_bans();
return true;
}
void ban_manager::save_bans() const
{
std::ofstream out;
out.exceptions(std::ios::eofbit | std::ios::failbit | std::ios::badbit);
try
{
out.open(BAN_FILE_NEW, std::ios::trunc);
for(std::vector<ban_data>::const_iterator i = this->bans.begin(); i != this->bans.end(); ++i)
i->write_save(out);
out.close();
}
catch(std::exception &e)
{
log_error("ban_manager::save_bans(): %s", e.what());
}
}
void ban_manager::load_bans()
{
if(this->load_old_format() == false)
{
std::ifstream in;
in.exceptions(std::ios::eofbit | std::ios::failbit | std::ios::badbit);
try
{
in.open(BAN_FILE_NEW, std::ios::in);
while(in.eof() == false)
{
std::string name;
int level;
std::string flags;
in >> name >> level >> flags;
this->bans.push_back(ban_data(level, name, str_read_flag(flags.c_str())));
}
in.close();
}
catch(std::exception &e)
{
log_error("ban_manager::load_bans(): %s", e.what());
}
}
}
bool ban_manager::load_old_format()
{
FILE *fp = NULL;
if ( ( fp = fopen( BAN_FILE, "r" ) ) == NULL )
return false;
while(!feof(fp))
{
std::string name = fread_word( fp );
int level = fread_number( fp );
int ban_flags = fread_flag( fp );
fread_to_eol( fp );
this->bans.push_back(ban_data(level, name, ban_flags));
}
fclose(fp);
// write in the new format.
this->save_bans();
// remove the old file.
unlink(BAN_FILE);
return true;
}
std::string ban_manager::print_bans() const
{
std::ostringstream out;
const char *_type;
const char *_perm;
out << "Banned sites level type status\r\n";
for(std::vector<ban_manager::ban_data>::const_iterator i = this->bans.begin(); i != this->bans.end(); ++i)
{
std::string name;
if(IS_SET(i->ban_flags, BAN_PREFIX))
name += "*";
name += i->name;
if(IS_SET(i->ban_flags, BAN_SUFFIX))
name += "*";
out << std::setw(12) << name << " ";
out << std::setprecision(3) << i->level << " ";
_type = IS_SET( i->ban_flags, BAN_NEWBIES ) ? "newbies" :
IS_SET( i->ban_flags, BAN_PERMIT ) ? "permit" :
IS_SET( i->ban_flags, BAN_ALL ) ? "all" : "";
_perm = IS_SET( i->ban_flags, BAN_PERMANENT ) ? "perm" : "temp";
out << std::setw(7) << std::left << _type << " ";
out << _perm;
out << "\r\n";
}
if(this->bans.empty() == true)
out << "(none)" << "\r\n";
return out.str();
}
std::vector<ban_manager::ban_data>::iterator ban_manager::find_ban(std::string _name, bool exact_match /* = false */)
{
std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
for(std::vector<ban_manager::ban_data>::iterator i = this->bans.begin(); i != this->bans.end(); ++i)
if(i->is_match(_name, exact_match) == true)
return i;
// else... not found
return this->bans.end();
}
std::vector<ban_manager::ban_data>::const_iterator ban_manager::find_ban(std::string _name, bool exact_match /* = false */) const
{
std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
for(std::vector<ban_manager::ban_data>::const_iterator i = this->bans.begin(); i != this->bans.end(); ++i)
if(i->is_match(_name, exact_match) == true)
return i;
// else... not found
return this->bans.end();
}
bool ban_manager::is_banned(std::string _name, int _type) const
{
// look for an exact match first.
std::vector<ban_manager::ban_data>::const_iterator i = this->find_ban(_name, true);
// if we didn't find an exact match, look for a wildcard match next.
if(i == this->bans.end())
i = this->find_ban(_name, false);
// if we still haven't found a matching ban, there is no ban, return false.
if(i == this->bans.end())
return false;
else if(IS_SET(i->ban_flags, _type))
return true;
// else...
return false;
}
ban_manager::ban_data::ban_data(int _level, std::string _name, int flags)
{
name = _name;
level = _level;
ban_flags = flags;
}
ban_manager::ban_data::ban_data(int _level, std::string _name, int _type, bool _perm)
{
name = _name;
level = _level;
ban_flags = _type;
if(_perm == true)
SET_BIT(this->ban_flags, BAN_PERMANENT);
this->parse_name();
}
ban_manager::ban_data::~ban_data()
{
}
void ban_manager::ban_data::parse_name()
{
// transform to lowercase.
std::transform(this->name.begin(), this->name.end(), this->name.begin(), tolower);
if(name.find("*") == 0)
{
name.erase(0, 1);
SET_BIT(this->ban_flags, BAN_PREFIX);
}
if(name.rfind("*") == (name.size() - 1))
{
SET_BIT(this->ban_flags, BAN_SUFFIX);
name.erase(name.size() - 1);
}
// if name is empty, it means both suffix and prefix are true.
else if(name.empty() == true)
SET_BIT(this->ban_flags, BAN_SUFFIX);
}
bool ban_manager::ban_data::is_match(std::string _name, bool exact_match) const
{
// transform arg to lowercase.
std::transform(_name.begin(), _name.end(), _name.begin(), tolower);
if( (exact_match == true && this->name == _name) ||
(exact_match == false && IS_SET(this->ban_flags, BAN_PREFIX) && _name.rfind(this->name) == (_name.size() - this->name.size())) ||
(exact_match == false && IS_SET(this->ban_flags, BAN_SUFFIX) && _name.find(this->name) == 0) )
return true;
// else...
return false;
}
void ban_manager::ban_data::write_save(std::ofstream &out) const
{
// only write if this is a permanent ban
if(IS_SET(this->ban_flags, BAN_PERMANENT))
out << this->name << " "
<< this->level << " "
<< print_flags(this->ban_flags) << std::endl;
}
void ban_manager::do_ban(CHAR_DATA *ch, const char *argument)
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
char arg3[MAX_INPUT_LENGTH];
argument = one_argument(argument, arg1);
argument = one_argument(argument, arg2);
argument = one_argument(argument, arg3);
// no arg means just print the ban list.
if(arg1[0] == '\0')
send_to_char(ban_manager::Instance()->print_bans().c_str(), ch);
// else we want to add a ban
else
{
std::string name(arg1);
int type = 0;
bool perm;
// arg1 is name
// arg2 is type
// arg3 is either perm or temp
// verify name contains something besides the wildcard character.
if(name.find_first_not_of("*") == std::string::npos)
{
ch_printf(ch, "Ban name must include at least 1 character besides the wildcard '*'");
return;
}
if(!str_prefix(arg2, "all"))
type = BAN_ALL;
else if(!str_prefix(arg2, "newbies"))
type = BAN_NEWBIES;
else if(!str_prefix(arg2, "permit"))
type = BAN_PERMIT;
else
{
ch_printf( ch, "Acceptable ban types are all, newbies, and permit.\r\n" );
return;
}
if(!str_prefix(arg3, "temp"))
perm = false;
else if(!str_prefix(arg3, "perm"))
perm = true;
else
{
ch_printf(ch, "Error: Must specify either 'perm' or 'temp' for ban length.\r\n");
return;
}
bool success = ban_manager::Instance()->add_ban(get_trust(ch), name, type, perm);
if(success == true)
ch_printf(ch, "%s has been banned.\r\n", name.c_str());
else
ch_printf(ch, "Error: Ban was not successful. Check for existing bans set to a level higher than your trust level.\r\n");
}
}
void ban_manager::do_permban(CHAR_DATA *ch, const char *argument)
{
send_to_char("Error: Permban command is obsolete. Use: ban sitename type perm/temp", ch);
}
void ban_manager::do_allow(CHAR_DATA *ch, const char *argument)
{
char arg1[MAX_INPUT_LENGTH];
bool success;
one_argument(argument, arg1);
if(arg1[0] == '\0')
{
ch_printf( ch, "Remove which site from the ban list?\r\n" );
return;
}
success = ban_manager::Instance()->remove_ban(get_trust(ch), arg1);
if(success == true)
ch_printf( ch, "Ban on %s lifted.\r\n", arg1 );
else
ch_printf( ch, "You are not powerful enough to lift that ban.\r\n" );
}