diff options
-rw-r--r-- | docs/conf/modules.conf.example | 4 | ||||
-rw-r--r-- | src/modules/m_permchannels.cpp | 74 |
2 files changed, 73 insertions, 5 deletions
diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 71cc9e8c6..54a667f34 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -1357,7 +1357,9 @@ # whenever +P is set, unset, or the topic/modes on a +P channel is changed. # If you want to do this, set the filename below, and uncomment the include. # -#<permchanneldb filename="data/permchannels.conf"> +# If 'listmodes' is true then all list modes (+b, +I, +e, +g...) will be +# saved. Defaults to false. +#<permchanneldb filename="data/permchannels.conf" listmodes="true"> #<include file="data/permchannels.conf"> # # You may also create channels on startup by using the <permchannels> block. diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index 1bcb2ac17..04171585b 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -22,9 +22,15 @@ /* $ModDesc: Provides support for channel mode +P to provide permanent channels */ +struct ListModeData +{ + std::string modes; + std::string params; +}; + // Not in a class due to circular dependancy hell. static std::string permchannelsconf; -static bool WriteDatabase() +static bool WriteDatabase(Module* mod, bool save_listmodes) { FILE *f; @@ -58,6 +64,44 @@ static bool WriteDatabase() if (!chan->IsModeSet('P')) continue; + std::string chanmodes = chan->ChanModes(true); + if (save_listmodes) + { + ListModeData lm; + + // Bans are managed by the core, so we have to process them separately + lm.modes = std::string(chan->bans.size(), 'b'); + for (BanList::const_iterator j = chan->bans.begin(); j != chan->bans.end(); ++j) + { + lm.params += j->data; + lm.params += ' '; + } + + // All other listmodes are managed by modules, so we need to ask them (call their + // OnSyncChannel() handler) to give our ProtoSendMode() a list of modes that are + // set on the channel. The ListModeData struct is passed as an opaque pointer + // that will be passed back to us by the module handling the mode. + FOREACH_MOD(I_OnSyncChannel, OnSyncChannel(chan, mod, &lm)); + + if (!lm.modes.empty()) + { + // Remove the last space + lm.params.erase(lm.params.end()-1); + + // If there is at least a space in chanmodes (that is, a non-listmode has a parameter) + // insert the listmode mode letters before the space. Otherwise just append them. + std::string::size_type p = chanmodes.find(' '); + if (p == std::string::npos) + chanmodes += lm.modes; + else + chanmodes.insert(p, lm.modes); + + // Append the listmode parameters (the masks themselves) + chanmodes += ' '; + chanmodes += lm.params; + } + } + std::string chants = ConvToStr(chan->age); std::string topicts = ConvToStr(chan->topicset); const char* items[] = @@ -73,7 +117,7 @@ static bool WriteDatabase() " topicsetby=", chan->setby.c_str(), " modes=", - chan->ChanModes(true), + chanmodes.c_str(), ">\n" }; @@ -170,6 +214,7 @@ class ModulePermanentChannels : public Module { PermChannel p; bool dirty; + bool save_listmodes; public: ModulePermanentChannels() : p(this), dirty(false) @@ -213,7 +258,9 @@ public: virtual void OnRehash(User *user) { - permchannelsconf = ServerInstance->Config->ConfValue("permchanneldb")->getString("filename"); + ConfigTag* tag = ServerInstance->Config->ConfValue("permchanneldb"); + permchannelsconf = tag->getString("filename"); + save_listmodes = tag->getBool("listmodes"); } void LoadDatabase() @@ -296,7 +343,7 @@ public: void OnBackgroundTimer(time_t) { if (dirty) - WriteDatabase(); + WriteDatabase(this, save_listmodes); dirty = false; } @@ -332,6 +379,25 @@ public: } } + void ProtoSendMode(void* opaque, TargetTypeFlags type, void* target, const std::vector<std::string>& modes, const std::vector<TranslateType>& translate) + { + // We never pass an empty modelist but better be sure + if (modes.empty()) + return; + + ListModeData* lm = static_cast<ListModeData*>(opaque); + + // Append the mode letters without the trailing '+' (for example "IIII", "gg") + lm->modes.append(modes[0].begin()+1, modes[0].end()); + + // Append the parameters + for (std::vector<std::string>::const_iterator i = modes.begin()+1; i != modes.end(); ++i) + { + lm->params += *i; + lm->params += ' '; + } + } + virtual Version GetVersion() { return Version("Provides support for channel mode +P to provide permanent channels",VF_VENDOR); |