From b55c842c9d8730e50865fb7dd98bce4aa85af0d7 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 9 Jul 2013 19:49:10 +0200 Subject: m_permchannels Construct the final line that will be saved in a std::string in WriteDatabase() --- src/modules/m_permchannels.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/modules/m_permchannels.cpp') diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index a59518b28..bd65c5822 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -51,13 +51,13 @@ static bool WriteDatabase() fputs("# Permchannels DB\n# This file is autogenerated; any changes will be overwritten!\n\n", f); // Now, let's write. + std::string line; for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { Channel* chan = i->second; if (!chan->IsModeSet('P')) continue; - char line[1024]; const char* items[] = { "\n" }; - int lpos = 0, item = 0, ipos = 0; - while (lpos < 1022 && item < 7) + line.clear(); + int item = 0, ipos = 0; + while (item < 7) { char c = items[item][ipos++]; if (c == 0) @@ -82,12 +83,14 @@ static bool WriteDatabase() } else if (c == '\\' || c == '"') { - line[lpos++] = '\\'; + line += '\\'; } - line[lpos++] = c; + line += c; } - line[--lpos] = 0; - fputs(line, f); + + // Erase last '"' + line.erase(line.end()-1); + fputs(line.c_str(), f); } int write_error = 0; -- cgit v1.3.1-10-gc9f91 From 86f8294c2de86b8d060abbb02f7c51c0ca0d9ead Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 9 Jul 2013 20:01:03 +0200 Subject: m_permchannels Save channel TS, topic set time and set by information When loading, ignore and log channels with a name longer than Limits.MaxChan --- src/modules/m_permchannels.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'src/modules/m_permchannels.cpp') diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index bd65c5822..1bcb2ac17 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -58,12 +58,20 @@ static bool WriteDatabase() if (!chan->IsModeSet('P')) continue; + std::string chants = ConvToStr(chan->age); + std::string topicts = ConvToStr(chan->topicset); const char* items[] = { "\n" @@ -71,7 +79,7 @@ static bool WriteDatabase() line.clear(); int item = 0, ipos = 0; - while (item < 7) + while (item < 13) { char c = items[item][ipos++]; if (c == 0) @@ -222,9 +230,9 @@ public: std::string topic = tag->getString("topic"); std::string modes = tag->getString("modes"); - if (channel.empty()) + if ((channel.empty()) || (channel.length() > ServerInstance->Config->Limits.ChanMax)) { - ServerInstance->Logs->Log("m_permchannels", DEBUG, "Malformed permchannels tag with empty channel name."); + ServerInstance->Logs->Log("m_permchannels", DEFAULT, "Ignoring permchannels tag with empty or too long channel name (\"" + channel + "\")"); continue; } @@ -232,19 +240,16 @@ public: if (!c) { - c = new Channel(channel, ServerInstance->Time()); - if (!topic.empty()) - { - c->SetTopic(NULL, topic, true); - - /* - * Due to the way protocol works in 1.2, we need to hack the topic TS in such a way that this - * topic will always win over others. - * - * This is scheduled for (proper) fixing in a later release, and can be removed at a later date. - */ - c->topicset = 42; - } + time_t TS = tag->getInt("ts"); + c = new Channel(channel, ((TS > 0) ? TS : ServerInstance->Time())); + + c->SetTopic(NULL, topic, true); + c->setby = tag->getString("topicsetby"); + unsigned int topicset = tag->getInt("topicts"); + // SetTopic() sets the topic TS to now, if there was no topicts saved then don't overwrite that with a 0 + if (topicset > 0) + c->topicset = topicset; + ServerInstance->Logs->Log("m_permchannels", DEBUG, "Added %s with topic %s", channel.c_str(), topic.c_str()); if (modes.empty()) -- cgit v1.3.1-10-gc9f91 From 261d5bb566f6383efea99e73c933a2af6f408341 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Tue, 9 Jul 2013 20:21:33 +0200 Subject: m_permchannels Add the ability to save listmodes --- docs/conf/modules.conf.example | 4 ++- src/modules/m_permchannels.cpp | 74 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 5 deletions(-) (limited to 'src/modules/m_permchannels.cpp') 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. # -# +# If 'listmodes' is true then all list modes (+b, +I, +e, +g...) will be +# saved. Defaults to false. +# # # # You may also create channels on startup by using the 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& modes, const std::vector& translate) + { + // We never pass an empty modelist but better be sure + if (modes.empty()) + return; + + ListModeData* lm = static_cast(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::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); -- cgit v1.3.1-10-gc9f91 From 4d41afdc2ecf36017154e7a460457c076c8aaa16 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Wed, 28 Aug 2013 19:27:14 +0200 Subject: m_permchannels Fix empty topic setby --- src/modules/m_permchannels.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/modules/m_permchannels.cpp') diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index 04171585b..0a7dc8ed9 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -292,6 +292,8 @@ public: c->SetTopic(NULL, topic, true); c->setby = tag->getString("topicsetby"); + if (c->setby.empty()) + c->setby = ServerInstance->Config->ServerName; unsigned int topicset = tag->getInt("topicts"); // SetTopic() sets the topic TS to now, if there was no topicts saved then don't overwrite that with a 0 if (topicset > 0) -- cgit v1.3.1-10-gc9f91