From 71f41ca13c61d8f8ba5f2d824e9cb1ae89e8e6ef Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 13 Apr 2023 00:00:02 -0700 Subject: [PATCH 1/4] [5.6] Revive option erc-query-on-unjoined-chan-privmsg * etc/ERC-NEWS: Mention reinstated option `erc-query-on-unjoined-chan-privmsg'. * lisp/erc/erc-backend.el (erc-server-PRIVMSG): Consider new option `erc-receive-query-display-defer' and revived option `erc-query-unjoined-chan-privmsg' when deciding whether to create a new query buffer. And only "open" a buffer for an unknown target when `erc-query-on-unjoined-chan-privmsg' is non-nil. * lisp/erc/erc.el (erc-query): Fix deprecation message. (erc-auto-query, erc-receive-query-display): Swap alias and aliased and add option to `erc-buffers' group. Mention the nonstandard meaning of nil for this option. (erc-receive-query-display-defer): Add compatibility switch to access legacy behavior for `erc-auto-query'. (erc-query-on-unjoined-chan-privmsg): Revise doc string. * test/lisp/erc/erc-scenarios-base-attach.el: New file. * test/lisp/erc/resources/base/channel-buffer-revival/reattach.eld: New file. (Bug#62833) --- etc/ERC-NEWS | 21 +- lisp/erc/erc-backend.el | 19 +- lisp/erc/erc.el | 63 ++++-- test/lisp/erc/erc-scenarios-base-attach.el | 191 ++++++++++++++++++ .../base/channel-buffer-revival/reattach.eld | 56 +++++ 5 files changed, 326 insertions(+), 24 deletions(-) create mode 100644 test/lisp/erc/erc-scenarios-base-attach.el create mode 100644 test/lisp/erc/resources/base/channel-buffer-revival/reattach.eld diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 8f1b89f268b..2ee88a80351 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -45,9 +45,16 @@ security issue led to new ERC buffers being "buried" on creation. On further reflection, this was judged to have been an overcorrection in the case of interactive invocations, hence the new option 'erc-interactive-display', which is set to 'buffer' (i.e., "take me -there") by default. Accompanying this addition are "display"-suffixed -aliases for related options 'erc-join-buffer' and 'erc-auto-query', -which users have reported as being difficult to discover and remember. +there") by default. + +Accompanying this addition are "display"-suffixed aliases for related +options 'erc-join-buffer' and 'erc-auto-query', which users have +reported as being difficult to discover and remember. As for the +latter option specifically (now known as 'erc-receive-query-display'), +assigning it a nil value now tells ERC to use 'erc-join-buffer' in its +place, much like with related buffer-display options, like +'erc-interactive-display'. The old nil behavior can still be gotten +via a new compatibility flag, 'erc-receive-query-display-defer'. ** Setting a module's mode variable via Customize earns a warning. Trying and failing to activate a module via its minor mode's Custom @@ -108,6 +115,14 @@ other than the symbol 'erc-button-buttonize-nicks' appearing in the "FORM" field (third element) of this entry are considered deprecated and will incur a warning. +** The option 'erc-query-on-unjoined-chan-privmsg' has been restored. +(Although it's now called 'erc-ensure-target-buffer-on-privmsg'.) +In ERC 5.5, this option was removed from the default client code and +thus prevented from influencing PRIVMSG handling because its precise +purpose could not be determined with any confidence. After some +consideration, it's now been wired back in with a slightly revised +role contingent on a few assumptions explained in its doc string. + ** Miscellaneous UX changes. Some minor quality-of-life niceties have finally made their way to ERC. For example, the function 'erc-echo-timestamp' is now diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index bdf4e2ddca2..98a1c117cfa 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -102,11 +102,11 @@ (require 'erc-common) (defvar erc--target) -(defvar erc-auto-query) (defvar erc-channel-list) (defvar erc-channel-users) (defvar erc-default-nicks) (defvar erc-default-recipients) +(defvar erc-ensure-target-buffer-on-privmsg) (defvar erc-format-nick-function) (defvar erc-format-query-as-channel-p) (defvar erc-hide-prompt) @@ -123,6 +123,8 @@ erc-nick (defvar erc-nick-change-attempt-count) (defvar erc-prompt-for-channel-key) (defvar erc-prompt-hidden) +(defvar erc-receive-query-display) +(defvar erc-receive-query-display-defer) (defvar erc-reuse-buffers) (defvar erc-verbose-server-ping) (defvar erc-whowas-on-nosuchnick) @@ -1831,11 +1833,16 @@ define-erc-response-handler (unless (or buffer noticep (string-empty-p tgt) (eq ?$ (aref tgt 0)) (erc-is-message-ctcp-and-not-action-p msg)) (if privp - (when erc-auto-query - (let ((erc-join-buffer erc-auto-query)) - (setq buffer (erc--open-target nick)))) - ;; A channel buffer has been killed but is still joined - (setq buffer (erc--open-target tgt)))) + (when-let ((erc-join-buffer + (or (and (not erc-receive-query-display-defer) + erc-receive-query-display) + (and erc-ensure-target-buffer-on-privmsg + (or erc-receive-query-display + erc-join-buffer))))) + (setq buffer (erc--open-target nick))) + ;; A channel buffer has been killed but is still joined. + (when erc-ensure-target-buffer-on-privmsg + (setq buffer (erc--open-target tgt))))) (when buffer (with-current-buffer buffer (when privp (erc--unhide-prompt)) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 284990e2d43..1e15f3d4280 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -3978,8 +3978,8 @@ erc-cmd-QUERY (unless user ;; currently broken, evil hack to display help anyway ;(erc-delete-query)))) - (signal 'wrong-number-of-arguments "")) - (let ((erc-join-buffer erc-query-display)) + (signal 'wrong-number-of-arguments '(erc-cmd-QUERY 0))) + (let ((erc-join-buffer erc-interactive-display)) (erc-with-server-buffer (erc--open-target user)))) @@ -4722,23 +4722,30 @@ erc-query "Open a query buffer on TARGET using SERVER-BUFFER. To change how this query window is displayed, use `let' to bind `erc-join-buffer' before calling this." - (declare (obsolete "bind `erc-cmd-query' and call `erc-cmd-QUERY'" "29.1")) + (declare (obsolete "call `erc-open' in a live server buffer" "29.1")) (unless (buffer-live-p server-buffer) (error "Couldn't switch to server buffer")) (with-current-buffer server-buffer (erc--open-target target))) -(defvaralias 'erc-receive-query-display 'erc-auto-query) -(defcustom erc-auto-query 'window-noselect +(defvaralias 'erc-auto-query 'erc-receive-query-display) +(defcustom erc-receive-query-display 'window-noselect "If non-nil, create a query buffer each time you receive a private message. If the buffer doesn't already exist, it is created. This can be set to a symbol, to control how the new query window should appear. The default behavior is to display the buffer in -a new window, but not to select it. See the documentation for -`erc-join-buffer' for a description of the available choices." +a new window but not to select it. See the documentation for +`erc-buffer-display' for a description of available values. + +Note that the legacy behavior of forgoing buffer creation +entirely when this option is nil requires setting the +compatibility flag `erc-receive-query-display-defer' to nil. Use +`erc-ensure-target-buffer-on-privmsg' to achieve the same effect." + :package-version '(ERC . "5.6") + :group 'erc-buffers :group 'erc-query - :type '(choice (const :tag "Don't create query window" nil) + :type '(choice (const :tag "Defer to value of `erc-buffer-display'" nil) (const :tag "Split window and select" window) (const :tag "Split window, don't select" window-noselect) (const :tag "New frame" frame) @@ -4746,15 +4753,41 @@ erc-auto-query (const :tag "Use current buffer" buffer) (const :tag "Use current buffer" t))) -;; FIXME either retire this or put it to use after determining how -;; it's meant to work. Clearly, the doc string does not describe -;; current behavior. It's currently only used by the obsolete -;; function `erc-auto-query'. -(defcustom erc-query-on-unjoined-chan-privmsg t - "If non-nil create query buffer on receiving any PRIVMSG at all. +(defcustom erc-receive-query-display-defer t + "How to interpret a null `erc-receive-query-display'. +When this option is non-nil, ERC defers to `erc-buffer-display' +upon seeing a nil value for `erc-receive-query-display', much +like it does with other buffer-display options, like +`erc-interactive-display'. Otherwise, when this option is nil, +ERC retains the legacy behavior of not creating a new query +buffer." + :package-version '(ERC . "5.6") + :group 'erc-buffers + :group 'erc-query + :type 'boolean) + +(defvaralias 'erc-query-on-unjoined-chan-privmsg + 'erc-ensure-target-buffer-on-privmsg) +(defcustom erc-ensure-target-buffer-on-privmsg t + "When non-nil, create a target buffer upon receiving a PRIVMSG. This includes PRIVMSGs directed to channels. If you are using an IRC bouncer, such as dircproxy, to keep a log of channels when you are -disconnected, you should set this option to t." +disconnected, you should set this option to t. + +For queries (direct messages), this option's non-nil meaning is +straightforward: if a buffer doesn't exist for the sender, create +one. For channels, the use case is more niche and usually +involves receiving playback (via commands like ZNC's +\"PLAYBUFFER\") for channels to which your bouncer is joined but +from which you've \"detached\". + +Note that this option was absent from ERC 5.5 because knowledge +of its intended role was \"unavailable\" during a major +refactoring involving buffer management. The option has since +been restored in ERC 5.6 but now also affects queries in the +manner implied above, which was lost sometime before ERC 5.4." + :package-version '(ERC . "5.6") ; revived + :group 'erc-buffers :group 'erc-query :type 'boolean) diff --git a/test/lisp/erc/erc-scenarios-base-attach.el b/test/lisp/erc/erc-scenarios-base-attach.el new file mode 100644 index 00000000000..ccf5d1f9582 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-attach.el @@ -0,0 +1,191 @@ +;;; erc-scenarios-base-attach.el --- Reattach scenarios -*- lexical-binding: t -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; See also: `erc-scenarios-base-channel-buffer-revival'. +;; +;; ERC 5.5 silently dropped support for the ancient option +;; `erc-query-on-unjoined-chan-privmsg' because the tangled logic in +;; and around the function `erc-auto-query' made it difficult to +;; divine its purpose. +;; +;; Based on the name, it was thought this option likely involved +;; controlling the creation of query buffers for unsolicited messages +;; from users with whom you don't share a common channel. However, +;; additional spelunking has recently revealed that it was instead +;; meant to service a feature offered by most bouncers that sends +;; PRIVMSGs directed at a channel you're no longer in and that you +;; haven't received a(nother) JOIN message for. IOW, this is meant to +;; support the following sequence of events: +;; +;; 1. /detach #chan +;; 2. kill buffer #chan or reconnect in new Emacs session +;; 3. /playbuffer #chan +;; +;; Note that the above slash commands are bouncer-specific aliases. +;; +;; Interested users can find more info by looking at this change set +;; from the ancient CVS repo: +;; +;; Author: Mario Lang +;; AuthorDate: Mon Nov 26 18:33:19 2001 +0000 +;; +;; * new function erc-BBDB-NICK to handle nickname anotation ... +;; * Applied antifuchs/mhp patches, the latest on erc-help, unmodified +;; * New variable: erc-reuse-buffers default to t. +;; * Modified erc-generate-new-buffer-name to use it. it checks if +;; server and port are the same, then one can assume thats the same +;; channel/query target again. + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +(ert-deftest erc-scenarios-base-attach--ensure-target-buffer--enabled () + :tags '(:expensive-test) + (should erc-ensure-target-buffer-on-privmsg) + + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/channel-buffer-revival") + (dumb-server (erc-d-run "localhost" t 'reattach)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :password "tester@vanilla/foonet:changeme" + :full-name "tester") + (should (string= (buffer-name) (format "127.0.0.1:%d" port))))) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (erc-cmd-MSG "*status playbuffer #chan")) + + (ert-info ("Playback appears in buffer #chan") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 10 "Buffer Playback...") + (funcall expect 10 "Was I a child") + (funcall expect 10 "Thou counterfeit'st most lively") + (funcall expect 10 "Playback Complete"))) + + (with-current-buffer "foonet" + (erc-cmd-MSG "*status attach #chan")) + + (ert-info ("Live output from #chan after more playback") + (with-current-buffer "#chan" + (funcall expect 10 "Buffer Playback...") + (funcall expect 10 "With what it loathes") + (funcall expect 10 "Not by his breath") + (funcall expect 10 "Playback Complete") + (funcall expect 10 "Ay, and the captain") + (erc-scenarios-common-say "bob: hi") + (funcall expect 10 "Pawn me to this"))))) + +(ert-deftest erc-scenarios-base-attach--ensure-target-buffer--disabled () + :tags '(:expensive-test) + (should erc-ensure-target-buffer-on-privmsg) + + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/channel-buffer-revival") + (dumb-server (erc-d-run "localhost" t 'reattach)) + (port (process-contact dumb-server :service)) + (erc-server-flood-penalty 0.1) + (erc-ensure-target-buffer-on-privmsg nil) ; off + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :password "tester@vanilla/foonet:changeme" + :full-name "tester") + (should (string= (buffer-name) (format "127.0.0.1:%d" port))))) + + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet")) + (erc-cmd-MSG "*status playbuffer #chan") + (ert-info ("Playback appears in buffer server buffer") + (erc-d-t-ensure-for -1 (not (get-buffer "#chan"))) + (funcall expect 10 "Buffer Playback...") + (funcall expect 10 "Was I a child") + (funcall expect 10 "Thou counterfeit'st most lively") + (funcall expect 10 "Playback Complete")) + (should-not (get-buffer "#chan")) + (erc-cmd-MSG "*status attach #chan")) + + (ert-info ("Buffer #chan joined") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 10 "Buffer Playback...") + (funcall expect 10 "With what it loathes") + (funcall expect 10 "Not by his breath") + (funcall expect 10 "Playback Complete") + (funcall expect 10 "Ay, and the captain") + (erc-scenarios-common-say "bob: hi") + (funcall expect 10 "Pawn me to this"))))) + + +;; We omit the `enabled' case for queries because it's the default for +;; this option and already covered many times over by other tests in +;; this directory. + +(ert-deftest erc-scenarios-base-attach--ensure-target-buffer--disabled-query () + :tags '(:expensive-test) + (should erc-ensure-target-buffer-on-privmsg) + + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/assoc/queries") + (dumb-server (erc-d-run "localhost" t 'non-erc)) + (port (process-contact dumb-server :service)) + (expect (erc-d-t-make-expecter)) + (erc-ensure-target-buffer-on-privmsg nil) + (erc-server-flood-penalty 0.1)) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :full-name "tester") + (erc-scenarios-common-assert-initial-buf-name nil port) + (erc-d-t-wait-for 5 (eq erc-network 'foonet)) + (funcall expect 15 "debug mode"))) + + (ert-info ("User dummy's greeting appears in server buffer") + (erc-d-t-wait-for -1 (get-buffer "dummy")) + (with-current-buffer "foonet" + (funcall expect 5 "hi") + + (ert-info ("Option being nil doesn't queries we create") + (with-current-buffer (erc-cmd-QUERY "nitwit") + (should (equal (buffer-name) "nitwit")) + (erc-scenarios-common-say "hola") + (funcall expect 5 "ciao"))) + + (erc-scenarios-common-say "howdy") + (funcall expect 5 "no target") + (erc-cmd-MSG "dummy howdy") + (funcall expect 5 "bye") + (erc-cmd-QUIT ""))))) + +;;; erc-scenarios-base-attach.el ends here diff --git a/test/lisp/erc/resources/base/channel-buffer-revival/reattach.eld b/test/lisp/erc/resources/base/channel-buffer-revival/reattach.eld new file mode 100644 index 00000000000..c3791ac3d49 --- /dev/null +++ b/test/lisp/erc/resources/base/channel-buffer-revival/reattach.eld @@ -0,0 +1,56 @@ +;; -*- mode: lisp-data; -*- +((pass 10 "PASS :tester@vanilla/foonet:changeme")) +((nick 10 "NICK tester")) +((user 10 "USER user 0 * :tester") + (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") + (0.00 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version ergo-v2.11.1") + (0.00 ":irc.foonet.org 003 tester :This server was created Thu, 13 Apr 2023 05:55:22 UTC") + (0.00 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.11.1 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv") + (0.00 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# CHATHISTORY=1000 ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX :are supported by this server") + (0.00 ":irc.foonet.org 005 tester KICKLEN=390 MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8ONLY WHOX :are supported by this server") + (0.00 ":irc.foonet.org 005 tester draft/CHATHISTORY=1000 :are supported by this server") + (0.00 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 server(s)") + (0.01 ":irc.foonet.org 252 tester 0 :IRC Operators online") + (0.00 ":irc.foonet.org 254 tester 1 :channels formed") + (0.00 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers") + (0.00 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3") + (0.00 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") + (0.00 ":irc.foonet.org 422 tester :MOTD File is missing")) + +((mode 10 "MODE tester +i") + (0.01 ":irc.foonet.org 221 tester +Zi")) + +((privmsg-play 10 "PRIVMSG *status :playbuffer #chan") + (0.05 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...") + (0.02 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:08:24] alice: Was I a child, to fear I know not what.") + (0.02 ":alice!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:08:29] bob: My lord, I do confess the ring was hers.") + (0.01 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:08:40] alice: My sons would never so dishonour me.") + (0.01 ":alice!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:09:54] bob: By the hand of a soldier, I will undertake it.") + (0.01 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:09:57] alice: Thou counterfeit'st most lively.") + (0.01 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.")) + +((privmsg-attach 10 "PRIVMSG *status :attach #chan") + (0.01 ":tester!~u@78a58pgahbr24.irc JOIN #chan")) + +((mode-chan 10 "MODE #chan") + (0.01 ":irc.foonet.org 353 tester = #chan :@alice bob tester") + (0.00 ":irc.foonet.org 366 tester #chan :End of /NAMES list.") + (0.00 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...") + (0.00 ":alice!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:10:01] bob: With what it loathes for that which is away.") + (0.00 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:10:30] alice: Ties up my tongue, and will not let me speak.") + (0.00 ":alice!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:11:26] bob: They say he is already in the forest of Arden, and a many merry men with him; and there they live like the old Robin Hood of England. They say many young gentlemen flock to him every day, and fleet the time carelessly, as they did in the golden world.") + (0.01 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :[06:11:29] alice: Not by his breath that is more miserable.") + (0.00 ":***!znc@znc.in PRIVMSG #chan :Playback Complete.") + (0.00 ":*status!znc@znc.in PRIVMSG tester :There was 1 channel matching [#chan]") + (0.03 ":*status!znc@znc.in PRIVMSG tester :Attached 1 channel") + (0.00 ":irc.foonet.org 324 tester #chan +Cnt") + (0.00 ":irc.foonet.org 329 tester #chan 1681365340") + (0.03 ":alice!~u@q2weir96jk3r2.irc PRIVMSG #chan :bob: Five or six thousand horse, I said,I will say true,or thereabouts, set down, for I'll speak truth.") + (0.02 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :alice: Riddling confession finds but riddling shrift.") + (0.04 ":alice!~u@q2weir96jk3r2.irc PRIVMSG #chan :bob: Ay, and the captain of his horse, Count Rousillon.")) + +((privmsg-bob 10 "PRIVMSG #chan :bob: hi") + (0.02 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :alice: But thankful even for hate, that is meant love.") + (0.02 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :tester: Come, come, elder brother, you are too young in this.") + (0.02 ":alice!~u@q2weir96jk3r2.irc PRIVMSG #chan :bob: Sir, we have known together in Orleans.") + (0.05 ":bob!~u@q2weir96jk3r2.irc PRIVMSG #chan :alice: Pawn me to this your honour, she is his.")) -- 2.39.2