aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorF. Jason Park2024-01-17 21:42:02 -0800
committerF. Jason Park2024-01-24 20:58:32 -0800
commitaedc8b55bfc4d2864d777ac17f6bcf70e4ee04ce (patch)
tree7291f1d8a0a61cd10155932281a00be7b85e2da7 /test
parentd85f561da03cd4705341a5a73f5c643f778e0f35 (diff)
downloademacs-aedc8b55bfc4d2864d777ac17f6bcf70e4ee04ce.tar.gz
emacs-aedc8b55bfc4d2864d777ac17f6bcf70e4ee04ce.zip
Actually derive channel membership from PREFIX in ERC
* lisp/erc/erc-backend.el (erc--with-isupport-data): Add comment for possibly superior alternate implementation. * lisp/erc/erc-common.el (erc--get-isupport-entry): Use helper to initialize traditional prefix slots in overridden well-known constructor. (erc--parsed-prefix): Reverse order of characters in the `letters' and `statuses' slots, in their defaults and also their definitions. (erc--strpos): New function, a utility for finding a single character in a string. * lisp/erc/erc.el (erc--define-channel-user-status-compat-getter): Modify to query advertised value for associated mode letter at runtime instead of baking it in. (erc-channel-user-voice, erc-channel-user-halfop, erc-channel-user-op, erc-channel-user-admin, erc-channel-user-owner): Supply second argument for fallback mode letter. (erc--cusr-status-p, erc--cusr-change-status): New functions for querying and modifying `erc-channel-user' statuses. (erc-send-input-line): Update speaker time in own nick's `erc-channel-member' entry. (erc-get-channel-membership-prefix): Adapt code to prefer advertised prefix for mode letter. (erc--parsed-prefix): Save "reversed" `letters' and `statuses' so that they're ordered from lowest to highest semantically. (erc--get-prefix-flag, erc--init-cusr-fallback-status, erc--compute-cusr-fallback-status): New functions for retrieving internal prefix values and massaging hard-coded traditional prefixes so they're compatible with existing `erc-channel-member' update code. (erc--partition-prefixed-names): New function, separated for testing and for conversion to a generic in the future when ERC supports extensions that list member rolls in a different format. (erc-channel-receive-names): Refactor to use new status-aware update and init workhorse functions for updating and initializing a `erc-channel-members' entry. (erc--create-current-channel-member): New "status-aware" function comprising the `addp' path of `erc-update-current-channel-member'. (erc--update-current-channel-member): New "status-aware" function comprising the "update" path of `erc-update-current-channel-member', which ran when an existing `erc-channel-members' entry for the queried nick was found. (erc-update-current-channel-member): Split code body into two constituent functions, both for readability and for usability, so callers can more explicitly request the desired operation in a "status-aware" manner. (erc--update-membership-prefix): Remove unused function, originally meant to be new in ERC 5.6. (erc--process-channel-modes): Call `erc--cusr-change-status' instead of `erc--update-membership-prefix'. (erc--shuffle-nuh-nickward): New utility function to ensure code like `erc--partition-prefixed-names' can use `erc--parse-nuh' in a practical and relatively convenient way in the near future. * test/lisp/erc/erc-scenarios-base-chan-modes.el (erc-scenarios-base-chan-modes--speaker-status): New test. * test/lisp/erc/erc-tests.el (erc--parsed-prefix): Reverse expected order of various slot values in `erc--parsed-prefix' objects. (erc--get-prefix-flag, erc--init-cusr-fallback-status, erc--compute-cusr-fallback-status, erc--cusr-status-p, erc--cusr-change-status): New tests. (erc--update-channel-modes, erc-process-input-line): Use newly available utilities imported from common library. * test/lisp/erc/resources/base/modes/speaker-status.eld: New file. (Bug#67220)
Diffstat (limited to 'test')
-rw-r--r--test/lisp/erc/erc-scenarios-base-chan-modes.el58
-rw-r--r--test/lisp/erc/erc-tests.el122
-rw-r--r--test/lisp/erc/resources/base/modes/speaker-status.eld69
3 files changed, 228 insertions, 21 deletions
diff --git a/test/lisp/erc/erc-scenarios-base-chan-modes.el b/test/lisp/erc/erc-scenarios-base-chan-modes.el
index 73fba65acf4..3183cd27370 100644
--- a/test/lisp/erc/erc-scenarios-base-chan-modes.el
+++ b/test/lisp/erc/erc-scenarios-base-chan-modes.el
@@ -81,4 +81,62 @@
81 (should-not erc-channel-user-limit) 81 (should-not erc-channel-user-limit)
82 (funcall expect 10 "<Chad> after")))) 82 (funcall expect 10 "<Chad> after"))))
83 83
84;; This asserts proper recognition of nonstandard prefixes advertised
85;; via the "PREFIX=" ISUPPORT parameter. Note that without the IRCv3
86;; `multi-prefix' extension, we can't easily sync a user's channel
87;; membership status on receipt of a 352/353 by parsing the "flags"
88;; parameter because even though servers remember multiple prefixes,
89;; they only ever return the one with the highest rank. For example,
90;; if on receipt of a 352, we were to "update" someone we believe to
91;; be @+ by changing them to a to @, we'd be guilty of willful
92;; munging. And if they later lose that @, we'd then see them as null
93;; when in fact they're still +. However, we *could* use a single
94;; degenerate prefix to "validate" an existing record to ensure
95;; correctness of our processing logic, but it's unclear how such a
96;; discrepancy ought to be handled beyond asking the user to file a
97;; bug.
98(ert-deftest erc-scenarios-base-chan-modes--speaker-status ()
99 :tags '(:expensive-test)
100 (erc-scenarios-common-with-cleanup
101 ((erc-scenarios-common-dialog "base/modes")
102 (erc-server-flood-penalty 0.1)
103 (dumb-server (erc-d-run "localhost" t 'speaker-status))
104 (erc-show-speaker-membership-status t)
105 (erc-autojoin-channels-alist '(("." "#chan")))
106 (expect (erc-d-t-make-expecter)))
107
108 (ert-info ("Connect to foonet")
109 (with-current-buffer (erc :server "127.0.0.1"
110 :port (process-contact dumb-server :service)
111 :nick "tester"
112 :user "tester")
113 (funcall expect 5 "Here on foonet, we provide services")))
114
115 (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
116
117 (ert-info ("Prefixes printed correctly in 353")
118 (funcall expect 10 "chan: +alice @fsbot -bob !foop"))
119
120 (ert-info ("Speakers honor option `erc-show-speaker-membership-status'")
121 (funcall expect 10 "<-bob> alice: Of that which hath")
122 (funcall expect 10 "<+alice> Hie you, make haste")
123 (funcall expect 10 "<!foop> hi"))
124
125 (ert-info ("Status conferred and rescinded")
126 (funcall expect 10 "*** foop (user@netadmin.example.net) has changed ")
127 (funcall expect 10 "mode for #chan to +v bob")
128 (funcall expect 10 "<+bob> alice: Fair as a text B")
129 (funcall expect 10 "<+alice> bob: Even as Apemantus")
130 (funcall expect 10 "mode for #chan to -v bob")
131 (funcall expect 10 "<-bob> alice: That's the way")
132 (funcall expect 10 "<+alice> Give it the beasts"))
133
134 ;; If it had instead overwritten it, our two states would be
135 ;; out of sync. (See comment above.)
136 (ert-info ("/WHO output confirms server shadowed V status")
137 (erc-scenarios-common-say "/who #chan")
138 (funcall expect 10 '(: "bob" (+ " ") "H-"))
139 (funcall expect 10 "<-bob> alice: Remains in danger")
140 (erc-cmd-QUIT "")))))
141
84;;; erc-scenarios-base-chan-modes.el ends here 142;;; erc-scenarios-base-chan-modes.el ends here
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 49c72836a22..b51bd67ae04 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -674,7 +674,7 @@
674 ;; checking if null beforehand. 674 ;; checking if null beforehand.
675 (should-not erc--parsed-prefix) 675 (should-not erc--parsed-prefix)
676 (should (equal (erc--parsed-prefix) 676 (should (equal (erc--parsed-prefix)
677 #s(erc--parsed-prefix nil "qaohv" "~&@%+" 677 #s(erc--parsed-prefix nil "vhoaq" "+%@&~"
678 ((?q . ?~) (?a . ?&) 678 ((?q . ?~) (?a . ?&)
679 (?o . ?@) (?h . ?%) (?v . ?+))))) 679 (?o . ?@) (?h . ?%) (?v . ?+)))))
680 (let ((cached (should erc--parsed-prefix))) 680 (let ((cached (should erc--parsed-prefix)))
@@ -696,7 +696,7 @@
696 (should (equal expected (erc--parsed-prefix-alist erc--parsed-prefix))) 696 (should (equal expected (erc--parsed-prefix-alist erc--parsed-prefix)))
697 (setq cached erc--parsed-prefix) 697 (setq cached erc--parsed-prefix)
698 (should (equal cached 698 (should (equal cached
699 #s(erc--parsed-prefix ("(ov)@+") "ov" "@+" 699 #s(erc--parsed-prefix ("(ov)@+") "vo" "+@"
700 ((?o . ?@) (?v . ?+))))) 700 ((?o . ?@) (?v . ?+)))))
701 ;; Second target buffer reuses cached value. 701 ;; Second target buffer reuses cached value.
702 (with-temp-buffer 702 (with-temp-buffer
@@ -714,6 +714,88 @@
714 (erc-with-server-buffer erc--parsed-prefix)) 714 (erc-with-server-buffer erc--parsed-prefix))
715 '((?q . ?~) (?h . ?%))))))) 715 '((?q . ?~) (?h . ?%)))))))
716 716
717(ert-deftest erc--get-prefix-flag ()
718 (erc-tests-common-make-server-buf (buffer-name))
719 (should-not erc--parsed-prefix)
720 (should (= (erc--get-prefix-flag ?v) 1))
721 (should (= (erc--get-prefix-flag ?h) 2))
722 (should (= (erc--get-prefix-flag ?o) 4))
723 (should (= (erc--get-prefix-flag ?a) 8))
724 (should (= (erc--get-prefix-flag ?q) 16))
725
726 (ert-info ("With optional `from-prefix-p'")
727 (should (= (erc--get-prefix-flag ?+ nil 'fpp) 1))
728 (should (= (erc--get-prefix-flag ?% nil 'fpp) 2))
729 (should (= (erc--get-prefix-flag ?@ nil 'fpp) 4))
730 (should (= (erc--get-prefix-flag ?& nil 'fpp) 8))
731 (should (= (erc--get-prefix-flag ?~ nil 'fpp) 16)))
732 (should erc--parsed-prefix))
733
734(ert-deftest erc--init-cusr-fallback-status ()
735 ;; Fallback behavior active because no `erc--parsed-prefix'.
736 (should-not erc--parsed-prefix)
737 (should (= 0 (erc--init-cusr-fallback-status nil nil nil nil nil)))
738 (should (= 1 (erc--init-cusr-fallback-status t nil nil nil nil)))
739 (should (= 4 (erc--init-cusr-fallback-status nil nil t nil nil)))
740 (should-not erc--parsed-prefix) ; not created in non-ERC buffer.
741
742 ;; Uses advertised server parameter.
743 (erc-tests-common-make-server-buf (buffer-name))
744 (setq erc-server-parameters '(("PREFIX" . "(YqaohvV)!~&@%+-")))
745 (should (= 0 (erc--init-cusr-fallback-status nil nil nil nil nil)))
746 (should (= 2 (erc--init-cusr-fallback-status t nil nil nil nil)))
747 (should (= 8 (erc--init-cusr-fallback-status nil nil t nil nil)))
748 (should erc--parsed-prefix))
749
750(ert-deftest erc--compute-cusr-fallback-status ()
751 ;; Useless without an `erc--parsed-prefix'.
752 (should (= 0 (erc--compute-cusr-fallback-status 0 nil nil nil nil nil)))
753 (should (= 0 (erc--compute-cusr-fallback-status 0 'on 'on 'on 'on 'on)))
754
755 (erc-tests-common-make-server-buf (buffer-name))
756 (should (= 0 (erc--compute-cusr-fallback-status 0 nil nil nil nil nil)))
757 (should (= 1 (erc--compute-cusr-fallback-status 0 'on nil nil nil nil)))
758 (should (= 1 (erc--compute-cusr-fallback-status 0 'on 'off 'off 'off 'off)))
759 (should (= 1 (erc--compute-cusr-fallback-status 1 'on 'off 'off 'off 'off)))
760 (should (= 1 (erc--compute-cusr-fallback-status 1 nil nil nil nil nil)))
761 (should (= 1 (erc--compute-cusr-fallback-status 3 nil 'off nil nil nil)))
762 (should (= 1 (erc--compute-cusr-fallback-status 7 nil 'off 'off nil nil)))
763 (should (= 4 (erc--compute-cusr-fallback-status 1 'off nil 'on nil nil))))
764
765(ert-deftest erc--cusr-status-p ()
766 (erc-tests-common-make-server-buf (buffer-name))
767 (should-not erc--parsed-prefix)
768 (let ((cusr (make-erc-channel-user :voice t :op t)))
769 (should-not (erc--cusr-status-p cusr ?q))
770 (should-not (erc--cusr-status-p cusr ?a))
771 (should-not (erc--cusr-status-p cusr ?h))
772 (should (erc--cusr-status-p cusr ?o))
773 (should (erc--cusr-status-p cusr ?v)))
774 (should erc--parsed-prefix))
775
776(ert-deftest erc--cusr-change-status ()
777 (erc-tests-common-make-server-buf (buffer-name))
778 (let ((cusr (make-erc-channel-user)))
779 (should-not (erc--cusr-status-p cusr ?o))
780 (should-not (erc--cusr-status-p cusr ?v))
781 (erc--cusr-change-status cusr ?o t)
782 (erc--cusr-change-status cusr ?v t)
783 (should (erc--cusr-status-p cusr ?o))
784 (should (erc--cusr-status-p cusr ?v))
785
786 (ert-info ("Reset with optional param")
787 (erc--cusr-change-status cusr ?q t 'reset)
788 (should-not (erc--cusr-status-p cusr ?o))
789 (should-not (erc--cusr-status-p cusr ?v))
790 (should (erc--cusr-status-p cusr ?q)))
791
792 (ert-info ("Clear with optional param")
793 (erc--cusr-change-status cusr ?v t)
794 (should (erc--cusr-status-p cusr ?v))
795 (erc--cusr-change-status cusr ?q nil 'reset)
796 (should-not (erc--cusr-status-p cusr ?v))
797 (should-not (erc--cusr-status-p cusr ?q)))))
798
717;; This exists as a reference to assert legacy behavior in order to 799;; This exists as a reference to assert legacy behavior in order to
718;; preserve and incorporate it as a fallback in the 5.6+ replacement. 800;; preserve and incorporate it as a fallback in the 5.6+ replacement.
719(ert-deftest erc-parse-modes () 801(ert-deftest erc-parse-modes ()
@@ -737,12 +819,9 @@
737 (should (equal (erc-parse-modes "-l") '(nil nil (("l" off nil)))))))) 819 (should (equal (erc-parse-modes "-l") '(nil nil (("l" off nil))))))))
738 820
739(ert-deftest erc--update-channel-modes () 821(ert-deftest erc--update-channel-modes ()
740 (erc-mode) 822 (erc-tests-common-make-server-buf)
741 (setq erc-channel-users (make-hash-table :test #'equal) 823 (setq erc-channel-users (make-hash-table :test #'equal)
742 erc-server-users (make-hash-table :test #'equal)
743 erc--isupport-params (make-hash-table)
744 erc--target (erc--target-from-string "#test")) 824 erc--target (erc--target-from-string "#test"))
745 (erc-tests-common-init-server-proc "sleep" "1")
746 825
747 (let ((orig-handle-fn (symbol-function 'erc--handle-channel-mode)) 826 (let ((orig-handle-fn (symbol-function 'erc--handle-channel-mode))
748 calls) 827 calls)
@@ -1715,13 +1794,13 @@
1715;; regardless of whether a command handler is summoned. 1794;; regardless of whether a command handler is summoned.
1716 1795
1717(ert-deftest erc-process-input-line () 1796(ert-deftest erc-process-input-line ()
1718 (let (erc-server-last-sent-time 1797 (erc-tests-common-make-server-buf)
1719 erc-server-flood-queue 1798 (let ((orig-erc-cmd-MSG (symbol-function 'erc-cmd-MSG))
1720 (orig-erc-cmd-MSG (symbol-function 'erc-cmd-MSG)) 1799 (pop-flood-queue (lambda () (erc-with-server-buffer
1721 (erc-default-recipients '("#chan")) 1800 (pop erc-server-flood-queue))))
1722 calls) 1801 calls)
1723 (with-temp-buffer 1802 (setq erc-server-current-nick "tester")
1724 (erc-tests-common-init-server-proc "sleep" "1") 1803 (with-current-buffer (erc--open-target "#chan")
1725 (cl-letf (((symbol-function 'erc-cmd-MSG) 1804 (cl-letf (((symbol-function 'erc-cmd-MSG)
1726 (lambda (line) 1805 (lambda (line)
1727 (push line calls) 1806 (push line calls)
@@ -1735,49 +1814,50 @@
1735 (ert-info ("Baseline") 1814 (ert-info ("Baseline")
1736 (erc-process-input-line "/msg #chan hi\n") 1815 (erc-process-input-line "/msg #chan hi\n")
1737 (should (equal (pop calls) " #chan hi")) 1816 (should (equal (pop calls) " #chan hi"))
1738 (should (equal (pop erc-server-flood-queue) 1817 (should (equal (funcall pop-flood-queue)
1739 '("PRIVMSG #chan :hi\r\n" . utf-8)))) 1818 '("PRIVMSG #chan :hi\r\n" . utf-8))))
1740 1819
1741 (ert-info ("Quote preserves line intact") 1820 (ert-info ("Quote preserves line intact")
1742 (erc-process-input-line "/QUOTE FAKE foo bar\n") 1821 (erc-process-input-line "/QUOTE FAKE foo bar\n")
1743 (should (equal (pop erc-server-flood-queue) 1822 (should (equal (funcall pop-flood-queue)
1744 '("FAKE foo bar\r\n" . utf-8)))) 1823 '("FAKE foo bar\r\n" . utf-8))))
1745 1824
1746 (ert-info ("Unknown command respected") 1825 (ert-info ("Unknown command respected")
1747 (erc-process-input-line "/FAKE foo bar\n") 1826 (erc-process-input-line "/FAKE foo bar\n")
1748 (should (equal (pop erc-server-flood-queue) 1827 (should (equal (funcall pop-flood-queue)
1749 '("FAKE foo bar\r\n" . utf-8)))) 1828 '("FAKE foo bar\r\n" . utf-8))))
1750 1829
1751 (ert-info ("Spaces preserved") 1830 (ert-info ("Spaces preserved")
1752 (erc-process-input-line "/msg #chan hi you\n") 1831 (erc-process-input-line "/msg #chan hi you\n")
1753 (should (equal (pop calls) " #chan hi you")) 1832 (should (equal (pop calls) " #chan hi you"))
1754 (should (equal (pop erc-server-flood-queue) 1833 (should (equal (funcall pop-flood-queue)
1755 '("PRIVMSG #chan :hi you\r\n" . utf-8)))) 1834 '("PRIVMSG #chan :hi you\r\n" . utf-8))))
1756 1835
1757 (ert-info ("Empty line honored") 1836 (ert-info ("Empty line honored")
1758 (erc-process-input-line "/msg #chan\n") 1837 (erc-process-input-line "/msg #chan\n")
1759 (should (equal (pop calls) " #chan")) 1838 (should (equal (pop calls) " #chan"))
1760 (should (equal (pop erc-server-flood-queue) 1839 (should (equal (funcall pop-flood-queue)
1761 '("PRIVMSG #chan :\r\n" . utf-8))))) 1840 '("PRIVMSG #chan :\r\n" . utf-8)))))
1762 1841
1763 (ert-info ("Implicit cmd via `erc-send-input-line-function'") 1842 (ert-info ("Implicit cmd via `erc-send-input-line-function'")
1764 1843
1765 (ert-info ("Baseline") 1844 (ert-info ("Baseline")
1766 (erc-process-input-line "hi\n") 1845 (erc-process-input-line "hi\n")
1767 (should (equal (pop erc-server-flood-queue) 1846 (should (equal (funcall pop-flood-queue)
1768 '("PRIVMSG #chan :hi\r\n" . utf-8)))) 1847 '("PRIVMSG #chan :hi\r\n" . utf-8))))
1769 1848
1770 (ert-info ("Spaces preserved") 1849 (ert-info ("Spaces preserved")
1771 (erc-process-input-line "hi you\n") 1850 (erc-process-input-line "hi you\n")
1772 (should (equal (pop erc-server-flood-queue) 1851 (should (equal (funcall pop-flood-queue)
1773 '("PRIVMSG #chan :hi you\r\n" . utf-8)))) 1852 '("PRIVMSG #chan :hi you\r\n" . utf-8))))
1774 1853
1775 (ert-info ("Empty line transmitted with injected-space kludge") 1854 (ert-info ("Empty line transmitted with injected-space kludge")
1776 (erc-process-input-line "\n") 1855 (erc-process-input-line "\n")
1777 (should (equal (pop erc-server-flood-queue) 1856 (should (equal (funcall pop-flood-queue)
1778 '("PRIVMSG #chan : \r\n" . utf-8)))) 1857 '("PRIVMSG #chan : \r\n" . utf-8))))
1779 1858
1780 (should-not calls)))))) 1859 (should-not calls)))))
1860 (erc-tests-common-kill-buffers))
1781 1861
1782(ert-deftest erc--get-inserted-msg-beg/basic () 1862(ert-deftest erc--get-inserted-msg-beg/basic ()
1783 (erc-tests-common-assert-get-inserted-msg/basic 1863 (erc-tests-common-assert-get-inserted-msg/basic
diff --git a/test/lisp/erc/resources/base/modes/speaker-status.eld b/test/lisp/erc/resources/base/modes/speaker-status.eld
new file mode 100644
index 00000000000..4a7d508e35c
--- /dev/null
+++ b/test/lisp/erc/resources/base/modes/speaker-status.eld
@@ -0,0 +1,69 @@
1;; -*- mode: lisp-data; -*-
2((nick 10 "NICK tester"))
3((user 10 "USER tester 0 * :unknown")
4 (0.00 ":irc.example.net NOTICE * :*** Looking up your hostname...")
5 (0.00 ":irc.example.net NOTICE tester :*** Could not resolve your hostname: Domain not found; using your IP address (10.0.2.100) instead.")
6 (0.09 ":irc.example.net 001 tester :Welcome to the foonet IRC Network tester!tester@10.0.2.100")
7 (0.01 ":irc.example.net 002 tester :Your host is irc.example.net, running version InspIRCd-3")
8 (0.01 ":irc.example.net 003 tester :This server was created 07:50:59 Jan 22 2024")
9 (0.03 ":irc.example.net 004 tester irc.example.net InspIRCd-3 BIRcgikorsw ACHIKMORTVXabcefghijklmnopqrstvyz :HIVXabefghjkloqvy")
10 (0.00 ":irc.example.net 005 tester ACCEPT=30 AWAYLEN=200 BOT=B CALLERID=g CASEMAPPING=ascii CHANLIMIT=#:20 CHANMODES=IXbeg,k,Hfjl,ACKMORTcimnprstz CHANNELLEN=64 CHANTYPES=# ELIST=CMNTU ESILENCE=CcdiNnPpTtx EXCEPTS=e :are supported by this server")
11 (0.01 ":irc.example.net 005 tester EXTBAN=,ACORTUacjrwz HOSTLEN=64 INVEX=I KEYLEN=32 KICKLEN=255 LINELEN=512 MAXLIST=I:100,X:100,b:100,e:100,g:100 MAXTARGETS=20 MODES=20 MONITOR=30 NAMELEN=128 NAMESX NETWORK=foonet :are supported by this server")
12 (0.01 ":irc.example.net 005 tester NICKLEN=30 PREFIX=(yqaohvV)!~&@%+- SAFELIST SILENCE=32 STATUSMSG=!~&@%+- TOPICLEN=307 UHNAMES USERIP USERLEN=10 USERMODES=,,s,BIRcgikorw WHOX :are supported by this server")
13 (0.01 ":irc.example.net 251 tester :There are 2 users and 2 invisible on 2 servers")
14 (0.00 ":irc.example.net 252 tester 1 :operator(s) online")
15 (0.00 ":irc.example.net 253 tester 1 :unknown connections")
16 (0.00 ":irc.example.net 254 tester 2 :channels formed")
17 (0.00 ":irc.example.net 255 tester :I have 4 clients and 1 servers")
18 (0.00 ":irc.example.net 265 tester :Current local users: 4 Max: 5")
19 (0.00 ":irc.example.net 266 tester :Current global users: 4 Max: 5")
20 (0.00 ":irc.example.net 375 tester :irc.example.net message of the day")
21 (0.00 ":irc.example.net 372 tester : https://github.com/inspircd/inspircd-docker/issues")
22 (0.00 ":irc.example.net 372 tester : ")
23 (0.00 ":irc.example.net 372 tester : Have fun with the image!")
24 (0.00 ":irc.example.net 376 tester :End of message of the day.")
25 (0.00 ":irc.example.net 501 tester x :is not a recognised user mode.")
26 (0.00 ":NickServ!NickServ@services.int NOTICE tester :Welcome to foonet, tester! Here on foonet, we provide services to enable the registration of nicknames and channels! For details, type \2/msg NickServ help\2 and \2/msg ChanServ help\2."))
27
28((mode 10 "MODE tester +i")
29 (0.01 ":tester!tester@10.0.2.100 MODE tester :+i"))
30
31((join 10 "JOIN #chan")
32 (0.02 ":tester!tester@10.0.2.100 JOIN :#chan")
33 (0.02 ":irc.example.net 353 tester = #chan :+alice @fsbot -bob !foop tester")
34 (0.03 ":irc.example.net 366 tester #chan :End of /NAMES list.")
35 (0.00 ":bob!bob@localhost PRIVMSG #chan :tester, welcome!")
36 (0.01 ":alice!alice@localhost PRIVMSG #chan :tester, welcome!"))
37
38((mode-chan 10 "MODE #chan")
39 (0.00 ":irc.example.net 324 tester #chan :+nt")
40 (0.01 ":irc.example.net 329 tester #chan :1705909863")
41 (0.03 ":bob!bob@localhost PRIVMSG #chan :alice: Of that which hath so faithfully been paid.")
42 (0.03 ":alice!alice@localhost PRIVMSG #chan :Hie you, make haste, for it grows very late.")
43 (0.03 ":foop!user@netadmin.example.net PRIVMSG #chan :hi")
44 ;; (0.07 ":alice!alice@localhost PRIVMSG #chan :bob: And make a clear way to the gods.")
45 ;; (0.04 ":bob!bob@localhost PRIVMSG #chan :Why, that they have; and bid them so be gone.")
46 ;; (0.08 ":bob!bob@localhost PRIVMSG #chan :alice: Now stay your strife: what shall be is dispatch'd.")
47 (0.06 ":foop!user@netadmin.example.net MODE #chan +v :bob")
48 (0.05 ":bob!bob@localhost PRIVMSG #chan :alice: Fair as a text B in a copy-book.")
49 (0.07 ":alice!alice@localhost PRIVMSG #chan :bob: Even as Apemantus does now; hate a lord with my heart.")
50 (0.03 ":bob!bob@localhost PRIVMSG #chan :Then here is a supplication for you. And when you come to him, at the first approach you must kneel; then kiss his foot; then deliver up your pigeons; and then look for your reward. I'll be at hand, sir; see you do it bravely.")
51 (0.05 ":foop!user@netadmin.example.net MODE #chan -v :bob")
52 (0.04 ":bob!bob@localhost PRIVMSG #chan :alice: That's the way: for women are light at midnight.")
53 (0.04 ":alice!alice@localhost PRIVMSG #chan :Give it the beasts, to be rid of the men.")
54 ;; (0.02 ":alice!alice@localhost PRIVMSG #chan :bob: Here comes young Master Ganymede, my new mistress's brother.")
55 )
56
57((who-chan 10 "who #chan")
58 (0.03 ":irc.example.net 352 tester #chan alice localhost irc.example.net alice H+ :0 Irc bot based on irc3 http://irc3.readthedocs.io")
59 (0.03 ":irc.example.net 352 tester #chan fsbot localhost irc.example.net fsbot H@ :0 fsbot")
60 (0.01 ":irc.example.net 352 tester #chan bob localhost irc.example.net bob H- :0 Irc bot based on irc3 http://irc3.readthedocs.io")
61 (0.01 ":irc.example.net 352 tester #chan user netadmin.example.net irc.example.net foop H*! :0 unknown")
62 (0.01 ":irc.example.net 352 tester #chan tester 10.0.2.100 irc.example.net tester H :0 unknown")
63 (0.01 ":irc.example.net 315 tester #chan :End of /WHO list.")
64 ;; (0.09 ":bob!bob@localhost PRIVMSG #chan :alice: Shall nothing wrong him. Thus it is, general.")
65 ;; (0.04 ":alice!alice@localhost PRIVMSG #chan :bob: His father and I were soldiers together; to whom I have been often bound for no less than my life. Here comes the Briton: let him be so entertained amongst you as suits, with gentlemen of your knowing, to a stranger of his quality.")
66 (0.04 ":bob!bob@localhost PRIVMSG #chan :alice: Remains in danger of her former tooth."))
67
68((quit 10 "QUIT :\2ERC\2")
69 (0.03 "ERROR :Closing link: (tester@10.0.2.100) [Quit: \2ERC\2 5.x (IRC client for GNU Emacs)]"))