diff --git a/conventional.yaml b/conventional.yaml index 257f61a3..4b1e8838 100644 --- a/conventional.yaml +++ b/conventional.yaml @@ -847,3 +847,18 @@ history: # allowing deletion of JSON export of an account's messages. this # may be needed for compliance with data privacy regulations. enable-account-indexing: false + + # options to control storage of TAGMSG + tagmsg-storage: + # by default, should TAGMSG be stored? + default: false + + # if `default` is false, store TAGMSG containing any of these tags: + whitelist: + - "+draft/react" + - "react" + + # if `default` is true, don't store TAGMSG containing any of these tags: + #blacklist: + # - "+draft/typing" + # - "typing" diff --git a/default.yaml b/default.yaml index c0c768a9..34a2e425 100644 --- a/default.yaml +++ b/default.yaml @@ -873,3 +873,18 @@ history: # allowing deletion of JSON export of an account's messages. this # may be needed for compliance with data privacy regulations. enable-account-indexing: false + + # options to control storage of TAGMSG + tagmsg-storage: + # by default, should TAGMSG be stored? + default: false + + # if `default` is false, store TAGMSG containing any of these tags: + whitelist: + - "+draft/react" + - "react" + + # if `default` is true, don't store TAGMSG containing any of these tags: + #blacklist: + # - "+draft/typing" + # - "typing" diff --git a/irc/channel.go b/irc/channel.go index 960b1a04..c138cacb 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -646,7 +646,7 @@ func channelHistoryStatus(config *Config, registered bool, storedStatus HistoryS } func (channel *Channel) AddHistoryItem(item history.Item, account string) (err error) { - if !item.IsStorable() { + if !itemIsStorable(&item, channel.server.Config()) { return } diff --git a/irc/config.go b/irc/config.go index 246a1043..97e2feab 100644 --- a/irc/config.go +++ b/irc/config.go @@ -612,6 +612,11 @@ type Config struct { AllowIndividualDelete bool `yaml:"allow-individual-delete"` EnableAccountIndexing bool `yaml:"enable-account-indexing"` } + TagmsgStorage struct { + Default bool + Whitelist []string + Blacklist []string + } `yaml:"tagmsg-storage"` } Filename string @@ -1283,6 +1288,16 @@ func (config *Config) Diff(oldConfig *Config) (addedCaps, removedCaps *caps.Set) return } +// determine whether we need to resize / create / destroy +// the in-memory history buffers: +func (config *Config) historyChangedFrom(oldConfig *Config) bool { + return config.History.Enabled != oldConfig.History.Enabled || + config.History.ChannelLength != oldConfig.History.ChannelLength || + config.History.ClientLength != oldConfig.History.ClientLength || + config.History.AutoresizeWindow != oldConfig.History.AutoresizeWindow || + config.History.Persistent != oldConfig.History.Persistent +} + func compileGuestRegexp(guestFormat string, casemapping Casemapping) (standard, folded *regexp.Regexp, err error) { if strings.Count(guestFormat, "?") != 0 || strings.Count(guestFormat, "*") != 1 { err = errors.New("guest format must contain 1 '*' and no '?'s") diff --git a/irc/handlers.go b/irc/handlers.go index eaa83e27..513ed716 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -2113,7 +2113,7 @@ func dispatchMessageToTarget(client *Client, tags map[string]string, histType hi AccountName: accountName, Tags: tags, } - if !item.IsStorable() || !allowedPlusR { + if !itemIsStorable(&item, config) || !allowedPlusR { return } targetedItem := item @@ -2136,6 +2136,32 @@ func dispatchMessageToTarget(client *Client, tags map[string]string, histType hi } } +func itemIsStorable(item *history.Item, config *Config) bool { + switch item.Type { + case history.Tagmsg: + if config.History.TagmsgStorage.Default { + for _, blacklistedTag := range config.History.TagmsgStorage.Blacklist { + if _, ok := item.Tags[blacklistedTag]; ok { + return false + } + } + return true + } else { + for _, whitelistedTag := range config.History.TagmsgStorage.Whitelist { + if _, ok := item.Tags[whitelistedTag]; ok { + return true + } + } + return false + } + case history.Privmsg, history.Notice: + // don't store CTCP other than ACTION + return !item.Message.IsRestrictedCTCPMessage() + default: + return true + } +} + // NPC func npcHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool { target := msg.Params[0] diff --git a/irc/history/history.go b/irc/history/history.go index bc5b45ed..9d09c92f 100644 --- a/irc/history/history.go +++ b/irc/history/history.go @@ -29,12 +29,6 @@ const ( initialAutoSize = 32 ) -// a Tagmsg that consists entirely of transient tags is not stored -var transientTags = map[string]bool{ - "+draft/typing": true, - "+typing": true, // future-proofing -} - // Item represents an event (e.g., a PRIVMSG or a JOIN) and its associated data type Item struct { Type ItemType @@ -57,23 +51,6 @@ func (item *Item) HasMsgid(msgid string) bool { return item.Message.Msgid == msgid } -func (item *Item) IsStorable() bool { - switch item.Type { - case Tagmsg: - for name := range item.Tags { - if !transientTags[name] { - return true - } - } - return false // all tags were blacklisted - case Privmsg, Notice: - // don't store CTCP other than ACTION - return !item.Message.IsRestrictedCTCPMessage() - default: - return true - } -} - type Predicate func(item *Item) (matches bool) func Reverse(results []Item) { diff --git a/irc/server.go b/irc/server.go index a4671e23..03ba0fb9 100644 --- a/irc/server.go +++ b/irc/server.go @@ -546,7 +546,7 @@ func (server *Server) applyConfig(config *Config) (err error) { server.channels.loadRegisteredChannels(config) } // resize history buffers as needed - if oldConfig.History != config.History { + if config.historyChangedFrom(oldConfig) { for _, channel := range server.channels.Channels() { channel.resizeHistory(config) }