+bool ModuleFilter::Tick(time_t)
+{
+ if (!dirty) // No need to write.
+ return true;
+
+ if (filterconf.empty()) // Nothing to write to.
+ {
+ dirty = false;
+ return true;
+ }
+
+ const std::string newfilterconf = filterconf + ".tmp";
+ std::ofstream stream(newfilterconf.c_str());
+ if (!stream.is_open()) // Filesystem probably not writable.
+ {
+ ServerInstance->SNO->WriteToSnoMask('f', "Unable to save filters to \"%s\": %s (%d)",
+ newfilterconf.c_str(), strerror(errno), errno);
+ return true;
+ }
+
+ stream
+ << "# This file was automatically generated by the " << INSPIRCD_VERSION << " filter module on " << InspIRCd::TimeString(ServerInstance->Time()) << "." << std::endl
+ << "# Any changes to this file will be automatically overwritten." << std::endl
+ << "# If you want to convert this to a normal config file you *MUST* remove the generated=\"yes\" keys!" << std::endl
+ << std::endl
+ << "<config format=\"xml\">" << std::endl;
+
+ for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); ++i)
+ {
+ // # <keyword reason="You qwertied!" action="block" flags="pn">
+ const FilterResult& filter = (*i);
+ if (filter.from_config)
+ continue;
+
+ stream << "<keyword generated=\"yes"
+ << "\" pattern=\"" << ServerConfig::Escape(filter.freeform)
+ << "\" reason=\"" << ServerConfig::Escape(filter.reason)
+ << "\" action=\"" << FilterActionToString(filter.action)
+ << "\" flags=\"" << filter.GetFlags();
+ if (filter.duration)
+ stream << "\" duration=\"" << InspIRCd::DurationString(filter.duration);
+ stream << "\">" << std::endl;
+ }
+
+ if (stream.fail()) // Filesystem probably not writable.
+ {
+ ServerInstance->SNO->WriteToSnoMask('f', "Unable to save filters to \"%s\": %s (%d)",
+ newfilterconf.c_str(), strerror(errno), errno);
+ return true;
+ }
+ stream.close();
+
+#ifdef _WIN32
+ remove(filterconf.c_str());
+#endif
+
+ // Use rename to move temporary to new db - this is guaranteed not to fuck up, even in case of a crash.
+ if (rename(newfilterconf.c_str(), filterconf.c_str()) < 0)
+ {
+ ServerInstance->SNO->WriteToSnoMask('f', "Unable to replace old filter config \"%s\" with \"%s\": %s (%d)",
+ filterconf.c_str(), newfilterconf.c_str(), strerror(errno), errno);
+ return true;
+ }
+
+ dirty = false;
+ return true;
+}
+