summaryrefslogtreecommitdiff
path: root/modules/commands
diff options
context:
space:
mode:
Diffstat (limited to 'modules/commands')
-rw-r--r--modules/commands/bs_assign.cpp65
-rw-r--r--modules/commands/bs_badwords.cpp187
-rw-r--r--modules/commands/bs_info.cpp127
-rw-r--r--modules/commands/bs_kick.cpp623
-rw-r--r--modules/commands/bs_set.cpp317
-rw-r--r--modules/commands/cs_akick.cpp2
-rw-r--r--modules/commands/cs_clone.cpp19
-rw-r--r--modules/commands/cs_drop.cpp13
-rw-r--r--modules/commands/cs_enforce.cpp4
-rw-r--r--modules/commands/cs_entrymsg.cpp48
-rw-r--r--modules/commands/cs_info.cpp45
-rw-r--r--modules/commands/cs_list.cpp83
-rw-r--r--modules/commands/cs_log.cpp126
-rw-r--r--modules/commands/cs_mode.cpp368
-rw-r--r--modules/commands/cs_seen.cpp2
-rw-r--r--modules/commands/cs_set.cpp263
-rw-r--r--modules/commands/cs_set_misc.cpp57
-rw-r--r--modules/commands/cs_suspend.cpp131
-rw-r--r--modules/commands/cs_topic.cpp129
-rw-r--r--modules/commands/greet.cpp210
-rw-r--r--modules/commands/hs_request.cpp60
-rw-r--r--modules/commands/ms_info.cpp9
-rw-r--r--modules/commands/ms_set.cpp36
-rw-r--r--modules/commands/ns_ajoin.cpp53
-rw-r--r--modules/commands/ns_alist.cpp6
-rw-r--r--modules/commands/ns_cert.cpp224
-rw-r--r--modules/commands/ns_group.cpp10
-rw-r--r--modules/commands/ns_info.cpp170
-rw-r--r--modules/commands/ns_list.cpp112
-rw-r--r--modules/commands/ns_recover.cpp49
-rw-r--r--modules/commands/ns_register.cpp63
-rw-r--r--modules/commands/ns_resetpass.cpp28
-rw-r--r--modules/commands/ns_set.cpp427
-rw-r--r--modules/commands/ns_set_misc.cpp57
-rw-r--r--modules/commands/ns_suspend.cpp125
-rw-r--r--modules/commands/os_defcon.cpp20
-rw-r--r--modules/commands/os_login.cpp21
-rw-r--r--modules/commands/os_noop.cpp20
38 files changed, 2633 insertions, 1676 deletions
diff --git a/modules/commands/bs_assign.cpp b/modules/commands/bs_assign.cpp
index 7b241f09e..ba925ad80 100644
--- a/modules/commands/bs_assign.cpp
+++ b/modules/commands/bs_assign.cpp
@@ -145,14 +145,69 @@ class CommandBSUnassign : public Command
}
};
+class CommandBSSetNoBot : public Command
+{
+ public:
+ CommandBSSetNoBot(Module *creator, const Anope::string &sname = "botserv/set/nobot") : Command(creator, sname, 2, 2)
+ {
+ this->SetDesc(_("Prevent a bot from being assigned to a channel"));
+ this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ ChannelInfo *ci = ChannelInfo::Find(params[0]);
+ const Anope::string &value = params[1];
+
+ if (ci == NULL)
+ {
+ source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
+ return;
+ }
+
+ if (value.equals_ci("ON"))
+ {
+ Log(LOG_ADMIN, source, this, ci) << "to enable nobot";
+
+ ci->Extend<bool>("BS_NOBOT");
+ if (ci->bi)
+ ci->bi->UnAssign(source.GetUser(), ci);
+ source.Reply(_("No-bot mode is now \002on\002 on channel %s."), ci->name.c_str());
+ }
+ else if (value.equals_ci("OFF"))
+ {
+ Log(LOG_ADMIN, source, this, ci) << "to disable nobot";
+
+ ci->Shrink<bool>("BS_NOBOT");
+ source.Reply(_("No-bot mode is now \002off\002 on channel %s."), ci->name.c_str());
+ }
+ else
+ this->OnSyntaxError(source, source.command);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(_(" \n"
+ "This option makes a channel be unassignable. If a bot\n"
+ "is already assigned to the channel, it is unassigned\n"
+ "automatically when you enable the option."));
+ return true;
+ }
+};
+
class BSAssign : public Module
{
+ ExtensibleItem<bool> nobot;
+
CommandBSAssign commandbsassign;
CommandBSUnassign commandbsunassign;
+ CommandBSSetNoBot commandbssetnobot;
public:
BSAssign(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandbsassign(this), commandbsunassign(this)
+ nobot(this, "BS_NOBOT"),
+ commandbsassign(this), commandbsunassign(this), commandbssetnobot(this)
{
}
@@ -163,7 +218,7 @@ class BSAssign : public Module
return;
AccessGroup access = c->ci->AccessFor(source);
- if (c->ci->HasExt("BS_NOBOT") || (!access.HasPriv("ASSIGN") && !source->HasPriv("botserv/administration")))
+ if (nobot.HasExt(c->ci) || (!access.HasPriv("ASSIGN") && !source->HasPriv("botserv/administration")))
{
targ->SendMessage(bi, ACCESS_DENIED);
return;
@@ -184,6 +239,12 @@ class BSAssign : public Module
bi->Assign(source, c->ci);
targ->SendMessage(bi, _("Bot \002%s\002 has been assigned to %s."), bi->nick.c_str(), c->name.c_str());
}
+
+ void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override
+ {
+ if (nobot.HasExt(ci))
+ info.AddOption(_("No bot"));
+ }
};
MODULE_INIT(BSAssign)
diff --git a/modules/commands/bs_badwords.cpp b/modules/commands/bs_badwords.cpp
index 22fa74714..ff9707778 100644
--- a/modules/commands/bs_badwords.cpp
+++ b/modules/commands/bs_badwords.cpp
@@ -10,11 +10,132 @@
*/
#include "module.h"
+#include "modules/bs_badwords.h"
+
+struct BadWordImpl : BadWord, Serializable
+{
+ BadWordImpl() : Serializable("BadWord") { }
+ ~BadWordImpl();
+
+ void Serialize(Serialize::Data &data) const anope_override
+ {
+ 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
+{
+ Serialize::Reference<ChannelInfo> ci;
+ typedef std::vector<BadWordImpl *> list;
+ Serialize::Checker<list> badwords;
+
+ BadWordsImpl(Extensible *obj) : ci(anope_dynamic_static_cast<ChannelInfo *>(obj)), badwords("BadWord") { }
+
+ BadWord* AddBadWord(const Anope::string &word, BadWordType type) anope_override
+ {
+ BadWordImpl *bw = new BadWordImpl();
+ bw->chan = ci->name;
+ bw->word = word;
+ bw->type = type;
+
+ this->badwords->push_back(bw);
+
+ FOREACH_MOD(OnBadWordAdd, (ci, bw));
+
+ return bw;
+ }
+
+ BadWord* GetBadWord(unsigned index) const anope_override
+ {
+ if (this->badwords->empty() || index >= this->badwords->size())
+ return NULL;
+
+ BadWordImpl *bw = (*this->badwords)[index];
+ bw->QueueUpdate();
+ return bw;
+ }
+
+ unsigned GetBadWordCount() const anope_override
+ {
+ return this->badwords->size();
+ }
+
+ void EraseBadWord(unsigned index) anope_override
+ {
+ if (this->badwords->empty() || index >= this->badwords->size())
+ return;
+
+ FOREACH_MOD(OnBadWordDel, (ci, (*this->badwords)[index]));
+
+ delete this->badwords->at(index);
+ }
+
+ void ClearBadWords() anope_override
+ {
+ while (!this->badwords->empty())
+ delete this->badwords->back();
+ }
+
+ void Check() anope_override
+ {
+ if (this->badwords->empty())
+ ci->Shrink<BadWords>("badwords");
+ }
+};
+
+BadWordImpl::~BadWordImpl()
+{
+ ChannelInfo *ci = ChannelInfo::Find(chan);
+ if (ci)
+ {
+ 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);
+ }
+ }
+}
+
+Serializable* BadWordImpl::Unserialize(Serializable *obj, Serialize::Data &data)
+{
+ Anope::string sci, sword;
+
+ data["ci"] >> sci;
+ data["word"] >> sword;
+
+ ChannelInfo *ci = ChannelInfo::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 BadwordsDelCallback : public NumberList
{
CommandSource &source;
ChannelInfo *ci;
+ BadWords *bw;
Command *c;
unsigned deleted;
bool override;
@@ -23,6 +144,7 @@ class BadwordsDelCallback : public NumberList
{
if (!source.AccessFor(ci).HasPriv("BADWORDS") && source.HasPriv("botserv/administration"))
this->override = true;
+ bw = ci->Require<BadWords>("badwords");
}
~BadwordsDelCallback()
@@ -37,12 +159,12 @@ class BadwordsDelCallback : public NumberList
void HandleNumber(unsigned Number) anope_override
{
- if (!Number || Number > ci->GetBadWordCount())
+ if (!bw || !Number || Number > bw->GetBadWordCount())
return;
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << ci->GetBadWord(Number - 1)->word;
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, c, ci) << "DEL " << bw->GetBadWord(Number - 1)->word;
++deleted;
- ci->EraseBadWord(Number - 1);
+ bw->EraseBadWord(Number - 1);
}
};
@@ -54,10 +176,11 @@ class CommandBSBadwords : public Command
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "LIST";
ListFormatter list;
+ BadWords *bw = ci->GetExt<BadWords>("badwords");
list.AddColumn("Number").AddColumn("Word").AddColumn("Type");
- if (!ci->GetBadWordCount())
+ if (!bw || !bw->GetBadWordCount())
{
source.Reply(_("%s bad words list is empty."), ci->name.c_str());
return;
@@ -68,40 +191,41 @@ class CommandBSBadwords : public Command
{
ListFormatter &list;
ChannelInfo *ci;
+ BadWords *bw;
public:
- BadwordsListCallback(ListFormatter &_list, ChannelInfo *_ci, const Anope::string &numlist) : NumberList(numlist, false), list(_list), ci(_ci)
+ BadwordsListCallback(ListFormatter &_list, ChannelInfo *_ci, BadWords *_bw, const Anope::string &numlist) : NumberList(numlist, false), list(_list), ci(_ci), bw(_bw)
{
}
void HandleNumber(unsigned Number) anope_override
{
- if (!Number || Number > ci->GetBadWordCount())
+ if (!Number || Number > bw->GetBadWordCount())
return;
- const BadWord *bw = ci->GetBadWord(Number - 1);
+ const BadWord *b = bw->GetBadWord(Number - 1);
ListFormatter::ListEntry entry;
entry["Number"] = stringify(Number);
- entry["Word"] = bw->word;
- entry["Type"] = bw->type == BW_SINGLE ? "(SINGLE)" : (bw->type == BW_START ? "(START)" : (bw->type == BW_END ? "(END)" : ""));
+ entry["Word"] = b->word;
+ entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
this->list.AddEntry(entry);
}
}
- nl_list(list, ci, word);
+ nl_list(list, ci, bw, word);
nl_list.Process();
}
else
{
- for (unsigned i = 0, end = ci->GetBadWordCount(); i < end; ++i)
+ for (unsigned i = 0, end = bw->GetBadWordCount(); i < end; ++i)
{
- const BadWord *bw = ci->GetBadWord(i);
+ const BadWord *b = bw->GetBadWord(i);
- if (!word.empty() && !Anope::Match(bw->word, word))
+ if (!word.empty() && !Anope::Match(b->word, word))
continue;
ListFormatter::ListEntry entry;
entry["Number"] = stringify(i + 1);
- entry["Word"] = bw->word;
- entry["Type"] = bw->type == BW_SINGLE ? "(SINGLE)" : (bw->type == BW_START ? "(START)" : (bw->type == BW_END ? "(END)" : ""));
+ entry["Word"] = b->word;
+ entry["Type"] = b->type == BW_SINGLE ? "(SINGLE)" : (b->type == BW_START ? "(START)" : (b->type == BW_END ? "(END)" : ""));
list.AddEntry(entry);
}
}
@@ -127,6 +251,7 @@ 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)
{
@@ -144,7 +269,7 @@ class CommandBSBadwords : public Command
}
unsigned badwordsmax = Config->GetModule(this->module)->Get<unsigned>("badwordsmax");
- if (ci->GetBadWordCount() >= badwordsmax)
+ if (badwords->GetBadWordCount() >= badwordsmax)
{
source.Reply(_("Sorry, you can only have %d bad words entries on a channel."), badwordsmax);
return;
@@ -152,9 +277,9 @@ class CommandBSBadwords : public Command
bool casesensitive = Config->GetModule("botserv")->Get<bool>("casesensitive");
- for (unsigned i = 0, end = ci->GetBadWordCount(); i < end; ++i)
+ for (unsigned i = 0, end = badwords->GetBadWordCount(); i < end; ++i)
{
- const BadWord *bw = ci->GetBadWord(i);
+ const BadWord *bw = badwords->GetBadWord(i);
if ((casesensitive && realword.equals_cs(bw->word)) || (!casesensitive && realword.equals_ci(bw->word)))
{
@@ -165,13 +290,21 @@ class CommandBSBadwords : public Command
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "ADD " << realword;
- ci->AddBadWord(realword, bwtype);
+ badwords->AddBadWord(realword, bwtype);
source.Reply(_("\002%s\002 added to %s bad words list."), realword.c_str(), ci->name.c_str());
}
void DoDelete(CommandSource &source, ChannelInfo *ci, const Anope::string &word)
{
+ BadWords *badwords = ci->GetExt<BadWords>("badwords");
+
+ if (!badwords || !badwords->GetBadWordCount())
+ {
+ source.Reply(_("%s bad words list is empty."), ci->name.c_str());
+ return;
+ }
+
/* Special case: is it a number/list? Only do search if it isn't. */
if (!word.empty() && isdigit(word[0]) && word.find_first_not_of("1234567890,-") == Anope::string::npos)
{
@@ -183,9 +316,9 @@ class CommandBSBadwords : public Command
unsigned i, end;
const BadWord *badword;
- for (i = 0, end = ci->GetBadWordCount(); i < end; ++i)
+ for (i = 0, end = badwords->GetBadWordCount(); i < end; ++i)
{
- badword = ci->GetBadWord(i);
+ badword = badwords->GetBadWord(i);
if (word.equals_ci(badword->word))
break;
@@ -202,10 +335,10 @@ class CommandBSBadwords : public Command
source.Reply(_("\002%s\002 deleted from %s bad words list."), badword->word.c_str(), ci->name.c_str());
- ci->EraseBadWord(i);
+ badwords->EraseBadWord(i);
}
- return;
+ badwords->Check();
}
void DoClear(CommandSource &source, ChannelInfo *ci)
@@ -213,7 +346,9 @@ class CommandBSBadwords : public Command
bool override = !source.AccessFor(ci).HasPriv("BADWORDS");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "CLEAR";
- ci->ClearBadWords();
+ BadWords *badwords = ci->GetExt<BadWords>("badwords");
+ if (badwords)
+ badwords->ClearBadWords();
source.Reply(_("Bad words list is now empty."));
}
@@ -309,10 +444,12 @@ class CommandBSBadwords : public Command
class BSBadwords : public Module
{
CommandBSBadwords commandbsbadwords;
+ ExtensibleItem<BadWordsImpl> badwords;
+ Serialize::Type badword_type;
public:
BSBadwords(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandbsbadwords(this)
+ commandbsbadwords(this), badwords(this, "badwords"), badword_type("BadWord", BadWordImpl::Unserialize)
{
}
};
diff --git a/modules/commands/bs_info.cpp b/modules/commands/bs_info.cpp
index 8bbfd0b18..a3eb9ce2d 100644
--- a/modules/commands/bs_info.cpp
+++ b/modules/commands/bs_info.cpp
@@ -36,16 +36,6 @@ class CommandBSInfo : public Command
buffers.push_back(buf);
}
- void CheckOptStr(Anope::string &buf, const Anope::string &flag, const char *option, Extensible *flags, const NickCore *nc)
- {
- if (flags->HasExt(flag))
- {
- if (!buf.empty())
- buf += ", ";
- buf += Language::Translate(nc, option);
- }
- }
-
public:
CommandBSInfo(Module *creator) : Command(creator, "botserv/info", 1, 1)
{
@@ -57,8 +47,8 @@ class CommandBSInfo : public Command
{
const Anope::string &query = params[0];
- const BotInfo *bi = BotInfo::Find(query, true);
- ChannelInfo *ci;
+ BotInfo *bi = BotInfo::Find(query, true);
+ ChannelInfo *ci = ChannelInfo::Find(query);
InfoFormatter info(source.nc);
if (bi)
@@ -70,6 +60,8 @@ class CommandBSInfo : public Command
info[_("Options")] = bi->oper_only ? _("Private") : _("None");
info[_("Used on")] = stringify(bi->GetChannelCount()) + " channel(s)";
+ FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
+
std::vector<Anope::string> replies;
info.Process(replies);
@@ -85,7 +77,7 @@ class CommandBSInfo : public Command
}
}
- else if ((ci = ChannelInfo::Find(query)))
+ else if (ci)
{
if (!source.AccessFor(ci).HasPriv("INFO") && !source.HasPriv("botserv/administration"))
{
@@ -99,114 +91,7 @@ class CommandBSInfo : public Command
Anope::string enabled = Language::Translate(source.nc, _("Enabled"));
Anope::string disabled = Language::Translate(source.nc, _("Disabled"));
- if (ci->HasExt("BS_KICK_BADWORDS"))
- {
- if (ci->ttb[TTB_BADWORDS])
- info[_("Bad words kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), ci->ttb[TTB_BADWORDS]);
- else
- info[_("Bad words kicker")] = enabled;
- }
- else
- info[_("Bad words kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_BOLDS"))
- {
- if (ci->ttb[TTB_BOLDS])
- info[_("Bolds kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), ci->ttb[TTB_BOLDS]);
- else
- info[_("Bolds kicker")] = enabled;
- }
- else
- info[_("Bolds kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_CAPS"))
- {
- if (ci->ttb[TTB_CAPS])
- info[_("Caps kicker")] = Anope::printf(_("%s (%d kick(s) to ban; minimum %d/%d%%"), enabled.c_str(), ci->ttb[TTB_CAPS], ci->capsmin, ci->capspercent);
- else
- info[_("Caps kicker")] = Anope::printf(_("%s (minimum %d/%d%%)"), enabled.c_str(), ci->capsmin, ci->capspercent);
- }
- else
- info[_("Caps kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_COLORS"))
- {
- if (ci->ttb[TTB_COLORS])
- info[_("Colors kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_COLORS]);
- else
- info[_("Colors kicker")] = enabled;
- }
- else
- info[_("Colors kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_FLOOD"))
- {
- if (ci->ttb[TTB_FLOOD])
- info[_("Flood kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d lines in %ds"), enabled.c_str(), ci->ttb[TTB_FLOOD], ci->floodlines, ci->floodsecs);
- else
- info[_("Flood kicker")] = Anope::printf(_("%s (%d lines in %ds)"), enabled.c_str(), ci->floodlines, ci->floodsecs);
- }
- else
- info[_("Flood kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_REPEAT"))
- {
- if (ci->ttb[TTB_REPEAT])
- info[_("Repeat kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), ci->ttb[TTB_REPEAT], ci->repeattimes);
- else
- info[_("Repeat kicker")] = Anope::printf(_("%s (%d times)"), enabled.c_str(), ci->repeattimes);
- }
- else
- info[_("Repeat kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_REVERSES"))
- {
- if (ci->ttb[TTB_REVERSES])
- info[_("Reverses kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_REVERSES]);
- else
- info[_("Reverses kicker")] = enabled;
- }
- else
- info[_("Reverses kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_UNDERLINES"))
- {
- if (ci->ttb[TTB_UNDERLINES])
- info[_("Underlines kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_UNDERLINES]);
- else
- info[_("Underlines kicker")] = enabled;
- }
- else
- info[_("Underlines kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_ITALICS"))
- {
- if (ci->ttb[TTB_ITALICS])
- info[_("Italics kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_ITALICS]);
- else
- info[_("Italics kicker")] = enabled;
- }
- else
- info[_("Italics kicker")] = disabled;
-
- if (ci->HasExt("BS_KICK_AMSGS"))
- {
- if (ci->ttb[TTB_AMSGS])
- info[_("AMSG kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), ci->ttb[TTB_AMSGS]);
- else
- info[_("AMSG kicker")] = enabled;
- }
- else
- info[_("AMSG kicker")] = disabled;
-
- Anope::string flags;
- CheckOptStr(flags, "BS_DONTKICKOPS", _("Ops protection"), ci, source.nc);
- CheckOptStr(flags, "BS_DONTKICKVOICES", _("Voices protection"), ci, source.nc);
- CheckOptStr(flags, "BS_FANTASY", _("Fantasy"), ci, source.nc);
- CheckOptStr(flags, "BS_GREET", _("Greet"), ci, source.nc);
- CheckOptStr(flags, "BS_NOBOT", _("No bot"), ci, source.nc);
-
- info[_("Options")] = flags.empty() ? _("None") : flags;
+ FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
std::vector<Anope::string> replies;
info.Process(replies);
diff --git a/modules/commands/bs_kick.cpp b/modules/commands/bs_kick.cpp
index 50d4a0e5f..b22dd9ccb 100644
--- a/modules/commands/bs_kick.cpp
+++ b/modules/commands/bs_kick.cpp
@@ -12,9 +12,107 @@
*/
#include "module.h"
+#include "modules/bs_kick.h"
+#include "modules/bs_badwords.h"
static Module *me;
+struct KickerDataImpl : KickerData
+{
+ KickerDataImpl(Extensible *obj)
+ {
+ amsgs = badwords = bolds = caps = colors = flood = italics = repeat = reverses = underlines = false;
+ for (int16_t i = 0; i < TTB_SIZE; ++i)
+ ttb[i] = 0;
+ capsmin = capspercent = 0;
+ floodlines = floodsecs = 0;
+ repeattimes = 0;
+
+ dontkickops = dontkickvoices = false;
+ }
+
+ void Check(ChannelInfo *ci) anope_override
+ {
+ if (amsgs || badwords || bolds || caps || colors || flood || italics || repeat || reverses || underlines)
+ return;
+
+ ci->Shrink<KickerData>("kickerdata");
+ }
+
+ struct ExtensibleItem : ::ExtensibleItem<KickerDataImpl>
+ {
+ ExtensibleItem(Module *m, const Anope::string &name) : ::ExtensibleItem<KickerDataImpl>(m, name) { }
+
+ void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override
+ {
+ if (s->GetSerializableType()->GetName() != "ChannelInfo")
+ return;
+
+ const ChannelInfo *ci = anope_dynamic_static_cast<const ChannelInfo *>(e);
+ KickerData *kd = this->Get(ci);
+ if (kd == NULL)
+ return;
+
+ data["kickerdata:amsgs"] << kd->amsgs;
+ data["kickerdata:badwords"] << kd->badwords;
+ data["kickerdata:bolds"] << kd->bolds;
+ data["kickerdata:caps"] << kd->caps;
+ data["kickerdata:colors"] << kd->colors;
+ data["kickerdata:flood"] << kd->flood;
+ data["kickerdata:italics"] << kd->italics;
+ data["kickerdata:repeat"] << kd->repeat;
+ data["kickerdata:reverses"] << kd->reverses;
+ data["kickerdata:underlines"] << kd->underlines;
+
+ data.SetType("capsmin", Serialize::Data::DT_INT); data["capsmin"] << kd->capsmin;
+ data.SetType("capspercent", Serialize::Data::DT_INT); data["capspercent"] << kd->capspercent;
+ data.SetType("floodlines", Serialize::Data::DT_INT); data["floodlines"] << kd->floodlines;
+ data.SetType("floodsecs", Serialize::Data::DT_INT); data["floodsecs"] << kd->floodsecs;
+ data.SetType("repeattimes", Serialize::Data::DT_INT); data["repeattimes"] << kd->repeattimes;
+ for (int16_t i = 0; i < TTB_SIZE; ++i)
+ data["ttb"] << kd->ttb[i] << " ";
+ }
+
+ void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override
+ {
+ if (s->GetSerializableType()->GetName() != "ChannelInfo")
+ return;
+
+ ChannelInfo *ci = anope_dynamic_static_cast<ChannelInfo *>(e);
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+
+ data["kickerdata:amsgs"] >> kd->amsgs;
+ data["kickerdata:badwords"] >> kd->badwords;
+ data["kickerdata:bolds"] >> kd->bolds;
+ data["kickerdata:caps"] >> kd->caps;
+ data["kickerdata:colors"] >> kd->colors;
+ data["kickerdata:flood"] >> kd->flood;
+ data["kickerdata:italics"] >> kd->italics;
+ data["kickerdata:repeat"] >> kd->repeat;
+ data["kickerdata:reverses"] >> kd->reverses;
+ data["kickerdata:underlines"] >> kd->underlines;
+
+ data["capsmin"] >> kd->capsmin;
+ data["capspercent"] >> kd->capspercent;
+ data["floodlines"] >> kd->floodlines;
+ data["floodsecs"] >> kd->floodsecs;
+ data["repeattimes"] >> kd->repeattimes;
+
+ Anope::string ttb, tok;
+ data["ttb"] >> ttb;
+ spacesepstream sep(ttb);
+ for (int i = 0; sep.GetToken(tok) && i < TTB_SIZE; ++i)
+ try
+ {
+ ttb[i] = convertTo<int16_t>(tok);
+ }
+ catch (const ConvertException &) { }
+
+ kd->Check(ci);
+ }
+ };
+};
+
class CommandBSKick : public Command
{
public:
@@ -99,7 +197,7 @@ class CommandBSKickBase : public Command
return false;
}
- void Process(CommandSource &source, ChannelInfo *ci, const Anope::string &param, const Anope::string &ttb, size_t ttb_idx, const Anope::string &optname, const Anope::string &mdname)
+ void Process(CommandSource &source, ChannelInfo *ci, const Anope::string &param, const Anope::string &ttb, size_t ttb_idx, const Anope::string &optname, KickerData *kd, bool &val)
{
if (param.equals_ci("ON"))
{
@@ -119,15 +217,15 @@ class CommandBSKickBase : public Command
return;
}
- ci->ttb[ttb_idx] = i;
+ kd->ttb[ttb_idx] = i;
}
else
- ci->ttb[ttb_idx] = 0;
+ kd->ttb[ttb_idx] = 0;
- ci->ExtendMetadata(mdname);
- if (ci->ttb[ttb_idx])
+ val = true;
+ if (kd->ttb[ttb_idx])
source.Reply(_("Bot will now kick for \002%s\002, and will place a ban\n"
- "after %d kicks for the same user."), optname.c_str(), ci->ttb[ttb_idx]);
+ "after %d kicks for the same user."), optname.c_str(), kd->ttb[ttb_idx]);
else
source.Reply(_("Bot will now kick for \002%s\002."), optname.c_str());
@@ -139,7 +237,7 @@ class CommandBSKickBase : public Command
bool override = !source.AccessFor(ci).HasPriv("SET");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable the " << optname << "kicker";
- ci->Shrink(mdname);
+ val = false;
source.Reply(_("Bot won't kick for \002%s\002 anymore."), optname.c_str());
}
else
@@ -160,7 +258,11 @@ class CommandBSKickAMSG : public CommandBSKickBase
{
ChannelInfo *ci;
if (CheckArguments(source, params, ci))
- Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_AMSGS, "AMSG", "BS_KICK_AMSGS");
+ {
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_AMSGS, "AMSG", kd, kd->amsgs);
+ kd->Check(ci);
+ }
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -188,7 +290,12 @@ class CommandBSKickBadwords : public CommandBSKickBase
{
ChannelInfo *ci;
if (CheckArguments(source, params, ci))
- Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BADWORDS, "badwords", "BS_KICK_BADWORDS");
+ {
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BADWORDS, "badwords", kd, kd->badwords);
+ kd->Check(ci);
+ }
+
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -219,7 +326,11 @@ class CommandBSKickBolds : public CommandBSKickBase
{
ChannelInfo *ci;
if (CheckArguments(source, params, ci))
- Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BOLDS, "bolds", "BS_KICK_BOLDS");
+ {
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_BOLDS, "bolds", kd, kd->bolds);
+ kd->Check(ci);
+ }
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -248,6 +359,8 @@ class CommandBSKickCaps : public CommandBSKickBase
if (!CheckArguments(source, params, ci))
return;
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+
if (params[1].equals_ci("ON"))
{
const Anope::string &ttb = params.size() > 2 ? params[2] : "",
@@ -258,52 +371,54 @@ class CommandBSKickCaps : public CommandBSKickBase
{
try
{
- ci->ttb[TTB_CAPS] = convertTo<int16_t>(ttb);
- if (ci->ttb[TTB_CAPS] < 0)
+ kd->ttb[TTB_CAPS] = convertTo<int16_t>(ttb);
+ if (kd->ttb[TTB_CAPS] < 0)
throw ConvertException();
}
catch (const ConvertException &)
{
- ci->ttb[TTB_CAPS] = 0;
+ kd->ttb[TTB_CAPS] = 0;
source.Reply(_("\002%s\002 cannot be taken as times to ban."), ttb.c_str());
return;
}
}
else
- ci->ttb[TTB_CAPS] = 0;
+ kd->ttb[TTB_CAPS] = 0;
- ci->capsmin = 10;
+ kd->capsmin = 10;
try
{
- ci->capsmin = convertTo<int16_t>(min);
+ kd->capsmin = convertTo<int16_t>(min);
}
catch (const ConvertException &) { }
- if (ci->capsmin < 1)
- ci->capsmin = 10;
+ if (kd->capsmin < 1)
+ kd->capsmin = 10;
- ci->capspercent = 25;
+ kd->capspercent = 25;
try
{
- ci->capspercent = convertTo<int16_t>(percent);
+ kd->capspercent = convertTo<int16_t>(percent);
}
catch (const ConvertException &) { }
- if (ci->capspercent < 1 || ci->capspercent > 100)
- ci->capspercent = 25;
+ if (kd->capspercent < 1 || kd->capspercent > 100)
+ kd->capspercent = 25;
- ci->ExtendMetadata("BS_KICK_CAPS");
- if (ci->ttb[TTB_CAPS])
+ kd->caps = true;
+ if (kd->ttb[TTB_CAPS])
source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n"
"%d characters and %d%% of the entire message), and will\n"
- "place a ban after %d kicks for the same user."), ci->capsmin, ci->capspercent, ci->ttb[TTB_CAPS]);
+ "place a ban after %d kicks for the same user."), kd->capsmin, kd->capspercent, kd->ttb[TTB_CAPS]);
else
source.Reply(_("Bot will now kick for \002caps\002 (they must constitute at least\n"
- "%d characters and %d%% of the entire message)."), ci->capsmin, ci->capspercent);
+ "%d characters and %d%% of the entire message)."), kd->capsmin, kd->capspercent);
}
else
{
- ci->Shrink("BS_KICK_CAPS");
+ kd->caps = false;
source.Reply(_("Bot won't kick for \002caps\002 anymore."));
}
+
+ kd->Check(ci);
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -335,7 +450,11 @@ class CommandBSKickColors : public CommandBSKickBase
{
ChannelInfo *ci;
if (CheckArguments(source, params, ci))
- Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_COLORS, "colors", "BS_KICK_COLORS");
+ {
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_COLORS, "colors", kd, kd->colors);
+ kd->Check(ci);
+ }
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -364,6 +483,8 @@ class CommandBSKickFlood : public CommandBSKickBase
if (!CheckArguments(source, params, ci))
return;
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+
if (params[1].equals_ci("ON"))
{
const Anope::string &ttb = params.size() > 2 ? params[2] : "",
@@ -386,45 +507,47 @@ class CommandBSKickFlood : public CommandBSKickBase
return;
}
- ci->ttb[TTB_FLOOD] = i;
+ kd->ttb[TTB_FLOOD] = i;
}
else
- ci->ttb[TTB_FLOOD] = 0;
+ kd->ttb[TTB_FLOOD] = 0;
- ci->floodlines = 6;
+ kd->floodlines = 6;
try
{
- ci->floodlines = convertTo<int16_t>(lines);
+ kd->floodlines = convertTo<int16_t>(lines);
}
catch (const ConvertException &) { }
- if (ci->floodlines < 2)
- ci->floodlines = 6;
+ if (kd->floodlines < 2)
+ kd->floodlines = 6;
- ci->floodsecs = 10;
+ kd->floodsecs = 10;
try
{
- ci->floodsecs = convertTo<int16_t>(secs);
+ kd->floodsecs = convertTo<int16_t>(secs);
}
catch (const ConvertException &) { }
- if (ci->floodsecs < 1)
- ci->floodsecs = 10;
- if (ci->floodsecs > Config->GetModule(me)->Get<time_t>("keepdata"))
- ci->floodsecs = Config->GetModule(me)->Get<time_t>("keepdata");
+ if (kd->floodsecs < 1)
+ kd->floodsecs = 10;
+ if (kd->floodsecs > Config->GetModule(me)->Get<time_t>("keepdata"))
+ kd->floodsecs = Config->GetModule(me)->Get<time_t>("keepdata");
- ci->ExtendMetadata("BS_KICK_FLOOD");
- if (ci->ttb[TTB_FLOOD])
+ kd->flood = true;
+ if (kd->ttb[TTB_FLOOD])
source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds\n"
- "and will place a ban after %d kicks for the same user."), ci->floodlines, ci->floodsecs, ci->ttb[TTB_FLOOD]);
+ "and will place a ban after %d kicks for the same user."), kd->floodlines, kd->floodsecs, kd->ttb[TTB_FLOOD]);
else
- source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds)."), ci->floodlines, ci->floodsecs);
+ source.Reply(_("Bot will now kick for \002flood\002 (%d lines in %d seconds)."), kd->floodlines, kd->floodsecs);
}
else if (params[1].equals_ci("OFF"))
{
- ci->Shrink("BS_KICK_FLOOD");
+ kd->flood = false;
source.Reply(_("Bot won't kick for \002flood\002 anymore."));
}
else
this->OnSyntaxError(source, params[1]);
+
+ kd->Check(ci);
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -454,7 +577,11 @@ class CommandBSKickItalics : public CommandBSKickBase
{
ChannelInfo *ci;
if (CheckArguments(source, params, ci))
- Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", "BS_KICK_ITALICS");
+ {
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", kd, kd->italics);
+ kd->Check(ci);
+ }
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -483,6 +610,8 @@ class CommandBSKickRepeat : public CommandBSKickBase
if (!CheckArguments(source, params, ci))
return;
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+
if (params[1].equals_ci("ON"))
{
const Anope::string &ttb = params[2],
@@ -504,36 +633,38 @@ class CommandBSKickRepeat : public CommandBSKickBase
return;
}
- ci->ttb[TTB_REPEAT] = i;
+ kd->ttb[TTB_REPEAT] = i;
}
else
- ci->ttb[TTB_REPEAT] = 0;
+ kd->ttb[TTB_REPEAT] = 0;
- ci->repeattimes = 3;
+ kd->repeattimes = 3;
try
{
- ci->repeattimes = convertTo<int16_t>(times);
+ kd->repeattimes = convertTo<int16_t>(times);
}
catch (const ConvertException &) { }
- if (ci->repeattimes < 2)
- ci->repeattimes = 3;
+ if (kd->repeattimes < 2)
+ kd->repeattimes = 3;
- ci->ExtendMetadata("BS_KICK_REPEAT");
- if (ci->ttb[TTB_REPEAT])
+ kd->repeat = true;
+ if (kd->ttb[TTB_REPEAT])
source.Reply(_("Bot will now kick for \002repeats\002 (users that say the\n"
"same thing %d times), and will place a ban after %d\n"
- "kicks for the same user."), ci->repeattimes, ci->ttb[TTB_REPEAT]);
+ "kicks for the same user."), kd->repeattimes, kd->ttb[TTB_REPEAT]);
else
source.Reply(_("Bot will now kick for \002repeats\002 (users that say the\n"
- "same thing %d times)."), ci->repeattimes);
+ "same thing %d times)."), kd->repeattimes);
}
else if (params[1].equals_ci("OFF"))
{
- ci->Shrink("BS_KICK_REPEAT");
+ kd->repeat = false;
source.Reply(_("Bot won't kick for \002repeats\002 anymore."));
}
else
this->OnSyntaxError(source, params[1]);
+
+ kd->Check(ci);
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -562,7 +693,11 @@ class CommandBSKickReverses : public CommandBSKickBase
{
ChannelInfo *ci;
if (CheckArguments(source, params, ci))
- Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", "BS_KICK_ITALICS");
+ {
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_REVERSES, "reverses", kd, kd->reverses);
+ kd->Check(ci);
+ }
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -589,7 +724,11 @@ class CommandBSKickUnderlines : public CommandBSKickBase
{
ChannelInfo *ci;
if (CheckArguments(source, params, ci))
- Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_ITALICS, "italics", "BS_KICK_ITALICS");
+ {
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ Process(source, ci, params[1], params.size() > 2 ? params[2] : "", TTB_UNDERLINES, "underlines", kd, kd->underlines);
+ kd->Check(ci);
+ }
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -603,7 +742,137 @@ class CommandBSKickUnderlines : public CommandBSKickBase
}
};
-struct BanData : ExtensibleItem
+class CommandBSSetDontKickOps : public Command
+{
+ public:
+ CommandBSSetDontKickOps(Module *creator, const Anope::string &sname = "botserv/set/dontkickops") : Command(creator, sname, 2, 2)
+ {
+ this->SetDesc(_("To protect ops against bot kicks"));
+ this->SetSyntax(_("\037channel\037 {ON | OFF}"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ ChannelInfo *ci = ChannelInfo::Find(params[0]);
+ if (ci == NULL)
+ {
+ source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
+ return;
+ }
+
+ AccessGroup access = source.AccessFor(ci);
+ if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET"))
+ {
+ source.Reply(ACCESS_DENIED);
+ return;
+ }
+
+ if (Anope::ReadOnly)
+ {
+ source.Reply(_("Sorry, bot option setting is temporarily disabled."));
+ return;
+ }
+
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ if (params[1].equals_ci("ON"))
+ {
+ bool override = !access.HasPriv("SET");
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickops";
+
+ kd->dontkickops = true;
+ source.Reply(_("Bot \002won't kick ops\002 on channel %s."), ci->name.c_str());
+ }
+ else if (params[1].equals_ci("OFF"))
+ {
+ bool override = !access.HasPriv("SET");
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickops";
+
+ kd->dontkickops = false;
+ source.Reply(_("Bot \002will kick ops\002 on channel %s."), ci->name.c_str());
+ }
+ else
+ this->OnSyntaxError(source, source.command);
+
+ kd->Check(ci);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(_(" \n"
+ "Enables or disables \002ops protection\002 mode on a channel.\n"
+ "When it is enabled, ops won't be kicked by the bot\n"
+ "even if they don't match the NOKICK level."));
+ return true;
+ }
+};
+
+class CommandBSSetDontKickVoices : public Command
+{
+ public:
+ CommandBSSetDontKickVoices(Module *creator, const Anope::string &sname = "botserv/set/dontkickvoices") : Command(creator, sname, 2, 2)
+ {
+ this->SetDesc(_("To protect voices against bot kicks"));
+ this->SetSyntax(_("\037channel\037 {ON | OFF}"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ ChannelInfo *ci = ChannelInfo::Find(params[0]);
+ if (ci == NULL)
+ {
+ source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
+ return;
+ }
+
+ AccessGroup access = source.AccessFor(ci);
+ if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET"))
+ {
+ source.Reply(ACCESS_DENIED);
+ return;
+ }
+
+ if (Anope::ReadOnly)
+ {
+ source.Reply(_("Sorry, bot option setting is temporarily disabled."));
+ return;
+ }
+
+ KickerData *kd = ci->Require<KickerData>("kickerdata");
+ if (params[1].equals_ci("ON"))
+ {
+ bool override = !access.HasPriv("SET");
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickvoices";
+
+ kd->dontkickvoices = true;
+ source.Reply(_("Bot \002won't kick voices\002 on channel %s."), ci->name.c_str());
+ }
+ else if (params[1].equals_ci("OFF"))
+ {
+ bool override = !access.HasPriv("SET");
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickvoices";
+
+ kd->dontkickvoices = false;
+ source.Reply(_("Bot \002will kick voices\002 on channel %s."), ci->name.c_str());
+ }
+ else
+ this->OnSyntaxError(source, source.command);
+
+ kd->Check(ci);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(_(" \n"
+ "Enables or disables \002voices protection\002 mode on a channel.\n"
+ "When it is enabled, voices won't be kicked by the bot\n"
+ "even if they don't match the NOKICK level."));
+ return true;
+ }
+};
+
+struct BanData
{
struct Data
{
@@ -613,11 +882,6 @@ struct BanData : ExtensibleItem
Data()
{
- this->Clear();
- }
-
- void Clear()
- {
last_use = 0;
for (int i = 0; i < TTB_SIZE; ++i)
this->ttb[i] = 0;
@@ -625,10 +889,12 @@ struct BanData : ExtensibleItem
};
private:
- typedef std::map<Anope::string, Data, ci::less> data_type;
+ typedef Anope::map<Data> data_type;
data_type data_map;
public:
+ BanData(Extensible *) { }
+
Data &get(const Anope::string &key)
{
return this->data_map[key];
@@ -654,14 +920,9 @@ struct BanData : ExtensibleItem
}
};
-struct UserData : ExtensibleItem
+struct UserData
{
- UserData()
- {
- this->Clear();
- }
-
- void Clear()
+ UserData(Extensible *)
{
last_use = last_start = Anope::CurTime;
lines = times = 0;
@@ -682,7 +943,6 @@ struct UserData : ExtensibleItem
Anope::string lastline;
};
-
class BanDataPurger : public Timer
{
public:
@@ -696,12 +956,12 @@ class BanDataPurger : public Timer
{
Channel *c = it->second;
- BanData *bd = c->GetExt<BanData *>("bs_main_bandata");
+ BanData *bd = c->GetExt<BanData>("bandata");
if (bd != NULL)
{
bd->purge();
if (bd->empty())
- c->Shrink("bs_main_bandata");
+ c->Shrink<BanData>("bandata");
}
}
}
@@ -709,6 +969,10 @@ class BanDataPurger : public Timer
class BSKick : public Module
{
+ ExtensibleItem<BanData> bandata;
+ ExtensibleItem<UserData> userdata;
+ KickerDataImpl::ExtensibleItem kickerdata;
+
CommandBSKick commandbskick;
CommandBSKickAMSG commandbskickamsg;
CommandBSKickBadwords commandbskickbadwords;
@@ -721,17 +985,14 @@ class BSKick : public Module
CommandBSKickReverses commandbskickreverse;
CommandBSKickUnderlines commandbskickunderlines;
+ CommandBSSetDontKickOps commandbssetdontkickops;
+ CommandBSSetDontKickVoices commandbssetdontkickvoices;
+
BanDataPurger purger;
BanData::Data &GetBanData(User *u, Channel *c)
{
- BanData *bd = c->GetExt<BanData *>("bs_main_bandata");
- if (bd == NULL)
- {
- bd = new BanData();
- c->Extend("bs_main_bandata", bd);
- }
-
+ BanData *bd = bandata.Require(c);
return bd->get(u->GetMask());
}
@@ -741,17 +1002,11 @@ class BSKick : public Module
if (uc == NULL)
return NULL;
- UserData *ud = uc->GetExt<UserData *>("bs_main_userdata");
- if (ud == NULL)
- {
- ud = new UserData();
- uc->Extend("bs_main_userdata", ud);
- }
-
+ UserData *ud = userdata.Require(uc);
return ud;
}
- void check_ban(ChannelInfo *ci, User *u, int ttbtype)
+ void check_ban(ChannelInfo *ci, User *u, KickerData *kd, int ttbtype)
{
/* Don't ban ulines */
if (u->server->IsULined())
@@ -760,9 +1015,9 @@ class BSKick : public Module
BanData::Data &bd = this->GetBanData(u, ci->c);
++bd.ttb[ttbtype];
- if (ci->ttb[ttbtype] && bd.ttb[ttbtype] >= ci->ttb[ttbtype])
+ if (kd->ttb[ttbtype] && bd.ttb[ttbtype] >= kd->ttb[ttbtype])
{
- /* Should not use == here because bd.ttb[ttbtype] could possibly be > ci->ttb[ttbtype]
+ /* Should not use == here because bd.ttb[ttbtype] could possibly be > kd->ttb[ttbtype]
* if the TTB was changed after it was not set (0) before and the user had already been
* kicked a few times. Bug #1056 - Adam */
@@ -793,26 +1048,136 @@ class BSKick : public Module
public:
BSKick(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
+ bandata(this, "bandata"),
+ userdata(this, "userdata"),
+ kickerdata(this, "kickerdata"),
+
commandbskick(this),
commandbskickamsg(this), commandbskickbadwords(this), commandbskickbolds(this), commandbskickcaps(this),
commandbskickcolors(this), commandbskickflood(this), commandbskickitalics(this), commandbskickrepeat(this),
commandbskickreverse(this), commandbskickunderlines(this),
+ commandbssetdontkickops(this), commandbssetdontkickvoices(this),
+
purger(this)
{
me = this;
}
- ~BSKick()
+ void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override
{
- for (channel_map::const_iterator cit = ChannelList.begin(), cit_end = ChannelList.end(); cit != cit_end; ++cit)
+ if (!ci)
+ return;
+
+ Anope::string enabled = Language::Translate(source.nc, _("Enabled"));
+ Anope::string disabled = Language::Translate(source.nc, _("Disabled"));
+ KickerData *kd = kickerdata.Get(ci);
+
+ if (kd && kd->badwords)
+ {
+ if (kd->ttb[TTB_BADWORDS])
+ info[_("Bad words kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BADWORDS]);
+ else
+ info[_("Bad words kicker")] = enabled;
+ }
+ else
+ info[_("Bad words kicker")] = disabled;
+
+ if (kd && kd->bolds)
+ {
+ if (kd->ttb[TTB_BOLDS])
+ info[_("Bolds kicker")] = Anope::printf("%s (%d kick(s) to ban)", enabled.c_str(), kd->ttb[TTB_BOLDS]);
+ else
+ info[_("Bolds kicker")] = enabled;
+ }
+ else
+ info[_("Bolds kicker")] = disabled;
+
+ if (kd && kd->caps)
+ {
+ if (kd->ttb[TTB_CAPS])
+ info[_("Caps kicker")] = Anope::printf(_("%s (%d kick(s) to ban; minimum %d/%d%%"), enabled.c_str(), kd->ttb[TTB_CAPS], kd->capsmin, kd->capspercent);
+ else
+ info[_("Caps kicker")] = Anope::printf(_("%s (minimum %d/%d%%)"), enabled.c_str(), kd->capsmin, kd->capspercent);
+ }
+ else
+ info[_("Caps kicker")] = disabled;
+
+ if (kd && kd->colors)
+ {
+ if (kd->ttb[TTB_COLORS])
+ info[_("Colors kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_COLORS]);
+ else
+ info[_("Colors kicker")] = enabled;
+ }
+ else
+ info[_("Colors kicker")] = disabled;
+
+ if (kd && kd->flood)
+ {
+ if (kd->ttb[TTB_FLOOD])
+ info[_("Flood kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d lines in %ds"), enabled.c_str(), kd->ttb[TTB_FLOOD], kd->floodlines, kd->floodsecs);
+ else
+ info[_("Flood kicker")] = Anope::printf(_("%s (%d lines in %ds)"), enabled.c_str(), kd->floodlines, kd->floodsecs);
+ }
+ else
+ info[_("Flood kicker")] = disabled;
+
+ if (kd && kd->repeat)
{
- Channel *c = cit->second;
- for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ++it)
- it->second->Shrink("bs_main_userdata");
- c->Shrink("bs_main_bandata");
+ if (kd->ttb[TTB_REPEAT])
+ info[_("Repeat kicker")] = Anope::printf(_("%s (%d kick(s) to ban; %d times)"), enabled.c_str(), kd->ttb[TTB_REPEAT], kd->repeattimes);
+ else
+ info[_("Repeat kicker")] = Anope::printf(_("%s (%d times)"), enabled.c_str(), kd->repeattimes);
+ }
+ else
+ info[_("Repeat kicker")] = disabled;
+
+ if (kd && kd->reverses)
+ {
+ if (kd->ttb[TTB_REVERSES])
+ info[_("Reverses kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_REVERSES]);
+ else
+ info[_("Reverses kicker")] = enabled;
}
+ else
+ info[_("Reverses kicker")] = disabled;
+
+ if (kd && kd->underlines)
+ {
+ if (kd->ttb[TTB_UNDERLINES])
+ info[_("Underlines kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_UNDERLINES]);
+ else
+ info[_("Underlines kicker")] = enabled;
+ }
+ else
+ info[_("Underlines kicker")] = disabled;
+
+ if (kd && kd->italics)
+ {
+ if (kd->ttb[TTB_ITALICS])
+ info[_("Italics kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_ITALICS]);
+ else
+ info[_("Italics kicker")] = enabled;
+ }
+ else
+ info[_("Italics kicker")] = disabled;
+
+ if (kd && kd->amsgs)
+ {
+ if (kd->ttb[TTB_AMSGS])
+ info[_("AMSG kicker")] = Anope::printf(_("%s (%d kick(s) to ban)"), enabled.c_str(), kd->ttb[TTB_AMSGS]);
+ else
+ info[_("AMSG kicker")] = enabled;
+ }
+ else
+ info[_("AMSG kicker")] = disabled;
+
+ if (kd && kd->dontkickops)
+ info.AddOption(_("Ops Protection"));
+ if (kd && kd->dontkickvoices)
+ info.AddOption(_("Voices Protection"));
}
void OnPrivmsg(User *u, Channel *c, Anope::string &msg) anope_override
@@ -828,12 +1193,15 @@ class BSKick : public Module
ChannelInfo *ci = c->ci;
if (ci == NULL)
return;
+ KickerData *kd = kickerdata.Get(ci);
+ if (kd == NULL)
+ return;
if (ci->AccessFor(u).HasPriv("NOKICK"))
return;
- else if (ci->HasExt("BS_DONTKICKOPS") && (c->HasUserStatus(u, "HALFOP") || c->HasUserStatus(u, "OP") || c->HasUserStatus(u, "PROTECT") || c->HasUserStatus(u, "OWNER")))
+ else if (kd->dontkickops && (c->HasUserStatus(u, "HALFOP") || c->HasUserStatus(u, "OP") || c->HasUserStatus(u, "PROTECT") || c->HasUserStatus(u, "OWNER")))
return;
- else if (ci->HasExt("BS_DONTKICKVOICES") && c->HasUserStatus(u, "VOICE"))
+ else if (kd->dontkickvoices && c->HasUserStatus(u, "VOICE"))
return;
Anope::string realbuf = msg;
@@ -851,47 +1219,47 @@ class BSKick : public Module
return;
/* Bolds kicker */
- if (ci->HasExt("BS_KICK_BOLDS") && realbuf.find(2) != Anope::string::npos)
+ if (kd->bolds && realbuf.find(2) != Anope::string::npos)
{
- check_ban(ci, u, TTB_BOLDS);
+ check_ban(ci, u, kd, TTB_BOLDS);
bot_kick(ci, u, _("Don't use bolds on this channel!"));
return;
}
/* Color kicker */
- if (ci->HasExt("BS_KICK_COLORS") && realbuf.find(3) != Anope::string::npos)
+ if (kd->colors && realbuf.find(3) != Anope::string::npos)
{
- check_ban(ci, u, TTB_COLORS);
+ check_ban(ci, u, kd, TTB_COLORS);
bot_kick(ci, u, _("Don't use colors on this channel!"));
return;
}
/* Reverses kicker */
- if (ci->HasExt("BS_KICK_REVERSES") && realbuf.find(22) != Anope::string::npos)
+ if (kd->reverses && realbuf.find(22) != Anope::string::npos)
{
- check_ban(ci, u, TTB_REVERSES);
+ check_ban(ci, u, kd, TTB_REVERSES);
bot_kick(ci, u, _("Don't use reverses on this channel!"));
return;
}
/* Italics kicker */
- if (ci->HasExt("BS_KICK_ITALICS") && realbuf.find(29) != Anope::string::npos)
+ if (kd->italics && realbuf.find(29) != Anope::string::npos)
{
- check_ban(ci, u, TTB_ITALICS);
+ check_ban(ci, u, kd, TTB_ITALICS);
bot_kick(ci, u, _("Don't use italics on this channel!"));
return;
}
/* Underlines kicker */
- if (ci->HasExt("BS_KICK_UNDERLINES") && realbuf.find(31) != Anope::string::npos)
+ if (kd->underlines && realbuf.find(31) != Anope::string::npos)
{
- check_ban(ci, u, TTB_UNDERLINES);
+ check_ban(ci, u, kd, TTB_UNDERLINES);
bot_kick(ci, u, _("Don't use underlines on this channel!"));
return;
}
/* Caps kicker */
- if (ci->HasExt("BS_KICK_CAPS") && realbuf.length() >= static_cast<unsigned>(ci->capsmin))
+ if (kd->caps && realbuf.length() >= static_cast<unsigned>(kd->capsmin))
{
int i = 0, l = 0;
@@ -908,26 +1276,27 @@ class BSKick : public Module
* percentage of caps to kick for; the rest is ignored. -GD
*/
- if ((i || l) && i >= ci->capsmin && i * 100 / (i + l) >= ci->capspercent)
+ if ((i || l) && i >= kd->capsmin && i * 100 / (i + l) >= kd->capspercent)
{
- check_ban(ci, u, TTB_CAPS);
+ check_ban(ci, u, kd, TTB_CAPS);
bot_kick(ci, u, _("Turn caps lock OFF!"));
return;
}
}
/* Bad words kicker */
- if (ci->HasExt("BS_KICK_BADWORDS"))
+ if (kd->badwords)
{
bool mustkick = false;
+ BadWords *badwords = ci->GetExt<BadWords>("badwords");
/* Normalize the buffer */
Anope::string nbuf = Anope::NormalizeBuffer(realbuf);
bool casesensitive = Config->GetModule("botserv")->Get<bool>("casesensitive");
- for (unsigned i = 0, end = ci->GetBadWordCount(); i < end; ++i)
+ for (unsigned i = 0; badwords && i < badwords->GetBadWordCount(); ++i)
{
- const BadWord *bw = ci->GetBadWord(i);
+ const BadWord *bw = badwords->GetBadWord(i);
if (bw->type == BW_ANY && ((casesensitive && nbuf.find(bw->word) != Anope::string::npos) || (!casesensitive && nbuf.find_ci(bw->word) != Anope::string::npos)))
mustkick = true;
@@ -983,7 +1352,7 @@ class BSKick : public Module
if (mustkick)
{
- check_ban(ci, u, TTB_BADWORDS);
+ check_ban(ci, u, kd, TTB_BADWORDS);
if (Config->GetModule(me)->Get<bool>("gentlebadwordreason"))
bot_kick(ci, u, _("Watch your language!"));
else
@@ -999,34 +1368,34 @@ class BSKick : public Module
if (ud)
{
/* Flood kicker */
- if (ci->HasExt("BS_KICK_FLOOD"))
+ if (kd->flood)
{
- if (Anope::CurTime - ud->last_start > ci->floodsecs)
+ if (Anope::CurTime - ud->last_start > kd->floodsecs)
{
ud->last_start = Anope::CurTime;
ud->lines = 0;
}
++ud->lines;
- if (ud->lines >= ci->floodlines)
+ if (ud->lines >= kd->floodlines)
{
- check_ban(ci, u, TTB_FLOOD);
+ check_ban(ci, u, kd, TTB_FLOOD);
bot_kick(ci, u, _("Stop flooding!"));
return;
}
}
/* Repeat kicker */
- if (ci->HasExt("BS_KICK_REPEAT"))
+ if (kd->repeat)
{
if (!ud->lastline.equals_ci(realbuf))
ud->times = 0;
else
++ud->times;
- if (ud->times >= ci->repeattimes)
+ if (ud->times >= kd->repeattimes)
{
- check_ban(ci, u, TTB_REPEAT);
+ check_ban(ci, u, kd, TTB_REPEAT);
bot_kick(ci, u, _("Stop repeating yourself!"));
return;
}
@@ -1039,9 +1408,9 @@ class BSKick : public Module
Channel *chan = it->second->chan;
++it;
- if (chan->ci && chan->ci->HasExt("BS_KICK_AMSGS") && !chan->ci->AccessFor(u).HasPriv("NOKICK"))
+ if (chan->ci && kd->amsgs && !chan->ci->AccessFor(u).HasPriv("NOKICK"))
{
- check_ban(chan->ci, u, TTB_AMSGS);
+ check_ban(chan->ci, u, kd, TTB_AMSGS);
bot_kick(chan->ci, u, _("Don't use AMSGs!"));
}
}
diff --git a/modules/commands/bs_set.cpp b/modules/commands/bs_set.cpp
index fa2bd716f..4e1e77ad1 100644
--- a/modules/commands/bs_set.cpp
+++ b/modules/commands/bs_set.cpp
@@ -127,314 +127,6 @@ class CommandBSSetBanExpire : public Command
}
};
-class CommandBSSetDontKickOps : public Command
-{
- public:
- CommandBSSetDontKickOps(Module *creator, const Anope::string &sname = "botserv/set/dontkickops") : Command(creator, sname, 2, 2)
- {
- this->SetDesc(_("To protect ops against bot kicks"));
- this->SetSyntax(_("\037channel\037 {ON | OFF}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- ChannelInfo *ci = ChannelInfo::Find(params[0]);
- if (ci == NULL)
- {
- source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
- return;
- }
-
- AccessGroup access = source.AccessFor(ci);
- if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET"))
- {
- source.Reply(ACCESS_DENIED);
- return;
- }
-
- if (Anope::ReadOnly)
- {
- source.Reply(_("Sorry, bot option setting is temporarily disabled."));
- return;
- }
-
- if (params[1].equals_ci("ON"))
- {
- bool override = !access.HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickops";
-
- ci->ExtendMetadata("BS_DONTKICKOPS");
- source.Reply(_("Bot \002won't kick ops\002 on channel %s."), ci->name.c_str());
- }
- else if (params[1].equals_ci("OFF"))
- {
- bool override = !access.HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickops";
-
- ci->Shrink("BS_DONTKICKOPS");
- source.Reply(_("Bot \002will kick ops\002 on channel %s."), ci->name.c_str());
- }
- else
- this->OnSyntaxError(source, source.command);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(_(" \n"
- "Enables or disables \002ops protection\002 mode on a channel.\n"
- "When it is enabled, ops won't be kicked by the bot\n"
- "even if they don't match the NOKICK level."));
- return true;
- }
-};
-
-class CommandBSSetDontKickVoices : public Command
-{
- public:
- CommandBSSetDontKickVoices(Module *creator, const Anope::string &sname = "botserv/set/dontkickvoices") : Command(creator, sname, 2, 2)
- {
- this->SetDesc(_("To protect voices against bot kicks"));
- this->SetSyntax(_("\037channel\037 {ON | OFF}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- ChannelInfo *ci = ChannelInfo::Find(params[0]);
- if (ci == NULL)
- {
- source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
- return;
- }
-
- AccessGroup access = source.AccessFor(ci);
- if (!source.HasPriv("botserv/administration") && !access.HasPriv("SET"))
- {
- source.Reply(ACCESS_DENIED);
- return;
- }
-
- if (Anope::ReadOnly)
- {
- source.Reply(_("Sorry, bot option setting is temporarily disabled."));
- return;
- }
-
- if (params[1].equals_ci("ON"))
- {
- bool override = !access.HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable dontkickvoices";
-
- ci->ExtendMetadata("BS_DONTKICKVOICES");
- source.Reply(_("Bot \002won't kick voices\002 on channel %s."), ci->name.c_str());
- }
- else if (params[1].equals_ci("OFF"))
- {
- bool override = !access.HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable dontkickvoices";
-
- ci->Shrink("BS_DONTKICKVOICES");
- source.Reply(_("Bot \002will kick voices\002 on channel %s."), ci->name.c_str());
- }
- else
- this->OnSyntaxError(source, source.command);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(_(" \n"
- "Enables or disables \002voices protection\002 mode on a channel.\n"
- "When it is enabled, voices won't be kicked by the bot\n"
- "even if they don't match the NOKICK level."));
- return true;
- }
-};
-
-class CommandBSSetFantasy : public Command
-{
- public:
- CommandBSSetFantasy(Module *creator, const Anope::string &sname = "botserv/set/fantasy") : Command(creator, sname, 2, 2)
- {
- this->SetDesc(_("Enable fantaisist commands"));
- this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- ChannelInfo *ci = ChannelInfo::Find(params[0]);
- const Anope::string &value = params[1];
-
- if (ci == NULL)
- {
- source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
- return;
- }
-
- if (!source.HasPriv("botserv/administration") && !source.AccessFor(ci).HasPriv("SET"))
- {
- source.Reply(ACCESS_DENIED);
- return;
- }
-
- if (Anope::ReadOnly)
- {
- source.Reply(_("Sorry, bot option setting is temporarily disabled."));
- return;
- }
-
- if (value.equals_ci("ON"))
- {
- bool override = !source.AccessFor(ci).HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable fantasy";
-
- ci->ExtendMetadata("BS_FANTASY");
- source.Reply(_("Fantasy mode is now \002on\002 on channel %s."), ci->name.c_str());
- }
- else if (value.equals_ci("OFF"))
- {
- bool override = !source.AccessFor(ci).HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable fantasy";
-
- ci->Shrink("BS_FANTASY");
- source.Reply(_("Fantasy mode is now \002off\002 on channel %s."), ci->name.c_str());
- }
- else
- this->OnSyntaxError(source, source.command);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(_(" \n"
- "Enables or disables \002fantasy\002 mode on a channel.\n"
- "When it is enabled, users will be able to use\n"
- "fantasy commands on a channel when prefixed\n"
- "with one of the following fantasy characters: \002%s\002\n"
- " \n"
- "Note that users wanting to use fantaisist\n"
- "commands MUST have enough access for both\n"
- "the FANTASIA and the command they are executing."),
- Config->GetModule("botserv")->Get<const Anope::string>("fantasycharacter", "!").c_str());
- return true;
- }
-};
-
-class CommandBSSetGreet : public Command
-{
- public:
- CommandBSSetGreet(Module *creator, const Anope::string &sname = "botserv/set/greet") : Command(creator, sname, 2, 2)
- {
- this->SetDesc(_("Enable greet messages"));
- this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- ChannelInfo *ci = ChannelInfo::Find(params[0]);
- const Anope::string &value = params[1];
-
- if (ci == NULL)
- {
- source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
- return;
- }
-
- if (!source.HasPriv("botserv/administration") && !source.AccessFor(ci).HasPriv("SET"))
- {
- source.Reply(ACCESS_DENIED);
- return;
- }
-
- if (Anope::ReadOnly)
- {
- source.Reply(_("Sorry, bot option setting is temporarily disabled."));
- return;
- }
-
- if (value.equals_ci("ON"))
- {
- bool override = !source.AccessFor(ci).HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable greets";
-
- ci->ExtendMetadata("BS_GREET");
- source.Reply(_("Greet mode is now \002on\002 on channel %s."), ci->name.c_str());
- }
- else if (value.equals_ci("OFF"))
- {
- bool override = !source.AccessFor(ci).HasPriv("SET");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable greets";
-
- ci->Shrink("BS_GREET");
- source.Reply(_("Greet mode is now \002off\002 on channel %s."), ci->name.c_str());
- }
- else
- this->OnSyntaxError(source, source.command);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(_(" \n"
- "Enables or disables \002greet\002 mode on a channel.\n"
- "When it is enabled, the bot will display greet\n"
- "messages of users joining the channel, provided\n"
- "they have enough access to the channel."));
- return true;
- }
-};
-
-class CommandBSSetNoBot : public Command
-{
- public:
- CommandBSSetNoBot(Module *creator, const Anope::string &sname = "botserv/set/nobot") : Command(creator, sname, 2, 2)
- {
- this->SetDesc(_("Prevent a bot from being assigned to a channel"));
- this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- ChannelInfo *ci = ChannelInfo::Find(params[0]);
- const Anope::string &value = params[1];
-
- if (ci == NULL)
- {
- source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
- return;
- }
-
- if (value.equals_ci("ON"))
- {
- Log(LOG_ADMIN, source, this, ci) << "to enable nobot";
-
- ci->ExtendMetadata("BS_NOBOT");
- if (ci->bi)
- ci->bi->UnAssign(source.GetUser(), ci);
- source.Reply(_("No-bot mode is now \002on\002 on channel %s."), ci->name.c_str());
- }
- else if (value.equals_ci("OFF"))
- {
- Log(LOG_ADMIN, source, this, ci) << "to disable nobot";
-
- ci->Shrink("BS_NOBOT");
- source.Reply(_("No-bot mode is now \002off\002 on channel %s."), ci->name.c_str());
- }
- else
- this->OnSyntaxError(source, source.command);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(_(" \n"
- "This option makes a channel be unassignable. If a bot\n"
- "is already assigned to the channel, it is unassigned\n"
- "automatically when you enable the option."));
- return true;
- }
-};
-
class CommandBSSetPrivate : public Command
{
public:
@@ -483,17 +175,12 @@ class BSSet : public Module
{
CommandBSSet commandbsset;
CommandBSSetBanExpire commandbssetbanexpire;
- CommandBSSetDontKickOps commandbssetdontkickops;
- CommandBSSetDontKickVoices commandbssetdontkickvoices;
- CommandBSSetFantasy commandbssetfantasy;
- CommandBSSetGreet commandbssetgreet;
- CommandBSSetNoBot commandbssetnobot;
CommandBSSetPrivate commandbssetprivate;
public:
BSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandbsset(this), commandbssetbanexpire(this), commandbssetdontkickops(this), commandbssetdontkickvoices(this),
- commandbssetfantasy(this), commandbssetgreet(this), commandbssetnobot(this), commandbssetprivate(this)
+ commandbsset(this), commandbssetbanexpire(this),
+ commandbssetprivate(this)
{
}
diff --git a/modules/commands/cs_akick.cpp b/modules/commands/cs_akick.cpp
index 17a20a0dd..3764c54fc 100644
--- a/modules/commands/cs_akick.cpp
+++ b/modules/commands/cs_akick.cpp
@@ -20,8 +20,8 @@ class CommandCSAKick : public Command
const NickAlias *na = NickAlias::Find(mask);
NickCore *nc = NULL;
const AutoKick *akick;
-
unsigned reasonmax = Config->GetModule("chanserv")->Get<unsigned>("reasonmax", "200");
+
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
diff --git a/modules/commands/cs_clone.cpp b/modules/commands/cs_clone.cpp
index d9ba97894..a1b04d103 100644
--- a/modules/commands/cs_clone.cpp
+++ b/modules/commands/cs_clone.cpp
@@ -10,6 +10,7 @@
*/
#include "module.h"
+#include "modules/bs_badwords.h"
class CommandCSClone : public Command
{
@@ -125,12 +126,16 @@ public:
}
else if (what.equals_ci("BADWORDS"))
{
- target_ci->ClearBadWords();
- for (unsigned i = 0; i < ci->GetBadWordCount(); ++i)
- {
- const BadWord *bw = ci->GetBadWord(i);
- target_ci->AddBadWord(bw->word, bw->type);
- }
+ BadWords *target_badwords = target_ci->GetExt<BadWords>("badwords"),
+ *badwords = ci->Require<BadWords>("badwords");
+ if (target_badwords)
+ target_badwords->ClearBadWords();
+ if (badwords)
+ for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i)
+ {
+ const BadWord *bw = badwords->GetBadWord(i);
+ target_badwords->AddBadWord(bw->word, bw->type);
+ }
source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str());
}
@@ -141,8 +146,6 @@ public:
}
Log(LOG_COMMAND, source, this, ci) << "to clone " << (what.empty() ? "everything from it" : what) << " to " << target_ci->name;
-
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
diff --git a/modules/commands/cs_drop.cpp b/modules/commands/cs_drop.cpp
index 3f14aea65..adbe1f2ca 100644
--- a/modules/commands/cs_drop.cpp
+++ b/modules/commands/cs_drop.cpp
@@ -37,23 +37,20 @@ class CommandCSDrop : public Command
return;
}
- if (ci->HasExt("SUSPENDED") && !source.HasCommand("chanserv/drop"))
- {
- source.Reply(CHAN_X_SUSPENDED, chan.c_str());
- return;
- }
-
if ((ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER")) && !source.HasCommand("chanserv/drop"))
{
source.Reply(ACCESS_DENIED);
return;
}
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnChanDrop, MOD_RESULT, (source, ci));
+ if (MOD_RESULT == EVENT_STOP)
+ return;
+
bool override = (ci->HasExt("SECUREFOUNDER") ? !source.IsFounder(ci) : !source.AccessFor(ci).HasPriv("FOUNDER"));
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "(founder was: " << (ci->GetFounder() ? ci->GetFounder()->display : "none") << ")";
- FOREACH_MOD(OnChanDrop, (ci));
-
Reference<Channel> c = ci->c;
delete ci;
diff --git a/modules/commands/cs_enforce.cpp b/modules/commands/cs_enforce.cpp
index e40676186..b683332f5 100644
--- a/modules/commands/cs_enforce.cpp
+++ b/modules/commands/cs_enforce.cpp
@@ -27,7 +27,7 @@ class CommandCSEnforce : public Command
* if it's off.
*/
bool hadsecureops = ci->HasExt("SECUREOPS");
- ci->ExtendMetadata("SECUREOPS");
+ ci->Extend<bool>("SECUREOPS");
for (Channel::ChanUserList::iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it)
{
@@ -37,7 +37,7 @@ class CommandCSEnforce : public Command
}
if (!hadsecureops)
- ci->Shrink("SECUREOPS");
+ ci->Shrink<bool>("SECUREOPS");
source.Reply(_("Secureops enforced on %s."), ci->name.c_str());
}
diff --git a/modules/commands/cs_entrymsg.cpp b/modules/commands/cs_entrymsg.cpp
index f94aca44c..d3d3bb71b 100644
--- a/modules/commands/cs_entrymsg.cpp
+++ b/modules/commands/cs_entrymsg.cpp
@@ -37,9 +37,9 @@ struct EntryMsg : Serializable
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
};
-struct EntryMessageList : Serialize::Checker<std::vector<EntryMsg *> >, ExtensibleItem
+struct EntryMessageList : Serialize::Checker<std::vector<EntryMsg *> >
{
- EntryMessageList() : Serialize::Checker<std::vector<EntryMsg *> >("EntryMsg") { }
+ EntryMessageList(Extensible *) : Serialize::Checker<std::vector<EntryMsg *> >("EntryMsg") { }
~EntryMessageList()
{
@@ -71,12 +71,9 @@ Serializable* EntryMsg::Unserialize(Serializable *obj, Serialize::Data &data)
return msg;
}
- EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
+ EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg");
if (messages == NULL)
- {
- messages = new EntryMessageList();
- ci->Extend("cs_entrymsg", messages);
- }
+ messages = ci->Extend<EntryMessageList>("entrymsg");
data["when"] >> swhen;
@@ -90,12 +87,9 @@ class CommandEntryMessage : public Command
private:
void DoList(CommandSource &source, ChannelInfo *ci)
{
- EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
+ EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg");
if (messages == NULL)
- {
- messages = new EntryMessageList();
- ci->Extend("cs_entrymsg", messages);
- }
+ messages = ci->Extend<EntryMessageList>("entrymsg");
if ((*messages)->empty())
{
@@ -129,12 +123,9 @@ class CommandEntryMessage : public Command
void DoAdd(CommandSource &source, ChannelInfo *ci, const Anope::string &message)
{
- EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
+ EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg");
if (messages == NULL)
- {
- messages = new EntryMessageList();
- ci->Extend("cs_entrymsg", messages);
- }
+ messages = ci->Extend<EntryMessageList>("entrymsg");
if ((*messages)->size() >= Config->GetModule(this->owner)->Get<unsigned>("maxentries"))
source.Reply(_("The entry message list for \002%s\002 is full."), ci->name.c_str());
@@ -148,12 +139,9 @@ class CommandEntryMessage : public Command
void DoDel(CommandSource &source, ChannelInfo *ci, const Anope::string &message)
{
- EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
+ EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg");
if (messages == NULL)
- {
- messages = new EntryMessageList();
- ci->Extend("cs_entrymsg", messages);
- }
+ messages = ci->Extend<EntryMessageList>("entrymsg");
if (!message.is_pos_number_only())
source.Reply(("Entry message \002%s\002 not found on channel \002%s\002."), message.c_str(), ci->name.c_str());
@@ -169,7 +157,7 @@ class CommandEntryMessage : public Command
delete (*messages)->at(i - 1);
(*messages)->erase((*messages)->begin() + i - 1);
if ((*messages)->empty())
- ci->Shrink("cs_entrymsg");
+ ci->Shrink<EntryMessageList>("entrymsg");
Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove a message";
source.Reply(_("Entry message \002%i\002 for \002%s\002 deleted."), i, ci->name.c_str());
}
@@ -185,14 +173,7 @@ class CommandEntryMessage : public Command
void DoClear(CommandSource &source, ChannelInfo *ci)
{
- EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
- if (messages != NULL)
- {
- for (unsigned i = 0; i < (*messages)->size(); ++i)
- delete (*messages)->at(i);
- (*messages)->clear();
- ci->Shrink("cs_entrymsg");
- }
+ ci->Shrink<EntryMessageList>("entrymsg");
Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove all messages";
source.Reply(_("Entry messages for \002%s\002 have been cleared."), ci->name.c_str());
@@ -267,9 +248,10 @@ class CSEntryMessage : public Module
{
Serialize::Type entrymsg_type;
CommandEntryMessage commandentrymsg;
+ ExtensibleItem<EntryMessageList> eml;
public:
- CSEntryMessage(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), entrymsg_type("EntryMsg", EntryMsg::Unserialize), commandentrymsg(this)
+ CSEntryMessage(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), entrymsg_type("EntryMsg", EntryMsg::Unserialize), commandentrymsg(this), eml(this, "entrymsg")
{
}
@@ -278,7 +260,7 @@ class CSEntryMessage : public Module
{
if (u && c && c->ci && u->server->IsSynced())
{
- EntryMessageList *messages = c->ci->GetExt<EntryMessageList *>("cs_entrymsg");
+ EntryMessageList *messages = c->ci->GetExt<EntryMessageList>("entrymsg");
if (messages != NULL)
for (unsigned i = 0; i < (*messages)->size(); ++i)
diff --git a/modules/commands/cs_info.cpp b/modules/commands/cs_info.cpp
index 0d3623c00..8f910fc83 100644
--- a/modules/commands/cs_info.cpp
+++ b/modules/commands/cs_info.cpp
@@ -13,17 +13,6 @@
class CommandCSInfo : public Command
{
- void CheckOptStr(Anope::string &buf, const Anope::string &opt, const char *str, const ChannelInfo *ci, const NickCore *nc)
- {
- if (ci->HasExt(opt))
- {
- if (!buf.empty())
- buf += ", ";
-
- buf += Language::Translate(nc, str);
- }
- }
-
public:
CommandCSInfo(Module *creator) : Command(creator, "chanserv/info", 1, 2)
{
@@ -66,43 +55,9 @@ class CommandCSInfo : public Command
info["Registered"] = Anope::strftime(ci->time_registered);
info["Last used"] = Anope::strftime(ci->last_used);
- const ModeLock *secret = ci->GetMLock("SECRET");
- if (!ci->last_topic.empty() && (show_all || ((!secret || secret->set == false) && (!ci->c || !ci->c->HasMode("SECRET")))))
- {
- info["Last topic"] = ci->last_topic;
- info["Topic set by"] = ci->last_topic_setter;
- }
-
if (show_all)
{
info["Ban type"] = stringify(ci->bantype);
-
- Anope::string optbuf;
- CheckOptStr(optbuf, "KEEPTOPIC", _("Topic Retention"), ci, nc);
- CheckOptStr(optbuf, "PEACE", _("Peace"), ci, nc);
- CheckOptStr(optbuf, "PRIVATE", _("Private"), ci, nc);
- CheckOptStr(optbuf, "RESTRICTED", _("Restricted Access"), ci, nc);
- CheckOptStr(optbuf, "SECURE", _("Secure"), ci, nc);
- CheckOptStr(optbuf, "SECUREFOUNDER", _("Secure Founder"), ci, nc);
- CheckOptStr(optbuf, "SECUREOPS", _("Secure Ops"), ci, nc);
- if (ci->HasExt("SIGNKICK"))
- CheckOptStr(optbuf, "SIGNKICK", _("Signed kicks"), ci, nc);
- else
- CheckOptStr(optbuf, "SIGNKICK_LEVEL", _("Signed kicks"), ci, nc);
- CheckOptStr(optbuf, "TOPICLOCK", _("Topic Lock"), ci, nc);
- CheckOptStr(optbuf, "PERSIST", _("Persistent"), ci, nc);
- CheckOptStr(optbuf, "NO_EXPIRE", _("No expire"), ci, nc);
- CheckOptStr(optbuf, "STATS", _("Chanstats"), ci, nc);
-
- info["Options"] = optbuf.empty() ? _("None") : optbuf;
-
- const Anope::string &ml = ci->GetMLockAsString(true);
- if (!ml.empty())
- info["Mode lock"] = ml;
-
- time_t chanserv_expire = Config->GetModule("chanserv")->Get<time_t>("expire", "14d");
- if (!ci->HasExt("NO_EXPIRE") && chanserv_expire && !Anope::NoExpire)
- info["Expires on"] = Anope::strftime(ci->last_used + chanserv_expire);
}
FOREACH_MOD(OnChanInfo, (source, ci, info, show_all));
diff --git a/modules/commands/cs_list.cpp b/modules/commands/cs_list.cpp
index 9e2df0a62..a92729b61 100644
--- a/modules/commands/cs_list.cpp
+++ b/modules/commands/cs_list.cpp
@@ -81,11 +81,11 @@ class CommandCSList : public Command
{
const ChannelInfo *ci = it->second;
- if (!is_servadmin && (ci->HasExt("PRIVATE") || ci->HasExt("SUSPENDED")))
+ if (!is_servadmin && (ci->HasExt("CS_PRIVATE") || ci->HasExt("SUSPENDED")))
continue;
else if (suspended && !ci->HasExt("SUSPENDED"))
continue;
- else if (channoexpire && !ci->HasExt("NO_EXPIRE"))
+ else if (channoexpire && !ci->HasExt("CS_NO_EXPIRE"))
continue;
if (pattern.equals_ci(ci->name) || ci->name.equals_ci(spattern) || Anope::Match(ci->name, pattern, false, true) || Anope::Match(ci->name, spattern, false, true))
@@ -93,7 +93,7 @@ class CommandCSList : public Command
if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nchans <= listmax)
{
bool isnoexpire = false;
- if (is_servadmin && (ci->HasExt("NO_EXPIRE")))
+ if (is_servadmin && (ci->HasExt("CS_NO_EXPIRE")))
isnoexpire = true;
ListFormatter::ListEntry entry;
@@ -159,14 +159,89 @@ class CommandCSList : public Command
}
};
+class CommandCSSetPrivate : public Command
+{
+ public:
+ CommandCSSetPrivate(Module *creator, const Anope::string &cname = "chanserv/set/private") : Command(creator, cname, 2, 2)
+ {
+ this->SetDesc(_("Hide channel from the LIST command"));
+ this->SetSyntax(_("\037channel\037 {ON | OFF}"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ ChannelInfo *ci = ChannelInfo::Find(params[0]);
+ if (ci == NULL)
+ {
+ source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
+ return;
+ }
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1]));
+ if (MOD_RESULT == EVENT_STOP)
+ return;
+
+ if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration"))
+ {
+ source.Reply(ACCESS_DENIED);
+ return;
+ }
+
+ if (params[1].equals_ci("ON"))
+ {
+ Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable private";
+ ci->Extend<bool>("CS_PRIVATE");
+ source.Reply(_("Private option for %s is now \002on\002."), ci->name.c_str());
+ }
+ else if (params[1].equals_ci("OFF"))
+ {
+ Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable private";
+ ci->Shrink<bool>("CS_PRIVATE");
+ source.Reply(_("Private option for %s is now \002off\002."), ci->name.c_str());
+ }
+ else
+ this->OnSyntaxError(source, "PRIVATE");
+
+ return;
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Enables or disables the \002private\002 option for a channel."));
+
+ BotInfo *bi;
+ Anope::string cmd;
+ if (Command::FindCommandFromService("chanserv/list", bi, cmd))
+ source.Reply(_("When \002private\002 is set, the channel will not appear in\n"
+ "%s's %s command."), bi->nick.c_str(), cmd.c_str());
+ return true;
+ }
+};
+
class CSList : public Module
{
CommandCSList commandcslist;
+ CommandCSSetPrivate commandcssetprivate;
+
+ SerializableExtensibleItem<bool> priv;
public:
- CSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandcslist(this)
+ CSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
+ commandcslist(this), commandcssetprivate(this), priv(this, "CS_PRIVATE")
{
}
+
+ void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override
+ {
+ if (!show_all)
+ return;
+
+ if (priv.HasExt(ci))
+ info.AddOption(_("Private"));
+ }
};
MODULE_INIT(CSList)
diff --git a/modules/commands/cs_log.cpp b/modules/commands/cs_log.cpp
index 969ebe5ab..bc6ba73c6 100644
--- a/modules/commands/cs_log.cpp
+++ b/modules/commands/cs_log.cpp
@@ -10,6 +10,77 @@
*/
#include "module.h"
+#include "modules/cs_log.h"
+
+struct LogSettingImpl : LogSetting, Serializable
+{
+ LogSettingImpl() : Serializable("LogSetting")
+ {
+ }
+
+ ~LogSettingImpl()
+ {
+ ChannelInfo *ci = ChannelInfo::Find(chan);
+ if (ci)
+ {
+ LogSettings *ls = ci->Require<LogSettings>("logsettings");
+ LogSettings::iterator it = std::find((*ls)->begin(), (*ls)->end(), this);
+ if (it != (*ls)->end())
+ (*ls)->erase(it);
+ }
+ }
+
+ void Serialize(Serialize::Data &data) const anope_override
+ {
+ data["ci"] << chan;
+ data["service_name"] << service_name;
+ data["command_service"] << command_service;
+ data["command_name"] << command_name;
+ data["method"] << method;
+ data["extra"] << extra;
+ data["creator"] << creator;
+ data.SetType("created", Serialize::Data::DT_INT); data["created"] << created;
+ }
+
+ static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
+ {
+ Anope::string sci;
+ data["ci"] >> sci;
+
+ ChannelInfo *ci = ChannelInfo::Find(sci);
+ if (ci == NULL)
+ return NULL;
+
+ LogSetting *ls;
+ if (obj)
+ ls = anope_dynamic_static_cast<LogSettingImpl *>(obj);
+ else
+ {
+ LogSettings *lsettings = ci->Require<LogSettings>("logsettings");
+ ls = new LogSettingImpl();
+ (*lsettings)->push_back(ls);
+ }
+
+ ls->chan = ci->name;
+ data["service_name"] >> ls->service_name;
+ data["command_service"] >> ls->command_service;
+ data["command_name"] >> ls->command_name;
+ data["method"] >> ls->method;
+ data["extra"] >> ls->extra;
+ data["creator"] >> ls->creator;
+ data["created"] >> ls->created;
+ }
+};
+
+struct LogSettingsImpl : LogSettings
+{
+ LogSettingsImpl(Extensible *) { }
+
+ LogSetting *Create() anope_override
+ {
+ return new LogSettingImpl();
+ }
+};
class CommandCSLog : public Command
{
@@ -32,16 +103,17 @@ public:
source.Reply(ACCESS_DENIED);
else if (params.size() == 1)
{
- if (ci->log_settings->empty())
+ LogSettings *ls = ci->Require<LogSettings>("logsettings");
+ if (!ls || (*ls)->empty())
source.Reply(_("There currently are no logging configurations for %s."), ci->name.c_str());
else
{
ListFormatter list;
list.AddColumn("Number").AddColumn("Service").AddColumn("Command").AddColumn("Method").AddColumn("");
- for (unsigned i = 0; i < ci->log_settings->size(); ++i)
+ for (unsigned i = 0; i < (*ls)->size(); ++i)
{
- const LogSetting *log = ci->log_settings->at(i);
+ const LogSetting *log = (*ls)->at(i);
ListFormatter::ListEntry entry;
entry["Number"] = stringify(i + 1);
@@ -63,6 +135,7 @@ public:
}
else if (params.size() > 2)
{
+ LogSettings *ls = ci->Require<LogSettings>("logsettings");
const Anope::string &command = params[1];
const Anope::string &method = params[2];
const Anope::string &extra = params.size() > 3 ? params[3] : "";
@@ -106,16 +179,15 @@ public:
bool override = !source.AccessFor(ci).HasPriv("SET");
- for (unsigned i = ci->log_settings->size(); i > 0; --i)
+ for (unsigned i = (*ls)->size(); i > 0; --i)
{
- LogSetting *log = ci->log_settings->at(i - 1);
+ LogSetting *log = (*ls)->at(i - 1);
if (log->service_name == bi->commands[command_name].name && log->method.equals_ci(method))
{
if (log->extra == extra)
{
delete log;
- ci->log_settings->erase(ci->log_settings->begin() + i - 1);
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to remove logging for " << command << " with method " << method << (extra == "" ? "" : " ") << extra;
source.Reply(_("Logging for command %s on %s with log method %s%s%s has been removed."), command_name.c_str(), bi->nick.c_str(), method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
}
@@ -129,8 +201,8 @@ public:
}
}
- LogSetting *log = new LogSetting();
- log->ci = ci;
+ LogSetting *log = new LogSettingImpl();
+ log->chan = ci->name;
log->service_name = bi->commands[command_name].name;
log->command_service = bi->nick;
log->command_name = command_name;
@@ -139,7 +211,8 @@ public:
log->created = Anope::CurTime;
log->creator = source.GetNick();
- ci->log_settings->push_back(log);
+ (*ls)->push_back(log);
+
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to log " << command << " with method " << method << (extra == "" ? "" : " ") << extra;
source.Reply(_("Logging is now active for command %s on %s, using log method %s%s%s."), command_name.c_str(), bi->nick.c_str(), method.c_str(), extra.empty() ? "" : " ", extra.empty() ? "" : extra.c_str());
@@ -180,10 +253,13 @@ class CSLog : public Module
{
ServiceReference<MemoServService> MSService;
CommandCSLog commandcslog;
+ ExtensibleItem<LogSettingsImpl> logsettings;
+ Serialize::Type logsetting_type;
public:
CSLog(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- MSService("MemoServService", "MemoServ"), commandcslog(this)
+ MSService("MemoServService", "MemoServ"), commandcslog(this), logsettings(this, "logsettings"),
+ logsetting_type("LogSetting", LogSettingImpl::Unserialize)
{
}
@@ -193,25 +269,27 @@ class CSLog : public Module
if (l->type != LOG_COMMAND || l->u == NULL || l->c == NULL || l->ci == NULL || !Me || !Me->IsSynced())
return;
- for (unsigned i = l->ci->log_settings->size(); i > 0; --i)
- {
- const LogSetting *log = l->ci->log_settings->at(i - 1);
-
- if (log->service_name == l->c->name)
+ LogSettings *ls = logsettings.Get(l->ci);
+ if (ls)
+ for (unsigned i = 0; i < (*ls)->size(); ++i)
{
- Anope::string buffer = l->u->nick + " used " + log->command_name + " " + l->buf.str();
+ const LogSetting *log = (*ls)->at(i);
- if (log->method.equals_ci("MESSAGE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL)
+ if (log->service_name == l->c->name)
{
- IRCD->SendPrivmsg(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str());
- l->ci->bi->lastmsg = Anope::CurTime;
+ Anope::string buffer = l->u->nick + " used " + log->command_name + " " + l->buf.str();
+
+ if (log->method.equals_ci("MESSAGE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL)
+ {
+ IRCD->SendPrivmsg(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str());
+ l->ci->bi->lastmsg = Anope::CurTime;
+ }
+ else if (log->method.equals_ci("NOTICE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL)
+ IRCD->SendNotice(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str());
+ else if (log->method.equals_ci("MEMO") && MSService && l->ci->WhoSends() != NULL)
+ MSService->Send(l->ci->WhoSends()->nick, l->ci->name, buffer, true);
}
- else if (log->method.equals_ci("NOTICE") && l->ci->c && l->ci->bi && l->ci->c->FindUser(l->ci->bi) != NULL)
- IRCD->SendNotice(l->ci->bi, log->extra + l->ci->c->name, "%s", buffer.c_str());
- else if (log->method.equals_ci("MEMO") && MSService && l->ci->WhoSends() != NULL)
- MSService->Send(l->ci->WhoSends()->nick, l->ci->name, buffer, true);
}
- }
}
};
diff --git a/modules/commands/cs_mode.cpp b/modules/commands/cs_mode.cpp
index 895bd3d5b..1299bc543 100644
--- a/modules/commands/cs_mode.cpp
+++ b/modules/commands/cs_mode.cpp
@@ -10,6 +10,234 @@
*/
#include "module.h"
+#include "modules/cs_mode.h"
+
+struct ModeLockImpl : ModeLock, Serializable
+{
+ ModeLockImpl() : Serializable("ModeLock")
+ {
+ }
+
+ ~ModeLockImpl()
+ {
+ ChannelInfo *chan = ChannelInfo::Find(ci);
+ if (chan)
+ {
+ ModeLocks *ml = chan->GetExt<ModeLocks>("modelocks");
+ if (ml)
+ ml->RemoveMLock(this);
+ }
+ }
+
+ void Serialize(Serialize::Data &data) const anope_override;
+ static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
+};
+
+struct ModeLocksImpl : ModeLocks
+{
+ Serialize::Reference<ChannelInfo> ci;
+ Serialize::Checker<ModeList> mlocks;
+
+ ModeLocksImpl(Extensible *obj) : ci(anope_dynamic_static_cast<ChannelInfo *>(obj)), mlocks("ModeLock")
+ {
+ }
+
+ bool HasMLock(ChannelMode *mode, const Anope::string &param, bool status) const anope_override
+ {
+ if (!mode)
+ return false;
+
+ for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
+ {
+ const ModeLock *ml = *it;
+
+ if (ml->name == mode->name && ml->set == status && ml->param == param)
+ return true;
+ }
+
+ return false;
+ }
+
+ bool SetMLock(ChannelMode *mode, bool status, const Anope::string &param, Anope::string setter, time_t created = Anope::CurTime) anope_override
+ {
+ if (!mode)
+ return false;
+
+ RemoveMLock(mode, status, param);
+
+ if (setter.empty())
+ setter = ci->GetFounder() ? ci->GetFounder()->display : "Unknown";
+
+ ModeLock *ml = new ModeLockImpl();
+ ml->ci = ci->name;
+ ml->set = status;
+ ml->name = mode->name;
+ ml->param = param;
+ ml->setter = setter;
+ ml->created = created;
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnMLock, MOD_RESULT, (this->ci, ml));
+ if (MOD_RESULT == EVENT_STOP)
+ {
+ delete ml;
+ return false;
+ }
+
+ this->mlocks->push_back(ml);
+ return true;
+ }
+
+ bool RemoveMLock(ChannelMode *mode, bool status, const Anope::string &param = "") anope_override
+ {
+ if (!mode)
+ return false;
+
+ for (ModeList::iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
+ {
+ ModeLock *m = *it;
+
+ if (m->name == mode->name)
+ {
+ // For list or status modes, we must check the parameter
+ if (mode->type == MODE_LIST || mode->type == MODE_STATUS)
+ if (m->param != param)
+ continue;
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnUnMLock, MOD_RESULT, (this->ci, m));
+ if (MOD_RESULT == EVENT_STOP)
+ break;
+
+ delete m;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void RemoveMLock(ModeLock *mlock) anope_override
+ {
+ ModeList::iterator it = std::find(this->mlocks->begin(), this->mlocks->end(), mlock);
+ if (it != this->mlocks->end())
+ this->mlocks->erase(it);
+ }
+
+ void ClearMLock() anope_override
+ {
+ ModeList ml;
+ this->mlocks->swap(ml);
+ for (unsigned i = 0; i < ml.size(); ++i)
+ delete ml[i];
+ }
+
+ const ModeList &GetMLock() const anope_override
+ {
+ return this->mlocks;
+ }
+
+ std::list<ModeLock *> GetModeLockList(const Anope::string &name) anope_override
+ {
+ std::list<ModeLock *> mlist;
+ for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
+ {
+ ModeLock *m = *it;
+ if (m->name == name)
+ mlist.push_back(m);
+ }
+ return mlist;
+ }
+
+ const ModeLock *GetMLock(const Anope::string &mname, const Anope::string &param = "") anope_override
+ {
+ for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
+ {
+ ModeLock *m = *it;
+
+ if (m->name == mname && m->param == param)
+ return m;
+ }
+
+ return NULL;
+ }
+
+ Anope::string GetMLockAsString(bool complete) const anope_override
+ {
+ Anope::string pos = "+", neg = "-", params;
+
+ for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
+ {
+ const ModeLock *ml = *it;
+ ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
+
+ if (!cm || cm->type == MODE_LIST || cm->type == MODE_STATUS)
+ continue;
+
+ if (ml->set)
+ pos += cm->mchar;
+ else
+ neg += cm->mchar;
+
+ if (complete && ml->set && !ml->param.empty() && cm->type == MODE_PARAM)
+ params += " " + ml->param;
+ }
+
+ if (pos.length() == 1)
+ pos.clear();
+ if (neg.length() == 1)
+ neg.clear();
+
+ return pos + neg + params;
+ }
+
+ void Check() anope_override
+ {
+ if (this->mlocks->empty())
+ ci->Shrink<ModeLocks>("modelocks");
+ }
+};
+
+void ModeLockImpl::Serialize(Serialize::Data &data) const
+{
+ data["ci"] << this->ci;
+ data["set"] << this->set;
+ data["name"] << this->name;
+ data["param"] << this->param;
+ data["setter"] << this->setter;
+ data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created;
+}
+
+Serializable* ModeLockImpl::Unserialize(Serializable *obj, Serialize::Data &data)
+{
+ Anope::string sci;
+
+ data["ci"] >> sci;
+
+ ChannelInfo *ci = ChannelInfo::Find(sci);
+ if (!ci)
+ return NULL;
+
+ ModeLockImpl *ml;
+ if (obj)
+ ml = anope_dynamic_static_cast<ModeLockImpl *>(obj);
+ else
+ {
+ ml = new ModeLockImpl();
+ ml->ci = ci->name;
+ }
+
+ data["set"] >> ml->set;
+ data["created"] >> ml->created;
+ data["setter"] >> ml->setter;
+ data["name"] >> ml->name;
+ data["param"] >> ml->param;
+
+ if (!obj)
+ ci->Require<ModeLocksImpl>("modelocks")->mlocks->push_back(ml);
+
+ return ml;
+}
class CommandCSMode : public Command
{
@@ -28,21 +256,20 @@ class CommandCSMode : public Command
const Anope::string &param = params.size() > 3 ? params[3] : "";
bool override = !source.AccessFor(ci).HasPriv("MODE");
+ ModeLocks *modelocks = ci->Require<ModeLocks>("modelocks");
if ((subcommand.equals_ci("ADD") || subcommand.equals_ci("SET")) && !param.empty())
{
/* If setting, remove the existing locks */
if (subcommand.equals_ci("SET"))
{
- const ChannelInfo::ModeList &mlocks = ci->GetMLock();
- for (ChannelInfo::ModeList::const_iterator it = mlocks.begin(), it_next; it != mlocks.end(); it = it_next)
+ const ModeLocks::ModeList mlocks = modelocks->GetMLock();
+ for (ModeLocks::ModeList::const_iterator it = mlocks.begin(); it != mlocks.end(); ++it)
{
- const ModeLock *ml = it->second;
+ const ModeLock *ml = *it;
ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
- it_next = it;
- ++it_next;
if (cm && cm->CanSet(source.GetUser()))
- ci->RemoveMLock(cm, ml->set, ml->param);
+ modelocks->RemoveMLock(cm, ml->set, ml->param);
}
}
@@ -86,7 +313,7 @@ class CommandCSMode : public Command
source.Reply(_("List for mode %c is full."), cm->mchar);
else
{
- ci->SetMLock(cm, adding, mode_param, source.GetNick());
+ modelocks->SetMLock(cm, adding, mode_param, source.GetNick());
if (adding)
{
@@ -110,8 +337,8 @@ class CommandCSMode : public Command
neg.clear();
Anope::string reply = pos + neg + pos_params + neg_params;
- source.Reply(_("%s locked on %s."), ci->GetMLockAsString(true).c_str(), ci->name.c_str());
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to lock " << ci->GetMLockAsString(true);
+ source.Reply(_("%s locked on %s."), modelocks->GetMLockAsString(true).c_str(), ci->name.c_str());
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to lock " << modelocks->GetMLockAsString(true);
if (ci->c)
ci->c->CheckModes();
@@ -154,7 +381,7 @@ class CommandCSMode : public Command
source.Reply(_("Missing parameter for mode %c."), cm->mchar);
else
{
- if (ci->RemoveMLock(cm, adding, mode_param))
+ if (modelocks->RemoveMLock(cm, adding, mode_param))
{
if (!mode_param.empty())
mode_param = " " + mode_param;
@@ -169,7 +396,7 @@ class CommandCSMode : public Command
}
else if (subcommand.equals_ci("LIST"))
{
- const ChannelInfo::ModeList &mlocks = ci->GetMLock();
+ const ModeLocks::ModeList mlocks = modelocks->GetMLock();
if (mlocks.empty())
{
source.Reply(_("Channel %s has no mode locks."), ci->name.c_str());
@@ -179,9 +406,9 @@ class CommandCSMode : public Command
ListFormatter list;
list.AddColumn("Mode").AddColumn("Param").AddColumn("Creator").AddColumn("Created");
- for (ChannelInfo::ModeList::const_iterator it = mlocks.begin(), it_end = mlocks.end(); it != it_end; ++it)
+ for (ModeLocks::ModeList::const_iterator it = mlocks.begin(), it_end = mlocks.end(); it != it_end; ++it)
{
- const ModeLock *ml = it->second;
+ const ModeLock *ml = *it;
ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
if (!cm)
continue;
@@ -481,12 +708,125 @@ class CommandCSMode : public Command
class CSMode : public Module
{
CommandCSMode commandcsmode;
+ ExtensibleItem<ModeLocksImpl> modelocks;
+ Serialize::Type modelocks_type;
public:
CSMode(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandcsmode(this)
+ commandcsmode(this), modelocks(this, "modelocks"), modelocks_type("ModeLock", ModeLockImpl::Unserialize)
+ {
+
+ }
+
+ EventReturn OnCheckModes(Channel *c) anope_override
+ {
+ if (!c->ci)
+ return EVENT_CONTINUE;
+
+ ModeLocks *ml = modelocks.Get(c->ci);
+ if (ml)
+ for (ModeLocks::ModeList::const_iterator it = ml->GetMLock().begin(), it_end = ml->GetMLock().end(); it != it_end; ++it)
+ {
+ const ModeLock *ml = *it;
+ ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
+ if (!cm)
+ continue;
+
+ if (cm->type == MODE_REGULAR)
+ {
+ if (!c->HasMode(cm->name) && ml->set)
+ c->SetMode(NULL, cm);
+ else if (c->HasMode(cm->name) && !ml->set)
+ c->RemoveMode(NULL, cm);
+ }
+ else if (cm->type == MODE_PARAM)
+ {
+ /* If the channel doesnt have the mode, or it does and it isn't set correctly */
+ if (ml->set)
+ {
+ Anope::string param;
+ c->GetParam(cm->name, param);
+
+ if (!c->HasMode(cm->name) || (!param.empty() && !ml->param.empty() && !param.equals_cs(ml->param)))
+ c->SetMode(NULL, cm, ml->param);
+ }
+ else
+ {
+ if (c->HasMode(cm->name))
+ c->RemoveMode(NULL, cm);
+ }
+
+ }
+ else if (cm->type == MODE_LIST)
+ {
+ if (ml->set)
+ c->SetMode(NULL, cm, ml->param);
+ else
+ c->RemoveMode(NULL, cm, ml->param);
+ }
+ }
+ }
+
+ EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) anope_override
+ {
+ if (!c->ci)
+ return EVENT_CONTINUE;
+
+ ModeLocks *ml = modelocks.Get(c->ci);
+ if (!ml)
+ return EVENT_CONTINUE;
+
+ if (ml->HasMLock(mode, param, false))
+ c->RemoveMode(c->ci->WhoSends(), mode, param);
+ }
+
+ EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) anope_override
+ {
+ if (!c->ci)
+ return EVENT_CONTINUE;
+
+ ModeLocks *ml = modelocks.Get(c->ci);
+ if (!ml)
+ return EVENT_CONTINUE;
+
+ if (ml->HasMLock(mode, param, true))
+ c->SetMode(c->ci->WhoSends(), mode, param);
+ }
+
+ void OnCreateChan(ChannelInfo *ci) anope_override
+ {
+ ModeLocks *ml = modelocks.Require(ci);
+ Anope::string modes;
+ spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("mlock", "+nrt"));
+ if (sep.GetToken(modes))
+ {
+ bool add = true;
+ for (unsigned i = 0; i < modes.length(); ++i)
+ {
+ if (modes[i] == '+')
+ add = true;
+ else if (modes[i] == '-')
+ add = false;
+ else
+ {
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]);
+ Anope::string param;
+ if (cm && (cm->type == MODE_REGULAR || sep.GetToken(param)))
+ ml->SetMLock(cm, add, param);
+ }
+ }
+ }
+ ml->Check();
+ }
+
+ void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_hidden) anope_override
{
+ if (!show_hidden)
+ return;
+ ModeLocks *ml = modelocks.Get(ci);
+ if (ml)
+ info[_("Mode lock")] = ml->GetMLockAsString(true);
}
};
diff --git a/modules/commands/cs_seen.cpp b/modules/commands/cs_seen.cpp
index 877fc31b7..9c0b6abfb 100644
--- a/modules/commands/cs_seen.cpp
+++ b/modules/commands/cs_seen.cpp
@@ -95,7 +95,7 @@ static bool ShouldHide(const Anope::string &channel, User *u)
if (targetchan && targetchan->HasMode("SECRET"))
return true;
- else if (targetchan_ci && targetchan_ci->HasExt("PRIVATE"))
+ else if (targetchan_ci && targetchan_ci->HasExt("CS_PRIVATE"))
return true;
else if (u && u->HasMode("PRIV"))
return true;
diff --git a/modules/commands/cs_set.cpp b/modules/commands/cs_set.cpp
index d07e544cc..d392f6b1d 100644
--- a/modules/commands/cs_set.cpp
+++ b/modules/commands/cs_set.cpp
@@ -10,6 +10,7 @@
*/
#include "module.h"
+#include "modules/cs_mode.h"
class CommandCSSet : public Command
{
@@ -86,13 +87,13 @@ class CommandCSSetAutoOp : public Command
if (params[1].equals_ci("ON"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable autoop";
- ci->Shrink("NOAUTOOP");
+ ci->Shrink<bool>("NOAUTOOP");
source.Reply(_("Services will now automatically give modes to users in \002%s\002."), ci->name.c_str());
}
else if (params[1].equals_ci("OFF"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable autoop";
- ci->ExtendMetadata("NOAUTOOP");
+ ci->Extend<bool>("NOAUTOOP");
source.Reply(_("Services will no longer automatically give modes to users in \002%s\002."), ci->name.c_str());
}
else
@@ -203,14 +204,14 @@ class CommandCSSetChanstats : public Command
if (params[1].equals_ci("ON"))
{
- ci->ExtendMetadata("STATS");
+ ci->Extend<bool>("CS_STATS");
source.Reply(_("Chanstats statistics are now enabled for this channel."));
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable chanstats";
}
else if (params[1].equals_ci("OFF"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable chanstats";
- ci->Shrink("STATS");
+ ci->Shrink<bool>("CS_STATS");
source.Reply(_("Chanstats statistics are now disabled for this channel."));
}
else
@@ -344,64 +345,6 @@ class CommandCSSetFounder : public Command
}
};
-class CommandCSSetKeepTopic : public Command
-{
- public:
- CommandCSSetKeepTopic(Module *creator, const Anope::string &cname = "chanserv/set/keeptopic") : Command(creator, cname, 2, 2)
- {
- this->SetDesc(_("Retain topic when channel is not in use"));
- this->SetSyntax(_("\037channel\037 {ON | OFF}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- ChannelInfo *ci = ChannelInfo::Find(params[0]);
- if (ci == NULL)
- {
- source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
- return;
- }
-
- EventReturn MOD_RESULT;
- FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1]));
- if (MOD_RESULT == EVENT_STOP)
- return;
-
- if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration"))
- {
- source.Reply(ACCESS_DENIED);
- return;
- }
-
- if (params[1].equals_ci("ON"))
- {
- Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable keeptopic";
- ci->ExtendMetadata("KEEPTOPIC");
- source.Reply(_("Topic retention option for %s is now \002on\002."), ci->name.c_str());
- }
- else if (params[1].equals_ci("OFF"))
- {
- Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable keeptopic";
- ci->Shrink("KEEPTOPIC");
- source.Reply(_("Topic retention option for %s is now \002off\002."), ci->name.c_str());
- }
- else
- this->OnSyntaxError(source, "KEEPTOPIC");
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Enables or disables the \002topic retention\002 option for a\n"
- "channel. When \002%s\002 is set, the topic for the\n"
- "channel will be remembered by %s even after the\n"
- "last user leaves the channel, and will be restored the\n"
- "next time the channel is created."), this->name.c_str(), source.service->nick.c_str());
- return true;
- }
-};
-
class CommandCSSetPeace : public Command
{
public:
@@ -433,13 +376,13 @@ class CommandCSSetPeace : public Command
if (params[1].equals_ci("ON"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable peace";
- ci->ExtendMetadata("PEACE");
+ ci->Extend<bool>("PEACE");
source.Reply(_("Peace option for %s is now \002on\002."), ci->name.c_str());
}
else if (params[1].equals_ci("OFF"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable peace";
- ci->Shrink("PEACE");
+ ci->Shrink<bool>("PEACE");
source.Reply(_("Peace option for %s is now \002off\002."), ci->name.c_str());
}
else
@@ -495,7 +438,7 @@ class CommandCSSetPersist : public Command
{
if (!ci->HasExt("PERSIST"))
{
- ci->ExtendMetadata("PERSIST");
+ ci->Extend<bool>("PERSIST");
/* Channel doesn't exist, create it */
if (!ci->c)
@@ -535,7 +478,9 @@ class CommandCSSetPersist : public Command
if (ci->c && !ci->c->HasMode("PERM"))
ci->c->SetMode(NULL, cm);
/* Add it to the channels mlock */
- ci->SetMLock(cm, true);
+ ModeLocks *ml = ci->Require<ModeLocks>("modelocks");
+ if (ml)
+ ml->SetMLock(cm, true);
}
}
@@ -546,7 +491,7 @@ class CommandCSSetPersist : public Command
{
if (ci->HasExt("PERSIST"))
{
- ci->Shrink("PERSIST");
+ ci->Shrink<bool>("PERSIST");
/* Unset perm mode */
if (cm)
@@ -554,7 +499,9 @@ class CommandCSSetPersist : public Command
if (ci->c && ci->c->HasMode("PERM"))
ci->c->RemoveMode(NULL, cm);
/* Remove from mlock */
- ci->RemoveMLock(cm, true);
+ ModeLocks *ml = ci->GetExt<ModeLocks>("modelocks");
+ if (ml)
+ ml->RemoveMLock(cm, true);
}
/* No channel mode, no BotServ, but using ChanServ as the botserv bot
@@ -608,68 +555,6 @@ class CommandCSSetPersist : public Command
}
};
-class CommandCSSetPrivate : public Command
-{
- public:
- CommandCSSetPrivate(Module *creator, const Anope::string &cname = "chanserv/set/private") : Command(creator, cname, 2, 2)
- {
- this->SetDesc(_("Hide channel from the LIST command"));
- this->SetSyntax(_("\037channel\037 {ON | OFF}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- ChannelInfo *ci = ChannelInfo::Find(params[0]);
- if (ci == NULL)
- {
- source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
- return;
- }
-
- EventReturn MOD_RESULT;
- FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1]));
- if (MOD_RESULT == EVENT_STOP)
- return;
-
- if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration"))
- {
- source.Reply(ACCESS_DENIED);
- return;
- }
-
- if (params[1].equals_ci("ON"))
- {
- Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable private";
- ci->ExtendMetadata("PRIVATE");
- source.Reply(_("Private option for %s is now \002on\002."), ci->name.c_str());
- }
- else if (params[1].equals_ci("OFF"))
- {
- Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable private";
- ci->Shrink("PRIVATE");
- source.Reply(_("Private option for %s is now \002off\002."), ci->name.c_str());
- }
- else
- this->OnSyntaxError(source, "PRIVATE");
-
- return;
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Enables or disables the \002private\002 option for a channel."));
-
- BotInfo *bi;
- Anope::string cmd;
- if (Command::FindCommandFromService("chanserv/list", bi, cmd))
- source.Reply(_("When \002private\002 is set, the channel will not appear in\n"
- "%s's %s command."), bi->nick.c_str(), cmd.c_str());
- return true;
- }
-};
-
class CommandCSSetRestricted : public Command
{
public:
@@ -702,13 +587,13 @@ class CommandCSSetRestricted : public Command
if (params[1].equals_ci("ON"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable restricted";
- ci->ExtendMetadata("RESTRICTED");
+ ci->Extend<bool>("RESTRICTED");
source.Reply(_("Restricted access option for %s is now \002on\002."), ci->name.c_str());
}
else if (params[1].equals_ci("OFF"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable restricted";
- ci->Shrink("RESTRICTED");
+ ci->Shrink<bool>("RESTRICTED");
source.Reply(_("Restricted access option for %s is now \002off\002."), ci->name.c_str());
}
else
@@ -758,13 +643,13 @@ class CommandCSSetSecure : public Command
if (params[1].equals_ci("ON"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure";
- ci->ExtendMetadata("SECURE");
+ ci->Extend<bool>("CS_SECURE");
source.Reply(_("Secure option for %s is now \002on\002."), ci->name.c_str());
}
else if (params[1].equals_ci("OFF"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure";
- ci->Shrink("SECURE");
+ ci->Shrink<bool>("CS_SECURE");
source.Reply(_("Secure option for %s is now \002off\002."), ci->name.c_str());
}
else
@@ -816,13 +701,13 @@ class CommandCSSetSecureFounder : public Command
if (params[1].equals_ci("ON"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure founder";
- ci->ExtendMetadata("SECUREFOUNDER");
+ ci->Extend<bool>("SECUREFOUNDER");
source.Reply(_("Secure founder option for %s is now \002on\002."), ci->name.c_str());
}
else if (params[1].equals_ci("OFF"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure founder";
- ci->Shrink("SECUREFOUNDER");
+ ci->Shrink<bool>("SECUREFOUNDER");
source.Reply(_("Secure founder option for %s is now \002off\002."), ci->name.c_str());
}
else
@@ -874,13 +759,13 @@ class CommandCSSetSecureOps : public Command
if (params[1].equals_ci("ON"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable secure ops";
- ci->ExtendMetadata("SECUREOPS");
+ ci->Extend<bool>("SECUREOPS");
source.Reply(_("Secure ops option for %s is now \002on\002."), ci->name.c_str());
}
else if (params[1].equals_ci("OFF"))
{
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable secure ops";
- ci->Shrink("SECUREOPS");
+ ci->Shrink<bool>("SECUREOPS");
source.Reply(_("Secure ops option for %s is now \002off\002."), ci->name.c_str());
}
else
@@ -904,7 +789,7 @@ class CommandCSSetSignKick : public Command
CommandCSSetSignKick(Module *creator, const Anope::string &cname = "chanserv/set/signkick") : Command(creator, cname, 2, 2)
{
this->SetDesc(_("Sign kicks that are done with the KICK command"));
- this->SetSyntax(_("\037channel\037 SIGNKICK {ON | LEVEL | OFF}"));
+ this->SetSyntax(_("\037channel\037 {ON | LEVEL | OFF}"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
@@ -929,23 +814,23 @@ class CommandCSSetSignKick : public Command
if (params[1].equals_ci("ON"))
{
- ci->ExtendMetadata("SIGNKICK");
- ci->Shrink("SIGNKICK_LEVEL");
+ ci->Extend<bool>("SIGNKICK");
+ ci->Shrink<bool>("SIGNKICK_LEVEL");
source.Reply(_("Signed kick option for %s is now \002on\002."), ci->name.c_str());
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable sign kick";
}
else if (params[1].equals_ci("LEVEL"))
{
- ci->ExtendMetadata("SIGNKICK_LEVEL");
- ci->Shrink("SIGNKICK");
+ ci->Extend<bool>("SIGNKICK_LEVEL");
+ ci->Shrink<bool>("SIGNKICK");
source.Reply(_("Signed kick option for %s is now \002on\002, but depends of the\n"
"level of the user that is using the command."), ci->name.c_str());
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable sign kick level";
}
else if (params[1].equals_ci("OFF"))
{
- ci->Shrink("SIGNKICK");
- ci->Shrink("SIGNKICK_LEVEL");
+ ci->Shrink<bool>("SIGNKICK");
+ ci->Shrink<bool>("SIGNKICK_LEVEL");
source.Reply(_("Signed kick option for %s is now \002off\002."), ci->name.c_str());
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable sign kick";
}
@@ -1075,13 +960,13 @@ class CommandCSSetNoexpire : public Command
if (params[1].equals_ci("ON"))
{
Log(LOG_ADMIN, source, this, ci) << "to enable noexpire";
- ci->ExtendMetadata("NO_EXPIRE");
+ ci->Extend<bool>("CS_NO_EXPIRE");
source.Reply(_("Channel %s \002will not\002 expire."), ci->name.c_str());
}
else if (params[1].equals_ci("OFF"))
{
Log(LOG_ADMIN, source, this, ci) << "to disable noexpire";
- ci->Shrink("NO_EXPIRE");
+ ci->Shrink<bool>("CS_NO_EXPIRE");
source.Reply(_("Channel %s \002will\002 expire."), ci->name.c_str());
}
else
@@ -1102,16 +987,17 @@ class CommandCSSetNoexpire : public Command
class CSSet : public Module
{
+ SerializableExtensibleItem<bool> persist, noautoop, stats, peace, securefounder,
+ restricted, secure, secureops, signkick, signkick_level, noexpire;
+
CommandCSSet commandcsset;
CommandCSSetAutoOp commandcssetautoop;
CommandCSSetBanType commandcssetbantype;
CommandCSSetChanstats commandcssetchanstats;
CommandCSSetDescription commandcssetdescription;
CommandCSSetFounder commandcssetfounder;
- CommandCSSetKeepTopic commandcssetkeeptopic;
CommandCSSetPeace commandcssetpeace;
CommandCSSetPersist commandcssetpersist;
- CommandCSSetPrivate commandcssetprivate;
CommandCSSetRestricted commandcssetrestricted;
CommandCSSetSecure commandcssetsecure;
CommandCSSetSecureFounder commandcssetsecurefounder;
@@ -1122,17 +1008,27 @@ class CSSet : public Module
public:
CSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
+ persist(this, "PERSIST"), noautoop(this, "NOAUTOOP"), stats(this, "CS_STATS"), peace(this, "PEACE"),
+ securefounder(this, "SECUREFOUNDER"), restricted(this, "RESTRICTED"),
+ secure(this, "CS_SECURE"), secureops(this, "SECUREOPS"), signkick(this, "SIGNKICK"),
+ signkick_level(this, "SIGNKICK_LEVEL"), noexpire(this, "CS_NO_EXPIRE"),
+
commandcsset(this), commandcssetautoop(this), commandcssetbantype(this), commandcssetchanstats(this),
- commandcssetdescription(this), commandcssetfounder(this), commandcssetkeeptopic(this),
- commandcssetpeace(this), commandcssetpersist(this), commandcssetprivate(this), commandcssetrestricted(this),
+ commandcssetdescription(this), commandcssetfounder(this),
+ commandcssetpeace(this), commandcssetpersist(this), commandcssetrestricted(this),
commandcssetsecure(this), commandcssetsecurefounder(this), commandcssetsecureops(this), commandcssetsignkick(this),
commandcssetsuccessor(this), commandcssetnoexpire(this)
{
}
+ void OnCreateChan(ChannelInfo *ci) anope_override
+ {
+ ci->bantype = Config->GetModule(this)->Get<int>("defbantype", "2");
+ }
+
EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override
{
- if (!c->ci || !c->ci->HasExt("RESTRICTED") || c->MatchesList(u, "EXCEPT"))
+ if (!c->ci || !restricted.HasExt(c->ci) || c->MatchesList(u, "EXCEPT"))
return EVENT_CONTINUE;
if (c->ci->AccessFor(u).empty() && (!c->ci->GetFounder() || u->Account() != c->ci->GetFounder()))
@@ -1143,30 +1039,30 @@ class CSSet : public Module
void OnDelChan(ChannelInfo *ci) anope_override
{
- if (ci->c && ci->HasExt("PERSIST"))
+ if (ci->c && persist.HasExt(ci))
ci->c->RemoveMode(ci->WhoSends(), "PERM", "", false);
- ci->Shrink("PERSIST");
+ persist.Unset(ci);
}
- EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, const Anope::string &mname, const Anope::string &param) anope_override
+ EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) anope_override
{
/* Channel mode +P or so was set, mark this channel as persistent */
- if (mname == "PERM" && c->ci)
+ if (mode->name == "PERM" && c->ci)
{
- c->ci->ExtendMetadata("PERSIST");
+ persist.Set(c->ci, true);
}
return EVENT_CONTINUE;
}
- EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, const Anope::string &mname, const Anope::string &param) anope_override
+ EventReturn OnChannelModeUnset(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) anope_override
{
- if (mname == "PERM")
+ if (mode->name == "PERM")
{
if (c->ci)
- c->ci->Shrink("PERSIST");
+ persist.Unset(c->ci);
- if (c->users.empty() && !c->syncing && c->CheckDelete())
+ if (c->CheckDelete())
{
delete c;
return EVENT_STOP;
@@ -1178,14 +1074,14 @@ class CSSet : public Module
EventReturn OnCheckDelete(Channel *c) anope_override
{
- if (c->ci && c->ci->HasExt("PERSIST"))
+ if (c->ci && persist.HasExt(c->ci))
return EVENT_STOP;
return EVENT_CONTINUE;
}
void OnJoinChannel(User *u, Channel *c) anope_override
{
- if (c->ci && c->ci->HasExt("PERSIST") && c->creation_time > c->ci->time_registered)
+ if (c->ci && persist.HasExt(c->ci) && c->creation_time > c->ci->time_registered)
{
Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->creation_time << " to " << c->ci->time_registered;
c->creation_time = c->ci->time_registered;
@@ -1198,10 +1094,47 @@ class CSSet : public Module
{
if (chan->ci)
{
- give_modes &= !chan->ci->HasExt("NOAUTOOP");
- take_modes |= chan->ci->HasExt("SECUREOPS");
+ if (noautoop.HasExt(chan->ci))
+ give_modes = false;
+ if (secureops.HasExt(chan->ci))
+ take_modes = true;
}
}
+
+ void OnPreChanExpire(ChannelInfo *ci, bool &expire) anope_override
+ {
+ if (noexpire.HasExt(ci))
+ expire = false;
+ }
+
+ void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override
+ {
+ if (!show_all)
+ return;
+
+ if (peace.HasExt(ci))
+ info.AddOption(_("Peace"));
+ if (restricted.HasExt(ci))
+ info.AddOption(_("Restricted Access"));
+ if (secure.HasExt(ci))
+ info.AddOption(_("Secure"));
+ if (securefounder.HasExt(ci))
+ info.AddOption(_("Secure Founder"));
+ if (secureops.HasExt(ci))
+ info.AddOption(_("Secure Ops"));
+ if (signkick.HasExt(ci) || signkick_level.HasExt(ci))
+ info.AddOption(_("Signed kicks"));
+ if (persist.HasExt(ci))
+ info.AddOption(_("Persistent"));
+ if (noexpire.HasExt(ci))
+ info.AddOption(_("No expire"));
+ if (stats.HasExt(ci))
+ info.AddOption(_("Chanstats"));
+
+ time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "14d");
+ if (!noexpire.HasExt(ci) && chanserv_expire && !Anope::NoExpire)
+ info["Expires on"] = Anope::strftime(ci->last_used + chanserv_expire);
+ }
};
MODULE_INIT(CSSet)
diff --git a/modules/commands/cs_set_misc.cpp b/modules/commands/cs_set_misc.cpp
index 21ebec815..5467e2b4e 100644
--- a/modules/commands/cs_set_misc.cpp
+++ b/modules/commands/cs_set_misc.cpp
@@ -10,14 +10,24 @@
#include "module.h"
+static Module *me;
+
static std::map<Anope::string, Anope::string> descriptions;
-struct CSMiscData : ExtensibleItem, Serializable
+struct CSMiscData;
+static Anope::map<ExtensibleItem<CSMiscData> *> items;
+static ExtensibleItem<CSMiscData> *GetItem(const Anope::string &name);
+
+struct CSMiscData : Serializable
{
Serialize::Reference<ChannelInfo> ci;
Anope::string name;
Anope::string data;
+ CSMiscData(Extensible *obj) : Serializable("CSMiscData"), ci(anope_dynamic_static_cast<ChannelInfo *>(obj))
+ {
+ }
+
CSMiscData(ChannelInfo *c, const Anope::string &n, const Anope::string &d) : Serializable("CSMiscData"), ci(c), name(n), data(d)
{
}
@@ -41,7 +51,7 @@ struct CSMiscData : ExtensibleItem, Serializable
if (ci == NULL)
return NULL;
- CSMiscData *d;
+ CSMiscData *d = NULL;
if (obj)
{
d = anope_dynamic_static_cast<CSMiscData *>(obj);
@@ -51,14 +61,27 @@ struct CSMiscData : ExtensibleItem, Serializable
}
else
{
- d = new CSMiscData(ci, sname, sdata);
- ci->Extend(sname, d);
+ ExtensibleItem<CSMiscData> *item = GetItem(sname);
+ if (item)
+ d = item->Set(ci, CSMiscData(ci, sname, sdata));
}
return d;
}
};
+static ExtensibleItem<CSMiscData> *GetItem(const Anope::string &name)
+{
+ ExtensibleItem<CSMiscData>* &it = items[name];
+ if (!it)
+ try
+ {
+ it = new ExtensibleItem<CSMiscData>(me, name);
+ }
+ catch (const ModuleException &) { }
+ return it;
+}
+
static Anope::string GetAttribute(const Anope::string &command)
{
size_t sp = command.rfind(' ');
@@ -97,14 +120,20 @@ class CommandCSSetMisc : public Command
Anope::string scommand = GetAttribute(source.command);
Anope::string key = "cs_set_misc:" + scommand;
- ci->Shrink(key);
+ ExtensibleItem<CSMiscData> *item = GetItem(key);
+ if (item == NULL)
+ return;
+
if (params.size() > 1)
{
- ci->Extend(key, new CSMiscData(ci, key, params[1]));
+ item->Set(ci, CSMiscData(ci, key, params[1]));
source.Reply(CHAN_SETTING_CHANGED, scommand.c_str(), ci->name.c_str(), params[1].c_str());
}
else
+ {
+ item->Unset(ci);
source.Reply(CHAN_SETTING_UNSET, scommand.c_str(), ci->name.c_str());
+ }
}
void OnServHelp(CommandSource &source) anope_override
@@ -136,6 +165,7 @@ class CSSetMisc : public Module
CSSetMisc(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
csmiscdata_type("CSMiscData", CSMiscData::Unserialize), commandcssetmisc(this)
{
+ me = this;
}
void OnReload(Configuration::Conf *conf) anope_override
@@ -161,17 +191,14 @@ class CSSetMisc : public Module
void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool ShowHidden) anope_override
{
- std::deque<Anope::string> list;
- ci->GetExtList(list);
-
- for (unsigned i = 0; i < list.size(); ++i)
+ Anope::map<ExtensibleItem<CSMiscData> *> items;
+ for (Anope::map<ExtensibleItem<CSMiscData> *>::iterator it = items.begin(); it != items.end(); ++it)
{
- if (list[i].find("cs_set_misc:") != 0)
- continue;
-
- CSMiscData *data = ci->GetExt<CSMiscData *>(list[i]);
+ ExtensibleItem<CSMiscData> *e = it->second;
+ CSMiscData *data = e->Get(ci);
+
if (data != NULL)
- info[list[i].substr(12).replace_all_cs("_", " ")] = data->data;
+ info[e->name.substr(12).replace_all_cs("_", " ")] = data->data;
}
}
};
diff --git a/modules/commands/cs_suspend.cpp b/modules/commands/cs_suspend.cpp
index e366e5dc0..b7ffccda6 100644
--- a/modules/commands/cs_suspend.cpp
+++ b/modules/commands/cs_suspend.cpp
@@ -10,6 +10,45 @@
*/
#include "module.h"
+#include "modules/cs_suspend.h"
+
+struct CSSuspendInfoImpl : CSSuspendInfo, Serializable
+{
+ CSSuspendInfoImpl(Extensible *) : Serializable("CSSuspendInfo") { }
+
+ void Serialize(Serialize::Data &data) const anope_override
+ {
+ data["chan"] << chan;
+ data["by"] << by;
+ data["reason"] << reason;
+ data["time"] << time;
+ data["expires"] << expires;
+ }
+
+ static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
+ {
+ Anope::string schan;
+ data["chan"] >> schan;
+
+ CSSuspendInfoImpl *si;
+ if (obj)
+ si = anope_dynamic_static_cast<CSSuspendInfoImpl *>(obj);
+ else
+ {
+ ChannelInfo *ci = ChannelInfo::Find(schan);
+ if (!ci)
+ return NULL;
+ si = ci->Extend<CSSuspendInfoImpl>("cs_suspend");
+ data["chan"] >> si->chan;
+ }
+
+ data["bi"] >> si->by;
+ data["reason"] >> si->reason;
+ data["time"] >> si->time;
+ data["expires"] >> si->expires;
+ return si;
+ }
+};
class CommandCSSuspend : public Command
{
@@ -46,11 +85,12 @@ class CommandCSSuspend : public Command
return;
}
- ci->ExtendMetadata("SUSPENDED");
- ci->ExtendMetadata("suspend:by", source.GetNick());
- if (!reason.empty())
- ci->ExtendMetadata("suspend:reason", reason);
- ci->ExtendMetadata("suspend:time", stringify(Anope::CurTime));
+ CSSuspendInfo *si = ci->Extend<CSSuspendInfo>("cs_suspend");
+ si->chan = ci->name;
+ si->by = source.GetNick();
+ si->reason = reason;
+ si->time = Anope::CurTime;
+ si->expires = expiry_secs ? expiry_secs + Anope::CurTime : 0;
if (ci->c)
{
@@ -68,15 +108,10 @@ class CommandCSSuspend : public Command
ci->c->Kick(NULL, users[i], "%s", !reason.empty() ? reason.c_str() : Language::Translate(users[i], _("This channel has been suspended.")));
}
- if (expiry_secs > 0)
- ci->ExtendMetadata("suspend:expire", stringify(Anope::CurTime + expiry_secs));
-
Log(LOG_ADMIN, source, this, ci) << (!reason.empty() ? reason : "No reason") << ", expires in " << (expiry_secs ? Anope::strftime(Anope::CurTime + expiry_secs) : "never");
source.Reply(_("Channel \002%s\002 is now suspended."), ci->name.c_str());
FOREACH_MOD(OnChanSuspend, (ci));
-
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -118,21 +153,16 @@ class CommandCSUnSuspend : public Command
}
/* Only UNSUSPEND already suspended channels */
- if (!ci->HasExt("SUSPENDED"))
+ CSSuspendInfo *si = ci->GetExt<CSSuspendInfo>("cs_suspend");
+ if (!si)
{
source.Reply(_("Channel \002%s\002 isn't suspended."), ci->name.c_str());
return;
}
- Anope::string *by = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:by"), *reason = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:reason");
- if (by != NULL)
- Log(LOG_ADMIN, source, this, ci) << " which was suspended by " << *by << " for: " << (reason && !reason->empty() ? *reason : "No reason");
+ Log(LOG_ADMIN, source, this, ci) << " which was suspended by " << si->by << " for: " << (!si->reason.empty() ? si->reason : "No reason");
- ci->Shrink("SUSPENDED");
- ci->Shrink("suspend:by");
- ci->Shrink("suspend:reason");
- ci->Shrink("suspend:expire");
- ci->Shrink("suspend:time");
+ ci->Shrink<CSSuspendInfo>("cs_suspend");
source.Reply(_("Channel \002%s\002 is now released."), ci->name.c_str());
@@ -155,66 +185,73 @@ class CSSuspend : public Module
{
CommandCSSuspend commandcssuspend;
CommandCSUnSuspend commandcsunsuspend;
+ ExtensibleItem<CSSuspendInfoImpl> suspend;
+ Serialize::Type suspend_type;
public:
CSSuspend(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandcssuspend(this), commandcsunsuspend(this)
+ commandcssuspend(this), commandcsunsuspend(this), suspend(this, "cs_suspend"),
+ suspend_type("CSSuspendInfo", CSSuspendInfoImpl::Unserialize)
{
-
}
void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_hidden) anope_override
{
- if (ci->HasExt("SUSPENDED"))
+ CSSuspendInfo *si = suspend.Get(ci);
+ if (si)
{
- Anope::string *by = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:by"), *reason = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:reason"), *t = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:time");
info["Suspended"] = "This channel is \2suspended\2.";
- if (by)
- info["Suspended by"] = *by;
- if (reason)
- info["Suspend reason"] = *reason;
- if (t)
- info["Suspended on"] = Anope::strftime(convertTo<time_t>(*t), source.GetAccount(), true);
+ if (!si->by.empty())
+ info["Suspended by"] = si->by;
+ if (!si->reason.empty())
+ info["Suspend reason"] = si->reason;
+ if (si->time)
+ info["Suspended on"] = Anope::strftime(si->time, source.GetAccount(), true);
+ if (si->expires)
+ info["Suspended expires"] = Anope::strftime(si->expires, source.GetAccount(), true);
}
}
void OnPreChanExpire(ChannelInfo *ci, bool &expire) anope_override
{
- if (!ci->HasExt("SUSPENDED"))
+ CSSuspendInfo *si = suspend.Get(ci);
+ if (!si)
return;
expire = false;
- Anope::string *str = ci->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:expire");
- if (str == NULL)
+ if (!si->expires)
return;
- try
+ if (si->expires < Anope::CurTime)
{
- time_t when = convertTo<time_t>(*str);
- if (when < Anope::CurTime)
- {
- ci->last_used = Anope::CurTime;
- ci->Shrink("SUSPENDED");
- ci->Shrink("suspend:expire");
- ci->Shrink("suspend:by");
- ci->Shrink("suspend:reason");
- ci->Shrink("suspend:time");
-
- Log(this) << "Expiring suspend for " << ci->name;
- }
+ ci->last_used = Anope::CurTime;
+ suspend.Unset(ci);
+
+ Log(this) << "Expiring suspend for " << ci->name;
}
- catch (const ConvertException &) { }
}
EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override
{
- if (u->HasMode("OPER") || !c->ci || !c->ci->HasExt("SUSPENDED"))
+ if (u->HasMode("OPER") || !c->ci || !suspend.HasExt(c->ci))
return EVENT_CONTINUE;
reason = Language::Translate(u, _("This channel may not be used."));
return EVENT_STOP;
}
+
+ EventReturn OnChanDrop(CommandSource &source, ChannelInfo *ci) anope_override
+ {
+ CSSuspendInfo *si = suspend.Get(ci);
+ if (si && !source.HasCommand("chanserv/drop"))
+ {
+ source.Reply(CHAN_X_SUSPENDED, ci->name.c_str());
+ return EVENT_STOP;
+ }
+
+ return EVENT_CONTINUE;
+ }
};
MODULE_INIT(CSSuspend)
diff --git a/modules/commands/cs_topic.cpp b/modules/commands/cs_topic.cpp
index 294689864..39ddfe8f9 100644
--- a/modules/commands/cs_topic.cpp
+++ b/modules/commands/cs_topic.cpp
@@ -10,9 +10,70 @@
*/
#include "module.h"
+#include "modules/cs_mode.h"
+
+class CommandCSSetKeepTopic : public Command
+{
+ public:
+ CommandCSSetKeepTopic(Module *creator, const Anope::string &cname = "chanserv/set/keeptopic") : Command(creator, cname, 2, 2)
+ {
+ this->SetDesc(_("Retain topic when channel is not in use"));
+ this->SetSyntax(_("\037channel\037 {ON | OFF}"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ ChannelInfo *ci = ChannelInfo::Find(params[0]);
+ if (ci == NULL)
+ {
+ source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
+ return;
+ }
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnSetChannelOption, MOD_RESULT, (source, this, ci, params[1]));
+ if (MOD_RESULT == EVENT_STOP)
+ return;
+
+ if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration"))
+ {
+ source.Reply(ACCESS_DENIED);
+ return;
+ }
+
+ if (params[1].equals_ci("ON"))
+ {
+ Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to enable keeptopic";
+ ci->Extend<bool>("KEEPTOPIC");
+ source.Reply(_("Topic retention option for %s is now \002on\002."), ci->name.c_str());
+ }
+ else if (params[1].equals_ci("OFF"))
+ {
+ Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to disable keeptopic";
+ ci->Shrink<bool>("KEEPTOPIC");
+ source.Reply(_("Topic retention option for %s is now \002off\002."), ci->name.c_str());
+ }
+ else
+ this->OnSyntaxError(source, "KEEPTOPIC");
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Enables or disables the \002topic retention\002 option for a\n"
+ "channel. When \002%s\002 is set, the topic for the\n"
+ "channel will be remembered by %s even after the\n"
+ "last user leaves the channel, and will be restored the\n"
+ "next time the channel is created."), source.command.c_str(), source.service->nick.c_str());
+ return true;
+ }
+};
class CommandCSTopic : public Command
{
+ ExtensibleRef<bool> topiclock;
+
void Lock(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
{
EventReturn MOD_RESULT;
@@ -20,7 +81,7 @@ class CommandCSTopic : public Command
if (MOD_RESULT == EVENT_STOP)
return;
- ci->ExtendMetadata("TOPICLOCK");
+ topiclock->Set(ci, true);
source.Reply(_("Topic lock option for %s is now \002on\002."), ci->name.c_str());
}
@@ -31,7 +92,7 @@ class CommandCSTopic : public Command
if (MOD_RESULT == EVENT_STOP)
return;
- ci->Shrink("TOPICLOCK");
+ topiclock->Unset(ci);
source.Reply(_("Topic lock option for %s is now \002off\002."), ci->name.c_str());
}
@@ -39,11 +100,11 @@ class CommandCSTopic : public Command
{
const Anope::string &topic = params.size() > 2 ? params[2] : "";
- bool has_topiclock = ci->HasExt("TOPICLOCK");
- ci->Shrink("TOPICLOCK");
+ bool *has_topiclock = topiclock->Get(ci);
+ topiclock->Unset(ci);
ci->c->ChangeTopic(source.GetNick(), topic, Anope::CurTime);
if (has_topiclock)
- ci->ExtendMetadata("TOPICLOCK");
+ topiclock->Set(ci, *has_topiclock);
bool override = !source.AccessFor(ci).HasPriv("TOPIC");
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << (!topic.empty() ? "to change the topic to: " : "to unset the topic") << (!topic.empty() ? topic : "");
@@ -71,7 +132,8 @@ class CommandCSTopic : public Command
}
public:
- CommandCSTopic(Module *creator) : Command(creator, "chanserv/topic", 2, 3)
+ CommandCSTopic(Module *creator) : Command(creator, "chanserv/topic", 2, 3),
+ topiclock("TOPICLOCK")
{
this->SetDesc(_("Manipulate the topic of the specified channel"));
this->SetSyntax(_("\037channel\037 SET [\037topic\037]"));
@@ -120,13 +182,66 @@ class CommandCSTopic : public Command
class CSTopic : public Module
{
CommandCSTopic commandcstopic;
+ CommandCSSetKeepTopic commandcssetkeeptopic;
+
+ SerializableExtensibleItem<bool> topiclock, keeptopic;
public:
CSTopic(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandcstopic(this)
+ commandcstopic(this), commandcssetkeeptopic(this), topiclock(this, "TOPICLOCK"), keeptopic(this, "KEEPTOPIC")
{
}
+
+ void OnChannelSync(Channel *c) anope_override
+ {
+ if (Me && Me->IsSynced() && c->ci)
+ {
+ /* Update channel topic */
+ if ((topiclock.HasExt(c->ci) || keeptopic.HasExt(c->ci)) && c->ci->last_topic != c->topic)
+ {
+ c->ChangeTopic(!c->ci->last_topic_setter.empty() ? c->ci->last_topic_setter : c->ci->WhoSends()->nick, c->ci->last_topic, c->ci->last_topic_time ? c->ci->last_topic_time : Anope::CurTime);
+ }
+ }
+ }
+
+ void OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic) anope_override
+ {
+ if (!c->ci)
+ return;
+
+ /* We only compare the topics here, not the time or setter. This is because some (old) IRCds do not
+ * allow us to set the topic as someone else, meaning we have to bump the TS and change the setter to us.
+ * This desyncs what is really set with what we have stored, and we end up resetting the topic often when
+ * it is not required
+ */
+ if (topiclock.HasExt(c->ci) && c->ci->last_topic != c->topic)
+ {
+ c->ChangeTopic(c->ci->last_topic_setter, c->ci->last_topic, c->ci->last_topic_time);
+ }
+ else
+ {
+ c->ci->last_topic = c->topic;
+ c->ci->last_topic_setter = c->topic_setter;
+ c->ci->last_topic_time = c->topic_ts;
+ }
+ }
+
+ void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all)
+ {
+ if (keeptopic.HasExt(ci))
+ info.AddOption(_("Topic Retention"));
+ if (topiclock.HasExt(ci))
+ info.AddOption(_("Topic Lock"));
+
+ ModeLocks *ml = ci->GetExt<ModeLocks>("modelocks");
+ const ModeLock *secret = ml ? ml->GetMLock("SECRET") : NULL;
+ if (!ci->last_topic.empty() && (show_all || ((!secret || secret->set == false) && (!ci->c || !ci->c->HasMode("SECRET")))))
+ {
+ info["Last topic"] = ci->last_topic;
+ info["Topic set by"] = ci->last_topic_setter;
+ }
+ }
};
MODULE_INIT(CSTopic)
diff --git a/modules/commands/greet.cpp b/modules/commands/greet.cpp
new file mode 100644
index 000000000..dd3fce66f
--- /dev/null
+++ b/modules/commands/greet.cpp
@@ -0,0 +1,210 @@
+/*
+ *
+ * (C) 2003-2013 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
+#include "module.h"
+
+class CommandBSSetGreet : public Command
+{
+ public:
+ CommandBSSetGreet(Module *creator, const Anope::string &sname = "botserv/set/greet") : Command(creator, sname, 2, 2)
+ {
+ this->SetDesc(_("Enable greet messages"));
+ this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ ChannelInfo *ci = ChannelInfo::Find(params[0]);
+ const Anope::string &value = params[1];
+
+ if (ci == NULL)
+ {
+ source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
+ return;
+ }
+
+ if (!source.HasPriv("botserv/administration") && !source.AccessFor(ci).HasPriv("SET"))
+ {
+ source.Reply(ACCESS_DENIED);
+ return;
+ }
+
+ if (Anope::ReadOnly)
+ {
+ source.Reply(_("Sorry, bot option setting is temporarily disabled."));
+ return;
+ }
+
+ if (value.equals_ci("ON"))
+ {
+ bool override = !source.AccessFor(ci).HasPriv("SET");
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to enable greets";
+
+ ci->Extend<bool>("BS_GREET");
+ source.Reply(_("Greet mode is now \002on\002 on channel %s."), ci->name.c_str());
+ }
+ else if (value.equals_ci("OFF"))
+ {
+ bool override = !source.AccessFor(ci).HasPriv("SET");
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to disable greets";
+
+ ci->Shrink<bool>("BS_GREET");
+ source.Reply(_("Greet mode is now \002off\002 on channel %s."), ci->name.c_str());
+ }
+ else
+ this->OnSyntaxError(source, source.command);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(_(" \n"
+ "Enables or disables \002greet\002 mode on a channel.\n"
+ "When it is enabled, the bot will display greet\n"
+ "messages of users joining the channel, provided\n"
+ "they have enough access to the channel."));
+ return true;
+ }
+};
+
+class CommandNSSetGreet : public Command
+{
+ public:
+ CommandNSSetGreet(Module *creator, const Anope::string &sname = "nickserv/set/greet", size_t min = 0) : Command(creator, sname, min, min + 1)
+ {
+ this->SetDesc(_("Associate a greet message with your nickname"));
+ this->SetSyntax(_("\037message\037"));
+ }
+
+ void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
+ {
+ const NickAlias *na = NickAlias::Find(user);
+ if (!na)
+ {
+ source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
+ return;
+ }
+ NickCore *nc = na->nc;
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
+ if (MOD_RESULT == EVENT_STOP)
+ return;
+
+ if (!param.empty())
+ {
+ Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the greet of " << nc->display;
+ nc->Extend<Anope::string>("greet", param);
+ source.Reply(_("Greet message for \002%s\002 changed to \002%s\002."), nc->display.c_str(), param.c_str());
+ }
+ else
+ {
+ Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to unset the greet of " << nc->display;
+ nc->Shrink<Anope::string>("greet");
+ source.Reply(_("Greet message for \002%s\002 unset."), nc->display.c_str());
+ }
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ this->Run(source, source.nc->display, params.size() > 0 ? params[0] : "");
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Makes the given message the greet of your nickname, that\n"
+ "will be displayed when joining a channel that has GREET\n"
+ "option enabled, provided that you have the necessary\n"
+ "access on it."));
+ return true;
+ }
+};
+
+class CommandNSSASetGreet : public CommandNSSetGreet
+{
+ public:
+ CommandNSSASetGreet(Module *creator) : CommandNSSetGreet(creator, "nickserv/saset/greet", 1)
+ {
+ this->ClearSyntax();
+ this->SetSyntax(_("\037nickname\037 \037message\037"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ this->Run(source, params[0], params.size() > 1 ? params[1] : "");
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Makes the given message the greet of the nickname, that\n"
+ "will be displayed when joining a channel that has GREET\n"
+ "option enabled, provided that the user has the necessary\n"
+ "access on it."));
+ return true;
+ }
+};
+
+class Greet : public Module
+{
+ /* channel setting for whether or not greet should be shown */
+ SerializableExtensibleItem<bool> bs_greet;
+ /* user greets */
+ SerializableExtensibleItem<Anope::string> ns_greet;
+
+ CommandBSSetGreet commandbssetgreet;
+ CommandNSSetGreet commandnssetgreet;
+ CommandNSSASetGreet commandnssasetgreet;
+
+ public:
+ Greet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
+ bs_greet(this, "BS_GREET"),
+ ns_greet(this, "greet"),
+ commandbssetgreet(this),
+ commandnssetgreet(this), commandnssasetgreet(this)
+ {
+ }
+
+ void OnJoinChannel(User *user, Channel *c) anope_override
+ {
+ /* Only display the greet if the main uplink we're connected
+ * to has synced, or we'll get greet-floods when the net
+ * recovers from a netsplit. -GD
+ */
+ if (!c->ci || !c->ci->bi || !user->server->IsSynced() || !user->Account())
+ return;
+
+ Anope::string *greet = ns_greet.Get(user->Account());
+ if (bs_greet.HasExt(c->ci) && greet != NULL && !greet->empty() && c->FindUser(c->ci->bi) && c->ci->AccessFor(user).HasPriv("GREET"))
+ {
+ IRCD->SendPrivmsg(c->ci->bi, c->name, "[%s] %s", user->Account()->display.c_str(), greet->c_str());
+ c->ci->bi->lastmsg = Anope::CurTime;
+ }
+ }
+
+ void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override
+ {
+ Anope::string *greet = ns_greet.Get(na->nc);
+ if (greet != NULL)
+ info[_("Greet")] = *greet;
+ }
+
+ void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override
+ {
+ if (bs_greet.HasExt(ci))
+ info.AddOption(_("Greet"));
+ }
+};
+
+MODULE_INIT(Greet)
diff --git a/modules/commands/hs_request.cpp b/modules/commands/hs_request.cpp
index 2b1299f93..5203b086b 100644
--- a/modules/commands/hs_request.cpp
+++ b/modules/commands/hs_request.cpp
@@ -21,14 +21,14 @@ static ServiceReference<MemoServService> memoserv("MemoServService", "MemoServ")
static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost);
-struct HostRequest : ExtensibleItem, Serializable
+struct HostRequest : Serializable
{
Anope::string nick;
Anope::string ident;
Anope::string host;
time_t time;
- HostRequest() : Serializable("HostRequest") { }
+ HostRequest(Extensible *) : Serializable("HostRequest") { }
void Serialize(Serialize::Data &data) const anope_override
{
@@ -51,14 +51,15 @@ struct HostRequest : ExtensibleItem, Serializable
if (obj)
req = anope_dynamic_static_cast<HostRequest *>(obj);
else
- req = new HostRequest;
- req->nick = na->nick;
- data["ident"] >> req->ident;
- data["host"] >> req->host;
- data["time"] >> req->time;
-
- if (!obj)
- na->Extend("hs_request", req);
+ req = na->Extend<HostRequest>("hostrequest");
+ if (req)
+ {
+ req->nick = na->nick;
+ data["ident"] >> req->ident;
+ data["host"] >> req->host;
+ data["time"] >> req->time;
+ }
+
return req;
}
};
@@ -148,12 +149,12 @@ class CommandHSRequest : public Command
return;
}
- HostRequest *req = new HostRequest;
- req->nick = source.GetNick();
- req->ident = user;
- req->host = host;
- req->time = Anope::CurTime;
- na->Extend("hs_request", req);
+ HostRequest req(na);
+ req.nick = source.GetNick();
+ req.ident = user;
+ req.host = host;
+ req.time = Anope::CurTime;
+ na->Extend<HostRequest>("hostrequest", req);
source.Reply(_("Your vHost has been requested."));
req_send_memos(owner, source, user, host);
@@ -186,7 +187,7 @@ class CommandHSActivate : public Command
const Anope::string &nick = params[0];
NickAlias *na = NickAlias::Find(nick);
- HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL;
+ HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL;
if (req)
{
na->SetVhost(req->ident, req->host, source.GetNick(), req->time);
@@ -197,7 +198,7 @@ class CommandHSActivate : public Command
source.Reply(_("vHost for %s has been activated."), na->nick.c_str());
Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host;
- na->Shrink("hs_request");
+ na->Shrink<HostRequest>("hostrequest");
}
else
source.Reply(_("No request for nick %s found."), nick.c_str());
@@ -231,10 +232,10 @@ class CommandHSReject : public Command
const Anope::string &reason = params.size() > 1 ? params[1] : "";
NickAlias *na = NickAlias::Find(nick);
- HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL;
+ HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL;
if (req)
{
- na->Shrink("hs_request");
+ na->Shrink<HostRequest>("hostrequest");
if (Config->GetModule(this->owner)->Get<bool>("memouser") && memoserv)
{
@@ -244,7 +245,7 @@ class CommandHSReject : public Command
else
message = _("[auto memo] Your requested vHost has been rejected.");
- memoserv->Send(source.service->nick, nick, message, true);
+ memoserv->Send(source.service->nick, nick, Language::Translate(source.GetAccount(), message.c_str()), true);
}
source.Reply(_("vHost for %s has been rejected."), nick.c_str());
@@ -252,8 +253,6 @@ class CommandHSReject : public Command
}
else
source.Reply(_("No request for nick %s found."), nick.c_str());
-
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -287,7 +286,7 @@ class CommandHSWaiting : public Command
for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it)
{
const NickAlias *na = it->second;
- HostRequest *hr = na->GetExt<HostRequest *>("hs_request");
+ HostRequest *hr = na->GetExt<HostRequest>("hostrequest");
if (!hr)
continue;
@@ -334,24 +333,17 @@ class HSRequest : public Module
CommandHSActivate commandhsactive;
CommandHSReject commandhsreject;
CommandHSWaiting commandhswaiting;
+ ExtensibleItem<HostRequest> hostrequest;
public:
HSRequest(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- request_type("HostRequest", HostRequest::Unserialize), commandhsrequest(this), commandhsactive(this), commandhsreject(this), commandhswaiting(this)
+ request_type("HostRequest", HostRequest::Unserialize), commandhsrequest(this), commandhsactive(this),
+ commandhsreject(this), commandhswaiting(this), hostrequest(this, "hostrequest")
{
if (!IRCD || !IRCD->CanSetVHost)
throw ModuleException("Your IRCd does not support vhosts");
}
-
- ~HSRequest()
- {
- for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it)
- {
- NickAlias *na = it->second;
- na->Shrink("hs_request");
- }
- }
};
static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost)
diff --git a/modules/commands/ms_info.cpp b/modules/commands/ms_info.cpp
index 67a504117..909ff4c82 100644
--- a/modules/commands/ms_info.cpp
+++ b/modules/commands/ms_info.cpp
@@ -27,7 +27,7 @@ class CommandMSInfo : public Command
const NickAlias *na = NULL;
ChannelInfo *ci = NULL;
const Anope::string &nname = !params.empty() ? params[0] : "";
- int hardmax = 0;
+ bool hardmax;
if (!nname.empty() && nname[0] != '#' && source.HasPriv("memoserv/info"))
{
@@ -38,7 +38,7 @@ class CommandMSInfo : public Command
return;
}
mi = &na->nc->memos;
- hardmax = na->nc->HasExt("MEMO_HARDMAX") ? 1 : 0;
+ hardmax = na->nc->HasExt("MEMO_HARDMAX");
}
else if (!nname.empty() && nname[0] == '#')
{
@@ -54,7 +54,7 @@ class CommandMSInfo : public Command
return;
}
mi = &ci->memos;
- hardmax = ci->HasExt("MEMO_HARDMAX") ? 1 : 0;
+ hardmax = ci->HasExt("MEMO_HARDMAX");
}
else if (!nname.empty()) /* It's not a chan and we aren't services admin */
{
@@ -64,7 +64,7 @@ class CommandMSInfo : public Command
else
{
mi = &nc->memos;
- hardmax = nc->HasExt("MEMO_HARDMAX") ? 1 : 0;
+ hardmax = nc->HasExt("MEMO_HARDMAX");
}
if (!nname.empty() && (ci || na->nc != nc))
@@ -178,7 +178,6 @@ class CommandMSInfo : public Command
else
source.Reply(_("You will not be notified of new memos."));
}
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
diff --git a/modules/commands/ms_set.cpp b/modules/commands/ms_set.cpp
index 9bf63b15d..e6d48d08a 100644
--- a/modules/commands/ms_set.cpp
+++ b/modules/commands/ms_set.cpp
@@ -25,27 +25,27 @@ class CommandMSSet : public Command
if (param.equals_ci("ON"))
{
- nc->ExtendMetadata("MEMO_SIGNON");
- nc->ExtendMetadata("MEMO_RECEIVE");
+ nc->Extend<bool>("MEMO_SIGNON");
+ nc->Extend<bool>("MEMO_RECEIVE");
source.Reply(_("%s will now notify you of memos when you log on and when they are sent to you."), MemoServ->nick.c_str());
}
else if (param.equals_ci("LOGON"))
{
- nc->ExtendMetadata("MEMO_SIGNON");
- nc->Shrink("MEMO_RECEIVE");
+ nc->Extend<bool>("MEMO_SIGNON");
+ nc->Shrink<bool>("MEMO_RECEIVE");
source.Reply(_("%s will now notify you of memos when you log on or unset /AWAY."), MemoServ->nick.c_str());
}
else if (param.equals_ci("NEW"))
{
- nc->Shrink("MEMO_SIGNON");
- nc->ExtendMetadata("MEMO_RECEIVE");
+ nc->Shrink<bool>("MEMO_SIGNON");
+ nc->Extend<bool>("MEMO_RECEIVE");
source.Reply(_("%s will now notify you of memos when they are sent to you."), MemoServ->nick.c_str());
}
else if (param.equals_ci("MAIL"))
{
if (!nc->email.empty())
{
- nc->ExtendMetadata("MEMO_MAIL");
+ nc->Extend<bool>("MEMO_MAIL");
source.Reply(_("You will now be informed about new memos via email."));
}
else
@@ -53,20 +53,18 @@ class CommandMSSet : public Command
}
else if (param.equals_ci("NOMAIL"))
{
- nc->Shrink("MEMO_MAIL");
+ nc->Shrink<bool>("MEMO_MAIL");
source.Reply(_("You will no longer be informed via email."));
}
else if (param.equals_ci("OFF"))
{
- nc->Shrink("MEMO_SIGNON");
- nc->Shrink("MEMO_RECEIVE");
- nc->Shrink("MEMO_MAIL");
+ nc->Shrink<bool>("MEMO_SIGNON");
+ nc->Shrink<bool>("MEMO_RECEIVE");
+ nc->Shrink<bool>("MEMO_MAIL");
source.Reply(_("%s will not send you any notification of memos."), MemoServ->nick.c_str());
}
else
this->OnSyntaxError(source, "");
-
- return;
}
void DoLimit(CommandSource &source, const std::vector<Anope::string> &params, MemoInfo *mi)
@@ -125,16 +123,16 @@ class CommandMSSet : public Command
if (!chan.empty())
{
if (!p2.empty())
- ci->ExtendMetadata("MEMO_HARDMAX");
+ ci->Extend<bool>("MEMO_HARDMAX");
else
- ci->Shrink("MEMO_HARDMAX");
+ ci->Shrink<bool>("MEMO_HARDMAX");
}
else
{
if (!p2.empty())
- nc->ExtendMetadata("MEMO_HARDMAX");
+ nc->Extend<bool>("MEMO_HARDMAX");
else
- nc->Shrink("MEMO_HARDMAX");
+ nc->Shrink<bool>("MEMO_HARDMAX");
}
limit = -1;
try
@@ -301,10 +299,12 @@ class CommandMSSet : public Command
class MSSet : public Module
{
CommandMSSet commandmsset;
+ PrimitiveExtensibleItem<bool> memo_signon, memo_receive, memo_mail, memo_hardmax;
public:
MSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandmsset(this)
+ commandmsset(this), memo_signon(this, "MEMO_SIGNON"), memo_receive(this, "MEMO_RECEIVE"), memo_mail(this, "MEMO_MAIL"),
+ memo_hardmax(this, "MEMO_HARDMAX")
{
}
diff --git a/modules/commands/ns_ajoin.cpp b/modules/commands/ns_ajoin.cpp
index 0304c7394..79d7fdf4a 100644
--- a/modules/commands/ns_ajoin.cpp
+++ b/modules/commands/ns_ajoin.cpp
@@ -13,9 +13,9 @@
struct AJoinEntry;
-struct AJoinList : Serialize::Checker<std::vector<AJoinEntry *> >, ExtensibleItem
+struct AJoinList : Serialize::Checker<std::vector<AJoinEntry *> >
{
- AJoinList() : Serialize::Checker<std::vector<AJoinEntry *> >("AJoinEntry") { }
+ AJoinList(Extensible *) : Serialize::Checker<std::vector<AJoinEntry *> >("AJoinEntry") { }
~AJoinList();
};
@@ -25,7 +25,7 @@ struct AJoinEntry : Serializable
Anope::string channel;
Anope::string key;
- AJoinEntry() : Serializable("AJoinEntry") { }
+ AJoinEntry(Extensible *) : Serializable("AJoinEntry") { }
void Serialize(Serialize::Data &sd) const anope_override
{
@@ -52,7 +52,7 @@ struct AJoinEntry : Serializable
aj = anope_dynamic_static_cast<AJoinEntry *>(obj);
else
{
- aj = new AJoinEntry();
+ aj = new AJoinEntry(nc);
aj->owner = nc;
}
@@ -61,12 +61,7 @@ struct AJoinEntry : Serializable
if (!obj)
{
- AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
- if (channels == NULL)
- {
- channels = new AJoinList();
- nc->Extend("ns_ajoin_channels", channels);
- }
+ AJoinList *channels = nc->Require<AJoinList>("ajoinlist");
(*channels)->push_back(aj);
}
@@ -84,12 +79,7 @@ class CommandNSAJoin : public Command
{
void DoList(CommandSource &source, NickCore *nc)
{
- AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
- if (channels == NULL)
- {
- channels = new AJoinList();
- nc->Extend("ns_ajoin_channels", channels);
- }
+ AJoinList *channels = nc->Require<AJoinList>("ajoinlist");
if ((*channels)->empty())
source.Reply(_("%s's auto join list is empty."), nc->display.c_str());
@@ -119,12 +109,7 @@ class CommandNSAJoin : public Command
void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &chan, const Anope::string &key)
{
- AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
- if (channels == NULL)
- {
- channels = new AJoinList();
- nc->Extend("ns_ajoin_channels", channels);
- }
+ AJoinList *channels = nc->Require<AJoinList>("ajoinlist");
unsigned i = 0;
for (; i < (*channels)->size(); ++i)
@@ -139,7 +124,7 @@ class CommandNSAJoin : public Command
source.Reply(CHAN_X_INVALID, chan.c_str());
else
{
- AJoinEntry *entry = new AJoinEntry();
+ AJoinEntry *entry = new AJoinEntry(nc);
entry->owner = nc;
entry->channel = chan;
entry->key = key;
@@ -150,12 +135,7 @@ class CommandNSAJoin : public Command
void DoDel(CommandSource &source, NickCore *nc, const Anope::string &chan)
{
- AJoinList *channels = nc->GetExt<AJoinList *>("ns_ajoin_channels");
- if (channels == NULL)
- {
- channels = new AJoinList();
- nc->Extend("ns_ajoin_channels", channels);
- }
+ AJoinList *channels = nc->Require<AJoinList>("ajoinlist");
unsigned i = 0;
for (; i < (*channels)->size(); ++i)
@@ -170,6 +150,9 @@ class CommandNSAJoin : public Command
(*channels)->erase((*channels)->begin() + i);
source.Reply(_("%s was removed from %s's auto join list."), chan.c_str(), nc->display.c_str());
}
+
+ if ((*channels)->empty())
+ nc->Shrink<AJoinList>("ajoinlist");
}
public:
@@ -233,10 +216,11 @@ class NSAJoin : public Module
{
Serialize::Type ajoinentry_type;
CommandNSAJoin commandnsajoin;
+ ExtensibleItem<AJoinList> ajoinlist;
public:
NSAJoin(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- ajoinentry_type("AJoinEntry", AJoinEntry::Unserialize), commandnsajoin(this)
+ ajoinentry_type("AJoinEntry", AJoinEntry::Unserialize), commandnsajoin(this), ajoinlist(this, "ajoinlist")
{
if (!IRCD->CanSVSJoin)
@@ -250,12 +234,9 @@ class NSAJoin : public Module
if (!NickServ)
return;
- AJoinList *channels = u->Account()->GetExt<AJoinList *>("ns_ajoin_channels");
+ AJoinList *channels = u->Account()->GetExt<AJoinList>("ajoinlist");
if (channels == NULL)
- {
- channels = new AJoinList();
- u->Account()->Extend("ns_ajoin_channels", channels);
- }
+ channels = u->Account()->Extend<AJoinList>("ajoinlist");
for (unsigned i = 0; i < (*channels)->size(); ++i)
{
@@ -284,7 +265,7 @@ class NSAJoin : public Module
continue;
else if (c->HasMode("ADMINONLY") && !u->HasMode("ADMIN"))
continue;
- else if (c->HasMode("SSL") && !(u->HasMode("SSL") || u->HasExt("SSL")))
+ else if (c->HasMode("SSL") && !(u->HasMode("SSL") || u->HasExt("ssl")))
continue;
else if (c->MatchesList(u, "BAN") == true && c->MatchesList(u, "EXCEPT") == false)
need_invite = true;
diff --git a/modules/commands/ns_alist.cpp b/modules/commands/ns_alist.cpp
index 591af44c3..2d7b02cfd 100644
--- a/modules/commands/ns_alist.cpp
+++ b/modules/commands/ns_alist.cpp
@@ -62,7 +62,7 @@ class CommandNSAList : public Command
{
++chan_count;
entry["Number"] = stringify(chan_count);
- entry["Channel"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name;
+ entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name;
entry["Access"] = "Founder";
list.AddEntry(entry);
continue;
@@ -72,7 +72,7 @@ class CommandNSAList : public Command
{
++chan_count;
entry["Number"] = stringify(chan_count);
- entry["Channel"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name;
+ entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name;
entry["Access"] = "Successor";
list.AddEntry(entry);
continue;
@@ -85,7 +85,7 @@ class CommandNSAList : public Command
++chan_count;
entry["Number"] = stringify(chan_count);
- entry["Channel"] = (ci->HasExt("NO_EXPIRE") ? "!" : "") + ci->name;
+ entry["Channel"] = (ci->HasExt("CS_NO_EXPIRE") ? "!" : "") + ci->name;
for (unsigned j = 0; j < access.size(); ++j)
entry["Access"] = entry["Access"] + ", " + access[j]->AccessSerialize();
entry["Access"] = entry["Access"].substr(2);
diff --git a/modules/commands/ns_cert.cpp b/modules/commands/ns_cert.cpp
index dc877e467..c87ff7179 100644
--- a/modules/commands/ns_cert.cpp
+++ b/modules/commands/ns_cert.cpp
@@ -10,15 +10,135 @@
*/
#include "module.h"
+#include "modules/ns_cert.h"
-static unsigned accessmax;
+struct NSCertListImpl : NSCertList
+{
+ Serialize::Reference<NickCore> nc;
+ std::vector<Anope::string> certs;
+
+ public:
+ NSCertListImpl(Extensible *obj) : nc(anope_dynamic_static_cast<NickCore *>(obj)) { }
+
+ /** Add an entry to the nick's certificate list
+ *
+ * @param entry The fingerprint to add to the cert list
+ *
+ * Adds a new entry into the cert list.
+ */
+ void AddCert(const Anope::string &entry) anope_override
+ {
+ this->certs.push_back(entry);
+ FOREACH_MOD(OnNickAddCert, (this->nc, entry));
+ }
+
+ /** Get an entry from the nick's cert list by index
+ *
+ * @param entry Index in the certificaate list vector to retrieve
+ * @return The fingerprint entry of the given index if within bounds, an empty string if the vector is empty or the index is out of bounds
+ *
+ * Retrieves an entry from the certificate list corresponding to the given index.
+ */
+ Anope::string GetCert(unsigned entry) const anope_override
+ {
+ if (entry >= this->certs.size())
+ return "";
+ return this->certs[entry];
+ }
+
+ unsigned GetCertCount() const anope_override
+ {
+ return this->certs.size();
+ }
+
+ /** Find an entry in the nick's cert list
+ *
+ * @param entry The fingerprint to search for
+ * @return True if the fingerprint is found in the cert list, false otherwise
+ *
+ * Search for an fingerprint within the cert list.
+ */
+ bool FindCert(const Anope::string &entry) const anope_override
+ {
+ return std::find(this->certs.begin(), this->certs.end(), entry) != this->certs.end();
+ }
+
+ /** Erase a fingerprint from the nick's certificate list
+ *
+ * @param entry The fingerprint to remove
+ *
+ * Removes the specified fingerprint from the cert list.
+ */
+ void EraseCert(const Anope::string &entry) anope_override
+ {
+ std::vector<Anope::string>::iterator it = std::find(this->certs.begin(), this->certs.end(), entry);
+ if (it != this->certs.end())
+ {
+ FOREACH_MOD(OnNickEraseCert, (this->nc, entry));
+ this->certs.erase(it);
+ }
+ }
+
+ /** Clears the entire nick's cert list
+ *
+ * Deletes all the memory allocated in the certificate list vector and then clears the vector.
+ */
+ void ClearCert() anope_override
+ {
+ FOREACH_MOD(OnNickClearCert, (this->nc));
+ this->certs.clear();
+ }
+
+ void Check() anope_override
+ {
+ if (this->certs.empty())
+ nc->Shrink<NSCertList>("certificates");
+ }
+
+ struct ExtensibleItem : ::ExtensibleItem<NSCertListImpl>
+ {
+ ExtensibleItem(Module *m, const Anope::string &name) : ::ExtensibleItem<NSCertListImpl>(m, name) { }
+
+ void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const anope_override
+ {
+ if (s->GetSerializableType()->GetName() != "NickCore")
+ return;
+
+ const NickCore *nc = anope_dynamic_static_cast<const NickCore *>(e);
+ NSCertList *certs = this->Get(nc);
+ if (certs == NULL || !certs->GetCertCount())
+ return;
+
+ for (unsigned i = 0; i < certs->GetCertCount(); ++i)
+ data["cert"] << certs->GetCert(i) << " ";
+ }
+
+ void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) anope_override
+ {
+ if (s->GetSerializableType()->GetName() != "NickCore")
+ return;
+
+ NickCore *nc = anope_dynamic_static_cast<NickCore *>(e);
+ NSCertListImpl *certs = this->Require(nc);
+
+ Anope::string buf;
+ data["cert"] >> buf;
+ spacesepstream sep(buf);
+ certs->certs.clear();
+ while (sep.GetToken(buf))
+ certs->certs.push_back(buf);
+ }
+ };
+};
class CommandNSCert : public Command
{
private:
void DoServAdminList(CommandSource &source, const NickCore *nc)
{
- if (nc->cert.empty())
+ NSCertList *cl = nc->GetExt<NSCertList>("certificates");
+
+ if (!cl || !cl->GetCertCount())
{
source.Reply(_("Certificate list for \002%s\002 is empty."), nc->display.c_str());
return;
@@ -33,9 +153,9 @@ class CommandNSCert : public Command
ListFormatter list;
list.AddColumn("Certificate");
- for (unsigned i = 0, end = nc->cert.size(); i < end; ++i)
+ for (unsigned i = 0; i < cl->GetCertCount(); ++i)
{
- Anope::string fingerprint = nc->GetCert(i);
+ const Anope::string &fingerprint = cl->GetCert(i);
ListFormatter::ListEntry entry;
entry["Certificate"] = fingerprint;
list.AddEntry(entry);
@@ -47,74 +167,74 @@ class CommandNSCert : public Command
list.Process(replies);
for (unsigned i = 0; i < replies.size(); ++i)
source.Reply(replies[i]);
-
- return;
}
void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &mask)
{
+ NSCertList *cl = nc->Require<NSCertList>("certificates");
- if (nc->cert.size() >= Config->GetModule(this->owner)->Get<unsigned>("accessmax"))
+ if (cl->GetCertCount() >= Config->GetModule(this->owner)->Get<unsigned>("accessmax"))
{
source.Reply(_("Sorry, you can only have %d certificate entries for a nickname."), Config->GetModule(this->owner)->Get<unsigned>("accessmax"));
return;
}
- if (source.GetUser() && !source.GetUser()->fingerprint.empty() && !nc->FindCert(source.GetUser()->fingerprint))
- {
- nc->AddCert(source.GetUser()->fingerprint);
- source.Reply(_("\002%s\002 added to your certificate list."), source.GetUser()->fingerprint.c_str());
- return;
- }
-
if (mask.empty())
{
- this->OnSyntaxError(source, "ADD");
+ if (source.GetUser() && !source.GetUser()->fingerprint.empty() && !cl->FindCert(source.GetUser()->fingerprint))
+ {
+ cl->AddCert(source.GetUser()->fingerprint);
+ source.Reply(_("\002%s\002 added to your certificate list."), source.GetUser()->fingerprint.c_str());
+ }
+ else
+ this->OnSyntaxError(source, "ADD");
+
return;
}
- if (nc->FindCert(mask))
+ if (cl->FindCert(mask))
{
source.Reply(_("Fingerprint \002%s\002 already present on your certificate list."), mask.c_str());
return;
}
- nc->AddCert(mask);
+ cl->AddCert(mask);
source.Reply(_("\002%s\002 added to your certificate list."), mask.c_str());
- return;
}
void DoDel(CommandSource &source, NickCore *nc, const Anope::string &mask)
{
- if (source.GetUser() && !source.GetUser()->fingerprint.empty() && nc->FindCert(source.GetUser()->fingerprint))
- {
- nc->EraseCert(source.GetUser()->fingerprint);
- source.Reply(_("\002%s\002 deleted from your certificate list."), source.GetUser()->fingerprint.c_str());
- return;
- }
+ NSCertList *cl = nc->Require<NSCertList>("certificates");
if (mask.empty())
{
- this->OnSyntaxError(source, "DEL");
+ if (source.GetUser() && !source.GetUser()->fingerprint.empty() && cl->FindCert(source.GetUser()->fingerprint))
+ {
+ cl->EraseCert(source.GetUser()->fingerprint);
+ source.Reply(_("\002%s\002 deleted from your certificate list."), source.GetUser()->fingerprint.c_str());
+ }
+ else
+ this->OnSyntaxError(source, "DEL");
+
return;
}
- if (!nc->FindCert(mask))
+ if (!cl->FindCert(mask))
{
source.Reply(_("\002%s\002 not found on your certificate list."), mask.c_str());
return;
}
source.Reply(_("\002%s\002 deleted from your certificate list."), mask.c_str());
- nc->EraseCert(mask);
-
- return;
+ cl->EraseCert(mask);
+ cl->Check();
}
void DoList(CommandSource &source, const NickCore *nc)
{
+ NSCertList *cl = nc->GetExt<NSCertList>("certificates");
- if (nc->cert.empty())
+ if (!cl || !cl->GetCertCount())
{
source.Reply(_("Your certificate list is empty."));
return;
@@ -123,10 +243,10 @@ class CommandNSCert : public Command
ListFormatter list;
list.AddColumn("Certificate");
- for (unsigned i = 0, end = nc->cert.size(); i < end; ++i)
+ for (unsigned i = 0; i < cl->GetCertCount(); ++i)
{
ListFormatter::ListEntry entry;
- entry["Certificate"] = nc->GetCert(i);
+ entry["Certificate"] = cl->GetCert(i);
list.AddEntry(entry);
}
@@ -197,8 +317,17 @@ class CommandNSCert : public Command
class NSCert : public Module
{
CommandNSCert commandnscert;
+ NSCertListImpl::ExtensibleItem certs;
+
+ public:
+ NSCert(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
+ commandnscert(this), certs(this, "certificates")
+ {
+ if (!IRCD || !IRCD->CanCertFP)
+ throw ModuleException("Your IRCd does not support ssl client certificates");
+ }
- void DoAutoIdentify(User *u)
+ void OnFingerprint(User *u) anope_override
{
NickAlias *na = NickAlias::Find(u->nick);
BotInfo *NickServ = Config->GetClient("NickServ");
@@ -208,29 +337,28 @@ class NSCert : public Module
return;
if (na->nc->HasExt("SUSPENDED"))
return;
- if (!na->nc->FindCert(u->fingerprint))
+
+ NSCertList *cl = certs.Get(na->nc);
+ if (!cl || !cl->FindCert(u->fingerprint))
return;
u->Identify(na);
u->SendMessage(NickServ, _("SSL Fingerprint accepted. You are now identified."));
- Log(u) << "automatically identified for account " << na->nc->display << " using a valid SSL fingerprint";
- return;
+ Log(u) << "automatically identified for account " << na->nc->display << " via SSL certificate fingerprint";
}
- public:
- NSCert(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandnscert(this)
+ EventReturn OnNickValidate(User *u, NickAlias *na) anope_override
{
+ NSCertList *cl = certs.Get(na->nc);
+ if (!u->fingerprint.empty() && cl && cl->FindCert(u->fingerprint))
+ {
+ u->Identify(na);
+ u->SendMessage(Config->GetClient("NickServ"), _("SSL fingerprint accepted, you are now identified."));
+ Log(u) << "automatically identified for account " << na->nc->display << " via SSL fingerprint.";
+ return EVENT_ALLOW;
+ }
- if (!IRCD || !IRCD->CanCertFP)
- throw ModuleException("Your IRCd does not support ssl client certificates");
-
-
- }
-
- void OnFingerprint(User *u) anope_override
- {
- DoAutoIdentify(u);
+ return EVENT_CONTINUE;
}
};
diff --git a/modules/commands/ns_group.cpp b/modules/commands/ns_group.cpp
index 989fc1385..160980bc9 100644
--- a/modules/commands/ns_group.cpp
+++ b/modules/commands/ns_group.cpp
@@ -10,6 +10,7 @@
*/
#include "module.h"
+#include "modules/ns_cert.h"
class NSGroupRequest : public IdentifyRequest
{
@@ -43,7 +44,6 @@ class NSGroupRequest : public IdentifyRequest
na->time_registered = na->last_seen = Anope::CurTime;
u->Login(target->nc);
- IRCD->SendLogin(u);
FOREACH_MOD(OnNickGroup, (u, target));
Log(LOG_COMMAND, source, cmd) << "makes " << nick << " join group of " << target->nick << " (" << target->nc->display << ") (email: " << (!target->nc->email.empty() ? target->nc->email : "none") << ")";
@@ -141,7 +141,9 @@ class CommandNSGroup : public Command
bool ok = false;
if (!na && u->Account())
ok = true;
- else if (!u->fingerprint.empty() && target->nc->FindCert(u->fingerprint))
+
+ NSCertList *cl = target->nc->GetExt<NSCertList>("certificates");
+ if (!u->fingerprint.empty() && cl && cl->FindCert(u->fingerprint))
ok = true;
if (ok == false && !pass.empty())
@@ -236,8 +238,6 @@ class CommandNSUngroup : public Command
nc->pass = oldcore->pass;
if (!oldcore->email.empty())
nc->email = oldcore->email;
- if (!oldcore->greet.empty())
- nc->greet = oldcore->greet;
nc->language = oldcore->language;
source.Reply(_("Nick %s has been ungrouped from %s."), na->nick.c_str(), oldcore->display.c_str());
@@ -303,7 +303,7 @@ class CommandNSGList : public Command
ListFormatter::ListEntry entry;
entry["Nick"] = na2->nick;
- entry["Expires"] = (na2->HasExt("NO_EXPIRE") || !nickserv_expire || Anope::NoExpire) ? "Does not expire" : ("expires in " + Anope::strftime(na2->last_seen + nickserv_expire));
+ entry["Expires"] = (na2->HasExt("NS_NO_EXPIRE") || !nickserv_expire || Anope::NoExpire) ? "Does not expire" : ("expires in " + Anope::strftime(na2->last_seen + nickserv_expire));
list.AddEntry(entry);
}
diff --git a/modules/commands/ns_info.cpp b/modules/commands/ns_info.cpp
index 864136cd8..8fc5aa639 100644
--- a/modules/commands/ns_info.cpp
+++ b/modules/commands/ns_info.cpp
@@ -13,17 +13,6 @@
class CommandNSInfo : public Command
{
- private:
- void CheckOptStr(NickCore *core, Anope::string &buf, const Anope::string &opt, const char *str, const Extensible *e, bool reverse_logic = false)
- {
- if (reverse_logic != e->HasExt(opt))
- {
- if (!buf.empty())
- buf += ", ";
-
- buf += Language::Translate(core, str);
- }
- }
public:
CommandNSInfo(Module *creator) : Command(creator, "nickserv/info", 0, 2)
{
@@ -105,34 +94,6 @@ class CommandNSInfo : public Command
else
info[_("VHost")] = na->GetVhostHost();
}
-
- if (!na->nc->greet.empty())
- info[_("Greet")] = na->nc->greet;
-
- Anope::string optbuf;
-
- CheckOptStr(source.nc, optbuf, "KILLPROTECT", _("Protection"), na->nc);
- CheckOptStr(source.nc, optbuf, "SECURE", _("Security"), na->nc);
- CheckOptStr(source.nc, optbuf, "PRIVATE", _("Private"), na->nc);
- CheckOptStr(source.nc, optbuf, "MSG", _("Message mode"), na->nc);
- CheckOptStr(source.nc, optbuf, "AUTOOP", _("Auto-op"), na->nc);
- CheckOptStr(source.nc, optbuf, "SUSPENDED", _("Suspended"), na->nc);
- CheckOptStr(source.nc, optbuf, "STATS", _("Chanstats"), na->nc);
- CheckOptStr(source.nc, optbuf, "NO_EXPIRE", _("No expire"), na);
-
- info[_("Options")] = optbuf.empty() ? _("None") : optbuf;
-
- if (na->nc->HasExt("UNCONFIRMED") == false)
- {
- time_t nickserv_expire = Config->GetModule("nickserv")->Get<time_t>("expire");
- if (!na->HasExt("NO_EXPIRE") && nickserv_expire && !Anope::NoExpire)
- info[_("Expires")] = Anope::strftime(na->last_seen + nickserv_expire);
- }
- else
- {
- time_t unconfirmed_expire = Config->GetModule("nickserv")->Get<time_t>("unconfirmedexpire", "1d");
- info[_("Expires")] = Anope::strftime(na->time_registered + unconfirmed_expire);
- }
}
FOREACH_MOD(OnNickInfo, (source, na, info, show_hidden));
@@ -159,13 +120,142 @@ class CommandNSInfo : public Command
}
};
+
+class CommandNSSetHide : public Command
+{
+ public:
+ CommandNSSetHide(Module *creator, const Anope::string &sname = "nickserv/set/hide", size_t min = 2) : Command(creator, sname, min, min + 1)
+ {
+ this->SetDesc(_("Hide certain pieces of nickname information"));
+ this->SetSyntax(_("{EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}"));
+ }
+
+ void Run(CommandSource &source, const Anope::string &user, const Anope::string &param, const Anope::string &arg)
+ {
+ const NickAlias *na = NickAlias::Find(user);
+ if (!na)
+ {
+ source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
+ return;
+ }
+ NickCore *nc = na->nc;
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
+ if (MOD_RESULT == EVENT_STOP)
+ return;
+
+ Anope::string onmsg, offmsg, flag;
+
+ if (param.equals_ci("EMAIL"))
+ {
+ flag = "HIDE_EMAIL";
+ onmsg = _("The E-mail address of \002%s\002 will now be hidden from %s INFO displays.");
+ offmsg = _("The E-mail address of \002%s\002 will now be shown in %s INFO displays.");
+ }
+ else if (param.equals_ci("USERMASK"))
+ {
+ flag = "HIDE_MASK";
+ onmsg = _("The last seen user@host mask of \002%s\002 will now be hidden from %s INFO displays.");
+ offmsg = _("The last seen user@host mask of \002%s\002 will now be shown in %s INFO displays.");
+ }
+ else if (param.equals_ci("STATUS"))
+ {
+ flag = "HIDE_STATUS";
+ onmsg = _("The services access status of \002%s\002 will now be hidden from %s INFO displays.");
+ offmsg = _("The services access status of \002%s\002 will now be shown in %s INFO displays.");
+ }
+ else if (param.equals_ci("QUIT"))
+ {
+ flag = "HIDE_QUIT";
+ onmsg = _("The last quit message of \002%s\002 will now be hidden from %s INFO displays.");
+ offmsg = _("The last quit message of \002%s\002 will now be shown in %s INFO displays.");
+ }
+ else
+ {
+ this->OnSyntaxError(source, "HIDE");
+ return;
+ }
+
+ if (arg.equals_ci("ON"))
+ {
+ Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display;
+ nc->Extend<bool>(flag);
+ source.Reply(onmsg.c_str(), nc->display.c_str(), source.service->nick.c_str());
+ }
+ else if (arg.equals_ci("OFF"))
+ {
+ Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display;
+ nc->Shrink<bool>(flag);
+ source.Reply(offmsg.c_str(), nc->display.c_str(), source.service->nick.c_str());
+ }
+ else
+ this->OnSyntaxError(source, "HIDE");
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ this->Run(source, source.nc->display, params[0], params[1]);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Allows you to prevent certain pieces of information from\n"
+ "being displayed when someone does a %s \002INFO\002 on your\n"
+ "nick. You can hide your E-mail address (\002EMAIL\002), last seen\n"
+ "user@host mask (\002USERMASK\002), your services access status\n"
+ "(\002STATUS\002) and last quit message (\002QUIT\002).\n"
+ "The second parameter specifies whether the information should\n"
+ "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str());
+ return true;
+ }
+};
+
+class CommandNSSASetHide : public CommandNSSetHide
+{
+ public:
+ CommandNSSASetHide(Module *creator) : CommandNSSetHide(creator, "nickserv/saset/hide", 3)
+ {
+ this->SetSyntax("\037nickname\037 {EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}");
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ this->ClearSyntax();
+ this->Run(source, params[0], params[1], params[2]);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Allows you to prevent certain pieces of information from\n"
+ "being displayed when someone does a %s \002INFO\002 on the\n"
+ "nick. You can hide the E-mail address (\002EMAIL\002), last seen\n"
+ "user@host mask (\002USERMASK\002), the services access status\n"
+ "(\002STATUS\002) and last quit message (\002QUIT\002).\n"
+ "The second parameter specifies whether the information should\n"
+ "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str());
+ return true;
+ }
+};
+
class NSInfo : public Module
{
CommandNSInfo commandnsinfo;
+ CommandNSSetHide commandnssethide;
+ CommandNSSASetHide commandnssasethide;
+
+ SerializableExtensibleItem<bool> hide_email, hide_usermask, hide_status, hide_quit;
+
public:
NSInfo(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandnsinfo(this)
+ commandnsinfo(this), commandnssethide(this), commandnssasethide(this),
+ hide_email(this, "HIDE_EMAIL"), hide_usermask(this, "HIDE_MASK"), hide_status(this, "HIDE_STATUS"),
+ hide_quit(this, "HIDE_QUIT")
{
}
diff --git a/modules/commands/ns_list.cpp b/modules/commands/ns_list.cpp
index a4e73e857..b1ab19971 100644
--- a/modules/commands/ns_list.cpp
+++ b/modules/commands/ns_list.cpp
@@ -83,9 +83,9 @@ class CommandNSList : public Command
const NickAlias *na = it->second;
/* Don't show private nicks to non-services admins. */
- if (na->nc->HasExt("PRIVATE") && !is_servadmin && na->nc != mync)
+ if (na->nc->HasExt("NS_PRIVATE") && !is_servadmin && na->nc != mync)
continue;
- else if (nsnoexpire && !na->HasExt("NO_EXPIRE"))
+ else if (nsnoexpire && !na->HasExt("NS_NO_EXPIRE"))
continue;
else if (suspended && !na->nc->HasExt("SUSPENDED"))
continue;
@@ -101,7 +101,7 @@ class CommandNSList : public Command
if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nnicks <= listmax)
{
bool isnoexpire = false;
- if (is_servadmin && na->HasExt("NO_EXPIRE"))
+ if (is_servadmin && na->HasExt("NS_NO_EXPIRE"))
isnoexpire = true;
ListFormatter::ListEntry entry;
@@ -177,14 +177,118 @@ class CommandNSList : public Command
}
};
+
+class CommandNSSetPrivate : public Command
+{
+ public:
+ CommandNSSetPrivate(Module *creator, const Anope::string &sname = "nickserv/set/private", size_t min = 1) : Command(creator, sname, min, min + 1)
+ {
+ this->SetDesc(_("Prevent the nickname from appearing in the LIST command"));
+ this->SetSyntax(_("{ON | OFF}"));
+ }
+
+ void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
+ {
+ const NickAlias *na = NickAlias::Find(user);
+ if (!na)
+ {
+ source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
+ return;
+ }
+ NickCore *nc = na->nc;
+
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
+ if (MOD_RESULT == EVENT_STOP)
+ return;
+
+ if (param.equals_ci("ON"))
+ {
+ Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable private for " << nc->display;
+ nc->Extend<bool>("NS_PRIVATE");
+ source.Reply(_("Private option is now \002on\002 for \002%s\002."), nc->display.c_str());
+ }
+ else if (param.equals_ci("OFF"))
+ {
+ Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable private for " << nc->display;
+ nc->Shrink<bool>("NS_PRIVATE");
+ source.Reply(_("Private option is now \002off\002 for \002%s\002."), nc->display.c_str());
+ }
+ else
+ this->OnSyntaxError(source, "PRIVATE");
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ this->Run(source, source.nc->display, params[0]);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Turns %s's privacy option on or off for your nick.\n"
+ "With \002PRIVATE\002 set, your nickname will not appear in\n"
+ "nickname lists generated with %s's \002LIST\002 command.\n"
+ "(However, anyone who knows your nickname can still get\n"
+ "information on it using the \002INFO\002 command.)"),
+ source.service->nick.c_str(), source.service->nick.c_str());
+ return true;
+ }
+};
+
+class CommandNSSASetPrivate : public CommandNSSetPrivate
+{
+ public:
+ CommandNSSASetPrivate(Module *creator) : CommandNSSetPrivate(creator, "nickserv/saset/private", 2)
+ {
+ this->ClearSyntax();
+ this->SetSyntax(_("\037nickname\037 {ON | OFF}"));
+ }
+
+ void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
+ {
+ this->Run(source, params[0], params[1]);
+ }
+
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
+ {
+ this->SendSyntax(source);
+ source.Reply(" ");
+ source.Reply(_("Turns %s's privacy option on or off for the nick.\n"
+ "With \002PRIVATE\002 set, the nickname will not appear in\n"
+ "nickname lists generated with %s's \002LIST\002 command.\n"
+ "(However, anyone who knows the nickname can still get\n"
+ "information on it using the \002INFO\002 command.)"),
+ source.service->nick.c_str(), source.service->nick.c_str());
+ return true;
+ }
+};
+
+
class NSList : public Module
{
CommandNSList commandnslist;
+ CommandNSSetPrivate commandnssetprivate;
+ CommandNSSASetPrivate commandnssasetprivate;
+
+ SerializableExtensibleItem<bool> priv;
+
public:
NSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandnslist(this)
+ commandnslist(this), commandnssetprivate(this), commandnssasetprivate(this),
+ priv(this, "NS_PRIVATE")
+ {
+ }
+
+ void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_all) anope_override
{
+ if (!show_all)
+ return;
+
+ if (priv.HasExt(na->nc))
+ info.AddOption(_("Private"));
}
};
diff --git a/modules/commands/ns_recover.cpp b/modules/commands/ns_recover.cpp
index 224b4e2ed..48c625ace 100644
--- a/modules/commands/ns_recover.cpp
+++ b/modules/commands/ns_recover.cpp
@@ -10,10 +10,11 @@
*/
#include "module.h"
+#include "modules/ns_cert.h"
static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
-struct NSRecoverExtensibleInfo : ExtensibleItem, std::map<Anope::string, ChannelStatus> { };
+typedef std::map<Anope::string, ChannelStatus> NSRecoverInfo;
class NSRecoverRequest : public IdentifyRequest
{
@@ -50,7 +51,7 @@ class NSRecoverRequest : public IdentifyRequest
// same person that is executing the command, so kill them off (old GHOST command).
else if (u->Account() == na->nc)
{
- if (!source.GetAccount() && na->nc->HasExt("SECURE"))
+ if (!source.GetAccount() && na->nc->HasExt("NS_SECURE"))
{
source.GetUser()->Login(u->Account());
Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << u->Account()->display;
@@ -60,11 +61,9 @@ class NSRecoverRequest : public IdentifyRequest
{
if (!u->chans.empty())
{
- NSRecoverExtensibleInfo *ei = new NSRecoverExtensibleInfo;
+ NSRecoverInfo *ei = source.GetUser()->Extend<NSRecoverInfo>("recover");
for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it)
(*ei)[it->first->name] = it->second->status;
-
- source.GetUser()->Extend("ns_recover_info", ei);
}
}
@@ -83,7 +82,7 @@ class NSRecoverRequest : public IdentifyRequest
/* User is not identified or not identified to the same account as the person using this command */
else
{
- if (!source.GetAccount() && na->nc->HasExt("SECURE"))
+ if (!source.GetAccount() && na->nc->HasExt("NS_SECURE"))
{
source.GetUser()->Login(na->nc); // Identify the user using the command if they arent identified
Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << na->nick << " (" << na->nc->display << ")";
@@ -161,9 +160,11 @@ class CommandNSRecover : public Command
bool ok = false;
if (source.GetAccount() == na->nc)
ok = true;
- else if (!na->nc->HasExt("SECURE") && source.GetUser() && na->nc->IsOnAccess(source.GetUser()))
+ else if (!na->nc->HasExt("NS_SECURE") && source.GetUser() && na->nc->IsOnAccess(source.GetUser()))
ok = true;
- else if (source.GetUser() && !source.GetUser()->fingerprint.empty() && na->nc->FindCert(source.GetUser()->fingerprint))
+
+ NSCertList *cl = na->nc->GetExt<NSCertList>("certificates");
+ if (source.GetUser() && !source.GetUser()->fingerprint.empty() && cl && cl->FindCert(source.GetUser()->fingerprint))
ok = true;
if (ok == false && !pass.empty())
@@ -200,10 +201,11 @@ class CommandNSRecover : public Command
class NSRecover : public Module
{
CommandNSRecover commandnsrecover;
+ PrimitiveExtensibleItem<NSRecoverInfo> recover;
public:
NSRecover(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandnsrecover(this)
+ commandnsrecover(this), recover(this, "recover")
{
if (Config->GetBlock("options")->Get<bool>("nonicknameownership"))
@@ -211,34 +213,15 @@ class NSRecover : public Module
}
- ~NSRecover()
- {
- for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
- it->second->Shrink("ns_recover_info");
-
- OnShutdown();
- }
-
- void OnShutdown() anope_override
- {
- /* On shutdown, restart, or mod unload, remove all of our holds for nicks (svshold or qlines)
- * because some IRCds do not allow us to have these automatically expire
- */
- for (nickalias_map::const_iterator it = NickAliasList->begin(); it != NickAliasList->end(); ++it)
- nickserv->Release(it->second);
- }
-
- void OnRestart() anope_override { OnShutdown(); }
-
void OnUserNickChange(User *u, const Anope::string &oldnick) anope_override
{
if (Config->GetModule(this)->Get<bool>("restoreonrecover"))
{
- NSRecoverExtensibleInfo *ei = u->GetExt<NSRecoverExtensibleInfo *>("ns_recover_info");
+ NSRecoverInfo *ei = recover.Get(u);
BotInfo *NickServ = Config->GetClient("NickServ");
if (ei != NULL && NickServ != NULL)
- for (std::map<Anope::string, ChannelStatus>::iterator it = ei->begin(), it_end = ei->end(); it != it_end;)
+ for (NSRecoverInfo::iterator it = ei->begin(), it_end = ei->end(); it != it_end;)
{
Channel *c = Channel::Find(it->first);
const Anope::string &cname = it->first;
@@ -257,11 +240,11 @@ class NSRecover : public Module
{
if (Config->GetModule(this)->Get<bool>("restoreonrecover"))
{
- NSRecoverExtensibleInfo *ei = u->GetExt<NSRecoverExtensibleInfo *>("ns_recover_info");
+ NSRecoverInfo *ei = recover.Get(u);
if (ei != NULL)
{
- std::map<Anope::string, ChannelStatus>::iterator it = ei->find(c->name);
+ NSRecoverInfo::iterator it = ei->find(c->name);
if (it != ei->end())
{
for (size_t i = 0; i < it->second.Modes().length(); ++i)
@@ -269,7 +252,7 @@ class NSRecover : public Module
ei->erase(it);
if (ei->empty())
- u->Shrink("ns_recover_info");
+ recover.Unset(u);
}
}
}
diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp
index 4064ce924..e8adec549 100644
--- a/modules/commands/ns_register.cpp
+++ b/modules/commands/ns_register.cpp
@@ -36,27 +36,27 @@ class CommandNSConfirm : public Command
source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str());
else
{
- na->nc->Shrink("UNCONFIRMED");
+ na->nc->Shrink<bool>("UNCONFIRMED");
Log(LOG_ADMIN, source, this) << "to confirm nick " << na->nick << " (" << na->nc->display << ")";
source.Reply(_("Nick \002%s\002 has been confirmed."), na->nick.c_str());
}
}
else if (source.nc)
{
- Anope::string *code = source.nc->GetExt<ExtensibleItemClass<Anope::string> *>("ns_register_passcode");
+ Anope::string *code = source.nc->GetExt<Anope::string>("passcode");
if (code != NULL && *code == passcode)
{
NickCore *nc = source.nc;
- nc->Shrink("ns_register_passcode");
+ nc->Shrink<Anope::string>("passcode");
Log(LOG_COMMAND, source, this) << "to confirm their email";
source.Reply(_("Your email address of \002%s\002 has been confirmed."), source.nc->email.c_str());
- nc->Shrink("UNCONFIRMED");
+ nc->Shrink<bool>("UNCONFIRMED");
if (source.GetUser())
{
IRCD->SendLogin(source.GetUser());
const NickAlias *na = NickAlias::Find(source.GetNick());
- if (!Config->GetBlock("options")->Get<bool>("nonicknameownership") && na != NULL && na->nc == source.GetAccount() && na->nc->HasExt("UNCONFIRMED") == false)
+ if (!Config->GetBlock("options")->Get<bool>("nonicknameownership") && na != NULL && na->nc == source.GetAccount() && !na->nc->HasExt("UNCONFIRMED"))
source.GetUser()->SetMode(source.service, "REGISTERED");
}
}
@@ -207,12 +207,12 @@ class CommandNSRegister : public Command
if (nsregister.equals_ci("admin"))
{
- nc->ExtendMetadata("UNCONFIRMED");
+ nc->Extend<bool>("UNCONFIRMED");
source.Reply(_("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed."));
}
else if (nsregister.equals_ci("mail"))
{
- nc->ExtendMetadata("UNCONFIRMED");
+ nc->Extend<bool>("UNCONFIRMED");
if (SendRegmail(u, na, source.service))
{
time_t unconfirmed_expire = Config->GetModule("nickserv")->Get<time_t>("unconfirmedexpire", "1d");
@@ -292,7 +292,7 @@ class CommandNSResend : public Command
if (na == NULL)
source.Reply(NICK_NOT_REGISTERED);
- else if (na->nc != source.GetAccount() || source.nc->HasExt("UNCONFIRMED") == false)
+ else if (na->nc != source.GetAccount() || !source.nc->HasExt("UNCONFIRMED"))
source.Reply(_("Your account is already confirmed."));
else
{
@@ -336,23 +336,55 @@ class NSRegister : public Module
CommandNSConfirm commandnsconfirm;
CommandNSResend commandnsrsend;
+ PrimitiveExtensibleItem<bool> unconfirmed;
+ PrimitiveExtensibleItem<Anope::string> passcode;
+
public:
NSRegister(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandnsregister(this), commandnsconfirm(this), commandnsrsend(this)
+ commandnsregister(this), commandnsconfirm(this), commandnsrsend(this), unconfirmed(this, "UNCONFIRMED"),
+ passcode(this, "passcode")
{
if (Config->GetModule(this)->Get<const Anope::string>("registration").equals_ci("disable"))
throw ModuleException("Module " + this->name + " will not load with registration disabled.");
}
+
+ void OnNickIdentify(User *u) anope_override
+ {
+ BotInfo *NickServ;
+ if (unconfirmed.HasExt(u->Account()) && (NickServ = Config->GetClient("NickServ")))
+ {
+ const Anope::string &nsregister = Config->GetModule(this)->Get<const Anope::string>("registration");
+ if (nsregister.equals_ci("admin"))
+ u->SendMessage(NickServ, _("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed."));
+ else
+ u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you when you registered."));
+ const NickAlias *this_na = NickAlias::Find(u->Account()->display);
+ time_t time_registered = Anope::CurTime - this_na->time_registered;
+ time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d");
+ if (unconfirmed_expire > time_registered)
+ u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s"), Anope::Duration(unconfirmed_expire - time_registered).c_str());
+ }
+ }
+
+ void OnPreNickExpire(NickAlias *na, bool &expire) anope_override
+ {
+ if (unconfirmed.HasExt(na->nc))
+ {
+ time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d");
+ if (unconfirmed_expire && Anope::CurTime - na->time_registered >= unconfirmed_expire)
+ expire = true;
+ }
+ }
};
static bool SendRegmail(User *u, const NickAlias *na, const BotInfo *bi)
{
NickCore *nc = na->nc;
- Anope::string *code = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("ns_register_passcode");
- Anope::string codebuf;
+ Anope::string *code = na->nc->GetExt<Anope::string>("passcode");
if (code == NULL)
{
+ code = na->nc->Extend<Anope::string>("passcode");
int chars[] = {
' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
@@ -362,22 +394,19 @@ static bool SendRegmail(User *u, const NickAlias *na, const BotInfo *bi)
};
int idx, min = 1, max = 62;
for (idx = 0; idx < 9; ++idx)
- codebuf += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min];
- nc->Extend("ns_register_passcode", new ExtensibleItemClass<Anope::string>(codebuf));
+ *code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min];
}
- else
- codebuf = *code;
Anope::string subject = Language::Translate(na->nc, Config->GetBlock("mail")->Get<const Anope::string>("registration_subject").c_str()),
message = Language::Translate(na->nc, Config->GetBlock("mail")->Get<const Anope::string>("registration_message").c_str());
subject = subject.replace_all_cs("%n", na->nick);
subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
- subject = subject.replace_all_cs("%c", codebuf);
+ subject = subject.replace_all_cs("%c", *code);
message = message.replace_all_cs("%n", na->nick);
message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
- message = message.replace_all_cs("%c", codebuf);
+ message = message.replace_all_cs("%c", *code);
return Mail::Send(u, nc, bi, subject, message);
}
diff --git a/modules/commands/ns_resetpass.cpp b/modules/commands/ns_resetpass.cpp
index 9b15e53ac..871864b6d 100644
--- a/modules/commands/ns_resetpass.cpp
+++ b/modules/commands/ns_resetpass.cpp
@@ -53,7 +53,7 @@ class CommandNSResetPass : public Command
}
};
-struct ResetInfo : ExtensibleItem
+struct ResetInfo
{
Anope::string code;
time_t time;
@@ -62,21 +62,14 @@ struct ResetInfo : ExtensibleItem
class NSResetPass : public Module
{
CommandNSResetPass commandnsresetpass;
+ PrimitiveExtensibleItem<ResetInfo> reset;
public:
NSResetPass(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandnsresetpass(this)
+ commandnsresetpass(this), reset(this, "reset")
{
if (!Config->GetBlock("mail")->Get<bool>("usemail"))
throw ModuleException("Not using mail.");
-
-
- }
-
- ~NSResetPass()
- {
- for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it)
- it->second->Shrink("ns_resetpass");
}
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) anope_override
@@ -85,24 +78,23 @@ class NSResetPass : public Module
{
NickAlias *na = NickAlias::Find(params[0]);
- ResetInfo *ri = na ? na->nc->GetExt<ResetInfo *>("ns_resetpass") : NULL;
+ ResetInfo *ri = na ? reset.Get(na->nc) : NULL;
if (na && ri)
{
NickCore *nc = na->nc;
const Anope::string &passcode = params[1];
if (ri->time < Anope::CurTime - 3600)
{
- nc->Shrink("ns_resetpass");
+ reset.Unset(nc);
source.Reply(_("Your password reset request has expired."));
}
else if (passcode.equals_cs(ri->code))
{
- nc->Shrink("ns_resetpass");
+ reset.Unset(nc);
+ nc->Shrink<bool>("UNCONFIRMED");
Log(LOG_COMMAND, source, &commandnsresetpass) << "confirmed RESETPASS to forcefully identify as " << na->nick;
- nc->Shrink("UNCONFIRMED");
-
if (source.GetUser())
{
source.GetUser()->Identify(na);
@@ -147,13 +139,11 @@ static bool SendResetEmail(User *u, const NickAlias *na, const BotInfo *bi)
message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
message = message.replace_all_cs("%c", passcode);
- ResetInfo *ri = new ResetInfo;
+ ResetInfo *ri = na->nc->Extend<ResetInfo>("reset");
ri->code = passcode;
ri->time = Anope::CurTime;
- NickCore *nc = na->nc;
- nc->Extend("ns_resetpass", ri);
- return Mail::Send(u, nc, bi, subject, message);
+ return Mail::Send(u, na->nc, bi, subject, message);
}
MODULE_INIT(NSResetPass)
diff --git a/modules/commands/ns_set.cpp b/modules/commands/ns_set.cpp
index 7b0de5565..08cf3966a 100644
--- a/modules/commands/ns_set.cpp
+++ b/modules/commands/ns_set.cpp
@@ -191,8 +191,6 @@ class CommandNSSASetPassword : public Command
source.Reply(_("Password for \002%s\002 changed to \002%s\002."), nc->display.c_str(), tmp_pass.c_str());
else
source.Reply(_("Password for \002%s\002 changed."), nc->display.c_str());
-
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &) anope_override
@@ -231,13 +229,13 @@ class CommandNSSetAutoOp : public Command
if (param.equals_ci("ON"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable autoop for " << na->nc->display;
- nc->ExtendMetadata("AUTOOP");
+ nc->Extend<bool>("AUTOOP");
source.Reply(_("Services will from now on set status modes on %s in channels."), nc->display.c_str());
}
else if (param.equals_ci("OFF"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable autoop for " << na->nc->display;
- nc->Shrink("AUTOOP");
+ nc->Shrink<bool>("AUTOOP");
source.Reply(_("Services will no longer set status modes on %s in channels."), nc->display.c_str());
}
else
@@ -313,19 +311,17 @@ class CommandNSSetChanstats : public Command
if (param.equals_ci("ON"))
{
Log(na->nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable chanstats for " << na->nc->display;
- na->nc->ExtendMetadata("STATS");
+ na->nc->Extend<bool>("NS_STATS");
source.Reply(_("Chanstat statistics are now enabled for your nick."));
}
else if (param.equals_ci("OFF"))
{
Log(na->nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable chanstats for " << na->nc->display;
- na->nc->Shrink("STATS");
+ na->nc->Shrink<bool>("NS_STATS");
source.Reply(_("Chanstat statistics are now disabled for your nick."));
}
else
this->OnSyntaxError(source, "CHANSTATS");
-
- return;
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
@@ -446,7 +442,7 @@ class CommandNSSASetDisplay : public CommandNSSetDisplay
class CommandNSSetEmail : public Command
{
- static bool SendConfirmMail(User *u, const BotInfo *bi)
+ static bool SendConfirmMail(User *u, const BotInfo *bi, const Anope::string &new_email)
{
int chars[] = {
' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
@@ -460,7 +456,9 @@ class CommandNSSetEmail : public Command
for (idx = 0; idx < 9; ++idx)
code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * static_cast<uint16_t>(rand()) / 65536.0) + min];
- u->Account()->Extend("ns_set_email_passcode", new ExtensibleItemClass<Anope::string>(code));
+ std::pair<Anope::string, Anope::string> *n = u->Account()->Extend<std::pair<Anope::string, Anope::string> >("ns_set_email");
+ n->first = new_email;
+ n->second = code;
Anope::string subject = Config->GetBlock("mail")->Get<const Anope::string>("emailchange_subject"),
message = Config->GetBlock("mail")->Get<const Anope::string>("emailchange_message");
@@ -473,7 +471,11 @@ class CommandNSSetEmail : public Command
message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
message = message.replace_all_cs("%c", code);
- return Mail::Send(u, u->Account(), bi, subject, message);
+ Anope::string old = u->Account()->email;
+ u->Account()->email = new_email;
+ bool b = Mail::Send(u, u->Account(), bi, subject, message);
+ u->Account()->email = old;
+ return b;
}
public:
@@ -516,12 +518,8 @@ class CommandNSSetEmail : public Command
if (!param.empty() && Config->GetModule("nickserv")->Get<bool>("forceemail", "yes") && !source.IsServicesOper())
{
- source.nc->Extend("ns_set_email", new ExtensibleItemClass<Anope::string>(param));
- Anope::string old = source.nc->email;
- source.nc->email = param;
- if (SendConfirmMail(source.GetUser(), source.service))
+ if (SendConfirmMail(source.GetUser(), source.service, param))
source.Reply(_("A confirmation e-mail has been sent to \002%s\002. Follow the instructions in it to change your e-mail address."), param.c_str());
- source.nc->email = old;
}
else
{
@@ -579,212 +577,6 @@ class CommandNSSASetEmail : public CommandNSSetEmail
}
};
-class CommandNSSetGreet : public Command
-{
- public:
- CommandNSSetGreet(Module *creator, const Anope::string &sname = "nickserv/set/greet", size_t min = 0) : Command(creator, sname, min, min + 1)
- {
- this->SetDesc(_("Associate a greet message with your nickname"));
- this->SetSyntax(_("\037message\037"));
- }
-
- void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
- {
- const NickAlias *na = NickAlias::Find(user);
- if (!na)
- {
- source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
- return;
- }
- NickCore *nc = na->nc;
-
- EventReturn MOD_RESULT;
- FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
- if (MOD_RESULT == EVENT_STOP)
- return;
-
- if (!param.empty())
- {
- Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the greet of " << nc->display;
- nc->greet = param;
- source.Reply(_("Greet message for \002%s\002 changed to \002%s\002."), nc->display.c_str(), nc->greet.c_str());
- }
- else
- {
- Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to unset the greet of " << nc->display;
- nc->greet.clear();
- source.Reply(_("Greet message for \002%s\002 unset."), nc->display.c_str());
- }
-
- return;
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- this->Run(source, source.nc->display, params.size() > 0 ? params[0] : "");
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Makes the given message the greet of your nickname, that\n"
- "will be displayed when joining a channel that has GREET\n"
- "option enabled, provided that you have the necessary\n"
- "access on it."));
- return true;
- }
-};
-
-class CommandNSSASetGreet : public CommandNSSetGreet
-{
- public:
- CommandNSSASetGreet(Module *creator) : CommandNSSetGreet(creator, "nickserv/saset/greet", 1)
- {
- this->ClearSyntax();
- this->SetSyntax(_("\037nickname\037 \037message\037"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- this->Run(source, params[0], params.size() > 1 ? params[1] : "");
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Makes the given message the greet of the nickname, that\n"
- "will be displayed when joining a channel that has GREET\n"
- "option enabled, provided that the user has the necessary\n"
- "access on it."));
- return true;
- }
-};
-
-class CommandNSSetHide : public Command
-{
- public:
- CommandNSSetHide(Module *creator, const Anope::string &sname = "nickserv/set/hide", size_t min = 2) : Command(creator, sname, min, min + 1)
- {
- this->SetDesc(_("Hide certain pieces of nickname information"));
- this->SetSyntax(_("{EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}"));
- }
-
- void Run(CommandSource &source, const Anope::string &user, const Anope::string &param, const Anope::string &arg)
- {
- const NickAlias *na = NickAlias::Find(user);
- if (!na)
- {
- source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
- return;
- }
- NickCore *nc = na->nc;
-
- EventReturn MOD_RESULT;
- FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
- if (MOD_RESULT == EVENT_STOP)
- return;
-
- Anope::string onmsg, offmsg, flag;
-
- if (param.equals_ci("EMAIL"))
- {
- flag = "HIDE_EMAIL";
- onmsg = _("The E-mail address of \002%s\002 will now be hidden from %s INFO displays.");
- offmsg = _("The E-mail address of \002%s\002 will now be shown in %s INFO displays.");
- }
- else if (param.equals_ci("USERMASK"))
- {
- flag = "HIDE_MASK";
- onmsg = _("The last seen user@host mask of \002%s\002 will now be hidden from %s INFO displays.");
- offmsg = _("The last seen user@host mask of \002%s\002 will now be shown in %s INFO displays.");
- }
- else if (param.equals_ci("STATUS"))
- {
- flag = "HIDE_STATUS";
- onmsg = _("The services access status of \002%s\002 will now be hidden from %s INFO displays.");
- offmsg = _("The services access status of \002%s\002 will now be shown in %s INFO displays.");
- }
- else if (param.equals_ci("QUIT"))
- {
- flag = "HIDE_QUIT";
- onmsg = _("The last quit message of \002%s\002 will now be hidden from %s INFO displays.");
- offmsg = _("The last quit message of \002%s\002 will now be shown in %s INFO displays.");
- }
- else
- {
- this->OnSyntaxError(source, "HIDE");
- return;
- }
-
- if (arg.equals_ci("ON"))
- {
- Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display;
- nc->ExtendMetadata(flag);
- source.Reply(onmsg.c_str(), nc->display.c_str(), source.service->nick.c_str());
- }
- else if (arg.equals_ci("OFF"))
- {
- Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change hide " << param << " to " << arg << " for " << nc->display;
- nc->Shrink(flag);
- source.Reply(offmsg.c_str(), nc->display.c_str(), source.service->nick.c_str());
- }
- else
- this->OnSyntaxError(source, "HIDE");
-
- return;
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- this->Run(source, source.nc->display, params[0], params[1]);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Allows you to prevent certain pieces of information from\n"
- "being displayed when someone does a %s \002INFO\002 on your\n"
- "nick. You can hide your E-mail address (\002EMAIL\002), last seen\n"
- "user@host mask (\002USERMASK\002), your services access status\n"
- "(\002STATUS\002) and last quit message (\002QUIT\002).\n"
- "The second parameter specifies whether the information should\n"
- "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str());
- return true;
- }
-};
-
-class CommandNSSASetHide : public CommandNSSetHide
-{
- public:
- CommandNSSASetHide(Module *creator) : CommandNSSetHide(creator, "nickserv/saset/hide", 3)
- {
- this->SetSyntax("\037nickname\037 {EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}");
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- this->ClearSyntax();
- this->Run(source, params[0], params[1], params[2]);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Allows you to prevent certain pieces of information from\n"
- "being displayed when someone does a %s \002INFO\002 on the\n"
- "nick. You can hide the E-mail address (\002EMAIL\002), last seen\n"
- "user@host mask (\002USERMASK\002), the services access status\n"
- "(\002STATUS\002) and last quit message (\002QUIT\002).\n"
- "The second parameter specifies whether the information should\n"
- "be displayed (\002OFF\002) or hidden (\002ON\002)."), source.service->nick.c_str());
- return true;
- }
-};
-
class CommandNSSetKill : public Command
{
public:
@@ -817,17 +609,17 @@ class CommandNSSetKill : public Command
if (param.equals_ci("ON"))
{
- nc->ExtendMetadata("KILLPROTECT");
- nc->Shrink("KILL_QUICK");
- nc->Shrink("KILL_IMMED");
+ nc->Extend<bool>("KILLPROTECT");
+ nc->Shrink<bool>("KILL_QUICK");
+ nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill on for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002."), nc->display.c_str());
}
else if (param.equals_ci("QUICK"))
{
- nc->ExtendMetadata("KILLPROTECT");
- nc->ExtendMetadata("KILL_QUICK");
- nc->Shrink("KILL_IMMED");
+ nc->Extend<bool>("KILLPROTECT");
+ nc->Extend<bool>("KILL_QUICK");
+ nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill quick for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with a reduced delay."), nc->display.c_str());
}
@@ -835,9 +627,9 @@ class CommandNSSetKill : public Command
{
if (Config->GetModule(this->owner)->Get<bool>("allowkillimmed"))
{
- nc->ExtendMetadata("KILLPROTECT");
- nc->ExtendMetadata("KILL_IMMED");
- nc->Shrink("KILL_QUICK");
+ nc->Extend<bool>("KILLPROTECT");
+ nc->Shrink<bool>("KILL_QUICK");
+ nc->Extend<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill immed for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with no delay."), nc->display.c_str());
}
@@ -846,9 +638,9 @@ class CommandNSSetKill : public Command
}
else if (param.equals_ci("OFF"))
{
- nc->Shrink("KILLPROTECT");
- nc->Shrink("KILL_QUICK");
- nc->Shrink("KILL_IMMED");
+ nc->Shrink<bool>("KILLPROTECT");
+ nc->Shrink<bool>("KILL_QUICK");
+ nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable kill for " << nc->display;
source.Reply(_("Protection is now \002off\002 for \002%s\002."), nc->display.c_str());
}
@@ -1053,19 +845,17 @@ class CommandNSSetMessage : public Command
if (param.equals_ci("ON"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable " << source.command << " for " << nc->display;
- nc->ExtendMetadata("MSG");
+ nc->Extend<bool>("MSG");
source.Reply(_("Services will now reply to \002%s\002 with \002messages\002."), nc->display.c_str());
}
else if (param.equals_ci("OFF"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable " << source.command << " for " << nc->display;
- nc->Shrink("MSG");
+ nc->Shrink<bool>("MSG");
source.Reply(_("Services will now reply to \002%s\002 with \002notices\002."), nc->display.c_str());
}
else
this->OnSyntaxError(source, "MSG");
-
- return;
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
@@ -1115,95 +905,6 @@ class CommandNSSASetMessage : public CommandNSSetMessage
}
};
-class CommandNSSetPrivate : public Command
-{
- public:
- CommandNSSetPrivate(Module *creator, const Anope::string &sname = "nickserv/set/private", size_t min = 1) : Command(creator, sname, min, min + 1)
- {
- this->SetDesc(_("Prevent the nickname from appearing in the LIST command"));
- this->SetSyntax(_("{ON | OFF}"));
- }
-
- void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
- {
- const NickAlias *na = NickAlias::Find(user);
- if (!na)
- {
- source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
- return;
- }
- NickCore *nc = na->nc;
-
- EventReturn MOD_RESULT;
- FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
- if (MOD_RESULT == EVENT_STOP)
- return;
-
- if (param.equals_ci("ON"))
- {
- Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable private for " << nc->display;
- nc->ExtendMetadata("PRIVATE");
- source.Reply(_("Private option is now \002on\002 for \002%s\002."), nc->display.c_str());
- }
- else if (param.equals_ci("OFF"))
- {
- Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable private for " << nc->display;
- nc->Shrink("PRIVATE");
- source.Reply(_("Private option is now \002off\002 for \002%s\002."), nc->display.c_str());
- }
- else
- this->OnSyntaxError(source, "PRIVATE");
-
- return;
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- this->Run(source, source.nc->display, params[0]);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Turns %s's privacy option on or off for your nick.\n"
- "With \002PRIVATE\002 set, your nickname will not appear in\n"
- "nickname lists generated with %s's \002LIST\002 command.\n"
- "(However, anyone who knows your nickname can still get\n"
- "information on it using the \002INFO\002 command.)"),
- source.service->nick.c_str(), source.service->nick.c_str());
- return true;
- }
-};
-
-class CommandNSSASetPrivate : public CommandNSSetPrivate
-{
- public:
- CommandNSSASetPrivate(Module *creator) : CommandNSSetPrivate(creator, "nickserv/saset/private", 2)
- {
- this->ClearSyntax();
- this->SetSyntax(_("\037nickname\037 {ON | OFF}"));
- }
-
- void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
- {
- this->Run(source, params[0], params[1]);
- }
-
- bool OnHelp(CommandSource &source, const Anope::string &) anope_override
- {
- this->SendSyntax(source);
- source.Reply(" ");
- source.Reply(_("Turns %s's privacy option on or off for the nick.\n"
- "With \002PRIVATE\002 set, the nickname will not appear in\n"
- "nickname lists generated with %s's \002LIST\002 command.\n"
- "(However, anyone who knows the nickname can still get\n"
- "information on it using the \002INFO\002 command.)"),
- source.service->nick.c_str(), source.service->nick.c_str());
- return true;
- }
-};
-
class CommandNSSetSecure : public Command
{
public:
@@ -1231,13 +932,13 @@ class CommandNSSetSecure : public Command
if (param.equals_ci("ON"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable secure for " << nc->display;
- nc->ExtendMetadata("SECURE");
+ nc->Extend<bool>("NS_SECURE");
source.Reply(_("Secure option is now \002on\002 for \002%s\002."), nc->display.c_str());
}
else if (param.equals_ci("OFF"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable secure for " << nc->display;
- nc->Shrink("SECURE");
+ nc->Shrink<bool>("NS_SECURE");
source.Reply(_("Secure option is now \002off\002 for \002%s\002."), nc->display.c_str());
}
else
@@ -1316,13 +1017,13 @@ class CommandNSSASetNoexpire : public Command
if (param.equals_ci("ON"))
{
Log(LOG_ADMIN, source, this) << "to enable noexpire " << na->nc->display;
- na->ExtendMetadata("NO_EXPIRE");
+ na->Extend<bool>("NS_NO_EXPIRE");
source.Reply(_("Nick %s \002will not\002 expire."), na->nick.c_str());
}
else if (param.equals_ci("OFF"))
{
Log(LOG_ADMIN, source, this) << "to disable noexpire " << na->nc->display;
- na->Shrink("NO_EXPIRE");
+ na->Shrink<bool>("NS_NO_EXPIRE");
source.Reply(_("Nick %s \002will\002 expire."), na->nick.c_str());
}
else
@@ -1355,12 +1056,6 @@ class NSSet : public Module
CommandNSSetEmail commandnssetemail;
CommandNSSASetEmail commandnssasetemail;
-
- CommandNSSetGreet commandnssetgreet;
- CommandNSSASetGreet commandnssasetgreet;
-
- CommandNSSetHide commandnssethide;
- CommandNSSASetHide commandnssasethide;
CommandNSSetKill commandnssetkill;
CommandNSSASetKill commandnssasetkill;
@@ -1374,14 +1069,17 @@ class NSSet : public Module
CommandNSSetPassword commandnssetpassword;
CommandNSSASetPassword commandnssasetpassword;
- CommandNSSetPrivate commandnssetprivate;
- CommandNSSASetPrivate commandnssasetprivate;
-
CommandNSSetSecure commandnssetsecure;
CommandNSSASetSecure commandnssasetsecure;
CommandNSSASetNoexpire commandnssasetnoexpire;
+ SerializableExtensibleItem<bool> autoop, chanstats, killprotect, kill_quick, kill_immed,
+ message, secure, noexpire;
+
+ /* email, passcode */
+ PrimitiveExtensibleItem<std::pair<Anope::string, Anope::string > > ns_set_email;
+
public:
NSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
commandnsset(this), commandnssaset(this),
@@ -1389,15 +1087,18 @@ class NSSet : public Module
commandnssetchanstats(this), commandnssasetchanstats(this),
commandnssetdisplay(this), commandnssasetdisplay(this),
commandnssetemail(this), commandnssasetemail(this),
- commandnssetgreet(this), commandnssasetgreet(this),
- commandnssethide(this), commandnssasethide(this),
commandnssetkill(this), commandnssasetkill(this),
commandnssetlanguage(this), commandnssasetlanguage(this),
commandnssetmessage(this), commandnssasetmessage(this),
commandnssetpassword(this), commandnssasetpassword(this),
- commandnssetprivate(this), commandnssasetprivate(this),
commandnssetsecure(this), commandnssasetsecure(this),
- commandnssasetnoexpire(this)
+ commandnssasetnoexpire(this),
+
+ autoop(this, "AUTOOP"), chanstats(this, "NS_STATS"), killprotect(this, "KILLPROTECT"),
+ kill_quick(this, "KILL_QUICK"), kill_immed(this, "KILL_IMMED"), message(this, "MSG"),
+ secure(this, "NS_SECURE"), noexpire(this, "NS_NO_EXPIRE"),
+
+ ns_set_email(this, "ns_set_email")
{
}
@@ -1408,16 +1109,15 @@ class NSSet : public Module
if (command->name == "nickserv/confirm" && !params.empty() && uac)
{
- Anope::string *new_email = uac->GetExt<ExtensibleItemClass<Anope::string> *>("ns_set_email"), *passcode = uac->GetExt<ExtensibleItemClass<Anope::string> *>("ns_set_email_passcode");
- if (new_email && passcode)
+ std::pair<Anope::string, Anope::string> *n = ns_set_email.Get(uac);
+ if (n)
{
- if (params[0] == *passcode)
+ if (params[0] == n->second)
{
- uac->email = *new_email;
+ uac->email = n->first;
Log(LOG_COMMAND, source, command) << "to confirm their email address change to " << uac->email;
source.Reply(_("Your email address has been changed to \002%s\002."), uac->email.c_str());
- uac->Shrink("ns_set_email");
- uac->Shrink("ns_set_email_passcode");
+ ns_set_email.Unset(uac);
return EVENT_STOP;
}
}
@@ -1431,9 +1131,34 @@ class NSSet : public Module
if (chan->ci)
{
/* Only give modes if autoop is set */
- give_modes &= !user->Account() || user->Account()->HasExt("AUTOOP");
+ give_modes &= !user->Account() || autoop.HasExt(user->Account());
}
}
+
+ void OnPreNickExpire(NickAlias *na, bool &expire) anope_override
+ {
+ if (noexpire.HasExt(na))
+ expire = false;
+ }
+
+ void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override
+ {
+ if (!show_hidden)
+ return;
+
+ if (killprotect.HasExt(na->nc))
+ info.AddOption(_("Protection"));
+ if (secure.HasExt(na->nc))
+ info.AddOption(_("Security"));
+ if (message.HasExt(na->nc))
+ info.AddOption(_("Message mode"));
+ if (autoop.HasExt(na->nc))
+ info.AddOption(_("Auto-op"));
+ if (chanstats.HasExt(na->nc))
+ info.AddOption(_("Chanstats"));
+ if (noexpire.HasExt(na->nc))
+ info.AddOption(_("No expire"));
+ }
};
MODULE_INIT(NSSet)
diff --git a/modules/commands/ns_set_misc.cpp b/modules/commands/ns_set_misc.cpp
index 15fb0ed33..5dfba99cb 100644
--- a/modules/commands/ns_set_misc.cpp
+++ b/modules/commands/ns_set_misc.cpp
@@ -11,14 +11,24 @@
#include "module.h"
+static Module *me;
+
static std::map<Anope::string, Anope::string> descriptions;
-struct NSMiscData : ExtensibleItem, Serializable
+struct NSMiscData;
+static Anope::map<ExtensibleItem<NSMiscData> *> items;
+static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name);
+
+struct NSMiscData : Serializable
{
Serialize::Reference<NickCore> nc;
Anope::string name;
Anope::string data;
+ NSMiscData(Extensible *obj) : Serializable("NSMiscData"), nc(anope_dynamic_static_cast<NickCore *>(obj))
+ {
+ }
+
NSMiscData(NickCore *ncore, const Anope::string &n, const Anope::string &d) : Serializable("NSMiscData"), nc(ncore), name(n), data(d)
{
}
@@ -52,14 +62,27 @@ struct NSMiscData : ExtensibleItem, Serializable
}
else
{
- d = new NSMiscData(nc, sname, sdata);
- nc->Extend(sname, d);
+ ExtensibleItem<NSMiscData> *item = GetItem(sname);
+ if (item)
+ d = item->Set(nc, NSMiscData(nc, sname, sdata));
}
return d;
}
};
+static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name)
+{
+ ExtensibleItem<NSMiscData>* &it = items[name];
+ if (!it)
+ try
+ {
+ it = new ExtensibleItem<NSMiscData>(me, name);
+ }
+ catch (const ModuleException &) { }
+ return it;
+}
+
static Anope::string GetAttribute(const Anope::string &command)
{
size_t sp = command.rfind(' ');
@@ -93,16 +116,20 @@ class CommandNSSetMisc : public Command
Anope::string scommand = GetAttribute(source.command);
Anope::string key = "ns_set_misc:" + scommand;
- nc->Shrink(key);
+ ExtensibleItem<NSMiscData> *item = GetItem(key);
+ if (item == NULL)
+ return;
+
if (!param.empty())
{
- nc->Extend(key, new NSMiscData(nc, key, param));
+ item->Set(nc, NSMiscData(nc, key, param));
source.Reply(CHAN_SETTING_CHANGED, scommand.c_str(), nc->display.c_str(), param.c_str());
}
else
+ {
+ item->Unset(nc);
source.Reply(CHAN_SETTING_UNSET, scommand.c_str(), nc->display.c_str());
-
- return;
+ }
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
@@ -155,6 +182,7 @@ class NSSetMisc : public Module
NSSetMisc(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
nsmiscdata_type("NSMiscData", NSMiscData::Unserialize), commandnssetmisc(this), commandnssasetmisc(this)
{
+ me = this;
}
void OnReload(Configuration::Conf *conf) anope_override
@@ -182,17 +210,14 @@ class NSSetMisc : public Module
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool ShowHidden) anope_override
{
- std::deque<Anope::string> list;
- na->nc->GetExtList(list);
-
- for (unsigned i = 0; i < list.size(); ++i)
+ Anope::map<ExtensibleItem<NSMiscData> *> items;
+ for (Anope::map<ExtensibleItem<NSMiscData> *>::iterator it = items.begin(); it != items.end(); ++it)
{
- if (list[i].find("ns_set_misc:") != 0)
- continue;
+ ExtensibleItem<NSMiscData> *e = it->second;
+ NSMiscData *data = e->Get(na->nc);
- NSMiscData *data = na->nc->GetExt<NSMiscData *>(list[i]);
- if (data)
- info[list[i].substr(12).replace_all_cs("_", " ")] = data->data;
+ if (data != NULL)
+ info[e->name.substr(12).replace_all_cs("_", " ")] = data->data;
}
}
};
diff --git a/modules/commands/ns_suspend.cpp b/modules/commands/ns_suspend.cpp
index 0db7cd951..76c195a34 100644
--- a/modules/commands/ns_suspend.cpp
+++ b/modules/commands/ns_suspend.cpp
@@ -10,9 +10,48 @@
*/
#include "module.h"
+#include "modules/ns_suspend.h"
static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
+struct NSSuspendInfoImpl : NSSuspendInfo, Serializable
+{
+ NSSuspendInfoImpl(Extensible *) : Serializable("NSSuspendInfo") { }
+
+ void Serialize(Serialize::Data &data) const anope_override
+ {
+ data["nick"] << nick;
+ data["by"] << by;
+ data["reason"] << reason;
+ data["time"] << when;
+ data["expires"] << expires;
+ }
+
+ static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
+ {
+ Anope::string snick;
+ data["nick"] >> snick;
+
+ NSSuspendInfoImpl *si;
+ if (obj)
+ si = anope_dynamic_static_cast<NSSuspendInfoImpl *>(obj);
+ else
+ {
+ NickAlias *na = NickAlias::Find(snick);
+ if (!na)
+ return NULL;
+ si = na->Extend<NSSuspendInfoImpl>("SUSPENDED");
+ data["nick"] >> si->nick;
+ }
+
+ data["bi"] >> si->by;
+ data["reason"] >> si->reason;
+ data["time"] >> si->when;
+ data["expires"] >> si->expires;
+ return si;
+ }
+};
+
class CommandNSSuspend : public Command
{
public:
@@ -60,18 +99,12 @@ class CommandNSSuspend : public Command
NickCore *nc = na->nc;
- nc->ExtendMetadata("SUSPENDED");
- nc->ExtendMetadata("SECURE");
- nc->Shrink("KILLPROTECT");
- nc->Shrink("KILL_QUICK");
- nc->Shrink("KILL_IMMED");
-
- nc->ExtendMetadata("suspend:by", source.GetNick());
- if (!reason.empty())
- nc->ExtendMetadata("suspend:reason", reason);
- if (expiry_secs > 0)
- nc->ExtendMetadata("suspend:expire", stringify(Anope::CurTime + expiry_secs));
- nc->ExtendMetadata("suspend:time", stringify(Anope::CurTime));
+ NSSuspendInfo *si = nc->Extend<NSSuspendInfo>("SUSPENDED");
+ si->nick = nc->display;
+ si->by = source.GetNick();
+ si->reason = reason;
+ si->when = Anope::CurTime;
+ si->expires = expiry_secs ? expiry_secs + Anope::CurTime : 0;
for (unsigned i = 0; i < nc->aliases->size(); ++i)
{
@@ -81,7 +114,7 @@ class CommandNSSuspend : public Command
{
na2->last_quit = reason;
- User *u2 = User::Find(na2->nick);
+ User *u2 = User::Find(na2->nick, true);
if (u2)
{
u2->Logout();
@@ -141,18 +174,12 @@ class CommandNSUnSuspend : public Command
return;
}
- na->nc->Shrink("SUSPENDED");
- na->nc->Shrink("suspend:expire");
- na->nc->Shrink("suspend:by");
- na->nc->Shrink("suspend:reason");
- na->nc->Shrink("suspend:time");
+ na->nc->Shrink<NSSuspendInfo>("SUSPENDED");
Log(LOG_ADMIN, source, this) << "for " << na->nick;
source.Reply(_("Nick %s is now released."), nick.c_str());
FOREACH_MOD(OnNickUnsuspended, (na));
-
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -168,55 +195,61 @@ class NSSuspend : public Module
{
CommandNSSuspend commandnssuspend;
CommandNSUnSuspend commandnsunsuspend;
+ ExtensibleItem<NSSuspendInfoImpl> suspend;
+ Serialize::Type suspend_type;
public:
NSSuspend(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandnssuspend(this), commandnsunsuspend(this)
+ commandnssuspend(this), commandnsunsuspend(this), suspend(this, "SUSPENDED"),
+ suspend_type("NSSuspendInfo", NSSuspendInfoImpl::Unserialize)
{
}
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override
{
- if (na->nc->HasExt("SUSPENDED"))
+ NSSuspendInfo *s = suspend.Get(na->nc);
+ if (s)
{
- Anope::string *by = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:by"), *reason = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:reason"), *t = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:time");
info["Suspended"] = "This nickname is \2suspended\2.";
- if (by)
- info["Suspended by"] = *by;
- if (reason)
- info["Suspend reason"] = *reason;
- if (t)
- info["Suspended on"] = Anope::strftime(convertTo<time_t>(*t), source.GetAccount(), true);
+ if (!s->by.empty())
+ info["Suspended by"] = s->by;
+ if (!s->reason.empty())
+ info["Suspend reason"] = s->reason;
+ if (s->when)
+ info["Suspended on"] = Anope::strftime(s->when, source.GetAccount(), true);
+ if (s->expires)
+ info["Suspended expires"] = Anope::strftime(s->expires, source.GetAccount(), true);
}
}
void OnPreNickExpire(NickAlias *na, bool &expire) anope_override
{
- if (!na->nc->HasExt("SUSPENDED"))
+ NSSuspendInfo *s = suspend.Get(na->nc);
+ if (!s)
return;
expire = false;
- Anope::string *str = na->nc->GetExt<ExtensibleItemClass<Anope::string> *>("suspend:expire");
- if (str == NULL)
+ if (!s->expires)
return;
- try
+ if (s->expires < Anope::CurTime)
{
- time_t when = convertTo<time_t>(*str);
- if (when < Anope::CurTime)
- {
- na->last_seen = Anope::CurTime;
- na->nc->Shrink("SUSPENDED");
- na->nc->Shrink("suspend:expire");
- na->nc->Shrink("suspend:by");
- na->nc->Shrink("suspend:reason");
- na->nc->Shrink("suspend:time");
-
- Log(LOG_NORMAL, "expire", Config->GetClient("NickServ")) << "Expiring suspend for " << na->nick;
- }
+ na->last_seen = Anope::CurTime;
+ suspend.Unset(na->nc);
+
+ Log(LOG_NORMAL, "expire", Config->GetClient("NickServ")) << "Expiring suspend for " << na->nick;
}
- catch (const ConvertException &) { }
+ }
+
+ EventReturn OnNickValidate(User *u, NickAlias *na) anope_override
+ {
+ NSSuspendInfo *s = suspend.Get(na->nc);
+ if (!s)
+ return EVENT_CONTINUE;
+
+ u->SendMessage(Config->GetClient("NickServ"), NICK_X_SUSPENDED, u->nick.c_str());
+ return EVENT_STOP;
}
};
diff --git a/modules/commands/os_defcon.cpp b/modules/commands/os_defcon.cpp
index 8bea10d0f..58d18558b 100644
--- a/modules/commands/os_defcon.cpp
+++ b/modules/commands/os_defcon.cpp
@@ -407,13 +407,11 @@ class OSDefcon : public Module
this->ParseModeString();
}
- EventReturn OnChannelModeSet(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string &param) anope_override
+ EventReturn OnChannelModeSet(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string &param) anope_override
{
- ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
-
- if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOff.count(mname))
+ if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOff.count(mode->name))
{
- c->RemoveMode(Config->GetClient("OperServ"), cm, param);
+ c->RemoveMode(Config->GetClient("OperServ"), mode, param);
return EVENT_STOP;
}
@@ -421,18 +419,16 @@ class OSDefcon : public Module
return EVENT_CONTINUE;
}
- EventReturn OnChannelModeUnset(Channel *c, MessageSource &, const Anope::string &mname, const Anope::string &) anope_override
+ EventReturn OnChannelModeUnset(Channel *c, MessageSource &, ChannelMode *mode, const Anope::string &) anope_override
{
- ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
-
- if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && cm && DConfig.DefConModesOn.count(mname))
+ if (DConfig.Check(DEFCON_FORCE_CHAN_MODES) && DConfig.DefConModesOn.count(mode->name))
{
Anope::string param;
- if (DConfig.GetDefConParam(mname, param))
- c->SetMode(Config->GetClient("OperServ"), cm, param);
+ if (DConfig.GetDefConParam(mode->name, param))
+ c->SetMode(Config->GetClient("OperServ"), mode, param);
else
- c->SetMode(Config->GetClient("OperServ"), cm);
+ c->SetMode(Config->GetClient("OperServ"), mode);
return EVENT_STOP;
diff --git a/modules/commands/os_login.cpp b/modules/commands/os_login.cpp
index 9d666188a..6c1edecfb 100644
--- a/modules/commands/os_login.cpp
+++ b/modules/commands/os_login.cpp
@@ -31,7 +31,7 @@ class CommandOSLogin : public Command
source.Reply(_("No oper block for your nick."));
else if (o->password.empty())
source.Reply(_("Your oper block doesn't require logging in."));
- else if (u->HasExt("os_login_password_correct"))
+ else if (u->HasExt("os_login"))
source.Reply(_("You are already identified."));
else if (o->password != password)
{
@@ -41,11 +41,9 @@ class CommandOSLogin : public Command
else
{
Log(LOG_ADMIN, source, this) << "and successfully identified to " << source.service->nick;
- u->Extend("os_login_password_correct");
+ u->Extend<bool>("os_login");
source.Reply(_("Password accepted."));
}
-
- return;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
@@ -80,12 +78,12 @@ class CommandOSLogout : public Command
source.Reply(_("No oper block for your nick."));
else if (o->password.empty())
source.Reply(_("Your oper block doesn't require logging in."));
- else if (!u->HasExt("os_login_password_correct"))
+ else if (!u->HasExt("os_login"))
source.Reply(_("You are not identified."));
else
{
Log(LOG_ADMIN, source, this);
- u->Shrink("os_login_password_correct");
+ u->Shrink<bool>("os_login");
source.Reply(_("You have been logged out."));
}
}
@@ -110,25 +108,20 @@ class OSLogin : public Module
{
CommandOSLogin commandoslogin;
CommandOSLogout commandoslogout;
+ ExtensibleItem<bool> os_login;
public:
OSLogin(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandoslogin(this), commandoslogout(this)
+ commandoslogin(this), commandoslogout(this), os_login(this, "os_login")
{
}
- ~OSLogin()
- {
- for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
- it->second->Shrink("os_login_password_correct");
- }
-
EventReturn IsServicesOper(User *u) anope_override
{
if (!u->Account()->o->password.empty())
{
- if (u->HasExt("os_login_password_correct"))
+ if (os_login.HasExt(u))
return EVENT_ALLOW;
return EVENT_STOP;
}
diff --git a/modules/commands/os_noop.cpp b/modules/commands/os_noop.cpp
index 171b11c94..0b5dc74d9 100644
--- a/modules/commands/os_noop.cpp
+++ b/modules/commands/os_noop.cpp
@@ -35,7 +35,7 @@ class CommandOSNOOP : public Command
{
/* Remove the O:lines */
IRCD->SendSVSNOOP(s, true);
- s->Extend("noop", new ExtensibleItemClass<Anope::string>(source.GetNick()));
+ s->Extend<Anope::string>("noop", source.GetNick());
Log(LOG_ADMIN, source, this) << "SET on " << s->GetName();
source.Reply(_("All operators from \002%s\002 have been removed."), s->GetName().c_str());
@@ -52,7 +52,7 @@ class CommandOSNOOP : public Command
}
else if (cmd.equals_ci("REVOKE"))
{
- s->Shrink("noop");
+ s->Shrink<Anope::string>("noop");
IRCD->SendSVSNOOP(s, false);
Log(LOG_ADMIN, source, this) << "REVOKE on " << s->GetName();
source.Reply(_("All O:lines of \002%s\002 have been reset."), s->GetName().c_str());
@@ -76,25 +76,23 @@ class CommandOSNOOP : public Command
class OSNOOP : public Module
{
CommandOSNOOP commandosnoop;
+ PrimitiveExtensibleItem<Anope::string> noop;
public:
OSNOOP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- commandosnoop(this)
+ commandosnoop(this), noop(this, "noop")
{
}
void OnUserModeSet(User *u, const Anope::string &mname) anope_override
{
- if (mname == "OPER" && u->server->HasExt("noop"))
+ Anope::string *setter;
+ if (mname == "OPER" && (setter = noop.Get(u->server)))
{
- Anope::string *setter = u->server->GetExt<ExtensibleItemClass<Anope::string> *>("noop");
- if (setter)
- {
- Anope::string reason = "NOOP command used by " + *setter;
- BotInfo *OperServ = Config->GetClient("OperServ");
- u->Kill(OperServ ? OperServ->nick : "", reason);
- }
+ Anope::string reason = "NOOP command used by " + *setter;
+ BotInfo *OperServ = Config->GetClient("OperServ");
+ u->Kill(OperServ ? OperServ->nick : "", reason);
}
}
};