+ if (adding == channel->IsModeSet(this))
+ return MODEACTION_DENY;
+
+ channel->SetMode(this, adding);
+ if (!adding)
+ channel->CheckDestroy();
+
+ return MODEACTION_ALLOW;
+ }
+};
+
+// Not in a class due to circular dependancy hell.
+static std::string permchannelsconf;
+static bool WriteDatabase(PermChannel& permchanmode)
+{
+ /*
+ * We need to perform an atomic write so as not to fuck things up.
+ * So, let's write to a temporary file, flush it, then rename the file..
+ * -- w00t
+ */
+
+ // If the user has not specified a configuration file then we don't write one.
+ if (permchannelsconf.empty())
+ return true;
+
+ std::string permchannelsnewconf = permchannelsconf + ".tmp";
+ std::ofstream stream(permchannelsnewconf.c_str());
+ if (!stream.is_open())
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot create database! %s (%d)", strerror(errno), errno);
+ ServerInstance->SNO->WriteToSnoMask('a', "database: cannot create new db: %s (%d)", strerror(errno), errno);
+ return false;
+ }
+
+ stream << "# This file is automatically generated by m_permchannels. Any changes will be overwritten." << std::endl
+ << "<config format=\"xml\">" << std::endl;
+
+ for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
+ {
+ Channel* chan = i->second;
+ if (!chan->IsModeSet(permchanmode))
+ continue;
+
+ stream << "<permchannels channel=\"" << ServerConfig::Escape(chan->name)
+ << "\" topic=\"" << ServerConfig::Escape(chan->topic)
+ << "\" modes=\"" << ServerConfig::Escape(chan->ChanModes(true))
+ << "\">" << std::endl;
+ }
+
+ if (stream.fail())
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot write to new database! %s (%d)", strerror(errno), errno);
+ ServerInstance->SNO->WriteToSnoMask('a', "database: cannot write to new db: %s (%d)", strerror(errno), errno);
+ return false;
+ }
+ stream.close();
+
+#ifdef _WIN32
+ if (remove(permchannelsconf.c_str()))
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot remove old database! %s (%d)", strerror(errno), errno);
+ ServerInstance->SNO->WriteToSnoMask('a', "database: cannot remove old database: %s (%d)", strerror(errno), errno);
+ return false;
+ }
+#endif
+ // Use rename to move temporary to new db - this is guarenteed not to fuck up, even in case of a crash.
+ if (rename(permchannelsnewconf.c_str(), permchannelsconf.c_str()) < 0)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Cannot move new to old database! %s (%d)", strerror(errno), errno);
+ ServerInstance->SNO->WriteToSnoMask('a', "database: cannot replace old with new db: %s (%d)", strerror(errno), errno);
+ return false;
+ }
+
+ return true;
+}
+
+class ModulePermanentChannels : public Module
+{
+ PermChannel p;
+ bool dirty;
+public:
+
+ ModulePermanentChannels() : p(this), dirty(false)
+ {
+ }
+
+ void init() CXX11_OVERRIDE
+ {
+ ServerInstance->Modules->AddService(p);
+
+ OnRehash(NULL);
+ }
+
+ CullResult cull()
+ {
+ /*
+ * DelMode can't remove the +P mode on empty channels, or it will break
+ * merging modes with remote servers. Remove the empty channels now as
+ * we know this is not the case.
+ */
+ chan_hash::iterator iter = ServerInstance->chanlist->begin();
+ while (iter != ServerInstance->chanlist->end())