emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 959fbcf34b 20/25: Favor network identities in erc-join


From: F. Jason Park
Subject: master 959fbcf34b 20/25: Favor network identities in erc-join
Date: Thu, 30 Jun 2022 18:29:54 -0400 (EDT)

branch: master
commit 959fbcf34b5dd04e1b4bf87c0b73afd784a41f7f
Author: F. Jason Park <jp@neverwas.me>
Commit: F. Jason Park <jp@neverwas.me>

    Favor network identities in erc-join
    
    * lisp/erc/erc-join.el (erc-autojoin-server-match): Favor network
    identities, falling back on old definition.
    (erc-autojoin--join): Add new helper containing common code from
    hookees `erc-autojoin-after-ident' and `erc-autojoin-channels'.
    (erc-autojoin-after-ident, erc-autojoin-channels): No longer make a
    point of returning nil because the hooks they're registered on,
    `erc-nickserv-identified-hook' and `erc-after-connect', don't stop on
    success.
    (erc-autojoin--mutate): Add helper for `erc-autojoin-add' and
    `erc-autojoin-remove'.
    (erc-autojoin-add, erc-autojoin-remove): Favor given network
    identities, over networks, when matching keys for
    `erc-autojoin-channels-alist'.
    
    * test/lisp/erc/erc-scenarios-base-reconnect.el: New file.
    * test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el: New file.
    * test/lisp/erc/erc-scenarios-join-netid-newcmd.el: New file.
    * test/lisp/erc/erc-scenarios-join-netid-recon-id.el: New file.
    * test/lisp/erc/erc-scenarios-join-netid-recon.el: New file.
    * test/lisp/erc/resources/erc-scenarios-common.el: New file.
    * test/lisp/erc/resources/join/legacy/foonet.eld: New file.
    * test/lisp/erc/resources/join/network-id/barnet.eld: New file.
    * test/lisp/erc/resources/join/network-id/foonet-again.eld: New file.
    * test/lisp/erc/resources/join/network-id/foonet.eld: New file.
    * test/lisp/erc/resources/join/reconnect/foonet-again.eld: New file.
    * test/lisp/erc/resources/join/reconnect/foonet.eld: New file.
---
 lisp/erc/erc-join.el                               | 121 +++----
 test/lisp/erc/erc-join-tests.el                    | 361 +++++++++++++++++++++
 test/lisp/erc/erc-scenarios-base-reconnect.el      |   2 +-
 .../lisp/erc/erc-scenarios-join-netid-newcmd-id.el |  50 +++
 test/lisp/erc/erc-scenarios-join-netid-newcmd.el   |  37 +++
 test/lisp/erc/erc-scenarios-join-netid-recon-id.el |  46 +++
 test/lisp/erc/erc-scenarios-join-netid-recon.el    |  36 ++
 test/lisp/erc/resources/erc-scenarios-common.el    | 108 ++++++
 test/lisp/erc/resources/join/legacy/foonet.eld     |  38 +++
 test/lisp/erc/resources/join/network-id/barnet.eld |  43 +++
 .../erc/resources/join/network-id/foonet-again.eld |  46 +++
 test/lisp/erc/resources/join/network-id/foonet.eld |  39 +++
 .../erc/resources/join/reconnect/foonet-again.eld  |  45 +++
 test/lisp/erc/resources/join/reconnect/foonet.eld  |  45 +++
 14 files changed, 945 insertions(+), 72 deletions(-)

diff --git a/lisp/erc/erc-join.el b/lisp/erc/erc-join.el
index 425de4dc56..d4edca236d 100644
--- a/lisp/erc/erc-join.el
+++ b/lisp/erc/erc-join.el
@@ -33,8 +33,6 @@
 ;;; Code:
 
 (require 'erc)
-(require 'auth-source)
-(require 'erc-networks)
 
 (defgroup erc-autojoin nil
   "Enable autojoining."
@@ -57,11 +55,16 @@
 Every element in the alist has the form (SERVER . CHANNELS).
 SERVER is a regexp matching the server, and channels is the list
 of channels to join.  SERVER can also be a symbol, in which case
-it is matched against the value of `erc-network' instead of
+it's matched against a non-nil `:id' passed to `erc' or `erc-tls'
+when connecting or the value of the current `erc-network' instead of
 `erc-server-announced-name' or `erc-session-server' (this can be
 useful when connecting to an IRC proxy that relays several
 networks under the same server).
 
+Note that for historical reasons, this option is mutated at runtime,
+which is regrettable but here to stay.  Please double check the value
+before saving it to a `custom-file'.
+
 If the channel(s) require channel keys for joining, the passwords
 are found via auth-source.  For instance, if you use ~/.authinfo
 as your auth-source backend, then put something like the
@@ -123,33 +126,32 @@ This is called from a timer set up by 
`erc-autojoin-channels'."
       (erc-autojoin-channels server nick))))
 
 (defun erc-autojoin-server-match (candidate)
-  "Match the current network or server against CANDIDATE.
-This should be a key from `erc-autojoin-channels-alist'."
-  (or (eq candidate (erc-network))
-      (and (stringp candidate)
-          (string-match-p candidate
-                           (or erc-server-announced-name
-                              erc-session-server)))))
+  "Match the current network ID or server against CANDIDATE.
+CANDIDATE is a key from `erc-autojoin-channels-alist'.  Return the
+matching entity, either a string or a non-nil symbol (in the case of a
+network or a network ID).  Return nil on failure."
+  (if (symbolp candidate)
+      (eq (or (erc-networks--id-given erc-networks--id) (erc-network))
+          candidate)
+    (when (stringp candidate)
+      (string-match-p candidate (or erc-server-announced-name
+                                    erc-session-server)))))
+
+(defun erc-autojoin--join ()
+  ;; This is called in the server buffer
+  (pcase-dolist (`(,name . ,channels) erc-autojoin-channels-alist)
+    (when-let ((match (erc-autojoin-server-match name)))
+      (dolist (chan channels)
+        (let ((buf (erc-get-buffer chan erc-server-process)))
+          (unless (and buf (with-current-buffer buf
+                             (erc--current-buffer-joined-p)))
+            (erc-server-join-channel match chan)))))))
 
 (defun erc-autojoin-after-ident (_network _nick)
   "Autojoin channels in `erc-autojoin-channels-alist'.
 This function is run from `erc-nickserv-identified-hook'."
-  (if erc--autojoin-timer
-      (setq erc--autojoin-timer
-           (cancel-timer erc--autojoin-timer)))
   (when (eq erc-autojoin-timing 'ident)
-    (let ((server (or erc-session-server erc-server-announced-name))
-         (joined (mapcar (lambda (buf)
-                           (with-current-buffer buf (erc-default-target)))
-                         (erc-channel-list erc-server-process))))
-      ;; We may already be in these channels, e.g. because the
-      ;; autojoin timer went off.
-      (dolist (l erc-autojoin-channels-alist)
-       (when (erc-autojoin-server-match (car l))
-         (dolist (chan (cdr l))
-           (unless (erc-member-ignore-case chan joined)
-             (erc-server-join-channel server chan)))))))
-  nil)
+    (erc-autojoin--join)))
 
 (defun erc-autojoin-channels (server nick)
   "Autojoin channels in `erc-autojoin-channels-alist'."
@@ -162,24 +164,7 @@ This function is run from `erc-nickserv-identified-hook'."
                              #'erc-autojoin-channels-delayed
                              server nick (current-buffer))))
     ;; `erc-autojoin-timing' is `connect':
-    (let ((server (or erc-session-server erc-server-announced-name)))
-      (dolist (l erc-autojoin-channels-alist)
-        (when (erc-autojoin-server-match (car l))
-         (dolist (chan (cdr l))
-           (let ((buffer
-                   (car (erc-buffer-filter
-                         (lambda ()
-                           (let ((current (erc-default-target)))
-                             (and (stringp current)
-                                  (erc-autojoin-server-match (car l))
-                                  (string-equal (erc-downcase chan)
-                                                (erc-downcase current)))))))))
-             (when (or (not buffer)
-                       (not (with-current-buffer buffer
-                               (erc--current-buffer-joined-p))))
-               (erc-server-join-channel server chan))))))))
-  ;; Return nil to avoid stomping on any other hook funcs.
-  nil)
+    (erc-autojoin--join)))
 
 (defun erc-autojoin-current-server ()
   "Compute the current server for lookup in `erc-autojoin-channels-alist'.
@@ -190,24 +175,29 @@ Respects `erc-autojoin-domain-only'."
        (match-string 1 server)
       server)))
 
+(defun erc-autojoin--mutate (proc parsed remove)
+  (when-let* ((nick (car (erc-parse-user (erc-response.sender parsed))))
+              ((erc-current-nick-p nick))
+              (chnl (car (erc-response.command-args parsed)))
+              (elem (or (and (erc--valid-local-channel-p chnl)
+                             (regexp-quote erc-server-announced-name))
+                        (erc-networks--id-given erc-networks--id)
+                        (erc-network)
+                        (with-current-buffer (process-buffer proc)
+                          (erc-autojoin-current-server))))
+              (test (if (symbolp elem) #'eq #'equal)))
+    (if remove
+        (let ((cs (delete chnl (assoc-default elem erc-autojoin-channels-alist
+                                              test))))
+          (setf (alist-get elem erc-autojoin-channels-alist nil (null cs) test)
+                cs))
+      (cl-pushnew chnl
+                  (alist-get elem erc-autojoin-channels-alist nil nil test)
+                  :test #'equal))))
+
 (defun erc-autojoin-add (proc parsed)
   "Add the channel being joined to `erc-autojoin-channels-alist'."
-  (let* ((chnl (erc-response.contents parsed))
-        (nick (car (erc-parse-user (erc-response.sender parsed))))
-        (server (with-current-buffer (process-buffer proc)
-                  (erc-autojoin-current-server))))
-    (when (erc-current-nick-p nick)
-      (let ((elem (or (assoc (erc-network) erc-autojoin-channels-alist)
-                     (assoc server erc-autojoin-channels-alist))))
-       (if elem
-           (unless (member chnl (cdr elem))
-             (setcdr elem (cons chnl (cdr elem))))
-         ;; This always keys on server, not network -- user can
-         ;; override by simply adding a network to
-         ;; `erc-autojoin-channels-alist'
-         (setq erc-autojoin-channels-alist
-               (cons (list server chnl)
-                     erc-autojoin-channels-alist))))))
+  (erc-autojoin--mutate proc parsed nil)
   ;; We must return nil to tell ERC to continue running the other
   ;; functions.
   nil)
@@ -216,18 +206,7 @@ Respects `erc-autojoin-domain-only'."
 
 (defun erc-autojoin-remove (proc parsed)
   "Remove the channel being left from `erc-autojoin-channels-alist'."
-  (let* ((chnl (car (erc-response.command-args parsed)))
-        (nick (car (erc-parse-user (erc-response.sender parsed))))
-        (server (with-current-buffer (process-buffer proc)
-                  (erc-autojoin-current-server))))
-    (when (erc-current-nick-p nick)
-      (let ((elem (or (assoc (erc-network) erc-autojoin-channels-alist)
-                     (assoc server erc-autojoin-channels-alist))))
-       (when elem
-         (setcdr elem (delete chnl (cdr elem)))
-         (unless (cdr elem)
-           (setq erc-autojoin-channels-alist
-                 (delete elem erc-autojoin-channels-alist)))))))
+  (erc-autojoin--mutate proc parsed 'remove)
   ;; We must return nil to tell ERC to continue running the other
   ;; functions.
   nil)
diff --git a/test/lisp/erc/erc-join-tests.el b/test/lisp/erc/erc-join-tests.el
new file mode 100644
index 0000000000..8210defbfb
--- /dev/null
+++ b/test/lisp/erc/erc-join-tests.el
@@ -0,0 +1,361 @@
+;;; erc-join-tests.el --- Tests for erc-join.  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2022 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 <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert-x)
+(require 'erc-join)
+(require 'erc-networks)
+
+(ert-deftest erc-autojoin-channels--connect ()
+  (should (eq erc-autojoin-timing 'connect))
+  (should (= erc-autojoin-delay 30))
+  (should-not erc--autojoin-timer)
+
+  (let (calls
+        common
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-server-send)
+               (lambda (line) (push line calls))))
+
+      (setq common
+            (lambda ()
+              (ert-with-test-buffer (:name "foonet")
+                (erc-mode)
+                (setq erc-server-process
+                      (start-process "true" (current-buffer) "true")
+                      erc-network 'FooNet
+                      erc-session-server "irc.gnu.chat"
+                      erc-server-current-nick "tester"
+                      erc-networks--id (erc-networks--id-create nil)
+                      erc-server-announced-name "foo.gnu.chat")
+                (set-process-query-on-exit-flag erc-server-process nil)
+                (erc-autojoin-channels erc-server-announced-name
+                                       "tester")
+                (should-not erc--autojoin-timer))))
+
+      (ert-info ("Join immediately on connect; server")
+        (let ((erc-autojoin-channels-alist '(("\\.gnu\\.chat\\'" "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Join immediately on connect; network")
+        (let ((erc-autojoin-channels-alist '((FooNet "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Do nothing; server")
+        (let ((erc-autojoin-channels-alist '(("bar\\.gnu\\.chat" "#chan"))))
+          (funcall common))
+        (should-not calls))
+
+      (ert-info ("Do nothing; network")
+        (let ((erc-autojoin-channels-alist '((BarNet "#chan"))))
+          (funcall common))
+        (should-not calls)))))
+
+(ert-deftest erc-autojoin-channels--delay ()
+  (should (eq erc-autojoin-timing 'connect))
+  (should (= erc-autojoin-delay 30))
+  (should-not erc--autojoin-timer)
+
+  (let (calls
+        common
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook
+        (erc-autojoin-timing 'ident)
+        (erc-autojoin-delay 0.05))
+
+    (cl-letf (((symbol-function 'erc-server-send)
+               (lambda (line) (push line calls)))
+              ((symbol-function 'erc-autojoin-after-ident)
+               (lambda (&rest _r) (error "I ran but shouldn't have"))))
+
+      (setq common
+            (lambda ()
+              (ert-with-test-buffer (:name "foonet")
+                (erc-mode)
+                (setq erc-server-process
+                      (start-process "true" (current-buffer) "true")
+                      erc-network 'FooNet
+                      erc-session-server "irc.gnu.chat"
+                      erc-server-current-nick "tester"
+                      erc-networks--id (erc-networks--id-create nil)
+                      erc-server-announced-name "foo.gnu.chat")
+                (set-process-query-on-exit-flag erc-server-process nil)
+                (should-not erc--autojoin-timer)
+                (erc-autojoin-channels erc-server-announced-name "tester")
+                (should erc--autojoin-timer)
+                (should-not calls)
+                (sleep-for 0.1))))
+
+      (ert-info ("Deferred on connect; server")
+        (let ((erc-autojoin-channels-alist '(("\\.gnu\\.chat\\'" "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Deferred on connect; network")
+        (let ((erc-autojoin-channels-alist '((FooNet "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Do nothing; server")
+        (let ((erc-autojoin-channels-alist '(("bar\\.gnu\\.chat" "#chan"))))
+          (funcall common))
+        (should-not calls)))))
+
+(ert-deftest erc-autojoin-channels--ident ()
+  (should (eq erc-autojoin-timing 'connect))
+  (should (= erc-autojoin-delay 30))
+  (should-not erc--autojoin-timer)
+
+  (let (calls
+        common
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook
+        (erc-autojoin-timing 'ident))
+
+    (cl-letf (((symbol-function 'erc-server-send)
+               (lambda (line) (push line calls))))
+
+      (setq common
+            (lambda ()
+              (ert-with-test-buffer (:name "foonet")
+                (erc-mode)
+                (setq erc-server-process
+                      (start-process "true" (current-buffer) "true")
+                      erc-network 'FooNet
+                      erc-server-current-nick "tester"
+                      erc-networks--id (erc-networks--id-create nil)
+                      erc-server-announced-name "foo.gnu.chat")
+                (set-process-query-on-exit-flag erc-server-process nil)
+                (erc-autojoin-after-ident 'FooNet "tester")
+                (should-not erc--autojoin-timer))))
+
+      (ert-info ("Join on NickServ hook; server")
+        (let ((erc-autojoin-channels-alist '(("\\.gnu\\.chat\\'" "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan")))
+
+      (ert-info ("Join on NickServ hook; network")
+        (let ((erc-autojoin-channels-alist '((FooNet "#chan"))))
+          (funcall common))
+        (should (equal (pop calls) "JOIN #chan"))))))
+
+(defun erc-join-tests--autojoin-add--common (setup &optional fwd)
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (ert-with-test-buffer (:name "foonet")
+        (erc-mode)
+        (setq erc-server-process
+              (start-process "true" (current-buffer) "true")
+              erc-server-current-nick "tester"
+              erc--isupport-params (make-hash-table)
+              erc-server-announced-name "foo.gnu.chat")
+        (puthash 'CHANTYPES '("&#") erc--isupport-params)
+        (funcall setup)
+        (set-process-query-on-exit-flag erc-server-process nil)
+        (should-not calls)
+
+        (ert-info ("Add #chan")
+          (erc-parse-server-response erc-server-process
+                                     (concat ":tester!~i@c.u JOIN #chan"
+                                             (and fwd " * :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist '((FooNet "#chan")))))
+
+        (ert-info ("More recently joined chans are prepended")
+          (erc-parse-server-response
+           erc-server-process ; with account username
+           (concat ":tester!~i@c.u JOIN #spam" (and fwd " tester :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam" "#chan")))))
+
+        (ert-info ("Duplicates skipped")
+          (erc-parse-server-response erc-server-process
+                                     (concat ":tester!~i@c.u JOIN #chan"
+                                             (and fwd " * :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam" "#chan")))))
+
+        (ert-info ("Server used for local channel")
+          (erc-parse-server-response erc-server-process
+                                     (concat ":tester!~i@c.u JOIN &local"
+                                             (and fwd " * :Tes Ter")))
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("foo\\.gnu\\.chat" "&local")
+                           (FooNet "#spam" "#chan")))))))))
+
+(ert-deftest erc-autojoin-add--network ()
+  (erc-join-tests--autojoin-add--common
+   (lambda () (setq erc-network 'FooNet
+                    erc-networks--id (erc-networks--id-create nil)))))
+
+(ert-deftest erc-autojoin-add--network-extended-syntax ()
+  (erc-join-tests--autojoin-add--common
+   (lambda () (setq erc-network 'FooNet
+                    erc-networks--id (erc-networks--id-create nil)))
+   'forward-compatible))
+
+(ert-deftest erc-autojoin-add--network-id ()
+  (erc-join-tests--autojoin-add--common
+   (lambda () (setq erc-network 'invalid
+                    erc-networks--id (erc-networks--id-create 'FooNet)))))
+
+(ert-deftest erc-autojoin-add--server ()
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (ert-info ("Network unavailable, announced name used")
+        (setq erc-autojoin-channels-alist nil)
+        (ert-with-test-buffer (:name "foonet")
+          (erc-mode)
+          (setq erc-server-process
+                (start-process "true" (current-buffer) "true")
+                erc-server-current-nick "tester"
+                erc-server-announced-name "foo.gnu.chat"
+                erc-networks--id (make-erc-networks--id)) ; assume too early
+          (set-process-query-on-exit-flag erc-server-process nil)
+          (should-not calls)
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~u@q6ddatxcq6txy.irc JOIN #chan")
+          (should calls)
+          (erc-autojoin-add erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("gnu.chat" "#chan")))))))))
+
+(defun erc-join-tests--autojoin-remove--common (setup)
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (setq erc-autojoin-channels-alist ; mutated, so can't quote whole thing
+            (list '(FooNet "#spam" "##chan")
+                  '(BarNet "#bar" "##bar")
+                  '("foo\\.gnu\\.chat" "&local")))
+
+      (ert-with-test-buffer (:name "foonet")
+        (erc-mode)
+        (setq erc-server-process
+              (start-process "true" (current-buffer) "true")
+              erc-server-current-nick "tester"
+              erc--isupport-params (make-hash-table)
+              erc-server-announced-name "foo.gnu.chat")
+        (puthash 'CHANTYPES '("&#") erc--isupport-params)
+        (funcall setup)
+        (set-process-query-on-exit-flag erc-server-process nil)
+        (should-not calls)
+
+        (ert-info ("Remove #chan")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART ##chan")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam")
+                           (BarNet "#bar" "##bar")
+                           ("foo\\.gnu\\.chat" "&local")))))
+
+        (ert-info ("Wrong network, nothing done")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART #bar")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam")
+                           (BarNet "#bar" "##bar")
+                           ("foo\\.gnu\\.chat" "&local")))))
+
+        (ert-info ("Local channel keyed by server found")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART &local")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '((FooNet "#spam") (BarNet "#bar" "##bar")))))))))
+
+(ert-deftest erc-autojoin-remove--network ()
+  (erc-join-tests--autojoin-remove--common
+   (lambda () (setq erc-network 'FooNet
+                    erc-networks--id (erc-networks--id-create nil)))))
+
+(ert-deftest erc-autojoin-remove--network-id ()
+  (erc-join-tests--autojoin-remove--common
+   (lambda () (setq erc-network 'fake-a-roo
+                    erc-networks--id (erc-networks--id-create 'FooNet)))))
+
+(ert-deftest erc-autojoin-remove--server ()
+  (let (calls
+        erc-autojoin-channels-alist
+        erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+    (cl-letf (((symbol-function 'erc-handle-parsed-server-response)
+               (lambda (_p m) (push m calls))))
+
+      (setq erc-autojoin-channels-alist (list '("gnu.chat" "#spam" "##chan")
+                                              '("fsf.chat" "#bar" "##bar")))
+
+      (ert-with-test-buffer (:name "foonet")
+        (erc-mode)
+        (setq erc-server-process
+              (start-process "true" (current-buffer) "true")
+              erc-server-current-nick "tester"
+              erc-server-announced-name "foo.gnu.chat"
+              ;; Assume special case w/o known network
+              erc-networks--id (make-erc-networks--id))
+        (set-process-query-on-exit-flag erc-server-process nil)
+        (should-not calls)
+
+        (ert-info ("Announced name matched, #chan removed")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART ##chan")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("gnu.chat" "#spam")
+                           ("fsf.chat" "#bar" "##bar")))))
+
+        (ert-info ("Wrong announced name, nothing done")
+          (erc-parse-server-response erc-server-process
+                                     ":tester!~i@c.u PART #bar")
+          (should calls)
+          (erc-autojoin-remove erc-server-process (pop calls))
+          (should (equal erc-autojoin-channels-alist
+                         '(("gnu.chat" "#spam")
+                           ("fsf.chat" "#bar" "##bar")))))))))
+
+;;; erc-join-tests.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-reconnect.el 
b/test/lisp/erc/erc-scenarios-base-reconnect.el
index aeb59e1870..30d692058d 100644
--- a/test/lisp/erc/erc-scenarios-base-reconnect.el
+++ b/test/lisp/erc/erc-scenarios-base-reconnect.el
@@ -95,7 +95,7 @@
       (with-current-buffer erc-server-buffer
         (funcall expect 10 "Connection failed!  Re-establishing")))
 
-    (should (equal erc-autojoin-channels-alist '(("foonet.org" "#chan"))))
+    (should (equal erc-autojoin-channels-alist '((FooNet "#chan"))))
 
     (funcall test)
 
diff --git a/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el 
b/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el
new file mode 100644
index 0000000000..e2e437321d
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el
@@ -0,0 +1,50 @@
+;;; erc-scenarios-join-netid-newcmd-id.el --- join netid newcmd scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd-id ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (erc :server "127.0.0.1"
+                        :port (with-current-buffer "oofnet"
+                                (process-contact erc-server-process :service))
+                        :nick "tester"
+                        :password "foonet:changeme"
+                        :full-name "tester"
+                        :id 'oofnet))))
+    (erc-scenarios-common--join-network-id connect 'oofnet nil)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd-ids ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (erc :server "127.0.0.1"
+                        :port (with-current-buffer "oofnet"
+                                (process-contact erc-server-process :service))
+                        :nick "tester"
+                        :password "foonet:changeme"
+                        :full-name "tester"
+                        :id 'oofnet))))
+    (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
+
+;;; erc-scenarios-join-netid-newcmd-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-netid-newcmd.el 
b/test/lisp/erc/erc-scenarios-join-netid-newcmd.el
new file mode 100644
index 0000000000..1a541a46b3
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-newcmd.el
@@ -0,0 +1,37 @@
+;;; erc-scenarios-join-netid-newcmd.el --- join netid newcmd scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--newcmd ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (erc :server "127.0.0.1"
+                        :port (with-current-buffer "foonet"
+                                (process-contact erc-server-process :service))
+                        :nick "tester"
+                        :password "foonet:changeme"
+                        :full-name "tester"))))
+    (erc-scenarios-common--join-network-id connect nil nil)))
+
+;;; erc-scenarios-join-netid-newcmd.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-netid-recon-id.el 
b/test/lisp/erc/erc-scenarios-join-netid-recon-id.el
new file mode 100644
index 0000000000..92bdd643de
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-recon-id.el
@@ -0,0 +1,46 @@
+;;; erc-scenarios-join-netid-recon-id.el --- join-netid-recon scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--recon-id ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (with-current-buffer "oofnet"
+                     (erc-cmd-RECONNECT)
+                     (should (eq (current-buffer)
+                                 (process-buffer erc-server-process)))
+                     (current-buffer)))))
+    (erc-scenarios-common--join-network-id connect 'oofnet nil)))
+
+(ert-deftest erc-scenarios-join-netid--recon-ids ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (with-current-buffer "oofnet"
+                     (erc-cmd-RECONNECT)
+                     (should (eq (current-buffer)
+                                 (process-buffer erc-server-process)))
+                     (current-buffer)))))
+    (erc-scenarios-common--join-network-id connect 'oofnet 'rabnet)))
+
+;;; erc-scenarios-join-netid-recon-id.el ends here
diff --git a/test/lisp/erc/erc-scenarios-join-netid-recon.el 
b/test/lisp/erc/erc-scenarios-join-netid-recon.el
new file mode 100644
index 0000000000..cbdba07e25
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-join-netid-recon.el
@@ -0,0 +1,36 @@
+;;; erc-scenarios-join-netid-recon.el --- join-netid-recon scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see
+;; <https://www.gnu.org/licenses/>.
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-join-netid--recon ()
+  :tags '(:expensive-test)
+  (let ((connect (lambda ()
+                   (with-current-buffer "foonet"
+                     (erc-cmd-RECONNECT)
+                     (should (eq (current-buffer)
+                                 (process-buffer erc-server-process)))
+                     (current-buffer)))))
+    (erc-scenarios-common--join-network-id connect nil nil)))
+
+;;; erc-scenarios-join-netid-recon.el ends here
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el 
b/test/lisp/erc/resources/erc-scenarios-common.el
index 6b380772fe..4c57624c33 100644
--- a/test/lisp/erc/resources/erc-scenarios-common.el
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -402,6 +402,114 @@ buffer-naming collisions involving bouncers in ERC."
 
     (funcall test)))
 
+;; XXX this is okay, but we also need to check that target buffers are
+;; already associated with a new process *before* a JOIN is sent by a
+;; server's playback burst.  This doesn't do that.
+;;
+;; This *does* check that superfluous JOINs sent by the autojoin
+;; module are harmless when they're not acked (superfluous because the
+;; bouncer/server intitates the JOIN).
+
+(defun erc-scenarios-common--join-network-id (foo-reconnector foo-id bar-id)
+  "Ensure channels rejoined by erc-join.el DTRT.
+Originally from scenario clash-of-chans/autojoin as described in
+Bug#48598: 28.0.50; buffer-naming collisions involving bouncers in ERC."
+  (erc-scenarios-common-with-cleanup
+      ((chan-buf-foo (format "#chan@%s" (or foo-id "foonet")))
+       (chan-buf-bar (format "#chan@%s" (or bar-id "barnet")))
+       (erc-scenarios-common-dialog "join/network-id")
+       (erc-d-t-cleanup-sleep-secs 1)
+       (erc-server-flood-penalty 0.5)
+       (dumb-server (erc-d-run "localhost" t 'foonet 'barnet 'foonet-again))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       erc-server-buffer-foo erc-server-process-foo
+       erc-server-buffer-bar erc-server-process-bar)
+
+    (should (memq 'autojoin erc-modules))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer
+          (setq erc-server-buffer-foo (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "foonet:changeme"
+                                           :full-name "tester"
+                                           :id foo-id))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-scenarios-common-assert-initial-buf-name foo-id port)
+        (erc-d-t-wait-for 5 (eq (erc-network) 'foonet))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("Join #chan, find sentinel, quit")
+      (with-current-buffer erc-server-buffer-foo (erc-cmd-JOIN "#chan"))
+      (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
+        (funcall expect 5 "vile thing")
+        (erc-cmd-QUIT "")))
+
+    (erc-d-t-wait-for 2 "Foonet connection deceased"
+      (not (erc-server-process-alive erc-server-buffer-foo)))
+
+    (should (equal erc-autojoin-channels-alist
+                   (if foo-id '((oofnet "#chan")) '((foonet "#chan")))))
+
+    (ert-info ("Connect to barnet")
+      (with-current-buffer
+          (setq erc-server-buffer-bar (erc :server "127.0.0.1"
+                                           :port port
+                                           :nick "tester"
+                                           :password "barnet:changeme"
+                                           :full-name "tester"
+                                           :id bar-id))
+        (setq erc-server-process-bar erc-server-process)
+        (erc-d-t-wait-for 5 (eq erc-network 'barnet))
+        (should (string= (buffer-name) (if bar-id "rabnet" "barnet")))))
+
+    (ert-info ("Server buffers are unique, no stray IP-based names")
+      (should-not (eq erc-server-buffer-foo erc-server-buffer-bar))
+      (should-not (erc-scenarios-common-buflist "127.0.0.1")))
+
+    (ert-info ("Only one #chan buffer exists")
+      (should (equal (list (get-buffer "#chan"))
+                     (erc-scenarios-common-buflist "#chan"))))
+
+    (ert-info ("#chan is not auto-joined")
+      (with-current-buffer "#chan"
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (should-not (process-live-p erc-server-process))
+        (erc-d-t-ensure-for 0.1 "server buffer remains foonet"
+          (eq erc-server-process erc-server-process-foo))))
+
+    (with-current-buffer erc-server-buffer-bar
+      (erc-cmd-JOIN "#chan")
+      (erc-d-t-wait-for 3 (get-buffer chan-buf-foo))
+      (erc-d-t-wait-for 3 (get-buffer chan-buf-bar))
+      (with-current-buffer chan-buf-bar
+        (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-bar))
+        (funcall expect 5 "marry her instantly")))
+
+    (ert-info ("Reconnect to foonet")
+      (with-current-buffer (setq erc-server-buffer-foo
+                                 (funcall foo-reconnector))
+        (should (member (if foo-id '(oofnet "#chan") '(foonet "#chan"))
+                        erc-autojoin-channels-alist))
+        (erc-d-t-wait-for 3 (erc-server-process-alive))
+        (setq erc-server-process-foo erc-server-process)
+        (erc-d-t-wait-for 2 (eq erc-network 'foonet))
+        (should (string= (buffer-name) (if foo-id "oofnet" "foonet")))
+        (funcall expect 5 "foonet")))
+
+    (ert-info ("#chan@foonet is clean, no cross-contamination")
+      (with-current-buffer chan-buf-foo
+        (erc-d-t-wait-for 3 (eq erc-server-process erc-server-process-foo))
+        (funcall expect 3 "<bob>")
+        (erc-d-t-absent-for 0.1 "<joe>")
+        (funcall expect 10 "not given me")))
+
+    (ert-info ("All #chan@barnet output received")
+      (with-current-buffer chan-buf-bar
+        (funcall expect 10 "hath an uncle here")))))
+
 (provide 'erc-scenarios-common)
 
 ;;; erc-scenarios-common.el ends here
diff --git a/test/lisp/erc/resources/join/legacy/foonet.eld 
b/test/lisp/erc/resources/join/legacy/foonet.eld
new file mode 100644
index 0000000000..344ba7c1da
--- /dev/null
+++ b/test/lisp/erc/resources/join/legacy/foonet.eld
@@ -0,0 +1,38 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (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 3.2 "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 6 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode 5 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :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 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: Live, and be 
prosperous; and farewell, good fellow."))
diff --git a/test/lisp/erc/resources/join/network-id/barnet.eld 
b/test/lisp/erc/resources/join/network-id/barnet.eld
new file mode 100644
index 0000000000..e33dd6be29
--- /dev/null
+++ b/test/lisp/erc/resources/join/network-id/barnet.eld
@@ -0,0 +1,43 @@
+;; -*- mode: lisp-data; -*-
+((pass 2 "PASS :barnet:changeme"))
+((nick 2 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (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 Mon, 10 May 2021 
00:58:22 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 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 12 "MODE tester +i"))
+;; No mode answer
+
+((join 2 "JOIN #chan")
+ (0 ":tester!~u@6yximxrnkg65a.irc JOIN #chan")
+ (0 ":irc.barnet.org 353 tester = #chan :@joe mike tester")
+ (0 ":irc.barnet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 1 "MODE #chan")
+ (0 ":irc.barnet.org 324 tester #chan +nt")
+ (0 ":irc.barnet.org 329 tester #chan 1620608304")
+ ;; Wait for foonet's buffer playback
+ (0.1 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: Go take her hence, and 
marry her instantly.")
+ (0.1 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: Of all the four, or the 
three, or the two, or one of the four.")
+ (0.1 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: And gives the crutch the 
cradle's infancy.")
+ (0.1 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: Such is the simplicity 
of man to hearken after the flesh.")
+ (0.05 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: The leaf to read them. 
Let us toward the king.")
+ (0.05 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: Many can brook the 
weather that love not the wind.")
+ (0.05 ":mike!~u@6yximxrnkg65a.irc PRIVMSG #chan :joe: And now, dear maid, be 
you as free to us.")
+ (0.00 ":joe!~u@6yximxrnkg65a.irc PRIVMSG #chan :mike: He hath an uncle here 
in Messina will be very much glad of it."))
+
+((linger 3.5 LINGER))
diff --git a/test/lisp/erc/resources/join/network-id/foonet-again.eld 
b/test/lisp/erc/resources/join/network-id/foonet-again.eld
new file mode 100644
index 0000000000..b230eff27c
--- /dev/null
+++ b/test/lisp/erc/resources/join/network-id/foonet-again.eld
@@ -0,0 +1,46 @@
+;; -*- mode: lisp-data; -*-
+((pass-redux 10 "PASS :foonet:changeme"))
+((nick-redux 1 "NICK tester"))
+
+((user-redux 1 "USER user 0 * :tester")
+ (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 Mon, 10 May 2021 
00:58:22 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 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.2 "MODE tester +i")
+ ;; No mode answer ^
+
+ ;; History
+ (0 ":tester!~u@q6ddatxcq6txy.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of /NAMES list.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Buffer Playback...")
+ (0 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :[02:43:23] alice: And soar with 
them above a common bound.")
+ (0 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :[02:43:27] bob: And be aveng'd 
on cursed Tamora.")
+ (0 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :[02:43:29] alice: He did love 
her, sir, as a gentleman loves a woman.")
+ (0 ":***!znc@znc.in PRIVMSG #chan :Playback Complete."))
+
+;; As a server, we ignore useless join sent by autojoin module
+((~join 10 "JOIN #chan"))
+
+((mode-redux 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620608304")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: Ay, madam, with the 
swiftest wing of speed.")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: Five times in that ere 
once in our five wits.")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: And bid him come to 
take his last farewell.")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: But we are spirits of 
another sort.")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: It was not given me, 
nor I did not buy it."))
+
+((linger 6 LINGER))
diff --git a/test/lisp/erc/resources/join/network-id/foonet.eld 
b/test/lisp/erc/resources/join/network-id/foonet.eld
new file mode 100644
index 0000000000..7d63f5f0c6
--- /dev/null
+++ b/test/lisp/erc/resources/join/network-id/foonet.eld
@@ -0,0 +1,39 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :foonet:changeme"))
+((nick 1 "NICK tester"))
+
+((user 1 "USER user 0 * :tester")
+ (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 Mon, 10 May 2021 
00:58:22 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 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.2 "MODE tester +i"))
+;; No mode answer ^
+
+((join 3 "JOIN #chan")
+ (0 ":tester!~u@q6ddatxcq6txy.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :@alice bob tester")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode 3 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620608304")
+ (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: Pray you, sir, deliver 
me this paper.")
+ (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: Wake when some vile 
thing is near."))
+
+((quit 3 "QUIT :\2ERC\2"))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/join/reconnect/foonet-again.eld 
b/test/lisp/erc/resources/join/reconnect/foonet-again.eld
new file mode 100644
index 0000000000..f1fcc439cc
--- /dev/null
+++ b/test/lisp/erc/resources/join/reconnect/foonet-again.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (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 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is still in debug mode."))
+
+((~join-chan 12 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((~join-spam 12 "JOIN #spam")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #spam")
+ (0 ":irc.foonet.org 353 tester = #spam :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #spam :End of NAMES list"))
+
+((~mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the 
forest of Arden."))
+
+((mode-spam 4 "MODE #spam")
+ (0 ":irc.foonet.org 324 tester #spam +nt")
+ (0 ":irc.foonet.org 329 tester #spam 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #spam :alice: Signior Iachimo will 
not from it. Pray, let us follow 'em.")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #spam :bob: Our queen and all her 
elves come here anon."))
diff --git a/test/lisp/erc/resources/join/reconnect/foonet.eld 
b/test/lisp/erc/resources/join/reconnect/foonet.eld
new file mode 100644
index 0000000000..efb269f5ae
--- /dev/null
+++ b/test/lisp/erc/resources/join/reconnect/foonet.eld
@@ -0,0 +1,45 @@
+;; -*- mode: lisp-data; -*-
+((pass 1 "PASS :changeme"))
+((nick 1 "NICK tester"))
+((user 1 "USER user 0 * :tester")
+ (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 3.2 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode.")
+
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #spam")
+ (0 ":irc.foonet.org 353 tester = #spam :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #spam :End of NAMES list"))
+
+((mode-chan 4 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!"))
+
+((mode-spam 4 "MODE #spam")
+ (0 ":irc.foonet.org 324 tester #spam +nt")
+ (0 ":irc.foonet.org 329 tester #spam 1620104779")
+ (0.1 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #spam :tester, welcome!")
+ (0.1 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #spam :tester, welcome!"))
+
+((drop 0 DROP))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]