Re: bug#68401: 30.0.50; ERC 5.6-git: `erc-cmd-GMSG', `erc-cmd-AMSG', `erc-cmd-GME', `erc-cmd-AME'. 2nd attempt

"J.P." <[email protected]> Tue, 13 Feb 2024 17:42:07 -0800
Newsgroups gmane.emacs.erc.general
Message-ID <[email protected]>
Emanuel Berg <[email protected]> writes:

> Tags: patch
>
>> Anyway here is the patch, note that this is different from
>> the one I just posted, it includes a note in etc/ERC-NEWS
>
> Okay, so it doesn't?
>
> Okay, but I have now verified that the patch includes that
> change, even tho it still has the same number and filename.
>
>> From 737777da67f78a50d50b416b3ebba0e343c907aa Mon Sep 17 00:00:00 2001
> From: Emanuel Berg <[email protected]>
> Date: Tue, 23 Jan 2024 14:21:49 +0100
> Subject: [PATCH 301/301] Make erc-cmd-AMSG session local; add /GMSG, /AME and
>  /GME
>
> * lisp/erc/erc.el (erc-cmd-AMSG): Make it consistent with the doc
> string by only affecting the current connection.
> (erc-cmd-GMSG, erc-cmd-AME, erc-cmd-GME): new IRC slash commands
                                            ^                     ^
From CONTRIBUTE:

  Some commenting rules in the GNU coding standards also apply to
  ChangeLog entries: they must be in English, and be complete sentences
  starting with a capital and ending with a period (except the summary
  line should not end in a period).

>
> Fixed bug in erc-cmd-GME
>
> * lisp/erc/erc.el (erc-cmd-GME): should be #'erc--connected-and-joined-p,
> not (erc--connected-and-joined-p)
> (Bug#68401)

This last item appears to describe an incremental patch revision only
known to this discussion thread on the tracker. These log messages are
instead meant to reflect the entirety of the proposed changeset relative
to what's currently on master. However, something like this might still
be helpful in the body of a discussion post (email).

>
> Test and files added
>
> * test/lisp/erc/erc-scenarios-misc-commands.el
> (erc-scenarios-misc-commands--AMSG-GMSG-AME-GME): New test.
> * test/lisp/erc/resources/commands/amsg-barnet.eld: New file.
> * test/lisp/erc/resources/commands/amsg-foonet.eld: New file.
>
> Added a note on `erc-cmd-AMGS' and its three new friends
>
> * etc/ERC-NEWS: Mentioned here.

FWIW, other Emacs commit messages don't seem to have these interspersed
sub-headers, like "Fixed bug in erc-cmd-GME" and "Test and files added".
And based on

  Each entry in a change log describes either an individual change or
  the smallest batch of changes that belong together, also known as a
  changeset. It is a good idea to start the change log entry with a
  header line: a single line that ... [1]

and

  Separate unrelated change log entries with blank lines. Don’t put
  blank lines between individual changes of an entry. [1]

it's my impression that's only done for "unrelated" entries in the same
patch. As it would seem your changes all affect the same (logical) area
of the code base and provide similar functionality as part of the same
feature set, I'd sooner remove them. Still, I do often see somewhat
arbitrary blanks breaking up groups of items belonging to the same
entry, just without their own header lines. So who really knows?

[1] https://www.gnu.org/prep/standards/html_node/Change-Log-Concepts.html
[2] https://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html

> ---
>  etc/ERC-NEWS                                  | 10 ++-
>  lisp/erc/erc.el                               | 38 +++++++--
>  test/lisp/erc/erc-scenarios-misc-commands.el  | 84 +++++++++++++++++++
>  .../erc/resources/commands/amsg-barnet.eld    | 52 ++++++++++++
>  .../erc/resources/commands/amsg-foonet.eld    | 52 ++++++++++++
>  5 files changed, 228 insertions(+), 8 deletions(-)
>  create mode 100644 test/lisp/erc/resources/commands/amsg-barnet.eld
>  create mode 100644 test/lisp/erc/resources/commands/amsg-foonet.eld
>
> diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
> index 1e88500d169..a4ea1573d64 100644
> --- a/etc/ERC-NEWS
> +++ b/etc/ERC-NEWS
> @@ -14,6 +14,12 @@ GNU Emacs since Emacs version 22.1.
>  
>  * Changes in ERC 5.6
>  
> +** Made `erc-cmd-AMSG' session local so it only affects the
> +current connection, this is now consistent with its docstring.

From CONTRIBUTE:

  Try to start each NEWS entry with a sentence that summarizes the entry
  and takes just one line -- this will allow reading NEWS in Outline
  mode after hiding the body of each entry.

Also, bug fixes aren't really announced unless they threaten to cause
widespread churn or introduce potentially debilitating breakage, so you
can probably just leave that out and only mention the new commands.

> +Also, the new IRC slash commands `erc-cmd-GMSG',
> +`erc-cmd-AME', and `erc-cmd-GME' were added and are available
   ^~~~~~~~~~~~^

For etc/*NEWS, I believe they prefer single 'quotes' for literal text
rather than traditional ones with an opening backtick.

> +
>  ** Module 'keep-place' has a more decorative cousin.
>  Remember your place in ERC buffers a bit more easily with the help of
>  a configurable, visible indicator.  Optionally sync the indicator to
> @@ -1367,7 +1373,7 @@ reconnection attempts that ERC will make per server.
>  in seconds, that ERC will wait between successive reconnect attempts.
>  
>  *** erc-server-send-ping-timeout: Determines when to consider a connection
> -stalled and restart it.  The default is	after 120 seconds.
> +stalled and restart it.  The default is   after 120 seconds.
                                          ~~~

Please collapse the expanded TAB into a single space.

>  
>  *** erc-system-name: Determines the system name to use when logging in.
>  The default is to figure this out by calling `system-name'.
> @@ -2386,5 +2392,5 @@ Local variables:
>  coding: utf-8
>  mode: outline
>  mode: emacs-news
> -paragraph-separate: "[ 	]*$"
> +paragraph-separate: "[  ]*$"
                          ^
I believe the TAB here is intentional, so please undo this hunk.

>  end:
> diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
> index 08dfa4b8f1b..3bd13f4a1a0 100644
> --- a/lisp/erc/erc.el
> +++ b/lisp/erc/erc.el
> @@ -4047,16 +4047,42 @@ erc--split-string-shell-cmd
>  ;;                    Input commands handlers
>  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>  
> -(defun erc-cmd-AMSG (line)
> -  "Send LINE to all channels of the current server that you are on."
> -  (interactive "sSend to all channels you're on: ")
> -  (setq line (erc-trim-string line))
> +(defun erc--connected-and-joined-p ()
> +  (and (erc--current-buffer-joined-p)
> +       erc-server-connected))
> +
> +(defun erc-cmd-GMSG (line)
> +  "Send LINE to all channels on all networks you are on."
> +  (setq line (string-remove-prefix " " line))
>    (erc-with-all-buffers-of-server nil
> -    (lambda ()
> -      (erc-channel-p (erc-default-target)))
> +      #'erc--connected-and-joined-p
> +    (erc-send-message line)))
> +(put 'erc-cmd-GMSG 'do-not-parse-args t)
> +
> +(defun erc-cmd-AMSG (line)
> +  "Send LINE to all channels of the current network.
> +Interactively, prompt for the line of text to send."
> +  (interactive "sSend to all channels on this network: ")
> +  (setq line (string-remove-prefix " " line))
> +  (erc-with-all-buffers-of-server erc-server-process
> +      #'erc--connected-and-joined-p
>      (erc-send-message line)))
>  (put 'erc-cmd-AMSG 'do-not-parse-args t)
>  
> +(defun erc-cmd-GME (line)
> +  "Send LINE as an action to all channels on all networks you are on."
> +  (erc-with-all-buffers-of-server nil
> +      #'erc--connected-and-joined-p
> +    (erc-cmd-ME line)))
> +(put 'erc-cmd-GME 'do-not-parse-args t)
> +
> +(defun erc-cmd-AME (line)
> +  "Send LINE as an action to all channels on the current network."
> +  (erc-with-all-buffers-of-server erc-server-process
> +      #'erc--connected-and-joined-p
> +    (erc-cmd-ME line)))
> +(put 'erc-cmd-AME 'do-not-parse-args t)
> +
>  (defun erc-cmd-SAY (line)
>    "Send LINE to the current query or channel as a message, not a command.
>  
> diff --git a/test/lisp/erc/erc-scenarios-misc-commands.el b/test/lisp/erc/erc-scenarios-misc-commands.el
> index d6ed53b5358..c6bb610b9df 100644
> --- a/test/lisp/erc/erc-scenarios-misc-commands.el
> +++ b/test/lisp/erc/erc-scenarios-misc-commands.el
> @@ -123,4 +123,88 @@ erc-scenarios-misc-commands--VHOST
>          (should (string= (erc-server-user-host (erc-get-server-user "tester"))
>                           "some.host.test.cc"))))))
>  

[...]

Emanuel Berg <[email protected]> writes:

> J.P. wrote:
>
>> What's not great is that the test still passes in spite of
>> this. It seems /GME is the only variant not covered, which
>> I guess is my fault. Perhaps you should improve the test so
>> it fails with the current patch applied and passes once
>> it's fixed.
>
> I'm not familiar with those tests so it is better you do
> that part, I think.

For reference, I have attached the revised test covering /GME. Don't
bother reincorporating it if you don't know how; I can do so when
installing.

>
>> Is this FIXME comment regarding your paperwork accurate?
>
> That had to do with my package on GNU ELPA [1] but that
> package has appeared so I suppose the paperwork issue has
> been solved.

I have confirmed this with the copyright clerk. Thanks.
0001-5.x-Add-tests-for-ERC-slash-commands-AMSG-GMSG-etc.patch (text/x-patch, 14.1 KB)
From e021f3c5e9990776af99bd6938b300bcef101719 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email protected]>
Date: Mon, 15 Jan 2024 22:40:44 -0800
Subject: [PATCH] [5.x] Add tests for ERC slash commands /AMSG, /GMSG, etc.

* test/lisp/erc/erc-scenarios-misc-commands.el
(erc-scenarios-misc-commands--AMSG-GMSG-AME-GME): New test.
* test/lisp/erc/resources/commands/amsg-barnet.eld: New file.
* test/lisp/erc/resources/commands/amsg-foonet.eld: New file.
(Bug#68401)
---
 test/lisp/erc/erc-scenarios-misc-commands.el  | 90 +++++++++++++++++++
 .../erc/resources/commands/amsg-barnet.eld    | 54 +++++++++++
 .../erc/resources/commands/amsg-foonet.eld    | 56 ++++++++++++
 3 files changed, 200 insertions(+)
 create mode 100644 test/lisp/erc/resources/commands/amsg-barnet.eld
 create mode 100644 test/lisp/erc/resources/commands/amsg-foonet.eld

diff --git a/test/lisp/erc/erc-scenarios-misc-commands.el b/test/lisp/erc/erc-scenarios-misc-commands.el
index d6ed53b5358..da6855caf57 100644
--- a/test/lisp/erc/erc-scenarios-misc-commands.el
+++ b/test/lisp/erc/erc-scenarios-misc-commands.el
@@ -123,4 +123,94 @@ erc-scenarios-misc-commands--VHOST
         (should (string= (erc-server-user-host (erc-get-server-user "tester"))
                          "some.host.test.cc"))))))
 
+;; This tests four related slash commands, /AMSG, /GMSG, /AME, /GME,
+;; the latter three introduced by bug#68401.  It mainly asserts
+;; correct routing behavior, especially not sending or inserting
+;; messages in buffers belonging to disconnected sessions.  Left
+;; unaddressed are interactions with the `command-indicator' module
+;; (`erc-noncommands-list') and whatever future `echo-message'
+;; implementation manifests out of bug#49860.
+(ert-deftest erc-scenarios-misc-commands--AMSG-GMSG-AME-GME ()
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "commands")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server-foonet (erc-d-run "localhost" t "srv-foonet" 'amsg-foonet))
+       (dumb-server-barnet (erc-d-run "localhost" t "srv-barnet" 'amsg-barnet))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to foonet and join #foo")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port (process-contact dumb-server-foonet :service)
+               :nick "tester")
+        (funcall expect 10 "debug mode")
+        (erc-cmd-JOIN "#foo")))
+
+    (ert-info ("Connect to barnet and join #bar")
+      (with-current-buffer
+          (erc :server "127.0.0.1"
+               :port (process-contact dumb-server-barnet :service)
+               :nick "tester")
+        (funcall expect 10 "debug mode")
+        (erc-cmd-JOIN "#bar")))
+
+    (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#foo"))
+      (funcall expect 10 "welcome"))
+    (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#bar"))
+      (funcall expect 10 "welcome"))
+
+    (ert-info ("/AMSG only sent to issuing context's server")
+      (with-current-buffer "foonet"
+        (erc-scenarios-common-say "/amsg 1 foonet only"))
+      (with-current-buffer "barnet"
+        (erc-scenarios-common-say "/amsg 2 barnet only"))
+      (with-current-buffer "#foo"
+        (funcall expect 10 "<tester> 1 foonet only")
+        (funcall expect 10 "<alice> bob: Our queen and all"))
+      (with-current-buffer "#bar"
+        (funcall expect 10 "<tester> 2 barnet only")
+        (funcall expect 10 "<joe> mike: And secretly to greet")))
+
+    (ert-info ("/AME only sent to issuing context's server")
+      (with-current-buffer "foonet"
+        (erc-scenarios-common-say "/ame 3 foonet only"))
+      (with-current-buffer "barnet"
+        (erc-scenarios-common-say "/ame 4 barnet only"))
+      (with-current-buffer "#foo"
+        (funcall expect 10 "* tester 3 foonet only")
+        (funcall expect 10 "<alice> bob: You have discharged this"))
+      (with-current-buffer "#bar"
+        (funcall expect 10 "* tester 4 barnet only")
+        (funcall expect 10 "<joe> mike: That same Berowne")))
+
+    (ert-info ("/GMSG and /GME sent to all servers")
+      (with-current-buffer "foonet"
+        (erc-scenarios-common-say "/gmsg 5 all nets")
+        (erc-scenarios-common-say "/gme 6 all nets"))
+      (with-current-buffer "#bar"
+        (funcall expect 10 "<tester> 5 all nets")
+        (funcall expect 10 "* tester 6 all nets")
+        (funcall expect 10 "<joe> mike: Mehercle! if their sons")))
+
+    (ert-info ("/GMSG and /GME only sent to connected servers")
+      (with-current-buffer "barnet"
+        (erc-cmd-QUIT "")
+        (funcall expect 10 "ERC finished"))
+      (with-current-buffer "#foo"
+        (funcall expect 10 "<tester> 5 all nets")
+        (funcall expect 10 "* tester 6 all nets")
+        (funcall expect 10 "<alice> bob: Stand you!"))
+      (with-current-buffer "foonet"
+        (erc-scenarios-common-say "/gmsg 7 all live nets")
+        (erc-scenarios-common-say "/gme 8 all live nets"))
+      ;; Message *not* inserted in disconnected buffer.
+      (with-current-buffer "#bar"
+        (funcall expect -0.1 "<tester> 7 all live nets")
+        (funcall expect -0.1 "* tester 8 all live nets")))
+
+    (with-current-buffer "#foo"
+      (funcall expect 10 "<tester> 7 all live nets")
+      (funcall expect 10 "* tester 8 all live nets")
+      (funcall expect 10 "<bob> alice: Live, and be prosperous;"))))
+
 ;;; erc-scenarios-misc-commands.el ends here
diff --git a/test/lisp/erc/resources/commands/amsg-barnet.eld b/test/lisp/erc/resources/commands/amsg-barnet.eld
new file mode 100644
index 00000000000..53b3e18651a
--- /dev/null
+++ b/test/lisp/erc/resources/commands/amsg-barnet.eld
@@ -0,0 +1,54 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :unknown")
+ (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
+ (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.barnet.org 003 tester :This server was created Tue, 04 May 2021 05:06:19 UTC")
+ (0 ":irc.barnet.org 004 tester irc.barnet.org oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.barnet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this server")
+ (0 ":irc.barnet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=barnet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.barnet.org 005 tester draft/CHATHISTORY=100 :are supported by this server")
+ (0 ":irc.barnet.org 251 tester :There are 0 users and 3 invisible on 1 server(s)")
+ (0 ":irc.barnet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.barnet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.barnet.org 254 tester 1 :channels formed")
+ (0 ":irc.barnet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.barnet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ (0 ":irc.barnet.org 221 tester +i")
+ (0 ":irc.barnet.org NOTICE tester :This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
+
+((join 10 "JOIN #bar")
+ (0 ":[email protected] JOIN #bar")
+ (0 ":irc.barnet.org 353 tester = #bar :@mike joe tester")
+ (0 ":irc.barnet.org 366 tester #bar :End of NAMES list"))
+
+((mode-bar 10 "MODE #bar")
+ (0 ":irc.barnet.org 324 tester #bar +nt")
+ (0 ":irc.barnet.org 329 tester #bar 1620104779")
+ (0.1 ":[email protected] PRIVMSG #bar :tester, welcome!")
+ (0.1 ":[email protected] PRIVMSG #bar :tester, welcome!")
+ (0.1 ":[email protected] PRIVMSG #bar :joe: Whipp'd first, sir, and hang'd after.")
+ (0.1 ":[email protected] PRIVMSG #bar :mike: We have yet many among us can gripe as hard as Cassibelan; I do not say I am one, but I have a hand. Why tribute ? why should we pay tribute ? If C sar can hide the sun from us with a blanket, or put the moon in his pocket, we will pay him tribute for light; else, sir, no more tribute, pray you now."))
+
+((privmsg-2 10 "PRIVMSG #bar :2 barnet only")
+ (0.1 ":[email protected] PRIVMSG #bar :joe: Double and treble admonition, and still forfeit in the same kind ? This would make mercy swear, and play the tyrant.")
+ (0.1 ":[email protected] PRIVMSG #bar :mike: And secretly to greet the empress' friends."))
+
+((privmsg-4 10 "PRIVMSG #bar :\1ACTION 4 barnet only\1")
+ (0.1 ":[email protected] PRIVMSG #bar :joe: You have not been inquired after: I have sat here all day.")
+ (0.1 ":[email protected] PRIVMSG #bar :mike: That same Berowne I'll torture ere I go."))
+
+((privmsg-5 10 "PRIVMSG #bar :5 all nets"))
+
+((privmsg-6 10 "PRIVMSG #bar :\1ACTION 6 all nets\1")
+ (0.1 ":[email protected] PRIVMSG #bar :joe: For mine own part,no offence to the general, nor any man of quality,I hope to be saved.")
+ (0.1 ":[email protected] PRIVMSG #bar :mike: Mehercle! if their sons be ingenuous, they shall want no instruction; if their daughters be capable, I will put it to them. But, vir sapit qui pauca loquitur. A soul feminine saluteth us."))
+
+((quit 5 "QUIT :\2ERC\2")
+ (0 ":[email protected] QUIT :Quit"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/commands/amsg-foonet.eld b/test/lisp/erc/resources/commands/amsg-foonet.eld
new file mode 100644
index 00000000000..eb3d84d646a
--- /dev/null
+++ b/test/lisp/erc/resources/commands/amsg-foonet.eld
@@ -0,0 +1,56 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :unknown")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
+
+((join 10 "JOIN #foo")
+ (0 ":[email protected] JOIN #foo")
+ (0 ":irc.foonet.org 353 tester = #foo :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #foo :End of NAMES list"))
+
+((mode-foo 10 "MODE #foo")
+ (0 ":irc.foonet.org 324 tester #foo +nt")
+ (0 ":irc.foonet.org 329 tester #foo 1620104779")
+ (0.1 ":[email protected] PRIVMSG #foo :tester, welcome!")
+ (0.1 ":[email protected] PRIVMSG #foo :tester, welcome!")
+ (0.1 ":[email protected] PRIVMSG #foo :alice: But, as it seems, did violence on herself.")
+ (0.1 ":[email protected] PRIVMSG #foo :bob: Well, this is the forest of Arden."))
+
+((privmsg-1 10 "PRIVMSG #foo :1 foonet only")
+ (0.1 ":[email protected] PRIVMSG #foo :alice: Signior Iachimo will not from it. Pray, let us follow 'em.")
+ (0.1 ":[email protected] PRIVMSG #foo :bob: Our queen and all her elves come here anon."))
+
+((privmsg-3 10 "PRIVMSG #foo :\1ACTION 3 foonet only\1")
+ (0.1 ":[email protected] PRIVMSG #foo :alice: The ground is bloody; search about the churchyard.")
+ (0.1 ":[email protected] PRIVMSG #foo :bob: You have discharged this honestly: keep it to yourself. Many likelihoods informed me of this before, which hung so tottering in the balance that I could neither believe nor misdoubt. Pray you, leave me: stall this in your bosom; and I thank you for your honest care. I will speak with you further anon."))
+
+((privmsg-5 10 "PRIVMSG #foo :5 all nets"))
+
+((privmsg-6 10 "PRIVMSG #foo :\1ACTION 6 all nets\1")
+ (0.1 ":[email protected] PRIVMSG #foo :alice: Give me that mattock, and the wrenching iron.")
+ (0.1 ":[email protected] PRIVMSG #foo :bob: Stand you! You have land enough of your own; but he added to your having, gave you some ground."))
+
+((privmsg-6 10 "PRIVMSG #foo :7 all live nets")
+ (0.1 ":[email protected] PRIVMSG #foo :alice: Excellent workman! Thou canst not paint a man so bad as is thyself."))
+
+((privmsg-6 10 "PRIVMSG #foo :\1ACTION 8 all live nets\1")
+ (0.1 ":[email protected] PRIVMSG #foo :bob: And will you, being a man of your breeding, be married under a bush, like a beggar ? Get you to church, and have a good priest that can tell you what marriage is: this fellow will but join you together as they join wainscot; then one of you will prove a shrunk panel, and like green timber, warp, warp.")
+ (0.1 ":[email protected] PRIVMSG #foo :alice: Live, and be prosperous; and farewell, good fellow."))
-- 
2.43.0