Subject: 29.0.60; ERC 5.4.1: ERC cannot join channels without the networks module

From: "J.P." <[email-masked]>
Date: Sun, 25 Dec 2022 21:46:48 -0800

Tags: patch

This is in reference to

  https://lists.gnu.org/archive/html/help-gnu-emacs/2022-12/msg00651.html

which affects query buffers as well as channels in what will become ERC
5.5 (both Emacs 29 and HEAD). To reproduce from emacs -Q:

  (require 'erc)
  (setq erc-modules (remq 'networks erc-modules))
  (erc :server "127.0.0.1" :port 6667 :nick "tester")

The attached patch tries to address this in a hopefully agreeable
manner. Thanks.

In GNU Emacs 29.0.60 (build 2, x86_64-pc-linux-gnu, GTK+ Version
 3.24.35, cairo version 1.17.6) of 2022-12-25 built on localhost
Repository revision: 6c00d126e7fe1f6e42a0c9454c2ab4a29dcd5989
Repository branch: emacs-29
Windowing system distributor 'The X.Org Foundation', version 11.0.12014000
System Description: Fedora Linux 36 (Workstation Edition)

Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NOTIFY
INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB

Important settings:
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: @im=ibus
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug message mailcap yank-media puny dired
dired-loaddefs rfc822 mml mml-sec epa derived epg rfc6068 epg-config
gnus-util text-property-search mm-decode mm-bodies mm-encode mail-parse
rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045
ietf-drums mm-util mail-prsvr mail-utils erc iso8601 time-date
auth-source cl-seq eieio eieio-core cl-macs password-cache json subr-x
map thingatpt pp format-spec cl-loaddefs cl-lib erc-backend erc-goodies
erc-networks byte-opt gv bytecomp byte-compile erc-common erc-compat
erc-loaddefs rmc iso-transl tooltip cconv eldoc paren electric uniquify
ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode lisp-mode prog-mode register
page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind inotify lcms2 dynamic-setting system-font-setting
font-render-setting cairo move-toolbar gtk x-toolkit xinput2 x multi-tty
make-network-process emacs)

Memory information:
((conses 16 64557 5365)
 (symbols 48 8608 0)
 (strings 32 23660 1450)
 (string-bytes 1 684415)
 (vectors 16 15218)
 (vector-slots 8 209308 10203)
 (floats 8 24 31)
 (intervals 56 222 0)
 (buffers 976 11))
>From df121708c73d6b7dfae6e8f59bfcc6000ef5c522 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Sun, 25 Dec 2022 21:36:53 -0800
Subject: [PATCH] Warn of absent networks module in ERC

* doc/misc/erc.texi: Add note in Modules chapter about the special
role of `networks'.
* etc/ERC-NEWS: Mention `networks' being a required module.
* lisp/erc/erc-backend.el (erc-server-connect): Print warning when
`networks' module missing from `erc-modules'.  Could be moved to
entry-point commands if third-party packages have a valid
"sans-networks" use case.
* lisp/erc/erc.el (erc-generate-new-buffer-name): Don't reconcile
buffer names when networks module not in play.
(erc-format-target-and/or-network): Don't assume networks module
loaded.
* test/lisp/erc/erc-scenarios-base-unstable.el:
(erc-scenarios-networks-no-module): New test.
* test/lisp/erc/resources/networks/no-module/basic.eld: New test data
file.
---
 doc/misc/erc.texi                             |  6 +++
 etc/ERC-NEWS                                  | 11 ++++-
 lisp/erc/erc-backend.el                       |  6 +++
 lisp/erc/erc.el                               |  6 ++-
 test/lisp/erc/erc-scenarios-base-unstable.el  | 49 +++++++++++++++++++
 .../resources/networks/no-module/basic.eld    | 44 +++++++++++++++++
 6 files changed, 119 insertions(+), 3 deletions(-)
 create mode 100644 test/lisp/erc/resources/networks/no-module/basic.eld

diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index 2ab2e90894..52fccc7438 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -529,6 +529,12 @@ Modules
 
 @end table
 
+Note that one module, @code{networks} (from the library
+@file{erc-networks}), is essential to core IRC operations and thus not
+listed above.  It can nevertheless still be removed, just like any
+other module.  However, doing so without taking special precautions
+will likely degrade the overall user experience.
+
 @subheading Local Modules
 @cindex local modules
 
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 76439f1d06..c7c9664f83 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -39,6 +39,14 @@ anew.  The pre-5.4 "disabled" behavior has been restored and will
 remain accessible for the foreseeable future, warts and all (e.g.,
 with its often superfluous "/DIALED-HOST" suffixing always present).
 
+** The 'networks' module is now quasi-required.
+The 'networks' module is now all but required for everyday interactive
+use.  A default member of 'erc-modules' since ERC 5.3, 'networks' has
+grown increasingly integral to core client operations over the years.
+From now on, only the most essential operations will be officially
+supported in its absence, and users will see a warning upon
+entry-point invocation when it's not present.
+
 ** Tighter auth-source integration with bigger changes on the horizon.
 The days of hit-and-miss auth-source queries are hopefully behind us.
 With the overhaul of the services module temporarily shelved and the
@@ -111,7 +119,8 @@ and 'erc-backend'.
 
 The function 'erc-network' always returns non-nil in server and target
 buffers belonging to a successfully established IRC connection, even
-after that connection has been closed.
+after that connection has been closed.  (Also see the note in the
+section above about the 'networks' module being semi-mandatory.)
 
 In 5.4, support for network symbols as keys was added for
 'erc-autojoin-channels-alist'.  This has been extended to include
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 43c5faad63..3c9003a198 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -119,6 +119,7 @@ erc-kill-server-buffer-on-quit
 (defvar erc-log-p)
 (defvar erc-minibuffer-ignored)
 (defvar erc-networks--id)
+(defvar erc-networks-mode)
 (defvar erc-nick)
 (defvar erc-nick-change-attempt-count)
 (defvar erc-prompt-for-channel-key)
@@ -696,6 +697,11 @@ erc-server-connect
     (message "%s" (erc-format-message
                    'login ?n
                    (with-current-buffer buffer (erc-current-nick))))
+    (unless erc-networks-mode
+      (setq msg (concat "Required module `networks' not loaded.  If this "
+                        " was unexpected, please add it to `erc-modules'."))
+      (erc-display-error-notice nil msg)
+      (lwarn 'erc :warning msg))
     ;; wait with script loading until we receive a confirmation (first
     ;; MOTD line)
     (if (eq (process-status process) 'connect)
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 6a5e001896..16a0aba77b 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1607,7 +1607,8 @@ erc-generate-new-buffer-name
   (when target ; compat
     (setq tgt-info (erc--target-from-string target)))
   (if tgt-info
-      (let* ((esid (erc-networks--id-symbol erc-networks--id))
+      (let* ((esid (and erc-networks--id
+                        (erc-networks--id-symbol erc-networks--id)))
              (name (if esid
                        (erc-networks--reconcile-buffer-names tgt-info
                                                              erc-networks--id)
@@ -6760,7 +6761,8 @@ erc-format-target-and/or-network
 If the name of the network is not available, then use the
 shortened server name instead."
   (if-let ((erc--target)
-           (name (if-let ((esid (erc-networks--id-symbol erc-networks--id)))
+           (name (if-let ((erc-networks--id)
+                          (esid (erc-networks--id-symbol erc-networks--id)))
                      (symbol-name esid)
                    (erc-shorten-server-name (or erc-server-announced-name
                                                 erc-session-server)))))
diff --git a/test/lisp/erc/erc-scenarios-base-unstable.el b/test/lisp/erc/erc-scenarios-base-unstable.el
index f5b8df6f4a..bd42a55482 100644
--- a/test/lisp/erc/erc-scenarios-base-unstable.el
+++ b/test/lisp/erc/erc-scenarios-base-unstable.el
@@ -132,4 +132,53 @@ erc-scenarios-base-aborted-reconnect
               (not (setq failed (zerop (cl-decf tries)))))))
     (should-not failed)))
 
+;; The `erc-networks' library has slowly become a hard dependency of
+;; the interactive client since its incorporation in 2006.  But its
+;; module, which was added in ERC 5.3 (2008) and thereafter loaded by
+;; default, only became quasi-required in ERC 5.5 (2022).  Despite
+;; this, a basic connection should still always succeed, at least long
+;; enough to warn users that their setup is abnormal.  Of course,
+;; third-party code intentionally omitting the module will have to
+;; override various erc-server-*-functions to avoid operating in a
+;; degraded state, which has likely been the case for a while.
+
+(ert-deftest erc-scenarios-networks-no-module ()
+  :tags '(:expensive-test)
+  (erc-networks-mode -1)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "networks/no-module")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'basic))
+       (port (process-contact dumb-server :service))
+       (erc-modules (remq 'networks erc-modules))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect and retain dialed name")
+      (with-no-warnings
+        (with-current-buffer (erc :server "127.0.0.1"
+                                  :port port
+                                  :nick "tester"
+                                  :user "tester"
+                                  :full-name "tester")
+          (funcall expect 10 "Required module `networks' not loaded")
+          (funcall expect 10 "This server is in debug mode")
+          ;; Buffer not named after network
+          (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+          (erc-cmd-JOIN "#chan"))))
+
+    (ert-info ("Join #chan, change nick, query op")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (funcall expect 20 "Even at thy teat thou")
+        (erc-cmd-NICK "dummy")
+        (funcall expect 10 "Your new nickname is dummy")
+        (erc-scenarios-common-say "/msg alice hi")))
+
+    (ert-info ("Switch to query and quit")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "alice"))
+        (funcall expect 20 "bye"))
+
+      (with-current-buffer (format "127.0.0.1:%d" port)
+        (erc-cmd-QUIT "")
+        (funcall expect 10 "finished")))))
+
 ;;; erc-scenarios-base-unstable.el ends here
diff --git a/test/lisp/erc/resources/networks/no-module/basic.eld b/test/lisp/erc/resources/networks/no-module/basic.eld
new file mode 100644
index 0000000000..f1bdbd1219
--- /dev/null
+++ b/test/lisp/erc/resources/networks/no-module/basic.eld
@@ -0,0 +1,44 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 1 "USER tester 0 * :tester")
+ (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.00 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version ergo-v2.8.0")
+ (0.00 ":irc.foonet.org 003 tester :This server was created Mon, 12 Dec 2022 01:25:38 UTC")
+ (0.00 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.8.0 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.00 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this server")
+ (0.00 ":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:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this server")
+ (0.00 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 server(s)")
+ (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.00 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.00 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0.00 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0.00 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0.01 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0.00 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode 10 "MODE tester +i")
+ (0.00 ":irc.foonet.org 221 tester +i")
+ (0.00 ":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 #chan")
+ (0.03 ":[email-masked] JOIN #chan"))
+
+((~nick 10 "NICK dummy")
+ (0.01 ":[email-masked] NICK dummy"))
+
+((mode-1 10 "MODE #chan")
+ (0.01 ":irc.foonet.org 353 tester = #chan :@alice bob foonet tester")
+ (0.00 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.03 ":irc.foonet.org 324 tester #chan +nt")
+ (0.00 ":irc.foonet.org 329 tester #chan 1670808354")
+ (0.00 ":[email-masked] PRIVMSG #chan :tester, welcome!")
+ (0.00 ":[email-masked] PRIVMSG #chan :tester, welcome!")
+ (0.03 ":[email-masked] PRIVMSG #chan :alice: Forbear it therefore; give your cause to heaven.")
+ (0.01 ":[email-masked] PRIVMSG #chan :bob: Even at thy teat thou hadst thy tyranny."))
+
+((privmsg 10 "PRIVMSG alice :hi")
+ (0.00 ":[email-masked] PRIVMSG dummy :bye"))
+
+((quit 10 "QUIT :\2ERC\2")
+ (0.03 ":[email-masked] QUIT :Quit: \2ERC\2"))
-- 
2.38.1