From 6740222ecbe576ba4f14ca0adad31f562fb5bb81 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Wed, 18 Dec 2019 17:38:14 -0500 Subject: [PATCH] fix #616 --- irc/accounts.go | 26 ++++++++++++++++++++- irc/channel.go | 19 ++++++++++++---- irc/database.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- irc/nickserv.go | 29 ++++++++++++++---------- 4 files changed, 116 insertions(+), 18 deletions(-) diff --git a/irc/accounts.go b/irc/accounts.go index 3b13bcca..530f3dff 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -1331,11 +1331,35 @@ const ( BouncerAllowedByUser ) +// controls whether/when clients without event-playback support see fake +// PRIVMSGs for JOINs +type ReplayJoinsSetting uint + +const ( + ReplayJoinsCommandsOnly = iota // replay in HISTORY or CHATHISTORY output + ReplayJoinsAlways // replay in HISTORY, CHATHISTORY, or autoreplay + ReplayJoinsNever // never replay +) + +func replayJoinsSettingFromString(str string) (result ReplayJoinsSetting, err error) { + switch strings.ToLower(str) { + case "commands-only": + result = ReplayJoinsCommandsOnly + case "always": + result = ReplayJoinsAlways + case "never": + result = ReplayJoinsNever + default: + err = errInvalidParams + } + return +} + type AccountSettings struct { AutoreplayLines *int NickEnforcement NickEnforcementMethod AllowBouncer BouncerAllowedSetting - AutoreplayJoins bool + ReplayJoins ReplayJoinsSetting } // ClientAccount represents a user account. diff --git a/irc/channel.go b/irc/channel.go index 0536e14b..dd03ad86 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -786,15 +786,26 @@ func stripMaskFromNick(nickMask string) (nick string) { } func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, autoreplay bool) { + if len(items) == 0 { + return + } + chname := channel.Name() client := rb.target eventPlayback := rb.session.capabilities.Has(caps.EventPlayback) extendedJoin := rb.session.capabilities.Has(caps.ExtendedJoin) - playJoinsAsPrivmsg := (!autoreplay || client.AccountSettings().AutoreplayJoins) - - if len(items) == 0 { - return + var playJoinsAsPrivmsg bool + if !eventPlayback { + switch client.AccountSettings().ReplayJoins { + case ReplayJoinsCommandsOnly: + playJoinsAsPrivmsg = !autoreplay + case ReplayJoinsAlways: + playJoinsAsPrivmsg = true + case ReplayJoinsNever: + playJoinsAsPrivmsg = false + } } + batchID := rb.StartNestedHistoryBatch(chname) defer rb.EndNestedBatch(batchID) diff --git a/irc/database.go b/irc/database.go index eddfab6c..9cc4c3b9 100644 --- a/irc/database.go +++ b/irc/database.go @@ -22,7 +22,7 @@ const ( // 'version' of the database schema keySchemaVersion = "db.version" // latest schema of the db - latestDbSchema = "7" + latestDbSchema = "8" ) type SchemaChanger func(*Config, *buntdb.Tx) error @@ -500,6 +500,59 @@ func schemaChangeV6ToV7(config *Config, tx *buntdb.Tx) error { return nil } +type accountSettingsLegacyV7 struct { + AutoreplayLines *int + NickEnforcement NickEnforcementMethod + AllowBouncer BouncerAllowedSetting + AutoreplayJoins bool +} + +type accountSettingsLegacyV8 struct { + AutoreplayLines *int + NickEnforcement NickEnforcementMethod + AllowBouncer BouncerAllowedSetting + ReplayJoins ReplayJoinsSetting +} + +// #616: change autoreplay-joins to replay-joins +func schemaChangeV7ToV8(config *Config, tx *buntdb.Tx) error { + prefix := "account.settings " + var accounts, blobs []string + tx.AscendGreaterOrEqual("", prefix, func(key, value string) bool { + var legacy accountSettingsLegacyV7 + var current accountSettingsLegacyV8 + if !strings.HasPrefix(key, prefix) { + return false + } + account := strings.TrimPrefix(key, prefix) + err := json.Unmarshal([]byte(value), &legacy) + if err != nil { + log.Printf("corrupt record for %s: %v\n", account, err) + return true + } + current.AutoreplayLines = legacy.AutoreplayLines + current.NickEnforcement = legacy.NickEnforcement + current.AllowBouncer = legacy.AllowBouncer + if legacy.AutoreplayJoins { + current.ReplayJoins = ReplayJoinsAlways + } else { + current.ReplayJoins = ReplayJoinsCommandsOnly + } + blob, err := json.Marshal(current) + if err != nil { + log.Printf("could not marshal record for %s: %v\n", account, err) + return true + } + accounts = append(accounts, account) + blobs = append(blobs, string(blob)) + return true + }) + for i, account := range accounts { + tx.Set(prefix+account, blobs[i], nil) + } + return nil +} + func init() { allChanges := []SchemaChange{ { @@ -532,6 +585,11 @@ func init() { TargetVersion: "7", Changer: schemaChangeV6ToV7, }, + { + InitialVersion: "7", + TargetVersion: "8", + Changer: schemaChangeV7ToV8, + }, } // build the index diff --git a/irc/nickserv.go b/irc/nickserv.go index fa3880dc..7c11e4a2 100644 --- a/irc/nickserv.go +++ b/irc/nickserv.go @@ -236,10 +236,12 @@ be replayed to you automatically when joining a channel. Your options are any positive number, 0 to disable the feature, and 'default' to use the server default.`, - `$bAUTOREPLAY-JOINS$b -'autoreplay-joins' controls whether autoreplayed channel history will include + `$bREPLAY-JOINS$b +'replay-joins' controls whether replayed channel history will include lines for join and part. This provides more information about the context of -messages, but may be spammy. Your options are 'on' and 'off'.`, +messages, but may be spammy. Your options are 'always', 'never', and the default +of 'commands-only' (the messages will be replayed in /HISTORY output, but not +during autoreplay).`, }, authRequired: true, enabled: servCmdRequiresAccreg, @@ -302,11 +304,14 @@ func displaySetting(settingName string, settings AccountSettings, client *Client } else { nsNotice(rb, fmt.Sprintf(client.t("You will receive %d lines of autoreplayed history"), *settings.AutoreplayLines)) } - case "autoreplay-joins": - if settings.AutoreplayJoins { - nsNotice(rb, client.t("You will see JOINs and PARTs in autoreplayed history lines")) - } else { - nsNotice(rb, client.t("You will not see JOINs and PARTs in autoreplayed history lines")) + case "replay-joins": + switch settings.ReplayJoins { + case ReplayJoinsCommandsOnly: + nsNotice(rb, client.t("You will see JOINs and PARTs in /HISTORY output, but not in autoreplay")) + case ReplayJoinsAlways: + nsNotice(rb, client.t("You will see JOINs and PARTs in /HISTORY output and in autoreplay")) + case ReplayJoinsNever: + nsNotice(rb, client.t("You will not see JOINs and PARTs in /HISTORY output or in autoreplay")) } case "bouncer": if !config.Accounts.Bouncer.Enabled { @@ -395,13 +400,13 @@ func nsSetHandler(server *Server, client *Client, command string, params []strin return } } - case "autoreplay-joins": - var newValue bool - newValue, err = utils.StringToBool(params[1]) + case "replay-joins": + var newValue ReplayJoinsSetting + newValue, err = replayJoinsSettingFromString(params[1]) if err == nil { munger = func(in AccountSettings) (out AccountSettings, err error) { out = in - out.AutoreplayJoins = newValue + out.ReplayJoins = newValue return } }