Reserve erc-normalize-port for equality comparisons

* etc/ERC-NEWS: Add entry explaining changes to entry point 'erc-tls'
and library functions `erc-normalize-port' and `erc-compute-port'.
* lisp/erc/erc.el (erc-normalize-port): Map "ircu" to 6665 instead of
6667, and add related IANA service mappings.  Return 0 for unknown
nonempty strings.
(erc-open): Pass `erc-session-port' through `erc-string-to-port' before
handing it to `erc-server-connect'.  This prevents the network machinery
from ever seeing a numeric string, like "6667".
(erc-select-read-args): Since `erc-compute-port' no longer relies on
`erc-normalize-port', ensure its input is a number.  Use
`erc-port-equal' instead of `eql'.
(erc-tls): Respect a configured non-nil `erc-port' option when the user
does not provide a :port keyword argument from Lisp code.
(erc-determine-parameters): Use `erc-compute-port' for initializing
`erc-session-port'.
(erc-compute-port): Don't pass the result through `erc-normalize-port',
which can convert it to an unintuitive form.
(erc--url-default-connect-function): Use `erc-compute-port' instead of
`erc-normalize-port'.
(erc-handle-irc-url): Use `erc-port-equal' for comparison.
* test/lisp/erc/erc-scenarios-auth-source.el
(erc-scenarios-common--auth-source): Allow tests to convey the automatic
port number to `erc-open' via `erc-port'.
(erc-scenarios-base-auth-source-server--dialed): Use `erc-port' option
instead of passing a :port parameter to entry-point command.
* test/lisp/erc/erc-tests.el (erc-normalize-port): New test.
(Bug#74516)
This commit is contained in:
F. Jason Park 2024-11-25 00:01:04 -08:00
parent d899519221
commit 3bf4ea9543
4 changed files with 92 additions and 37 deletions

View file

@ -62,6 +62,32 @@ of concerns and the newer module's "experimental" status, the migration
was deemed worth any potential disruption, despite this being a point
release. ERC appreciates your understanding in this matter.
** Entry-point command 'erc-tls' once again considers option 'erc-port'.
In its zeal to enforce a preference for TLS connections, ERC 5.5 went a
bit far in disregarding the useful user option 'erc-port'. When called
from Lisp code without a ':port' keyword, 'erc-tls' once again respects
the option.
** Changes in the library API.
*** Function 'erc-normalize-port' may return 0 instead of nil.
When given a nonempty, non-numeric string, this function now returns 0.
Moreover, ERC officially requests that users not use its output for
anything but comparing port equality, which was always its intended
purpose.
*** Function 'erc-compute-port' no longer uses 'erc-normalize-port'.
An uninformed change in ERC 5.5 led to 'erc-compute-port' filtering its
result through 'erc-normalize-port', which brought unwelcome type
coercion and possible null return values. This defied its purpose of
ensuring a usable port. Users reliant on the aberrant 5.5 behavior
should wrap its return value in 'erc-normalize-port'.
*** Local variable 'erc-session-port' may be a string.
Although this has always been the case, string values are now more
likely to be seen because ERC no longer coerces service names to port
numbers.
* Changes in ERC 5.6

View file

@ -1987,13 +1987,12 @@ the existing buffers will be reused."
"old behavior when t now permanent" "29.1")
(defun erc-normalize-port (port)
"Normalize the port specification PORT to integer form.
PORT may be an integer, a string or a symbol. If it is a string or a
symbol, it may have these values:
* irc -> 194
* ircs -> 994
* ircd -> 6667
* ircd-dalnet -> 7000"
"Normalize known PORT specifications to an integer.
Expect PORT to be an integer, a string, or a symbol to coerce into a
standardized form for the express purpose of equality comparisons. If
PORT is an IANA recognized service, return its numeric mapping. Do the
same for a few traditional but nonstandard names. Return nil in
pathological cases."
;; These were updated somewhat in 2022 to reflect modern standards
;; and practices. See also:
;;
@ -2001,7 +2000,7 @@ symbol, it may have these values:
;; https://www.iana.org/assignments/service-names-port-numbers
(cond
((symbolp port)
(erc-normalize-port (symbol-name port)))
(and port (erc-normalize-port (symbol-name port))))
((stringp port)
(let ((port-nr (string-to-number port)))
(cond
@ -2011,14 +2010,19 @@ symbol, it may have these values:
194)
((string-equal port "ircs")
994)
((string-equal port "ircu") 6667) ; 6665-6669
((string-equal port "ircu") 6665)
((string-equal port "ircu-2") 6666)
((string-equal port "ircu-3") 6667)
((string-equal port "ircu-4") 6668)
((string-equal port "ircu-5") 6669)
((string-equal port "ircd") ; nonstandard (irc-serv is 529)
6667)
((string-equal port "ircs-u") 6697)
((string-equal port "ircd-dalnet")
7000)
((string-empty-p port) nil)
(t
nil))))
0))))
((numberp port)
port)
(t
@ -2665,7 +2669,7 @@ side effect of setting the current buffer to the one it returns. Use
(if connect
(erc-server-connect erc-session-server
erc-session-port
(erc-string-to-port erc-session-port)
buffer
erc-session-client-certificate)
(erc-update-mode-line))
@ -2769,8 +2773,8 @@ properties needed by entry-point commands, like `erc-tls'."
(port (or (url-portspec url)
(erc-compute-port
(let ((d (erc-compute-port sp))) ; may be a string
(read-string (format-prompt "Port" d)
nil nil d)))))
(erc-string-to-port
(read-string (format-prompt "Port" d) nil nil d))))))
;; Trust the user not to connect twice accidentally. We
;; can't use `erc-already-logged-in' to check for an existing
;; connection without modifying it to consider USER and PASS.
@ -2792,10 +2796,10 @@ properties needed by entry-point commands, like `erc-tls'."
(format-prompt "Server password" p)
"Server password (optional): ")))
(if erc-prompt-for-password (read-passwd m nil p) p)))
(opener (and (or sp (eql port erc-default-port-tls)
(opener (and (or sp (erc-port-equal port erc-default-port-tls)
(and (equal server erc-default-server)
(not (string-prefix-p "irc://" input))
(eql port erc-default-port)
(erc-port-equal port erc-default-port)
(y-or-n-p "Connect using TLS instead? ")
(setq port erc-default-port-tls)))
#'erc-open-tls-stream))
@ -2891,7 +2895,8 @@ and defers to `erc-compute-port', `erc-compute-user', and
;;;###autoload
(cl-defun erc-tls (&key (server (erc-compute-server))
(port (erc-compute-port 'ircs-u))
(port (let ((erc-default-port erc-default-port-tls))
(erc-compute-port)))
(nick (erc-compute-nick))
(user (erc-compute-user))
password
@ -8839,7 +8844,7 @@ Sets the buffer local variables:
- `erc-server-current-nick'"
(setq erc-session-connector erc-server-connect-function
erc-session-server (erc-compute-server server)
erc-session-port (or port erc-default-port)
erc-session-port (erc-compute-port port)
erc-session-user-full-name (erc-compute-full-name name)
erc-session-username (erc-compute-user user)
erc-session-password (erc--compute-server-password passwd nick))
@ -8912,8 +8917,12 @@ non-nil value is found.
- PORT (the argument passed to this function)
- The `erc-port' option
- The `erc-default-port' variable"
(erc-normalize-port (or port erc-port erc-default-port)))
- The `erc-default-port' variable
Note that between ERC 5.5 and 5.6.1, this function filtered its result
through `erc-normalize-port', which introduced regrettable surprises,
such as unwelcome, possibly null, type conversions."
(or (and port (not (equal "" port)) port) erc-port erc-default-port))
;; time routines
@ -9873,9 +9882,8 @@ by `erc' and `erc-tls'."
(or (eql 6697 (plist-get plist :port))
(yes-or-no-p "Connect using TLS? "))))
(erc-server (plist-get plist :server))
(erc-port (or (plist-get plist :port)
(and ircsp (erc-normalize-port 'ircs-u))
erc-port))
(erc-default-port (if ircsp erc-default-port-tls erc-default-port))
(erc-port (erc-compute-port (plist-get plist :port)))
(erc-nick (or (plist-get plist :nick) erc-nick))
(erc-password (plist-get plist :password))
(args (erc-select-read-args)))
@ -9907,9 +9915,9 @@ Customize `erc-url-connect-function' to override this."
(and (string-equal erc-session-server host)
;; Ports only matter when dialed hosts
;; match and we have sufficient info.
(or (not port)
(= (erc-normalize-port erc-session-port)
port)))))))))
(or (null port)
(erc-port-equal erc-session-port
port)))))))))
key deferred)
(unless server-buffer
(setq deferred t

View file

@ -44,15 +44,19 @@
(string-join ents "\n")))
(auth-sources (list netrc-file))
(auth-source-do-cache nil)
(erc-port (and (eq erc-port 'test) (number-to-string port)))
(erc-scenarios-common-extra-teardown (lambda ()
(delete-file netrc-file))))
(delete-file netrc-file)))
;; With a `cl-defun', a keyword's presence prevents the default
;; init form from being evaluated, even if its value is nil.
(args `( :server "127.0.0.1"
,@(and (null erc-port) (list :port port))
:nick "tester"
:full-name "tester"
:id ,id)))
(ert-info ("Connect")
(with-current-buffer (erc :server "127.0.0.1"
:port port
:nick "tester"
:full-name "tester"
:id id)
(with-current-buffer (apply #'erc args)
(should (string= (buffer-name) (if id
(symbol-name id)
(format "127.0.0.1:%d" port))))
@ -60,12 +64,13 @@
(ert-deftest erc-scenarios-base-auth-source-server--dialed ()
:tags '(:expensive-test)
(erc-scenarios-common--auth-source
nil 'foonet
"machine GNU.chat port %d user tester password fake"
"machine FooNet port %d user tester password fake"
"machine 127.0.0.1 port %d user tester password changeme"
"machine 127.0.0.1 port %d user imposter password fake"))
(let ((erc-port 'test))
(erc-scenarios-common--auth-source
nil 'foonet
"machine GNU.chat port %d user tester password fake"
"machine FooNet port %d user tester password fake"
"machine 127.0.0.1 port \"%s\" user tester password changeme" ; correct
"machine 127.0.0.1 port %d user imposter password fake")))
(ert-deftest erc-scenarios-base-auth-source-server--netid ()
:tags '(:expensive-test)

View file

@ -3057,6 +3057,22 @@
(should-not (buffer-live-p spam-buffer))
(kill-buffer chan-buffer)))
(ert-deftest erc-normalize-port ()
;; The empty string, nil, and unsupported types become nil.
(should-not (erc-normalize-port ""))
(should-not (erc-normalize-port nil))
(should-not (erc-normalize-port (current-buffer)))
;; Unrecognized names are coerced to 0.
(should (equal 0 (erc-normalize-port "fake")))
;; Numbers pass through, but numeric strings are coerced.
(should (equal 6667 (erc-normalize-port 6667)))
(should (equal 6697 (erc-normalize-port "6697")))
;; Strange IANA mappings recognized.
(should (equal 6665 (erc-normalize-port "ircu"))))
(defvar erc-tests--ipv6-examples
'("1:2:3:4:5:6:7:8"
"::ffff:10.0.0.1" "::ffff:1.2.3.4" "::ffff:0.0.0.0"