CBan rewritten to use the XLine API. Untested as yet.

git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@9432 e03df62e-2008-0410-955e-edbf42e46eb7
This commit is contained in:
w00t 2008-04-08 19:42:23 +00:00
parent 80c42b2f46
commit ff32b2e66c

View File

@ -12,42 +12,76 @@
*/
#include "inspircd.h"
#include "xline.h"
/* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */
/** Holds a CBAN item
*/
class CBan : public classbase
class CBan : public XLine
{
public:
irc::string chname;
std::string set_by;
time_t set_on;
long length;
std::string reason;
irc::string matchtext;
CBan()
CBan(InspIRCd* Instance, time_t s_time, long d, const char* src, const char* re, const char *ch) : XLine(Instance, s_time, d, src, re, "CBAN")
{
this->matchtext = ch;
}
~CBan()
{
}
CBan(irc::string cn, std::string sb, time_t so, long ln, std::string rs) : chname(cn), set_by(sb), set_on(so), length(ln), reason(rs)
// XXX I shouldn't have to define this
bool Matches(User *u)
{
return false;
}
bool Matches(const std::string &s)
{
if (matchtext == s)
return true;
return false;
}
void DisplayExpiry()
{
ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed CBan %s (set by %s %ld seconds ago)", this->matchtext.c_str(), this->source, this->duration);
}
const char* Displayable()
{
return matchtext.c_str();
}
};
bool CBanComp(const CBan &ban1, const CBan &ban2);
/** An XLineFactory specialized to generate cban pointers
*/
class CBanFactory : public XLineFactory
{
public:
CBanFactory(InspIRCd* Instance) : XLineFactory(Instance, "CBAN") { }
typedef std::vector<CBan> cbanlist;
/** Generate a shun
*/
XLine* Generate(time_t set_time, long duration, const char* source, const char* reason, const char* xline_specific_mask)
{
return new CBan(ServerInstance, set_time, duration, source, reason, xline_specific_mask);
}
/* cbans is declared here, as our type is right above. Don't try move it. */
cbanlist cbans;
bool AutoApplyToUserList(XLine *x)
{
return false; // No, we apply to channels.
}
};
/** Handle /CBAN
*/
class CommandCban : public Command
class CommandCBan : public Command
{
public:
CommandCban(InspIRCd* Me) : Command(Me, "CBAN", "o", 1)
CommandCBan(InspIRCd* Me) : Command(Me, "CBAN", "o", 1)
{
this->source = "m_cban.so";
this->syntax = "<channel> [<duration> :<reason>]";
@ -61,184 +95,107 @@ class CommandCban : public Command
if(pcnt == 1)
{
/* form: CBAN #channel removes a CBAN */
for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
if (ServerInstance->XLines->DelLine(parameters[0], "CBAN", user))
{
if (parameters[0] == iter->chname)
{
long remaining = iter->length + ServerInstance->Time();
user->WriteNumeric(386, "%s %s :Removed CBAN due to expire at %s (%s)", user->nick, iter->chname.c_str(), ServerInstance->TimeString(remaining).c_str(), iter->reason.c_str());
cbans.erase(iter);
break;
}
}
}
else if (pcnt >= 2)
{
/* full form to add a CBAN */
if (ServerInstance->IsChannel(parameters[0]))
{
// parameters[0] = #channel
// parameters[1] = 1h3m2s
// parameters[2] = Tortoise abuser
long length = ServerInstance->Duration(parameters[1]);
std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";
cbans.push_back(CBan(parameters[0], user->nick, ServerInstance->Time(), length, reason));
std::sort(cbans.begin(), cbans.end(), CBanComp);
if(length > 0)
{
user->WriteNumeric(385, "%s %s :Added %lu second channel ban (%s)", user->nick, parameters[0], length, reason.c_str());
ServerInstance->SNO->WriteToSnoMask('A', "%s added %lu second channel ban on %s (%s)", user->nick, length, parameters[0], reason.c_str());
}
else
{
user->WriteNumeric(385, "%s %s :Added permanent channel ban (%s)", user->nick, parameters[0], reason.c_str());
ServerInstance->SNO->WriteToSnoMask('A', "%s added permanent channel ban on %s (%s)", user->nick, parameters[0], reason.c_str());
}
ServerInstance->SNO->WriteToSnoMask('x',"%s Removed CBan on %s.",user->nick,parameters[0]);
}
else
{
user->WriteNumeric(403, "%s %s :Invalid channel name", user->nick, parameters[0]);
return CMD_FAILURE;
user->WriteServ("NOTICE %s :*** CBan %s not found in list, try /stats C.",user->nick,parameters[0]);
}
return CMD_SUCCESS;
}
else if (pcnt >= 2)
{
// Adding - XXX todo make this respect <insane> tag perhaps..
long duration = ServerInstance->Duration(parameters[1]);
CBan *r = NULL;
try
{
r = new CBan(ServerInstance, ServerInstance->Time(), duration, user->nick, parameters[2], parameters[0]);
}
catch (...)
{
; // Do nothing. If we get here, the regex was fucked up, and they already got told it fucked up.
}
if (r)
{
if (ServerInstance->XLines->AddLine(r, user))
{
if (!duration)
{
ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent CBan for %s.", user->nick, parameters[0]);
}
else
{
time_t c_requires_crap = duration + ServerInstance->Time();
ServerInstance->SNO->WriteToSnoMask('x', "%s added timed CBan for %s, expires on %s", user->nick, parameters[0],
ServerInstance->TimeString(c_requires_crap).c_str());
}
ServerInstance->XLines->ApplyLines();
}
else
{
delete r;
user->WriteServ("NOTICE %s :*** CBan for %s already exists", user->nick, parameters[0]);
}
}
}
/* we want this routed! */
return CMD_SUCCESS;
return CMD_FAILURE;
}
};
bool CBanComp(const CBan &ban1, const CBan &ban2)
{
return ((ban1.set_on + ban1.length) < (ban2.set_on + ban2.length));
}
class ModuleCBan : public Module
{
CommandCban* mycommand;
CommandCBan* mycommand;
CBanFactory *f;
public:
ModuleCBan(InspIRCd* Me) : Module(Me)
{
mycommand = new CommandCban(Me);
f = new CBanFactory(ServerInstance);
ServerInstance->XLines->RegisterFactory(f);
mycommand = new CommandCBan(Me);
ServerInstance->AddCommand(mycommand);
Implementation eventlist[] = { I_OnUserPreJoin, I_OnSyncOtherMetaData, I_OnDecodeMetaData, I_OnStats };
ServerInstance->Modules->Attach(eventlist, this, 4);
}
virtual ~ModuleCBan()
{
ServerInstance->XLines->UnregisterFactory(f);
}
virtual int OnStats(char symbol, User* user, string_list &results)
{
ExpireBans();
if(symbol == 'C')
{
for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();
results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+iter->chname.c_str()+" "+iter->set_by+" "+ConvToStr(iter->set_on)+" "+ConvToStr(iter->length)+" "+ConvToStr(remaining)+" :"+iter->reason);
}
}
return 0;
}
virtual int OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs)
{
ExpireBans();
/* check cbans in here, and apply as necessary. */
for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
XLine *rl = ServerInstance->XLines->MatchesLine("CBAN", cname);
if (rl)
{
if(iter->chname == cname && !user->modes[UM_OPERATOR])
{
// Channel is banned.
user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick, cname, iter->reason.c_str());
ServerInstance->SNO->WriteToSnoMask('A', "%s tried to join %s which is CBANed (%s)", user->nick, cname, iter->reason.c_str());
return 1;
}
// Channel is banned.
user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick, cname, rl->reason);
ServerInstance->SNO->WriteToSnoMask('A', "%s tried to join %s which is CBANed (%s)", user->nick, cname, rl->reason);
return 1;
}
return 0;
}
virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable)
{
for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "cban", EncodeCBan(*iter));
}
}
virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
{
if((target_type == TYPE_OTHER) && (extname == "cban"))
{
cbans.push_back(DecodeCBan(extdata));
std::sort(cbans.begin(), cbans.end(), CBanComp);
}
}
virtual ~ModuleCBan()
{
}
virtual Version GetVersion()
{
return Version(1, 2, 0, 1, VF_COMMON | VF_VENDOR, API_VERSION);
}
std::string EncodeCBan(const CBan &ban)
{
std::ostringstream stream;
stream << ban.chname << " " << ban.set_by << " " << ban.set_on << " " << ban.length << " :" << ban.reason;
return stream.str();
}
CBan DecodeCBan(const std::string &data)
{
CBan res;
int set_on;
irc::tokenstream tokens(data);
tokens.GetToken(res.chname);
tokens.GetToken(res.set_by);
tokens.GetToken(set_on);
res.set_on = set_on;
tokens.GetToken(res.length);
tokens.GetToken(res.reason);
return res;
}
void ExpireBans()
{
bool go_again = true;
while (go_again)
{
go_again = false;
for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
{
/* 0 == permanent, don't mess with them! -- w00t */
if (iter->length != 0)
{
if (iter->set_on + iter->length <= ServerInstance->Time())
{
ServerInstance->SNO->WriteToSnoMask('A', "%li second CBAN on %s (%s) set on %s expired", iter->length, iter->chname.c_str(), iter->reason.c_str(), ServerInstance->TimeString(iter->set_on).c_str());
cbans.erase(iter);
go_again = true;
}
}
if (go_again == true)
break;
}
}
}
};
MODULE_INIT(ModuleCBan)