summaryrefslogtreecommitdiff
path: root/modules/commands/bs_badwords.cpp
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2014-11-24 14:27:23 -0500
committerAdam <Adam@anope.org>2014-11-24 14:27:23 -0500
commit42238034490fb5479d787bd1695750387d508200 (patch)
treec93c62e0e1c936e656ae5b9ee1b62380ce2a194c /modules/commands/bs_badwords.cpp
parentd492923610d9c9146b2a2b63de38deab2cfd4ca7 (diff)
Rewrite serializable to have field level granularity
Represent serializable objects in a digraph, and as a result made most object relationships implicitly defined, and use the graph to trace references between objects to determine relationships. Edges may also be marked as having a dependency of the object they point to, which allows for automatic cleanup and deletion of most objects when no longer needed. Additionally, this allows not having to require in-memory copies of everything when using external databases. db_sql has been rewritten for this and now always requires a database to function. db_sql with MySQL now requires InnoDB to make use of transactions and foreign key constraints.
Diffstat (limited to 'modules/commands/bs_badwords.cpp')
-rw-r--r--modules/commands/bs_badwords.cpp268
1 files changed, 120 insertions, 148 deletions
diff --git a/modules/commands/bs_badwords.cpp b/modules/commands/bs_badwords.cpp
index 38748724e..744f625e1 100644
--- a/modules/commands/bs_badwords.cpp
+++ b/modules/commands/bs_badwords.cpp
@@ -14,136 +14,120 @@
static EventHandlers<Event::BadWordEvents> *bwevents;
-struct BadWordImpl : BadWord, Serializable
+class BadWordImpl : public BadWord
{
- BadWordImpl() : Serializable("BadWord") { }
- ~BadWordImpl();
+ public:
+ BadWordImpl(Serialize::TypeBase *type) : BadWord(type) { }
+ BadWordImpl(Serialize::TypeBase *type, Serialize::ID id) : BadWord(type, id) { }
+
+ ChanServ::Channel *GetChannel() override;
+
+ void SetChannel(ChanServ::Channel *c) override;
+
+ Anope::string GetWord() override;
+
+ void SetWord(const Anope::string &w) override;
+
+ BadWordType GetType() override;
+
+ void SetType(const BadWordType &t) override;
+};
- void Serialize(Serialize::Data &data) const override
+class BadWordsType : public Serialize::Type<BadWordImpl>
+{
+ public:
+ Serialize::ObjectField<BadWordImpl, ChanServ::Channel *> channel;
+ Serialize::Field<BadWordImpl, Anope::string> word;
+ Serialize::Field<BadWordImpl, BadWordType> type;
+
+ BadWordsType(Module *me) : Serialize::Type<BadWordImpl>(me, "BadWord")
+ , channel(this, "ci", true)
+ , word(this, "word")
+ , type(this, "type")
{
- data["ci"] << this->chan;
- data["word"] << this->word;
- data.SetType("type", Serialize::Data::DT_INT); data["type"] << this->type;
}
-
- static Serializable* Unserialize(Serializable *obj, Serialize::Data &);
};
-struct BadWordsImpl : BadWords
+ChanServ::Channel *BadWordImpl::GetChannel()
{
- Serialize::Reference<ChanServ::Channel> ci;
- typedef std::vector<BadWordImpl *> list;
- Serialize::Checker<list> badwords;
+ return Get(&BadWordsType::channel);
+}
- BadWordsImpl(Extensible *obj) : ci(anope_dynamic_static_cast<ChanServ::Channel *>(obj)), badwords("BadWord") { }
+void BadWordImpl::SetChannel(ChanServ::Channel *c)
+{
+ Set(&BadWordsType::channel, c);
+}
- ~BadWordsImpl();
+Anope::string BadWordImpl::GetWord()
+{
+ return Get(&BadWordsType::word);
+}
- BadWord* AddBadWord(const Anope::string &word, BadWordType type) override
- {
- BadWordImpl *bw = new BadWordImpl();
- bw->chan = ci->name;
- bw->word = word;
- bw->type = type;
+void BadWordImpl::SetWord(const Anope::string &w)
+{
+ Set(&BadWordsType::word, w);
+}
- this->badwords->push_back(bw);
+BadWordType BadWordImpl::GetType()
+{
+ return Get(&BadWordsType::type);
+}
- (*bwevents)(&Event::BadWordEvents::OnBadWordAdd, ci, bw);
+void BadWordImpl::SetType(const BadWordType &t)
+{
+ Set(&BadWordsType::type, t);
+}
- return bw;
- }
+struct BadWordsImpl : BadWords
+{
+ BadWordsImpl(Module *me) : BadWords(me) { }
- BadWord* GetBadWord(unsigned index) const override
+ BadWord* AddBadWord(ChanServ::Channel *ci, const Anope::string &word, BadWordType type) override
{
- if (this->badwords->empty() || index >= this->badwords->size())
- return NULL;
+ BadWord *bw = badword.Create();
+ bw->SetChannel(ci);
+ bw->SetWord(word);
+ bw->SetType(type);
+
+ (*bwevents)(&Event::BadWordEvents::OnBadWordAdd, ci, bw);
- BadWordImpl *bw = (*this->badwords)[index];
- bw->QueueUpdate();
return bw;
}
- unsigned GetBadWordCount() const override
+ std::vector<BadWord *> GetBadWords(ChanServ::Channel *ci)
{
- return this->badwords->size();
+ return ci->GetRefs<BadWord *>(badword);
}
- void EraseBadWord(unsigned index) override
+ BadWord* GetBadWord(ChanServ::Channel *ci, unsigned index) override
{
- if (this->badwords->empty() || index >= this->badwords->size())
- return;
-
- (*bwevents)(&Event::BadWordEvents::OnBadWordDel, ci, (*this->badwords)[index]);
-
- delete this->badwords->at(index);
+ auto bw = GetBadWords(ci);
+ return index < bw.size() ? bw[index] : nullptr;
}
- void ClearBadWords() override
+ unsigned GetBadWordCount(ChanServ::Channel *ci) override
{
- while (!this->badwords->empty())
- delete this->badwords->back();
+ return GetBadWords(ci).size();
}
- void Check() override
+ void EraseBadWord(ChanServ::Channel *ci, unsigned index) override
{
- if (this->badwords->empty())
- ci->Shrink<BadWords>("badwords");
- }
-};
+ auto bws = GetBadWords(ci);
+ if (index >= bws.size())
+ return;
+
+ BadWord *bw = bws[index];
+ (*bwevents)(&Event::BadWordEvents::OnBadWordDel, ci, bw);
-BadWordsImpl::~BadWordsImpl()
-{
- for (list::iterator it = badwords->begin(); it != badwords->end();)
- {
- BadWord *bw = *it;
- ++it;
delete bw;
}
-}
-BadWordImpl::~BadWordImpl()
-{
- ChanServ::Channel *ci = ChanServ::Find(chan);
- if (ci)
+ void ClearBadWords(ChanServ::Channel *ci) override
{
- BadWordsImpl *badwords = ci->GetExt<BadWordsImpl>("badwords");
- if (badwords)
- {
- BadWordsImpl::list::iterator it = std::find(badwords->badwords->begin(), badwords->badwords->end(), this);
- if (it != badwords->badwords->end())
- badwords->badwords->erase(it);
- }
+ for (BadWord *bw : GetBadWords(ci))
+ delete bw;
}
-}
-
-Serializable* BadWordImpl::Unserialize(Serializable *obj, Serialize::Data &data)
-{
- Anope::string sci, sword;
-
- data["ci"] >> sci;
- data["word"] >> sword;
-
- ChanServ::Channel *ci = ChanServ::Find(sci);
- if (!ci)
- return NULL;
-
- unsigned int n;
- data["type"] >> n;
-
- BadWordImpl *bw;
- if (obj)
- bw = anope_dynamic_static_cast<BadWordImpl *>(obj);
- else
- bw = new BadWordImpl();
- bw->chan = sci;
- bw->word = sword;
- bw->type = static_cast<BadWordType>(n);
-
- BadWordsImpl *bws = ci->Require<BadWordsImpl>("badwords");
- bws->badwords->push_back(bw);
-
- return bw;
-}
+};
class CommandBSBadwords : public Command
{
@@ -153,13 +137,12 @@ class CommandBSBadwords : public Command
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "LIST";
ListFormatter list(source.GetAccount());
- BadWords *bw = ci->GetExt<BadWords>("badwords");
list.AddColumn(_("Number")).AddColumn(_("Word")).AddColumn(_("Type"));
- if (!bw || !bw->GetBadWordCount())
+ if (!badwords->GetBadWordCount(ci))
{
- source.Reply(_("The bad word list of \002{0}\002 is empty."), ci->name);
+ source.Reply(_("The bad word list of \002{0}\002 is empty."), ci->GetName());
return;
}
@@ -168,45 +151,45 @@ class CommandBSBadwords : public Command
NumberList(word, false,
[&](unsigned int num)
{
- if (!num || num > bw->GetBadWordCount())
+ if (!num || num > badwords->GetBadWordCount(ci))
return;
- const BadWord *b = bw->GetBadWord(num - 1);
+ BadWord *b = badwords->GetBadWord(ci, num - 1);
ListFormatter::ListEntry entry;
entry["Number"] = stringify(num);
- entry["Word"] = b->word;
- entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
+ entry["Word"] = b->GetWord();
+ entry["Type"] = b->GetType() == BW_SINGLE ? "(SINGLE)" : (b->GetType() == BW_START ? "(START)" : (b->GetType() == BW_END ? "(END)" : ""));
list.AddEntry(entry);
},
[](){});
}
else
{
- for (unsigned i = 0, end = bw->GetBadWordCount(); i < end; ++i)
+ for (unsigned i = 0, end = badwords->GetBadWordCount(ci); i < end; ++i)
{
- const BadWord *b = bw->GetBadWord(i);
+ BadWord *b = badwords->GetBadWord(ci, i);
- if (!word.empty() && !Anope::Match(b->word, word))
+ if (!word.empty() && !Anope::Match(b->GetWord(), word))
continue;
ListFormatter::ListEntry entry;
entry["Number"] = stringify(i + 1);
- entry["Word"] = b->word;
- entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
+ entry["Word"] = b->GetWord();
+ entry["Type"] = b->GetType() == BW_SINGLE ? "(SINGLE)" : (b->GetType() == BW_START ? "(START)" : (b->GetType() == BW_END ? "(END)" : ""));
list.AddEntry(entry);
}
}
if (list.IsEmpty())
{
- source.Reply(_("No matching entries on the bad word list of \002{0}\002."), ci->name);
+ source.Reply(_("No matching entries on the bad word list of \002{0}\002."), ci->GetName());
return;
}
std::vector<Anope::string> replies;
list.Process(replies);
- source.Reply(_("Bad words list for \002{0}\002:"), ci->name);
+ source.Reply(_("Bad words list for \002{0}\002:"), ci->GetName());
for (unsigned i = 0; i < replies.size(); ++i)
source.Reply(replies[i]);
@@ -219,7 +202,6 @@ class CommandBSBadwords : public Command
size_t pos = word.rfind(' ');
BadWordType bwtype = BW_ANY;
Anope::string realword = word;
- BadWords *badwords = ci->Require<BadWords>("badwords");
if (pos != Anope::string::npos)
{
@@ -237,7 +219,7 @@ class CommandBSBadwords : public Command
}
unsigned badwordsmax = Config->GetModule(this->module)->Get<unsigned>("badwordsmax");
- if (badwords->GetBadWordCount() >= badwordsmax)
+ if (badwords->GetBadWordCount(ci) >= badwordsmax)
{
source.Reply(_("Sorry, you can only have \002{0}\002 bad words entries on a channel."), badwordsmax);
return;
@@ -245,31 +227,25 @@ class CommandBSBadwords : public Command
bool casesensitive = Config->GetModule(this->module)->Get<bool>("casesensitive");
- for (unsigned i = 0, end = badwords->GetBadWordCount(); i < end; ++i)
- {
- const BadWord *bw = badwords->GetBadWord(i);
-
- if ((casesensitive && realword.equals_cs(bw->word)) || (!casesensitive && realword.equals_ci(bw->word)))
+ for (BadWord *bw : badwords->GetBadWords(ci))
+ if ((casesensitive && realword.equals_cs(bw->GetWord())) || (!casesensitive && realword.equals_ci(bw->GetWord())))
{
- source.Reply(_("\002{0}\002 already exists in \002{1}\002 bad words list."), bw->word, ci->name);
+ source.Reply(_("\002{0}\002 already exists in \002{1}\002 bad words list."), bw->GetWord(), ci->GetName());
return;
}
- }
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "ADD " << realword;
- badwords->AddBadWord(realword, bwtype);
+ badwords->AddBadWord(ci, realword, bwtype);
- source.Reply(_("\002{0}\002 added to \002{1}\002 bad words list."), realword, ci->name);
+ source.Reply(_("\002{0}\002 added to \002{1}\002 bad words list."), realword, ci->GetName());
}
void DoDelete(CommandSource &source, ChanServ::Channel *ci, const Anope::string &word)
{
- BadWords *badwords = ci->GetExt<BadWords>("badwords");
-
- if (!badwords || !badwords->GetBadWordCount())
+ if (!badwords->GetBadWordCount(ci))
{
- source.Reply(_("Bad word list for \002{0}\002 is empty."), ci->name);
+ source.Reply(_("Bad word list for \002{0}\002 is empty."), ci->GetName());
return;
}
@@ -283,50 +259,48 @@ class CommandBSBadwords : public Command
NumberList(word, true,
[&](unsigned int num)
{
- if (!num || num > badwords->GetBadWordCount())
+ if (!num || num > badwords->GetBadWordCount(ci))
return;
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "DEL " << badwords->GetBadWord(num - 1)->word;
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "DEL " << badwords->GetBadWord(ci, num - 1)->GetWord();
++deleted;
- badwords->EraseBadWord(num - 1);
+ badwords->EraseBadWord(ci, num - 1);
},
[&]()
{
if (!deleted)
- source.Reply(_("No matching entries on the bad word list of \002{0}\002."), ci->name);
+ source.Reply(_("No matching entries on the bad word list of \002{0}\002."), ci->GetName());
else if (deleted == 1)
- source.Reply(_("Deleted \0021\002 entry from bad word list of \002{0}\002."), ci->name);
+ source.Reply(_("Deleted \0021\002 entry from bad word list of \002{0}\002."), ci->GetName());
else
- source.Reply(_("Deleted \002{0}\002 entries from the bad word list of \002{1}\002."), deleted, ci->name);
+ source.Reply(_("Deleted \002{0}\002 entries from the bad word list of \002{1}\002."), deleted, ci->GetName());
});
}
else
{
unsigned i, end;
- const BadWord *badword;
+ BadWord *bw;
- for (i = 0, end = badwords->GetBadWordCount(); i < end; ++i)
+ for (i = 0, end = badwords->GetBadWordCount(ci); i < end; ++i)
{
- badword = badwords->GetBadWord(i);
+ bw = badwords->GetBadWord(ci, i);
- if (word.equals_ci(badword->word))
+ if (word.equals_ci(bw->GetWord()))
break;
}
if (i == end)
{
- source.Reply(_("\002{0}\002 was not found on the bad word list of \002{1}\002."), word, ci->name);
+ source.Reply(_("\002{0}\002 was not found on the bad word list of \002{1}\002."), word, ci->GetName());
return;
}
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "DEL " << badword->word;
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "DEL " << bw->GetWord();
- source.Reply(_("\002{0}\002 deleted from \002{1}\002 bad words list."), badword->word, ci->name);
+ source.Reply(_("\002{0}\002 deleted from \002{1}\002 bad words list."), bw->GetWord(), ci->GetName());
- badwords->EraseBadWord(i);
+ bw->Delete();
}
-
- badwords->Check();
}
void DoClear(CommandSource &source, ChanServ::Channel *ci)
@@ -334,9 +308,7 @@ class CommandBSBadwords : public Command
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "CLEAR";
- BadWords *badwords = ci->GetExt<BadWords>("badwords");
- if (badwords)
- badwords->ClearBadWords();
+ badwords->ClearBadWords(ci);
source.Reply(_("Bad words list is now empty."));
}
@@ -372,7 +344,7 @@ class CommandBSBadwords : public Command
if (!source.AccessFor(ci).HasPriv("BADWORDS") && (!need_args || !source.HasPriv("botserv/administration")))
{
- source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "BADWORDS", ci->name);
+ source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "BADWORDS", ci->GetName());
return;
}
@@ -475,16 +447,16 @@ class CommandBSBadwords : public Command
class BSBadwords : public Module
{
CommandBSBadwords commandbsbadwords;
- ExtensibleItem<BadWordsImpl> badwords;
- Serialize::Type badword_type;
+ BadWordsImpl badwords;
EventHandlers<Event::BadWordEvents> events;
+ BadWordsType bwtype;
public:
BSBadwords(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
, commandbsbadwords(this)
- , badwords(this, "badwords")
- , badword_type("BadWord", BadWordImpl::Unserialize)
+ , badwords(this)
, events(this, "Badwords")
+ , bwtype(this)
{
bwevents = &events;
}