From: "J.P." <jp@neverwas.me>
To: 56514@debbugs.gnu.org
Cc: emacs-erc@gnu.org
Subject: bug#56514: 29.0.50; Improve ERC's URI scheme integration for irc:// links
Date: Fri, 11 Nov 2022 06:05:16 -0800 [thread overview]
Message-ID: <87iljl4meb.fsf__20759.4029417791$1668175592$gmane$org@neverwas.me> (raw)
In-Reply-To: <87pmiabvd5.fsf@neverwas.me> (J. P.'s message of "Tue, 12 Jul 2022 01:14:46 -0700")
[-- Attachment #1: Type: text/plain, Size: 147 bytes --]
v6. Fixed compat function. Removed convenience function for browsing
URLs. Deleted nonsensical paragraph from doc (overdue). Added test
scenario.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0000-v5-v6.diff --]
[-- Type: text/x-patch, Size: 7650 bytes --]
From 2d35563e0ac22686bb69100536692cb026fc67f2 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Fri, 11 Nov 2022 00:12:34 -0800
Subject: [PATCH 0/5] *** NOT A PATCH ***
*** BLURB HERE ***
F. Jason Park (5):
Accommodate ircs:// URLs in url-irc and browse-url
Refactor erc-select-read-args
Default to TLS port when calling erc-tls from lisp
Add optional server param to erc-networks--determine
Improve new connections in erc-handle-irc-url
doc/misc/erc.texi | 28 +++
etc/NEWS | 20 ++
lisp/erc/erc-backend.el | 6 +
lisp/erc/erc-compat.el | 19 ++
lisp/erc/erc-networks.el | 9 +-
lisp/erc/erc.el | 192 ++++++++++-----
lisp/net/browse-url.el | 24 ++
lisp/url/url-irc.el | 32 ++-
test/lisp/erc/erc-networks-tests.el | 17 ++
test/lisp/erc/erc-scenarios-misc.el | 28 +++
test/lisp/erc/erc-tests.el | 226 ++++++++++++++++++
.../lisp/erc/resources/join/legacy/foonet.eld | 2 +-
test/lisp/net/browse-url-tests.el | 9 +
13 files changed, 537 insertions(+), 75 deletions(-)
Interdiff:
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index d01eab1bbb..9742fc3c22 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -998,10 +998,10 @@ Integrations
@subheading URL
For anything to work, you'll want to set @code{url-irc-function} to
-@code{url-irc-erc}. As a rule of thumb, libraries that rely directly
-on @code{url-retrieve} should be good to go out the box from Emacs
-29.1 onward. On older versions of Emacs, you may need to
-@code{(require 'erc)} beforehand. @pxref{Retrieving URLs,,, url, URL}.
+@code{url-irc-erc}. As a rule of thumb, libraries relying directly on
+@code{url-retrieve} should be fine out the box from Emacs 29.1 onward.
+On older versions of Emacs, you may need to @code{(require 'erc)}
+beforehand. @pxref{Retrieving URLs,,, url, URL}.
For other apps and libraries, such as those relying on the
higher-level @code{browse-url}, you'll oftentimes be asked to specify
@@ -1012,22 +1012,11 @@ Integrations
need a function as well:
@lisp
- '("\\birc6?s?://[][a-z0-9.,@@_:+%?&/#-]+"
- 0 t erc-browse-url-handler 0)
+ '("\\birc6?s?://[][a-z0-9.,@@_:+%?&/#-]+" 0 t browse-url-irc 0)
@end lisp
-@defun erc-browse-url-handler url &rest args
-An autoloaded convenience function for use in options like those
-mentioned above. @var{url} must be a string. In Emacs 29 and above,
-the function @code{browse-url-irc} can be used instead.
-@end defun
-
@noindent
-Keep in mind that when fiddling with these options, it may be easier
-(and more polite) to connect to a local server or a test network, like
-@samp{ircs://testnet.ergo.chat/#test}, since these generally don't
-require authentication.
-
+Users on Emacs 28 and below may need to use @code{browse-url} instead.
@node Options
@section Options
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index 683d19dfc7..340d90ba96 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -32,6 +32,7 @@
;;; Code:
(require 'compat nil 'noerror)
+(eval-when-compile (require 'url-parse))
;;;###autoload(autoload 'erc-define-minor-mode "erc-compat")
(define-obsolete-function-alias 'erc-define-minor-mode
@@ -168,20 +169,23 @@ erc-compat--with-memoization
`(cl--generic-with-memoization ,table ,@forms))
(t `(progn ,@forms))))
-(declare-function browse-url-irc "browse-url" (url &rest _))
+(defvar url-irc-function)
-(defun erc-compat--browse-url-irc (string &rest _)
- "Parse STRING and call `url-irc'."
+(defun erc-compat--29-browse-url-irc (string &rest _)
+ (cl-assert (< emacs-major-version 29))
(require 'url-irc)
- (if (< emacs-major-version 29)
- ;; `url-irc' binds this in Emacs 29+.
- (let ((url-current-object (url-generic-parse-url string)))
- (url-irc url-current-object))
- (browse-url-irc string)))
+ (let* ((url (url-generic-parse-url string))
+ (url-irc-function
+ (if (function-equal url-irc-function 'url-irc-erc)
+ (lambda (host port chan user pass)
+ (erc-handle-irc-url host port chan user pass (url-type url)))
+ url-irc-function)))
+ (url-irc url)))
(when (< emacs-major-version 29)
- (add-to-list 'browse-url-default-handlers
- '("\\`irc6?s?://" . erc-compat--browse-url-irc)))
+ (unless (assoc "\\`irc6?s?://" browse-url-default-handlers)
+ (push '("\\`irc6?s?://" . erc-compat--29-browse-url-irc)
+ browse-url-default-handlers)))
(provide 'erc-compat)
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 51a97c8de1..cfd1c34ef0 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -7195,7 +7195,7 @@ erc--url-default-connect-function
(apply (if ircsp #'erc-tls #'erc) args)))
;;;###autoload
-(defun erc-handle-irc-url (host port channel nick password scheme)
+(defun erc-handle-irc-url (host port channel nick password &optional scheme)
"Use ERC to IRC on HOST:PORT in CHANNEL.
If ERC is already connected to HOST:PORT, simply /join CHANNEL.
Otherwise, connect to HOST:PORT as NICK and /join CHANNEL.
@@ -7247,14 +7247,6 @@ erc-handle-irc-url
(with-current-buffer server-buffer
(erc-cmd-JOIN channel key))))))
-(defvar url-irc-function)
-
-;;;###autoload
-(defun erc-browse-url-handler (url &rest _)
- "Launch an ERC session when given an irc:// URL."
- (let ((url-irc-function 'url-irc-erc))
- (erc-compat--browse-url-irc url)))
-
(provide 'erc)
;;; erc.el ends here
diff --git a/test/lisp/erc/erc-scenarios-misc.el b/test/lisp/erc/erc-scenarios-misc.el
index ded620ccc1..8557a77906 100644
--- a/test/lisp/erc/erc-scenarios-misc.el
+++ b/test/lisp/erc/erc-scenarios-misc.el
@@ -177,4 +177,32 @@ erc-scenarios-dcc-chat-accept
(erc-scenarios-common-say "Hi")
(funcall expect 10 "Hola")))))
+(defvar url-irc-function)
+
+(ert-deftest erc-scenarios-handle-irc-url ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "join/legacy")
+ (dumb-server (erc-d-run "localhost" t 'foonet))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (url-irc-function 'url-irc-erc)
+ (erc-url-connect-function
+ (lambda (scheme &rest r)
+ (ert-info ("Connect to foonet")
+ (should (equal scheme "irc"))
+ (with-current-buffer (apply #'erc `(:full-name "tester" ,@r))
+ (should (string= (buffer-name)
+ (format "127.0.0.1:%d" port)))
+ (current-buffer))))))
+
+ (with-temp-buffer
+ (insert (format ";; irc://tester:changeme@127.0.0.1:%d/#chan" port))
+ (goto-char 10)
+ (browse-url-at-point))
+
+ (ert-info ("Connected")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+ (funcall expect 10 "welcome")))))
+
;;; erc-scenarios-misc.el ends here
diff --git a/test/lisp/erc/resources/join/legacy/foonet.eld b/test/lisp/erc/resources/join/legacy/foonet.eld
index 344ba7c1da..4025094a59 100644
--- a/test/lisp/erc/resources/join/legacy/foonet.eld
+++ b/test/lisp/erc/resources/join/legacy/foonet.eld
@@ -1,5 +1,5 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :changeme"))
+((pass 10 "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")
--
2.38.1
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Accommodate-ircs-URLs-in-url-irc-and-browse-url.patch --]
[-- Type: text/x-patch, Size: 9108 bytes --]
From ee1c51c8f8309aa7f3761d71789be41c68a31591 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 11 Jul 2022 05:14:57 -0700
Subject: [PATCH 1/5] Accommodate ircs:// URLs in url-irc and browse-url
* lisp/url/url-irc.el (url-irc-function): Change signature of function
interface to expect a final "scheme" argument, such as "ircs".
(url-irc): Call `url-irc-function' with new positional argument, the
scheme extracted via `url-type' from the input URL.
(url-irc-erc, url-irc-rcirc, url-irc-zenirc): Accept a URL scheme as a
sixth positional arg.
(url-ircs-default-port, url-ircs): Add new autoloaded constant and
alias for `url-scheme-get-property' to recognize. Do this to avoid
having to add another file.
* lisp/net/browse-url.el (browse-url-irc-function): Add new option.
(browse-url--irc): Add new function to call `browse-url-irc-function'.
(browse-url-default-handlers): Add "irc://" entry.
(browse-url-irc): Add new function to serve as general handler for
"irc://" URLS. Accept trailing variadic args to accommodate
non-browse-url interfaces as well.
* test/lisp/net/browse-url-tests.el
(browse-url-tests-select-handler-irc): Add test for "irc://" URL
pattern.
* etc/NEWS: Mention select browse-url and url-irc
changes. (Bug#56514.)
---
etc/NEWS | 20 +++++++++++++++++++
lisp/net/browse-url.el | 24 +++++++++++++++++++++++
lisp/url/url-irc.el | 32 ++++++++++++++++++++++++-------
test/lisp/net/browse-url-tests.el | 9 +++++++++
4 files changed, 78 insertions(+), 7 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS
index ab64eff74e..500ac5e50b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -438,6 +438,12 @@ The user options 'url-gateway-rlogin-host',
'url-gateway-rlogin-parameters', and 'url-gateway-rlogin-user-name'
are also obsolete.
+---
+** The user function 'url-irc-function' now takes a 'scheme' argument.
+The user option 'url-irc-function' is now called with a sixth argument
+corresponding to the scheme portion of the target URL. For example,
+this would be "ircs" for a URL like "ircs://irc.libera.chat".
+
---
** The linum.el library is now obsolete.
We recommend using either the built-in 'display-line-numbers-mode', or
@@ -2616,6 +2622,17 @@ This user option decides which URL scheme that 'browse-url' and
related functions will use by default. For example, you could
customize this to "https" to always prefer HTTPS URLs.
+---
+*** New user option 'browse-url-irc-function'.
+This option specifies a function for opening irc:// links. It
+defaults to the new function 'browse-url-irc'.
+
+---
+*** New function 'browse-url-irc'.
+This multipurpose autoloaded function can be used for opening irc://
+and ircs:// URLS by any caller that passes a URL string as an initial
+arg.
+
---
*** Support for the Netscape web browser has been removed.
This support has been obsolete since Emacs 25.1. The final version of
@@ -2842,6 +2859,9 @@ remote host are shown. Alternatively, the user option
*** 'outlineify-sticky' command is renamed to 'allout-outlinify-sticky'.
The old name is still available as an obsolete function alias.
+---
+*** The url-irc library now understands ircs:// links.
+
---
*** New command 'world-clock-copy-time-as-kill' for 'M-x world-clock'.
It copies the current line into the kill ring.
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el
index 1597f3651a..7ac6396d31 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -222,6 +222,14 @@ browse-url-man-function
(function :tag "Other function"))
:version "26.1")
+(defcustom browse-url-irc-function 'browse-url-irc
+ "Function to open an irc:// link."
+ :type '(choice
+ (function-item :tag "Emacs IRC" :value browse-url-irc)
+ (const :tag "None" nil)
+ (function :tag "Other function"))
+ :version "29.1")
+
(defcustom browse-url-button-regexp
(concat
"\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|gemini\\|"
@@ -547,6 +555,11 @@ browse-url--browser-kind-man
(function-put 'browse-url--man 'browse-url-browser-kind
#'browse-url--browser-kind-man)
+(defun browse-url--irc (url &rest args)
+ "Call `browse-url-irc-function' with URL and ARGS."
+ (funcall browse-url-irc-function url args))
+(function-put 'browse-url--irc 'browse-url-browser-kind 'internal)
+
(defun browse-url--browser (url &rest args)
"Call `browse-url-browser-function' with URL and ARGS."
(funcall browse-url-browser-function url args))
@@ -565,6 +578,7 @@ browse-url--non-html-file-url-p
(defvar browse-url-default-handlers
'(("\\`mailto:" . browse-url--mailto)
("\\`man:" . browse-url--man)
+ ("\\`irc6?s?://" . browse-url--irc)
(browse-url--non-html-file-url-p . browse-url-emacs))
"Like `browse-url-handlers' but populated by Emacs and packages.
@@ -1510,6 +1524,16 @@ browse-url-text-emacs
(function-put 'browse-url-text-emacs 'browse-url-browser-kind 'internal)
+;; --- irc ---
+
+;;;###autoload
+(defun browse-url-irc (url &rest _)
+ "Call `url-irc' directly after parsing URL.
+This function is a fit for options like `gnus-button-alist'."
+ (url-irc (url-generic-parse-url url)))
+
+(function-put 'browse-url-irc 'browse-url-browser-kind 'internal)
+
;; --- mailto ---
(autoload 'rfc6068-parse-mailto-url "rfc6068")
diff --git a/lisp/url/url-irc.el b/lisp/url/url-irc.el
index 9161f7d13e..f97b6de6fe 100644
--- a/lisp/url/url-irc.el
+++ b/lisp/url/url-irc.el
@@ -38,11 +38,13 @@ url-irc-function
PORT - the port number of the IRC server to contact
CHANNEL - What channel on the server to visit right away (can be nil)
USER - What username to use
-PASSWORD - What password to use"
+PASSWORD - What password to use.
+ SCHEME - a URI scheme, such as \"irc\" or \"ircs\""
:type '(choice (const :tag "rcirc" :value url-irc-rcirc)
(const :tag "ERC" :value url-irc-erc)
(const :tag "ZEN IRC" :value url-irc-zenirc)
(function :tag "Other"))
+ :version "29.1" ; Added SCHEME
:group 'url)
;; External.
@@ -51,7 +53,7 @@ url-irc-function
(defvar zenirc-server-alist)
(defvar zenirc-buffer-name)
-(defun url-irc-zenirc (host port channel user password)
+(defun url-irc-zenirc (host port channel user password _)
(let ((zenirc-buffer-name (if (and user host port)
(format "%s@%s:%d" user host port)
(format "%s:%d" host port)))
@@ -65,14 +67,14 @@ url-irc-zenirc
(insert "/join " channel)
(zenirc-send-line))))
-(defun url-irc-rcirc (host port channel user password)
+(defun url-irc-rcirc (host port channel user password _)
(let ((chan (when channel (concat "#" channel))))
(rcirc-connect host port user nil nil (when chan (list chan)) password)
(when chan
(switch-to-buffer (concat chan "@" host)))))
-(defun url-irc-erc (host port channel user password)
- (erc-handle-irc-url host port channel user password))
+(defun url-irc-erc (host port channel user password scheme)
+ (erc-handle-irc-url host port channel user password scheme))
;;;###autoload
(defun url-irc (url)
@@ -80,16 +82,32 @@ url-irc
(port (url-port url))
(pass (url-password url))
(user (url-user url))
- (chan (url-filename url)))
+ (chan (url-filename url))
+ (type (url-type url))
+ (compatp (eql 5 (cdr (func-arity url-irc-function)))))
(if (url-target url)
(setq chan (concat chan "#" (url-target url))))
(if (string-match "^/" chan)
(setq chan (substring chan 1 nil)))
(if (= (length chan) 0)
(setq chan nil))
- (funcall url-irc-function host port chan user pass)
+ (when compatp
+ (lwarn 'url :error "Obsolete value for `url-irc-function'"))
+ (apply url-irc-function
+ host port chan user pass (unless compatp (list type)))
nil))
+;;;; ircs://
+
+;; The function `url-scheme-get-property' tries and fails to load the
+;; nonexistent url-ircs.el but falls back to using the following:
+
+;;;###autoload
+(defconst url-ircs-default-port 6697 "Default port for IRCS connections.")
+
+;;;###autoload
+(defalias 'url-ircs 'url-irc)
+
(provide 'url-irc)
;;; url-irc.el ends here
diff --git a/test/lisp/net/browse-url-tests.el b/test/lisp/net/browse-url-tests.el
index 1c993958b8..dc81976821 100644
--- a/test/lisp/net/browse-url-tests.el
+++ b/test/lisp/net/browse-url-tests.el
@@ -56,6 +56,15 @@ browse-url-tests-select-handler-man
'browse-url--man))
(should-not (browse-url-select-handler "man:ls" 'external)))
+(ert-deftest browse-url-tests-select-handler-irc ()
+ (should (eq (browse-url-select-handler "irc://localhost" 'internal)
+ 'browse-url--irc))
+ (should-not (browse-url-select-handler "irc://localhost" 'external))
+ (should (eq (browse-url-select-handler "irc6://localhost")
+ 'browse-url--irc))
+ (should (eq (browse-url-select-handler "ircs://tester@irc.gnu.org/#chan")
+ 'browse-url--irc)))
+
(ert-deftest browse-url-tests-select-handler-file ()
(should (eq (browse-url-select-handler "file://foo.txt")
'browse-url-emacs))
--
2.38.1
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0002-Refactor-erc-select-read-args.patch --]
[-- Type: text/x-patch, Size: 11099 bytes --]
From 3b6eeb91e25da87c33a0da6a4b768cbbc60d96d8 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 11 Jul 2022 05:14:57 -0700
Subject: [PATCH 2/5] Refactor erc-select-read-args
* lisp/erc/erc-backend.el (erc--server-connect-dumb-ipv6-regexp): Add
liberal pattern for matching bracketed IPv6 addresses.
(erc-server-connect): Remove brackets from IPv6 hosts before
connecting.
* lisp/erc/erc.el (erc--ensure-url): Add compat adapter to massage
partial URLs given as input that may be missing the scheme:// portion.
(erc-select-read-args): Keep bracketed IPv6 hosts
intact. Make this function fully URL-aware (was only partially so).
Accept optional `input' argument.
* lisp/erc/erc-tests.el (erc-tests--ipv6-examples,
erc--server-connect-dumb-ipv6-regexp, erc-select-read-args): Add test
reading user input during interactive invocations of entry points.
(Bug#56514.)
---
lisp/erc/erc-backend.el | 6 +++
lisp/erc/erc.el | 83 ++++++++++++++++++-----------------
test/lisp/erc/erc-tests.el | 89 ++++++++++++++++++++++++++++++++++++++
3 files changed, 136 insertions(+), 42 deletions(-)
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 026b34849a..1cb0876367 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -625,12 +625,18 @@ erc-open-network-stream
(let ((p (plist-put parameters :nowait t)))
(apply #'open-network-stream name buffer host service p)))
+(defvar erc--server-connect-dumb-ipv6-regexp
+ ;; Not for validation (gives false positives).
+ (rx bot "[" (group (+ (any xdigit digit ":.")) (? "%" (+ alnum))) "]" eot))
+
(defun erc-server-connect (server port buffer &optional client-certificate)
"Perform the connection and login using the specified SERVER and PORT.
We will store server variables in the buffer given by BUFFER.
CLIENT-CERTIFICATE may optionally be used to specify a TLS client
certificate to use for authentication when connecting over
TLS (see `erc-session-client-certificate' for more details)."
+ (when (string-match erc--server-connect-dumb-ipv6-regexp server)
+ (setq server (match-string 1 server)))
(let ((msg (erc-format-message 'connect ?S server ?p port)) process
(args `(,(format "erc-%s-%s" server port) nil ,server ,port)))
(when client-certificate
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 6b14cf87e2..7f25afa8c5 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -70,7 +70,7 @@
(require 'auth-source)
(require 'time-date)
(require 'iso8601)
-(eval-when-compile (require 'subr-x))
+(eval-when-compile (require 'subr-x) (require 'url-parse))
(defconst erc-version "5.4.1"
"This version of ERC.")
@@ -2094,52 +2094,51 @@ erc-after-connect
:group 'erc-hooks
:type '(repeat function))
+(defun erc--ensure-url (input)
+ (unless (string-match (rx bot "irc" (? "6") (? "s") "://") input)
+ (when (and (string-match (rx (? (+ any) "@")
+ (or (group (* (not "[")) ":" (* any))
+ (+ any))
+ ":" (+ (not (any ":]"))) eot)
+ input)
+ (match-beginning 1))
+ (setq input (concat "[" (substring input (match-beginning 1)) "]")))
+ (setq input (concat "irc://" input)))
+ input)
+
;;;###autoload
(defun erc-select-read-args ()
"Prompt the user for values of nick, server, port, and password."
- (let (user-input server port nick passwd)
- (setq user-input (read-string
- "IRC server: "
- (erc-compute-server) 'erc-server-history-list))
-
- (if (string-match "\\(.*\\):\\(.*\\)\\'" user-input)
- (setq port (erc-string-to-port (match-string 2 user-input))
- user-input (match-string 1 user-input))
- (setq port
- (erc-string-to-port (read-string
- "IRC port: " (erc-port-to-string
- (erc-compute-port))))))
-
- (if (string-match "\\`\\(.*\\)@\\(.*\\)" user-input)
- (setq nick (match-string 1 user-input)
- user-input (match-string 2 user-input))
- (setq nick
- (if (erc-already-logged-in server port nick)
- (read-string
- (erc-format-message 'nick-in-use ?n nick)
- nick 'erc-nick-history-list)
- (read-string
- "Nickname: " (erc-compute-nick nick)
- 'erc-nick-history-list))))
-
- (setq server user-input)
-
- (setq passwd (if erc-prompt-for-password
- (read-passwd "Server password: ")
- (with-suppressed-warnings ((obsolete erc-password))
- erc-password)))
+ (require 'url-parse)
+ (let* ((input (let ((d (erc-compute-server)))
+ (read-string (format "Server (default is %S): " d)
+ nil 'erc-server-history-list d)))
+ ;; For legacy reasons, also accept a URL without a scheme.
+ (url (url-generic-parse-url (erc--ensure-url input)))
+ (server (url-host url))
+ (sp (and (or (string-suffix-p "s" (url-type url))
+ (and (equal server erc-default-server)
+ (not (string-prefix-p "irc://" input))))
+ 'ircs-u))
+ (port (or (url-portspec url)
+ (erc-compute-port
+ (let ((d (erc-compute-port sp))) ; may be a string
+ (read-string (format "Port (default is %s): " 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.
+ (nick (or (url-user url)
+ (let ((d (erc-compute-nick)))
+ (read-string (format "Nickname (default is %S): " d)
+ nil 'erc-nick-history-list d))))
+ (passwd (or (url-password url)
+ (if erc-prompt-for-password
+ (read-passwd "Server password (optional): ")
+ (with-suppressed-warnings ((obsolete erc-password))
+ erc-password)))))
(when (and passwd (string= "" passwd))
(setq passwd nil))
-
- (while (erc-already-logged-in server port nick)
- ;; hmm, this is a problem when using multiple connections to a bnc
- ;; with the same nick. Currently this code prevents using more than one
- ;; bnc with the same nick. actually it would be nice to have
- ;; bncs transparent, so that erc-compute-buffer-name displays
- ;; the server one is connected to.
- (setq nick (read-string
- (erc-format-message 'nick-in-use ?n nick)
- nick 'erc-nick-history-list)))
(list :server server :port port :nick nick :password passwd)))
;;;###autoload
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index c88dd9888d..f72db816af 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -953,4 +953,93 @@ erc-message
(kill-buffer "ExampleNet")
(kill-buffer "#chan")))
+(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"
+ "1:2:3:4:5:6:77:88" "::ffff:255.255.255.255"
+ "fe08::7:8" "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
+ "1:2:3:4:5:6:7:8" "1::" "1:2:3:4:5:6:7::" "1::8"
+ "1:2:3:4:5:6::8" "1:2:3:4:5:6::8" "1::7:8" "1:2:3:4:5::7:8"
+ "1:2:3:4:5::8" "1::6:7:8" "1:2:3:4::6:7:8" "1:2:3:4::8"
+ "1::5:6:7:8" "1:2:3::5:6:7:8" "1:2:3::8" "1::4:5:6:7:8"
+ "1:2::4:5:6:7:8" "1:2::8" "1::3:4:5:6:7:8" "1::3:4:5:6:7:8"
+ "1::8" "::2:3:4:5:6:7:8" "::2:3:4:5:6:7:8" "::8"
+ "::" "fe08::7:8%eth0" "fe08::7:8%1" "::255.255.255.255"
+ "::ffff:255.255.255.255" "::ffff:0:255.255.255.255"
+ "2001:db8:3:4::192.0.2.33" "64:ff9b::192.0.2.33"))
+
+(ert-deftest erc--server-connect-dumb-ipv6-regexp ()
+ (dolist (a erc-tests--ipv6-examples)
+ (should-not (string-match erc--server-connect-dumb-ipv6-regexp a))
+ (should (string-match erc--server-connect-dumb-ipv6-regexp
+ (concat "[" a "]")))))
+
+(ert-deftest erc-select-read-args ()
+
+ (ert-info ("Defaults to TLS")
+ (should (equal (ert-simulate-keys "\r\r\r\r"
+ (erc-select-read-args))
+ (list :server "irc.libera.chat"
+ :port 6697
+ :nick (user-login-name)
+ :password nil))))
+
+ (ert-info ("Override default TLS")
+ (should (equal (ert-simulate-keys "irc://irc.libera.chat\r\r\r\r"
+ (erc-select-read-args))
+ (list :server "irc.libera.chat"
+ :port 6667
+ :nick (user-login-name)
+ :password nil))))
+
+ (ert-info ("Address includes port")
+ (should (equal (ert-simulate-keys
+ "localhost:6667\rnick\r\r"
+ (erc-select-read-args))
+ (list :server "localhost"
+ :port 6667
+ :nick "nick"
+ :password nil))))
+
+ (ert-info ("Address includes nick, password skipped via option")
+ (should (equal (ert-simulate-keys "nick@localhost:6667\r"
+ (let (erc-prompt-for-password)
+ (erc-select-read-args)))
+ (list :server "localhost"
+ :port 6667
+ :nick "nick"
+ :password nil))))
+
+ (ert-info ("Addresss includes nick and password")
+ (should (equal (ert-simulate-keys "nick:sesame@localhost:6667\r"
+ (erc-select-read-args))
+ (list :server "localhost"
+ :port 6667
+ :nick "nick"
+ :password "sesame"))))
+
+ (ert-info ("IPv6 address plain")
+ (should (equal (ert-simulate-keys "::1\r\r\r\r"
+ (erc-select-read-args))
+ (list :server "[::1]"
+ :port 6667
+ :nick (user-login-name)
+ :password nil))))
+
+ (ert-info ("IPv6 address with port")
+ (should (equal (ert-simulate-keys "[::1]:6667\r\r\r"
+ (erc-select-read-args))
+ (list :server "[::1]"
+ :port 6667
+ :nick (user-login-name)
+ :password nil))))
+
+ (ert-info ("IPv6 address includes nick")
+ (should (equal (ert-simulate-keys "nick@[::1]:6667\r\r"
+ (erc-select-read-args))
+ (list :server "[::1]"
+ :port 6667
+ :nick "nick"
+ :password nil)))))
+
;;; erc-tests.el ends here
--
2.38.1
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0003-Default-to-TLS-port-when-calling-erc-tls-from-lisp.patch --]
[-- Type: text/x-patch, Size: 4806 bytes --]
From 6f3717e60b223090d84a198ee80c1d90ec7a0263 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 11 Jul 2022 05:14:57 -0700
Subject: [PATCH 3/5] Default to TLS port when calling erc-tls from lisp
* lisp/erc/erc.el (erc-normalize-port): Add standard IANA port-name
mappings for 6667 and 6697.
(erc-open): Add note to doc string explaining that params `connect'
and `channel' are mutually exclusive.
(erc-tls): Call `erc-compute-port' with override.
(erc-compute-port): Call `erc-normalize-port' with result'.
* test/lisp/erc/erc-tests.el (erc-tls): Add simplistic test focusing
on default parameters. (Bug#56514.)
---
lisp/erc/erc.el | 17 +++++++++++----
test/lisp/erc/erc-tests.el | 42 ++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 7f25afa8c5..28370d7724 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1542,6 +1542,11 @@ erc-normalize-port
* ircs -> 994
* ircd -> 6667
* ircd-dalnet -> 7000"
+ ;; These were updated somewhat in 2022 to reflect modern standards
+ ;; and practices. See also:
+ ;;
+ ;; https://datatracker.ietf.org/doc/html/rfc7194#section-1
+ ;; https://www.iana.org/assignments/service-names-port-numbers
(cond
((symbolp port)
(erc-normalize-port (symbol-name port)))
@@ -1554,8 +1559,10 @@ erc-normalize-port
194)
((string-equal port "ircs")
994)
- ((string-equal port "ircd")
+ ((string-equal port "ircu") 6667) ; 6665-6669
+ ((string-equal port "ircd") ; nonstandard (irc-serv is 529)
6667)
+ ((string-equal port "ircs-u") 6697)
((string-equal port "ircd-dalnet")
7000)
(t
@@ -1924,7 +1931,9 @@ erc-open
If CONNECT is non-nil, connect to the server. Otherwise assume
already connected and just create a separate buffer for the new
-target CHANNEL.
+target given by CHANNEL, meaning these parameters are mutually
+exclusive. Note that CHANNEL may also be a query; its name has
+been retained for historical reasons.
Use PASSWD as user password on the server. If TGT-LIST is
non-nil, use it to initialize `erc-default-recipients'.
@@ -2183,7 +2192,7 @@ 'erc-ssl
;;;###autoload
(cl-defun erc-tls (&key (server (erc-compute-server))
- (port (erc-compute-port))
+ (port (erc-compute-port 'ircs-u))
(nick (erc-compute-nick))
(user (erc-compute-user))
password
@@ -6390,7 +6399,7 @@ erc-compute-port
- PORT (the argument passed to this function)
- The `erc-port' option
- The `erc-default-port' variable"
- (or port erc-port erc-default-port))
+ (erc-normalize-port (or port erc-port erc-default-port)))
;; time routines
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index f72db816af..db54cb4889 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1042,4 +1042,46 @@ erc-select-read-args
:nick "nick"
:password nil)))))
+(ert-deftest erc-tls ()
+ (let (calls)
+ (cl-letf (((symbol-function 'user-login-name)
+ (lambda (&optional _) "tester"))
+ ((symbol-function 'erc-open)
+ (lambda (&rest r) (push r calls))))
+
+ (ert-info ("Defaults")
+ (erc-tls)
+ (should (equal (pop calls)
+ '("irc.libera.chat" 6697 "tester" "unknown" t
+ nil nil nil nil nil "user" nil))))
+
+ (ert-info ("Full")
+ (erc-tls :server "irc.gnu.org"
+ :port 7000
+ :user "bobo"
+ :nick "bob"
+ :full-name "Bob's Name"
+ :password "bob:changeme"
+ :client-certificate t
+ :id 'GNU.org)
+ (should (equal (pop calls)
+ '("irc.gnu.org" 7000 "bob" "Bob's Name" t
+ "bob:changeme" nil nil nil t "bobo" GNU.org))))
+
+ ;; Values are often nil when called by lisp code, which leads to
+ ;; null params. This is why `erc-open' recomputes almost
+ ;; everything.
+ (ert-info ("Fallback")
+ (let ((erc-nick "bob")
+ (erc-server "irc.gnu.org")
+ (erc-email-userid "bobo")
+ (erc-user-full-name "Bob's Name"))
+ (erc-tls :server nil
+ :port 7000
+ :nick nil
+ :password "bob:changeme"))
+ (should (equal (pop calls)
+ '(nil 7000 nil "Bob's Name" t
+ "bob:changeme" nil nil nil nil "bobo" nil)))))))
+
;;; erc-tests.el ends here
--
2.38.1
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0004-Add-optional-server-param-to-erc-networks-determine.patch --]
[-- Type: text/x-patch, Size: 2937 bytes --]
From 960c1ec9f753a9c61f6353c12a8e616bd4121ca5 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 11 Jul 2022 05:14:57 -0700
Subject: [PATCH 4/5] Add optional server param to erc-networks--determine
* lisp/erc/erc-networks.el (erc-networks--determine): Accept optional
`server' argument.
* test/lisp/erc/erc-networks-tests.el (erc-networks--determine): Add
test. (Bug#56514.)
---
lisp/erc/erc-networks.el | 9 +++++----
test/lisp/erc/erc-networks-tests.el | 17 +++++++++++++++++
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index dba6ead073..b3e5fcf1a3 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -1256,14 +1256,15 @@ erc-set-network-name
(defconst erc-networks--name-missing-sentinel (gensym "Unknown ")
"Value to cover rare case of a literal NETWORK=nil.")
-(defun erc-networks--determine ()
+(defun erc-networks--determine (&optional server)
"Return the name of the network as a symbol.
-Search `erc-networks-alist' for a known entity matching
+Search `erc-networks-alist' for a known entity matching SERVER or
`erc-server-announced-name'. If that fails, use the display name
given by the `RPL_ISUPPORT' NETWORK parameter."
(or (cl-loop for (name matcher) in erc-networks-alist
- when (and matcher (string-match (concat matcher "\\'")
- erc-server-announced-name))
+ when (and matcher
+ (string-match (concat matcher "\\'")
+ (or server erc-server-announced-name)))
return name)
(and-let* ((vanity (erc--get-isupport-entry 'NETWORK 'single))
((intern vanity))))
diff --git a/test/lisp/erc/erc-networks-tests.el b/test/lisp/erc/erc-networks-tests.el
index 32bdfa11ff..fc12bf7ce3 100644
--- a/test/lisp/erc/erc-networks-tests.el
+++ b/test/lisp/erc/erc-networks-tests.el
@@ -1704,4 +1704,21 @@ erc-networks--update-server-identity--triple-new
(erc-networks-tests--clean-bufs))
+(ert-deftest erc-networks--determine ()
+ (should (eq (erc-networks--determine "irc.libera.chat") 'Libera.Chat))
+ (should (eq (erc-networks--determine "irc.oftc.net") 'OFTC))
+ (should (eq (erc-networks--determine "irc.dal.net") 'DALnet))
+
+ (let ((erc-server-announced-name "zirconium.libera.chat"))
+ (should (eq (erc-networks--determine) 'Libera.Chat)))
+ (let ((erc-server-announced-name "weber.oftc.net"))
+ (should (eq (erc-networks--determine) 'OFTC)))
+ (let ((erc-server-announced-name "redemption.ix.us.dal.net"))
+ (should (eq (erc-networks--determine) 'DALnet)))
+
+ ;; Failure
+ (let ((erc-server-announced-name "irc-us2.alphachat.net"))
+ (should (eq (erc-networks--determine)
+ erc-networks--name-missing-sentinel))))
+
;;; erc-networks-tests.el ends here
--
2.38.1
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #7: 0005-Improve-new-connections-in-erc-handle-irc-url.patch --]
[-- Type: text/x-patch, Size: 15917 bytes --]
From 2d35563e0ac22686bb69100536692cb026fc67f2 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Mon, 11 Jul 2022 05:14:57 -0700
Subject: [PATCH 5/5] Improve new connections in erc-handle-irc-url
* lisp/erc/erc.el (erc-handle-irc-url): Add optional "scheme"
parameter. Fix `erc-open' invocation so that the server buffer is
named correctly by deferring to a new customizable opener. Arrange
for JOINing a channel in a manner similar to ERC's autojoin module.
(erc-url-connect-function): Add new option for creating a new ERC
connection based on info parsed from a URL.
(erc--url-default-connect-function): New function to serve as an
interactive-only fallback when a user hasn't specified a URL connect
function.
* lisp/erc/erc-compat.el (erc-compat--29-browse-url--irc): Add new
compatibility function for `browse-url-irc' and add it to
`browse-url-default-handlers' on Emacs versions below 29.
* lisp/erc/erc-tests.el (erc-tests--make-server-buf,
erc-tests--make-client-buf): Add helpers for creating dummy ERC
buffers.
(erc-handle-irc-url): Add test.
* test/lisp/erc/erc-scenarios-misc.el (erc-scenarios-handle-irc-url):
Add new test.
* test/lisp/erc/resources/join/legacy/foonet.eld: Relax
timeout. (Bug#56514.)
---
doc/misc/erc.texi | 28 ++++++
lisp/erc/erc-compat.el | 19 ++++
lisp/erc/erc.el | 92 ++++++++++++++----
test/lisp/erc/erc-scenarios-misc.el | 28 ++++++
test/lisp/erc/erc-tests.el | 95 +++++++++++++++++++
.../lisp/erc/resources/join/legacy/foonet.eld | 2 +-
6 files changed, 246 insertions(+), 18 deletions(-)
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index 3db83197f9..9742fc3c22 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -79,6 +79,7 @@ Top
* Connecting:: Ways of connecting to an IRC server.
* Sample Configuration:: An example configuration file.
+* Integrations:: Integrations available for ERC.
* Options:: Options that are available for ERC.
@end detailmenu
@@ -526,6 +527,7 @@ Advanced Usage
@menu
* Connecting:: Ways of connecting to an IRC server.
* Sample Configuration:: An example configuration file.
+* Integrations:: Integrations available for ERC.
* Options:: Options that are available for ERC.
@end menu
@@ -990,6 +992,32 @@ Sample Configuration
;; (setq erc-kill-server-buffer-on-quit t)
@end lisp
+@node Integrations
+@section Integrations
+@cindex integrations
+
+@subheading URL
+For anything to work, you'll want to set @code{url-irc-function} to
+@code{url-irc-erc}. As a rule of thumb, libraries relying directly on
+@code{url-retrieve} should be fine out the box from Emacs 29.1 onward.
+On older versions of Emacs, you may need to @code{(require 'erc)}
+beforehand. @pxref{Retrieving URLs,,, url, URL}.
+
+For other apps and libraries, such as those relying on the
+higher-level @code{browse-url}, you'll oftentimes be asked to specify
+a pattern, sometimes paired with a function that accepts a string URL
+as a first argument. For example, with EWW, you may need to tack
+something like @code{"\\|\\`irc6?s?:"} onto the end of
+@code{eww-use-browse-url}. But with @code{gnus-button-alist}, you'll
+need a function as well:
+
+@lisp
+ '("\\birc6?s?://[][a-z0-9.,@@_:+%?&/#-]+" 0 t browse-url-irc 0)
+@end lisp
+
+@noindent
+Users on Emacs 28 and below may need to use @code{browse-url} instead.
+
@node Options
@section Options
@cindex options
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index 03bd8f1352..340d90ba96 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -32,6 +32,7 @@
;;; Code:
(require 'compat nil 'noerror)
+(eval-when-compile (require 'url-parse))
;;;###autoload(autoload 'erc-define-minor-mode "erc-compat")
(define-obsolete-function-alias 'erc-define-minor-mode
@@ -168,6 +169,24 @@ erc-compat--with-memoization
`(cl--generic-with-memoization ,table ,@forms))
(t `(progn ,@forms))))
+(defvar url-irc-function)
+
+(defun erc-compat--29-browse-url-irc (string &rest _)
+ (cl-assert (< emacs-major-version 29))
+ (require 'url-irc)
+ (let* ((url (url-generic-parse-url string))
+ (url-irc-function
+ (if (function-equal url-irc-function 'url-irc-erc)
+ (lambda (host port chan user pass)
+ (erc-handle-irc-url host port chan user pass (url-type url)))
+ url-irc-function)))
+ (url-irc url)))
+
+(when (< emacs-major-version 29)
+ (unless (assoc "\\`irc6?s?://" browse-url-default-handlers)
+ (push '("\\`irc6?s?://" . erc-compat--29-browse-url-irc)
+ browse-url-default-handlers)))
+
(provide 'erc-compat)
;;; erc-compat.el ends here
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 28370d7724..cfd1c34ef0 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -7169,25 +7169,83 @@ erc-get-parsed-vector-type
;; Teach url.el how to open irc:// URLs with ERC.
;; To activate, customize `url-irc-function' to `url-irc-erc'.
-;; FIXME change user to nick, and use API to find server buffer
+(defcustom erc-url-connect-function nil
+ "When non-nil, a function used to connect to an IRC URL.
+Called with a string meant to represent a URL scheme, like
+\"ircs\", followed by any number of keyword arguments recognized
+by `erc' and `erc-tls'."
+ :group 'erc
+ :package-version '(ERC . "5.4.1") ; FIXME increment on release
+ :type '(choice (const nil) function))
+
+(defun erc--url-default-connect-function (scheme &rest plist)
+ (let* ((ircsp (if scheme
+ (string-suffix-p "s" scheme)
+ (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-nick (or (plist-get plist :nick) erc-nick))
+ (erc-password (plist-get plist :password))
+ (args (erc-select-read-args)))
+ (unless ircsp
+ (setq ircsp (eql 6697 erc-port)))
+ (apply (if ircsp #'erc-tls #'erc) args)))
+
;;;###autoload
-(defun erc-handle-irc-url (host port channel user password)
- "Use ERC to IRC on HOST:PORT in CHANNEL as USER with PASSWORD.
+(defun erc-handle-irc-url (host port channel nick password &optional scheme)
+ "Use ERC to IRC on HOST:PORT in CHANNEL.
If ERC is already connected to HOST:PORT, simply /join CHANNEL.
-Otherwise, connect to HOST:PORT as USER and /join CHANNEL."
- (let ((server-buffer
- (car (erc-buffer-filter
- (lambda ()
- (and (string-equal erc-session-server host)
- (= erc-session-port port)
- (erc-open-server-buffer-p)))))))
- (with-current-buffer (or server-buffer (current-buffer))
- (if (and server-buffer channel)
- (erc-cmd-JOIN channel)
- (erc-open host port (or user (erc-compute-nick)) (erc-compute-full-name)
- (not server-buffer) password nil channel
- (when server-buffer
- (get-buffer-process server-buffer)))))))
+Otherwise, connect to HOST:PORT as NICK and /join CHANNEL.
+
+Beginning with ERC 5.5, new connections require human intervention.
+Customize `erc-url-connect-function' to override this."
+ (when (eql port 0) (setq port nil))
+ (let* ((net (erc-networks--determine host))
+ (server-buffer
+ ;; Viable matches may slip through the cracks for unknown
+ ;; networks. Additional passes could likely improve things.
+ (car (erc-buffer-filter
+ (lambda ()
+ (and (not erc--target)
+ (erc-server-process-alive)
+ ;; Always trust a matched network.
+ (or (and net (eq net (erc-network)))
+ (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)))))))))
+ key deferred)
+ (unless server-buffer
+ (setq deferred t
+ server-buffer (apply (or erc-url-connect-function
+ #'erc--url-default-connect-function)
+ scheme
+ :server host
+ `(,@(and port (list :port port))
+ ,@(and nick (list :nick nick))
+ ,@(and password `(:password ,password))))))
+ (when channel
+ ;; These aren't percent-decoded by default
+ (when (string-prefix-p "%" channel)
+ (setq channel (url-unhex-string channel)))
+ (cl-multiple-value-setq (channel key) (split-string channel "[?]"))
+ (if deferred
+ ;; Alternatively, we could make this a defmethod, so when
+ ;; autojoin is loaded, it can do its own thing. Also, as
+ ;; with `erc-once-with-server-event', it's fine to set local
+ ;; hooks here because they're killed when reconnecting.
+ (with-current-buffer server-buffer
+ (letrec ((f (lambda (&rest _)
+ (remove-hook 'erc-after-connect f t)
+ (erc-cmd-JOIN channel key))))
+ (add-hook 'erc-after-connect f nil t)))
+ (with-current-buffer server-buffer
+ (erc-cmd-JOIN channel key))))))
(provide 'erc)
diff --git a/test/lisp/erc/erc-scenarios-misc.el b/test/lisp/erc/erc-scenarios-misc.el
index ded620ccc1..8557a77906 100644
--- a/test/lisp/erc/erc-scenarios-misc.el
+++ b/test/lisp/erc/erc-scenarios-misc.el
@@ -177,4 +177,32 @@ erc-scenarios-dcc-chat-accept
(erc-scenarios-common-say "Hi")
(funcall expect 10 "Hola")))))
+(defvar url-irc-function)
+
+(ert-deftest erc-scenarios-handle-irc-url ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "join/legacy")
+ (dumb-server (erc-d-run "localhost" t 'foonet))
+ (port (process-contact dumb-server :service))
+ (expect (erc-d-t-make-expecter))
+ (url-irc-function 'url-irc-erc)
+ (erc-url-connect-function
+ (lambda (scheme &rest r)
+ (ert-info ("Connect to foonet")
+ (should (equal scheme "irc"))
+ (with-current-buffer (apply #'erc `(:full-name "tester" ,@r))
+ (should (string= (buffer-name)
+ (format "127.0.0.1:%d" port)))
+ (current-buffer))))))
+
+ (with-temp-buffer
+ (insert (format ";; irc://tester:changeme@127.0.0.1:%d/#chan" port))
+ (goto-char 10)
+ (browse-url-at-point))
+
+ (ert-info ("Connected")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+ (funcall expect 10 "welcome")))))
+
;;; erc-scenarios-misc.el ends here
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index db54cb4889..f83e8c8717 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1084,4 +1084,99 @@ erc-tls
'(nil 7000 nil "Bob's Name" t
"bob:changeme" nil nil nil nil "bobo" nil)))))))
+(defun erc-tests--make-server-buf (name)
+ (with-current-buffer (get-buffer-create name)
+ (erc-mode)
+ (setq erc-server-process (start-process "sleep" (current-buffer)
+ "sleep" "1")
+ erc-session-server (concat "irc." name ".org")
+ erc-session-port 6667
+ erc-network (intern name))
+ (set-process-query-on-exit-flag erc-server-process nil)
+ (current-buffer)))
+
+(defun erc-tests--make-client-buf (server name)
+ (unless (bufferp server)
+ (setq server (get-buffer server)))
+ (with-current-buffer (get-buffer-create name)
+ (erc-mode)
+ (setq erc--target (erc--target-from-string name))
+ (dolist (v '(erc-server-process
+ erc-session-server
+ erc-session-port
+ erc-network))
+ (set v (buffer-local-value v server)))
+ (current-buffer)))
+
+(ert-deftest erc-handle-irc-url ()
+ (let* (calls
+ rvbuf
+ erc-networks-alist
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook
+ (erc-url-connect-function
+ (lambda (&rest r)
+ (push r calls)
+ (if (functionp rvbuf) (funcall rvbuf) rvbuf))))
+
+ (cl-letf (((symbol-function 'erc-cmd-JOIN)
+ (lambda (&rest r) (push r calls))))
+
+ (with-current-buffer (erc-tests--make-server-buf "foonet")
+ (setq rvbuf (current-buffer)))
+ (erc-tests--make-server-buf "barnet")
+ (erc-tests--make-server-buf "baznet")
+
+ (ert-info ("Unknown network")
+ (erc-handle-irc-url "irc.foonet.org" 6667 "#chan" nil nil "irc")
+ (should (equal '("#chan" nil) (pop calls)))
+ (should-not calls))
+
+ (ert-info ("Unknown network, no port")
+ (erc-handle-irc-url "irc.foonet.org" nil "#chan" nil nil "irc")
+ (should (equal '("#chan" nil) (pop calls)))
+ (should-not calls))
+
+ (ert-info ("Known network, no port")
+ (setq erc-networks-alist '((foonet "irc.foonet.org")))
+ (erc-handle-irc-url "irc.foonet.org" nil "#chan" nil nil "irc")
+ (should (equal '("#chan" nil) (pop calls)))
+ (should-not calls))
+
+ (ert-info ("Known network, different port")
+ (erc-handle-irc-url "irc.foonet.org" 6697 "#chan" nil nil "irc")
+ (should (equal '("#chan" nil) (pop calls)))
+ (should-not calls))
+
+ (ert-info ("Known network, existing chan with key")
+ (erc-tests--make-client-buf "foonet" "#chan")
+ (erc-handle-irc-url "irc.foonet.org" nil "#chan?sec" nil nil "irc")
+ (should (equal '("#chan" "sec") (pop calls)))
+ (should-not calls))
+
+ (ert-info ("Unknown network, connect, no chan")
+ (erc-handle-irc-url "irc.gnu.org" nil nil nil nil "irc")
+ (should (equal '("irc" :server "irc.gnu.org") (pop calls)))
+ (should-not calls))
+
+ (ert-info ("Unknown network, connect, chan")
+ (with-current-buffer "foonet"
+ (should-not (local-variable-p 'erc-after-connect)))
+ (setq rvbuf (lambda () (erc-tests--make-server-buf "gnu")))
+ (erc-handle-irc-url "irc.gnu.org" nil "#spam" nil nil "irc")
+ (should (equal '("irc" :server "irc.gnu.org") (pop calls)))
+ (should-not calls)
+ (with-current-buffer "gnu"
+ (should (local-variable-p 'erc-after-connect))
+ (funcall (car erc-after-connect))
+ (should (equal '("#spam" nil) (pop calls)))
+ (should-not erc-after-connect)
+ (should-not (local-variable-p 'erc-after-connect)))
+ (should-not calls))))
+
+ (when noninteractive
+ (kill-buffer "foonet")
+ (kill-buffer "barnet")
+ (kill-buffer "baznet")
+ (kill-buffer "#chan")))
+
;;; erc-tests.el ends here
diff --git a/test/lisp/erc/resources/join/legacy/foonet.eld b/test/lisp/erc/resources/join/legacy/foonet.eld
index 344ba7c1da..4025094a59 100644
--- a/test/lisp/erc/resources/join/legacy/foonet.eld
+++ b/test/lisp/erc/resources/join/legacy/foonet.eld
@@ -1,5 +1,5 @@
;; -*- mode: lisp-data; -*-
-((pass 1 "PASS :changeme"))
+((pass 10 "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")
--
2.38.1
next prev parent reply other threads:[~2022-11-11 14:05 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <87pmiabvd5.fsf@neverwas.me>
2022-07-12 12:49 ` bug#56514: 29.0.50; Improve ERC's URI scheme integration for irc:// links Lars Ingebrigtsen
[not found] ` <87edyqzeag.fsf@gnus.org>
2022-07-13 14:44 ` J.P.
[not found] ` <874jzl2hsv.fsf@neverwas.me>
2022-07-13 15:55 ` Stefan Kangas
[not found] ` <CADwFkmkgXKH3y2i1si76V_NOuSyJENVrCLdEJ1AfDHEv9qh8jw@mail.gmail.com>
2022-07-14 7:00 ` J.P.
[not found] ` <874jzkuqk3.fsf@neverwas.me>
2022-11-08 14:09 ` J.P.
2022-11-08 15:16 ` Stefan Kangas
[not found] ` <CADwFkm=d+8wb6o_EwvKZWR7yc4tbwscgZ-YPzBnSqty42W+_Pg@mail.gmail.com>
2022-11-09 13:41 ` J.P.
2022-11-08 14:41 ` bug#56514: ircs:// integration for rcirc (bug#56514) J.P.
2022-11-11 14:05 ` J.P. [this message]
[not found] ` <87iljl4meb.fsf@neverwas.me>
2022-11-16 14:22 ` bug#56514: 29.0.50; Improve ERC's URI scheme integration for irc:// links J.P.
2022-12-30 14:20 ` J.P.
2023-11-06 2:34 ` J.P.
[not found] ` <875y2flics.fsf@neverwas.me>
2023-11-11 10:15 ` Eli Zaretskii
2022-07-12 8:14 J.P.
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='87iljl4meb.fsf__20759.4029417791$1668175592$gmane$org@neverwas.me' \
--to=jp@neverwas.me \
--cc=56514@debbugs.gnu.org \
--cc=emacs-erc@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).