diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index c6df14ba8..2a687b164 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -413,12 +413,16 @@ # maxlines - The maximum number of lines of chat history to send to a # # joining users. Defaults to 50. # # # +# maxduration - The maximum period to keep chat history for. Defaults # +# to 4 weeks. # +# # # prefixmsg - Whether to send an explanatory message to clients that # # don't support the chathistory batch type. Defaults to # # yes. # # # # diff --git a/src/modules/m_chanhistory.cpp b/src/modules/m_chanhistory.cpp index f7dc37265..26fb5e474 100644 --- a/src/modules/m_chanhistory.cpp +++ b/src/modules/m_chanhistory.cpp @@ -80,8 +80,42 @@ struct HistoryList final class HistoryMode final : public ParamMode> { +private: + bool ParseDuration(User* user, irc::sepstream& stream, unsigned long& duration) + { + std::string durationstr; + if (!stream.GetToken(durationstr)) + return false; + + if (!Duration::TryFrom(durationstr, duration) || duration == 0) + return false; + + if (IS_LOCAL(user) && duration > maxduration) + duration = maxduration; // Clamp for local users. + + return true; + } + + bool ParseLines(User* user, irc::sepstream& stream, unsigned long& lines) + { + std::string linesstr; + if (!stream.GetToken(linesstr)) + return false; + + lines = ConvToNum(linesstr); + if (lines == 0) + return false; + + if (IS_LOCAL(user) && lines > maxlines) + lines = maxlines; // Clamp for local users. + + return true; + } + public: + unsigned long maxduration; unsigned long maxlines; + HistoryMode(Module* Creator) : ParamMode>(Creator, "history", 'H') { @@ -90,44 +124,30 @@ public: bool OnSet(User* source, Channel* channel, std::string& parameter) override { - std::string::size_type colon = parameter.find(':'); - if (colon == std::string::npos) - { - source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); - return false; - } + irc::sepstream stream(parameter, ':'); - std::string duration(parameter, colon+1); - if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!Duration::IsValid(duration)))) + unsigned long lines; + unsigned long duration; + if (!ParseLines(source, stream, lines) || !ParseDuration(source, stream, duration)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return false; } - unsigned long len = ConvToNum(parameter.substr(0, colon)); - unsigned long time; - if (!Duration::TryFrom(duration, time) || len == 0 || (len > maxlines && IS_LOCAL(source))) - { - source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); - return false; - } - if (len > maxlines) - len = maxlines; - HistoryList* history = ext.Get(channel); if (history) { // Shrink the list if the new line number limit is lower than the old one - if (len < history->lines.size()) - history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len)); + if (lines < history->lines.size()) + history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - lines)); - history->maxlen = len; - history->maxtime = time; + history->maxlen = lines; + history->maxtime = duration; history->Prune(); } else { - ext.SetFwd(channel, len, time); + ext.SetFwd(channel, lines, duration); } return true; } @@ -210,6 +230,7 @@ public: void ReadConfig(ConfigStatus& status) override { const auto& tag = ServerInstance->Config->ConfValue("chanhistory"); + historymode.maxduration = tag->getNum("maxduration", 60*60*24*28, 1); historymode.maxlines = tag->getNum("maxlines", 50, 1); prefixmsg = tag->getBool("prefixmsg", true); dobots = tag->getBool("bots", true);