From b5269970249871a8889950a3e47bdff51eb0420c Mon Sep 17 00:00:00 2001 From: plugd Date: Tue, 9 Aug 2022 12:53:31 +1000 Subject: [PATCH 01/12] Make elpher-go-current respect default url scheme. --- elpher.el | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/elpher.el b/elpher.el index b18a897..53ca1e4 100644 --- a/elpher.el +++ b/elpher.el @@ -2267,7 +2267,8 @@ supports the old protocol elpher, where the link is self-contained." "Go to a particular gopher site HOST-OR-URL. When run interactively HOST-OR-URL is read from the minibuffer." (interactive (list - (read-string (format "Visit URL (default scheme %s): " (elpher-get-default-url-scheme))))) + (read-string (format "Visit URL (default scheme %s): " + (elpher-get-default-url-scheme))))) (let ((trimmed-host-or-url (string-trim host-or-url))) (unless (string-empty-p trimmed-host-or-url) (let ((page (elpher-page-from-url trimmed-host-or-url @@ -2284,10 +2285,14 @@ Unlike `elpher-go', the reader is initialized with the URL of the current page." (interactive) (let* ((address (elpher-page-address elpher-current-page)) - (url (read-string (format "Visit URL (default scheme %s): " (elpher-get-default-url-scheme)) + (url (read-string (format "Visit URL (default scheme %s): " + (elpher-get-default-url-scheme)) (elpher-address-to-url address)))) - (unless (string-empty-p (string-trim url)) - (elpher-visit-page (elpher-page-from-url url))))) + (let ((trimmed-url (string-trim url))) + (unless (string-empty-p trimmed-url) + (elpher-with-clean-buffer + (elpher-visit-page + (elpher-page-from-url trimmed-url (elpher-get-default-url-scheme)))))))) (defun elpher-redraw () "Redraw current page." -- 2.20.1 From 01494219e616a5739e278aba9838a64ae3ddbebd Mon Sep 17 00:00:00 2001 From: plugd Date: Wed, 12 Oct 2022 09:37:31 +0200 Subject: [PATCH 02/12] Opened issue regarding client certificate scope. --- ISSUES.org | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ISSUES.org b/ISSUES.org index 60c6a99..ba0185c 100644 --- a/ISSUES.org +++ b/ISSUES.org @@ -4,7 +4,20 @@ * Open Bugs -** OPEN Sanitize certificate names +** OPEN Improve client certificate scope :gemini: +:LOGBOOK: +- State "OPEN" from [2022-10-12 Wed 09:33] +:END: + +Once activated, elpher continues to use a client certificate +for any connections to the host on which it was activated. +However, it's now common to restrict certificates also to paths +_below_ the path where the certificate was activated. + +I.e. gemini://example.com/~userA/ certificates are not applied +automatically to gemini://example.com/~userB/. + +** OPEN Sanitize certificate names :gemini: :LOGBOOK: - State "OPEN" from [2020-06-22 Mon 10:32] :END: -- 2.20.1 From 786bf0699b970d302e932d0d1004d7db182574d1 Mon Sep 17 00:00:00 2001 From: plugd Date: Thu, 23 Mar 2023 13:48:24 +0100 Subject: [PATCH 03/12] Sensibly handle C-g when requesting gemini input. --- elpher.el | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/elpher.el b/elpher.el index 53ca1e4..966e659 100644 --- a/elpher.el +++ b/elpher.el @@ -1,6 +1,6 @@ ;;; elpher.el --- A friendly gopher and gemini client -*- lexical-binding: t -*- -;; Copyright (C) 2019-2022 Tim Vaughan +;; Copyright (C) 2019-2023 Tim Vaughan ;; Copyright (C) 2020-2022 Elpher contributors (See info manual for full list) ;; Author: Tim Vaughan @@ -1352,14 +1352,17 @@ that the response was malformed." (elpher-with-clean-buffer (insert "Gemini server is requesting input.")) (let* ((query-string - (if (eq (elt response-code 1) ?1) - (read-passwd (concat response-meta ": ")) - (read-string (concat response-meta ": ")))) + (with-local-quit + (if (eq (elt response-code 1) ?1) + (read-passwd (concat response-meta ": ")) + (read-string (concat response-meta ": "))))) (query-address (seq-copy (elpher-page-address elpher-current-page))) (old-fname (url-filename query-address))) - (setf (url-filename query-address) - (concat old-fname "?" (url-build-query-string `((,query-string))))) - (elpher-get-gemini-response query-address renderer))) + (if (not query-string) + (elpher-visit-previous-page) + (setf (url-filename query-address) + (concat old-fname "?" (url-build-query-string `((,query-string))))) + (elpher-get-gemini-response query-address renderer)))) (?2 ; Normal response (funcall renderer response-body response-meta)) (?3 ; Redirect -- 2.20.1 From 2f66d418cf4ed176b12c24eaadb5240b49da0448 Mon Sep 17 00:00:00 2001 From: plugd Date: Thu, 23 Mar 2023 13:54:16 +0100 Subject: [PATCH 04/12] Patch release. --- RELEASE | 8 +++++++- config.mk | 2 +- elpher-pkg.el | 2 +- elpher.el | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/RELEASE b/RELEASE index ade220d..1a08de8 100644 --- a/RELEASE +++ b/RELEASE @@ -7,9 +7,15 @@ When preparing a new release, set the version number: 2. in elpher.el: metadata at the top 3. in elpher.el: definition of elpher-version 4. in elpher-pkg.el: second argument to 'define-package' + +For anything besides a patch release, a note describing +the changes should be added to the documentation. In +the instance that the documentation itself is significantly +changed, also update the documentation version: + 5. in elpher.texi: 'settitle' declaration at the top -Make sure the documentation is up to date and builds: +After any documentation updates, make sure it builds: make elpher.info elpher.html elpher.pdf diff --git a/config.mk b/config.mk index e406f6b..801cb55 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ PKG = elpher -VERSION = 3.4.2 +VERSION = 3.4.3 INSTALLINFO = install-info MAKEINFO = makeinfo diff --git a/elpher-pkg.el b/elpher-pkg.el index d7becef..bb8d23f 100644 --- a/elpher-pkg.el +++ b/elpher-pkg.el @@ -1,4 +1,4 @@ -(define-package "elpher" "3.4.2" "A friendly gopher and gemini client" +(define-package "elpher" "3.4.3" "A friendly gopher and gemini client" '((emacs "27.1")) :keywords ("convenience") :authors (("Tim Vaughan" . "plugd@thelambdalab.xyz")) diff --git a/elpher.el b/elpher.el index 966e659..bacb047 100644 --- a/elpher.el +++ b/elpher.el @@ -5,7 +5,7 @@ ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 3.4.2 +;; Version: 3.4.3 ;; Keywords: comm gopher ;; Homepage: https://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "27.1")) @@ -71,7 +71,7 @@ ;;; Global constants ;; -(defconst elpher-version "3.4.2" +(defconst elpher-version "3.4.3" "Current version of elpher.") (defconst elpher-margin-width 6 -- 2.20.1 From 31641d57f7bb95c8a8903a8d2c7ac8104603b7c4 Mon Sep 17 00:00:00 2001 From: plugd Date: Wed, 29 Mar 2023 09:31:42 +0200 Subject: [PATCH 05/12] Added gophers (gopher with TLS) to external link handlers. --- elpher.el | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/elpher.el b/elpher.el index bacb047..809e41f 100644 --- a/elpher.el +++ b/elpher.el @@ -2191,6 +2191,11 @@ supports the old protocol elpher, where the link is self-contained." :export (lambda (link description format _plist) (elpher-org-export-link link description format "gopher")) :follow (lambda (link _arg) (elpher-org-follow-link link "gopher"))) + (org-link-set-parameters + "gophers" + :export (lambda (link description format _plist) + (elpher-org-export-link link description format "gophers")) + :follow (lambda (link _arg) (elpher-org-follow-link link "gophers"))) (org-link-set-parameters "finger" :export (lambda (link description format _plist) @@ -2212,7 +2217,7 @@ supports the old protocol elpher, where the link is self-contained." (if (boundp 'browse-url-default-handlers) (add-to-list 'browse-url-default-handlers - '("^\\(gopher\\|finger\\|gemini\\)://" . elpher-browse-url-elpher)) + '("^\\(gopher\\|gophers\\|finger\\|gemini\\)://" . elpher-browse-url-elpher)) ;; Patch `browse-url-browser-function' for older ones. The value of ;; that variable is `browse-url-default-browser' by default, so ;; that's the function that gets advised. If the value is an alist, @@ -2223,7 +2228,7 @@ supports the old protocol elpher, where the link is self-contained." (lambda (url &rest _args) "Handle gemini, gopher, and finger schemes using Elpher." (let ((scheme (downcase (car (split-string url ":" t))))) - (if (member scheme '("gemini" "gopher" "finger")) + (if (member scheme '("gemini" "gopher" "gophers" "finger")) ;; `elpher-go' always returns nil, which will stop the ;; advice chain here in a before-while (elpher-go url) @@ -2238,13 +2243,13 @@ supports the old protocol elpher, where the link is self-contained." ;; Make mu4e aware of the gemini world (setq mu4e~view-beginning-of-url-regexp - "\\(?:https?\\|gopher\\|finger\\|gemini\\)://\\|mailto:") + "\\(?:https?\\|gopher\\|gophers\\|finger\\|gemini\\)://\\|mailto:") ;; eww: ;; Let elpher handle gemini, gopher links in eww buffer. (setq eww-use-browse-url - "\\`mailto:\\|\\(\\`gemini\\|\\`gopher\\|\\`finger\\)://") + "\\`mailto:\\|\\(\\`gemini\\|\\`gopher\\|\\`gophers\\|\\`finger\\)://") ;;; Interactive procedures -- 2.20.1 From 5982f725ac58e53efe63e47ffa28bc41c8306318 Mon Sep 17 00:00:00 2001 From: plugd Date: Fri, 31 Mar 2023 09:40:40 +0200 Subject: [PATCH 06/12] Cleanly handle C-g at client certificate prompt. --- elpher.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/elpher.el b/elpher.el index 809e41f..2ba5e8e 100644 --- a/elpher.el +++ b/elpher.el @@ -1391,7 +1391,8 @@ that the response was malformed." (insert "Gemini server is requesting a valid TLS certificate:\n\n")) (auto-fill-mode 1) (elpher-gemini-insert-text response-meta)) - (let ((chosen-certificate (elpher-choose-client-certificate))) + (let ((chosen-certificate + (with-local-quit (elpher-choose-client-certificate)))) (unless chosen-certificate (error "Gemini server requires a client certificate and none was provided")) (setq elpher-client-certificate chosen-certificate)) -- 2.20.1 From 593310c145f1836781b16abed4503969e642212e Mon Sep 17 00:00:00 2001 From: plugd Date: Fri, 31 Mar 2023 09:49:24 +0200 Subject: [PATCH 07/12] Added missing @node for several sections in the texinfo. --- elpher.texi | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/elpher.texi b/elpher.texi index ff2979a..c9e3838 100644 --- a/elpher.texi +++ b/elpher.texi @@ -1,7 +1,7 @@ \input texinfo @c -*-texinfo-*- @setfilename elpher.info -@settitle Elpher Manual v3.4.0 +@settitle Elpher Manual v3.4.1 @dircategory Emacs @direntry @@ -11,7 +11,7 @@ @copying This manual documents Elpher, a gopher and gemini client for Emacs. -Copyright @copyright{} 2019-2022 Tim Vaughan@* +Copyright @copyright{} 2019-2023 Tim Vaughan@* Copyright @copyright{} 2021 Daniel Semyonov@* Copyright @copyright{} 2021 Alex Schroeder @@ -66,12 +66,30 @@ the file COPYING in the same directory as this file for more details. @detailmenu --- The Detailed Node Listing --- +Installation + +* Installing from ELPA or MELPA:: Installing from a package repository +* Installing by hand:: Installing directly from the source + Navigation * Within-page navigation:: Moving about within a page * Between-page navigation:: Commands for moving between pages * History and Caching:: Explanation of how Elpher represents history +Gemini support + +* Client Certificates for Gemini:: Accessing secure gemini pages +* Hiding preformatted text in text/gemini documents:: An accessibility option + +News + +* v3.4.0:: +* v3.3.0:: +* v3.2.0:: +* v3.1.0:: +* v3.0.0:: + @end detailmenu @end menu @@ -123,6 +141,12 @@ have some ideas. @node Installation, Quick Start, Introduction, Top @chapter Installation +@menu +* Installing from ELPA or MELPA:: Installing from a package repository +* Installing by hand:: Installing directly from the source +@end menu + +@node Installing from ELPA or MELPA, , Installation, Installation @section Installing from ELPA or MELPA Elpher is available on the non-GNU ELPA package archive. If you are @@ -147,6 +171,7 @@ install Elpher: @kbd{M-x package-delete @key{RET} elpher @key{RET}}. @end example +@node Installing by hand, , Installing from ELPA or MELPA, Installation @section Installing by hand It is also possible to install Elpher directly by downloading the file @@ -574,6 +599,12 @@ I should emphasize however that, while it is definitely functional, Elpher's gemini support is still experimental, and various aspects will change as the protocol develops further. +@menu +* Client Certificates for Gemini:: Accessing secure gemini pages +* Hiding preformatted text in text/gemini documents:: An accessibility option +@end menu + +@node Client Certificates for Gemini, , Gemini support, Gemini support @section Client Certificates for Gemini Gemini makes explicit use of the client certificate mechanism that TLS @@ -641,6 +672,7 @@ In either case, ``forgetting'' means that the details of the key and certificate file pair are erased from memory. Furthermore, in the case of throw-away certificates, the corresponding files are deleted. +@node Hiding preformatted text in text/gemini documents, , Client Certificates for Gemini, Gemini support @section Hiding preformatted text in text/gemini documents Preformatted text is often used to display ``ASCII art'' or other @@ -818,6 +850,15 @@ See the customization group itself for details. This chapter documents the major changes introduced by Elpher releases. +@menu +* v3.4.0:: +* v3.3.0:: +* v3.2.0:: +* v3.1.0:: +* v3.0.0:: +@end menu + +@node v3.4.0, , News, News @section v3.4.0 @subsection Toggling preformatted text visibility @@ -832,6 +873,7 @@ block. This feature is intended to make it easier for people using screen readers to read text/gemini documents. +@node v3.3.0, , v3.4.0, News @section v3.3.0 This version includes lots of bug fixes, as well as a couple of new @@ -853,6 +895,7 @@ characters and displays the decoded IRI. (For security reasons, the @code{elpher-info-current} command (@kbd{I}) always displays both the decoded IRI and the URI when they differ.) +@node v3.2.0, , v3.3.0, News @section v3.2.0 This version introduces several minor changes which, together, make it @@ -879,6 +922,7 @@ of the document to be loaded as elpher's ``start page''. By default this is set to @samp{about:welcome}, but any elpher-accessible URL is valid. @pxref{Customization} for suggestions. +@node v3.1.0, , v3.2.0, News @section v3.1.0 @subsection Bookmarks system @@ -901,6 +945,7 @@ use the customization variable @code{elpher-use-emacs-bookmark-menu} to have the @key{B} key open the Emacs bookmark menu directly, as in the previous release. +@node v3.0.0, , v3.1.0, News @section v3.0.0 @subsection Bookmarks system -- 2.20.1 From 82b66a5b91eb3a67a6e23b3d5fa0a518054cb6f8 Mon Sep 17 00:00:00 2001 From: plugd Date: Thu, 4 May 2023 13:23:00 +0200 Subject: [PATCH 08/12] Prespecify client certs for certain URLs. --- elpher.el | 77 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/elpher.el b/elpher.el index 2ba5e8e..5f215db 100644 --- a/elpher.el +++ b/elpher.el @@ -6,7 +6,7 @@ ;; Author: Tim Vaughan ;; Created: 11 April 2019 ;; Version: 3.4.3 -;; Keywords: comm gopher +;; Keywords: comm gopher gemini ;; Homepage: https://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "27.1")) @@ -241,6 +241,13 @@ meaningfully." "Label of button used to toggle formatted text." :type '(string)) +(defcustom elpher-client-certificate-map nil + "An alist representing a mapping between gemini URLs and the names +of client certificates which will be automatically activated for those +URLs. Beware that the certificates will also be active for all +subdirectories of the given URLs." + :type '(alist :key-type string :value-type string)) + ;; Face customizations (defgroup elpher-faces nil @@ -951,7 +958,8 @@ the host operating system and the local network capabilities.)" ;;; Client-side TLS Certificate Management ;; -(defun elpher-generate-certificate (common-name key-file cert-file &optional temporary) +(defun elpher-generate-certificate (common-name key-file cert-file url-prefix + &optional temporary) "Generate a key and a self-signed client TLS certificate using openssl. The Common Name field of the certificate is set to COMMON-NAME. The @@ -979,22 +987,21 @@ by `gnutls-boot-parameters`." "-subj" (concat "/CN=" common-name) "-keyout" exp-key-file "-out" exp-cert-file) - (list (elpher-address-host (elpher-page-address elpher-current-page)) - temporary exp-key-file exp-cert-file)) + (list url-prefix temporary exp-key-file exp-cert-file)) (error (message "Check that openssl is installed, or customize `elpher-openssl-command`.") (error "Program 'openssl', required for certificate generation, not found"))))) -(defun elpher-generate-throwaway-certificate () +(defun elpher-generate-throwaway-certificate (url-prefix) "Generate and return details of a throwaway certificate. The key and certificate files will be deleted when they are no longer needed for this session." (let* ((file-base (make-temp-name "elpher")) (key-file (concat temporary-file-directory file-base ".key")) (cert-file (concat temporary-file-directory file-base ".crt"))) - (elpher-generate-certificate file-base key-file cert-file t))) + (elpher-generate-certificate file-base key-file cert-file url-prefix t))) -(defun elpher-generate-persistent-certificate (file-base common-name) +(defun elpher-generate-persistent-certificate (file-base common-name url-prefix) "Generate and return details of a persistent certificate. The argument FILE-BASE is used as the base for the key and certificate files, while COMMON-NAME specifies the common name field of the @@ -1003,20 +1010,20 @@ certificate. The key and certificate files are written to in `elpher-certificate-directory'." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) - (elpher-generate-certificate common-name key-file cert-file))) + (elpher-generate-certificate common-name key-file cert-file url-prefix))) -(defun elpher-get-existing-certificate (file-base) +(defun elpher-get-existing-certificate (file-base url-prefix) "Return a certificate object corresponding to an existing certificate. It is assumed that the key files FILE-BASE.key and FILE-BASE.crt exist in the directory `elpher-certificate-directory'." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) - (list (elpher-address-host (elpher-page-address elpher-current-page)) + (list (elpher-address-to-url (elpher-page-address elpher-current-page)) nil (expand-file-name key-file) (expand-file-name cert-file)))) -(defun elpher-install-and-use-existing-certificate (key-file-src cert-file-src file-base) +(defun elpher-install-certificate (key-file-src cert-file-src file-base) "Install a key+certificate file pair in `elpher-certificate-directory'. The strings KEY-FILE-SRC and CERT-FILE-SRC are the existing key and certificate files to install. The argument FILE-BASE is used as the @@ -1026,9 +1033,12 @@ base for the installed key and certificate files." (if (or (file-exists-p key-file) (file-exists-p cert-file)) (error "A certificate with base name %s is already installed" file-base)) + (unless (and (file-exists-p key-file-src) + (file-exists-p cert-file-src)) + (error "Either of the key or certificate files do not exist")) (copy-file key-file-src key-file) (copy-file cert-file-src cert-file) - (list (elpher-address-host (elpher-page-address elpher-current-page)) + (list (elpher-address-to-url (elpher-page-address elpher-current-page)) nil (expand-file-name key-file) (expand-file-name cert-file)))) @@ -1068,8 +1078,8 @@ that certificate matches the host in ADDRESS. If `elpher-current-certificate' is non-nil, and its host name doesn't match that of ADDRESS, the certificate is forgotten." (if elpher-client-certificate - (if (string= (car elpher-client-certificate) - (elpher-address-host address)) + (if (string-prefix-p (car elpher-client-certificate) + (elpher-address-to-url address)) (list (cddr elpher-client-certificate)) (elpher-forget-current-certificate) (message "Disabling client certificate for new host") @@ -1392,7 +1402,9 @@ that the response was malformed." (auto-fill-mode 1) (elpher-gemini-insert-text response-meta)) (let ((chosen-certificate - (with-local-quit (elpher-choose-client-certificate)))) + (with-local-quit + (elpher-acquire-client-certificate + (elpher-address-to-url (elpher-page-address elpher-current-page)))))) (unless chosen-certificate (error "Gemini server requires a client certificate and none was provided")) (setq elpher-client-certificate chosen-certificate)) @@ -1402,17 +1414,35 @@ that the response was malformed." (error "Gemini server response unknown: %s %s" response-code response-meta)))))) +(defun elpher-acquire-client-certificate (url-prefix) + "Select a pre-defined client certificate or prompt for one. +In this case, \"pre-defined\" means a certificate provided by +the `elpher-client-certificate-map' variable." + (let ((entry (assoc url-prefix + elpher-client-certificate-map + #'string-prefix-p))) + (if entry + (let ((cert-url-prefix (car entry)) + (cert-name (cadr entry))) + (message "Using certificate \"%s\" specified in elpher-client-certificate-map" + cert-name) + (elpher-get-existing-certificate cert-name cert-url-prefix)) + (elpher-prompt-for-client-certificate url-prefix)))) + (defun elpher--read-answer-polyfill (question answers) "Polyfill for `read-answer' in Emacs 26.1. QUESTION is a string containing a question, and ANSWERS -is a list of possible answers." - (completing-read question (mapcar 'identity answers))) +is a list of possible answers, or an alist whose keys +are the possible answers." + (completing-read question answers)) (if (fboundp 'read-answer) (defalias 'elpher-read-answer 'read-answer) (defalias 'elpher-read-answer 'elpher--read-answer-polyfill)) -(defun elpher-choose-client-certificate () + + +(defun elpher-prompt-for-client-certificate (url-prefix) "Prompt for a client certificate to use to establish a TLS connection." (let* ((read-answer-short t)) (pcase (read-answer "What do you want to do? " @@ -1433,7 +1463,7 @@ is a list of possible answers." nil (if (member file-base existing-certificates) (setq elpher-client-certificate - (elpher-get-existing-certificate file-base)) + (elpher-get-existing-certificate file-base url-prefix)) (pcase (read-answer "Generate new certificate or install externally-generated one? " '(("new" ?n "generate new certificate") @@ -1446,15 +1476,16 @@ is a list of possible answers." file-base))) (message "New key and self-signed certificate written to %s" elpher-certificate-directory) - (elpher-generate-persistent-certificate file-base common-name))) + (elpher-generate-persistent-certificate file-base + common-name + url-prefix))) ("install" (let* ((cert-file (read-file-name "Certificate file: " nil nil t)) (key-file (read-file-name "Key file: " nil nil t))) (message "Key and certificate installed in %s for future use" elpher-certificate-directory) - (elpher-install-and-use-existing-certificate key-file - cert-file - file-base))) + (elpher-install-certificate key-file cert-file file-base + url-prefix))) ("abort" nil)))))) ("abort" nil)))) -- 2.20.1 From 81f2883614c303184116449ec3583ef5c136ec2f Mon Sep 17 00:00:00 2001 From: plugd Date: Fri, 5 May 2023 10:17:17 +0200 Subject: [PATCH 09/12] Fixed small cert-related bugs, updated docs. --- ISSUES.org | 49 ++++++++++++++++++---------------- config.mk | 2 +- elpher-pkg.el | 2 +- elpher.el | 74 ++++++++++++++++++++++++++++++++------------------- elpher.texi | 42 +++++++++++++++++++++-------- 5 files changed, 106 insertions(+), 63 deletions(-) diff --git a/ISSUES.org b/ISSUES.org index ba0185c..363c25f 100644 --- a/ISSUES.org +++ b/ISSUES.org @@ -4,19 +4,6 @@ * Open Bugs -** OPEN Improve client certificate scope :gemini: -:LOGBOOK: -- State "OPEN" from [2022-10-12 Wed 09:33] -:END: - -Once activated, elpher continues to use a client certificate -for any connections to the host on which it was activated. -However, it's now common to restrict certificates also to paths -_below_ the path where the certificate was activated. - -I.e. gemini://example.com/~userA/ certificates are not applied -automatically to gemini://example.com/~userB/. - ** OPEN Sanitize certificate names :gemini: :LOGBOOK: - State "OPEN" from [2020-06-22 Mon 10:32] @@ -138,6 +125,20 @@ pop the stack, meaning that subsequent "u" commands would succeed. The fix is just to zero out the history list in the `elpher` function just as `elpher-current-page` is cleared. +** CLOSED Improve client certificate scope :gemini: +:LOGBOOK: +- State "CLOSED" from "OPEN" [2023-05-05 Fri 10:09] +- State "OPEN" from [2022-10-12 Wed 09:33] +:END: + +Once activated, elpher continues to use a client certificate +for any connections to the host on which it was activated. +However, it's now common to restrict certificates also to paths +_below_ the path where the certificate was activated. + +I.e. gemini://example.com/~userA/ certificates are not applied +automatically to gemini://example.com/~userB/. + * Open Enhancements ** OPEN Allow multiple elpher buffers [33%] @@ -151,16 +152,6 @@ this can happen: - [X] shift history out of node tree and into separate stack - [ ] make history stack variables buffer-local - [ ] have elpher-with-clean-buffer select appropriate buffer - -** OPEN Make installing existing certificates easier - :LOGBOOK: - - State "OPEN" from "CLOSED" [2020-06-22 Mon 10:34] - :END: - -It's naive to think that people don't have client certificates created -outside of elpher. Thus we need some easy way to "install" these -certificates, either by copying them or by referencing them in some -way. * Closed Enhancements @@ -329,3 +320,15 @@ and there aren't any other hotspots. - State "CLOSED" from "OPEN" [2021-08-09 Mon 17:46] :END: This used to be available, but was removed during a refactor. + + +** CLOSED Make installing existing certificates easier + :LOGBOOK: + - State "CLOSED" from "OPEN" [2023-05-05 Fri 10:10] + - State "OPEN" from "CLOSED" [2020-06-22 Mon 10:34] + :END: + +It's naive to think that people don't have client certificates created +outside of elpher. Thus we need some easy way to "install" these +certificates, either by copying them or by referencing them in some +way. diff --git a/config.mk b/config.mk index 801cb55..11af4ef 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ PKG = elpher -VERSION = 3.4.3 +VERSION = 3.5.0 INSTALLINFO = install-info MAKEINFO = makeinfo diff --git a/elpher-pkg.el b/elpher-pkg.el index bb8d23f..5cdbef2 100644 --- a/elpher-pkg.el +++ b/elpher-pkg.el @@ -1,4 +1,4 @@ -(define-package "elpher" "3.4.3" "A friendly gopher and gemini client" +(define-package "elpher" "3.5.0" "A friendly gopher and gemini client" '((emacs "27.1")) :keywords ("convenience") :authors (("Tim Vaughan" . "plugd@thelambdalab.xyz")) diff --git a/elpher.el b/elpher.el index 5f215db..608f09d 100644 --- a/elpher.el +++ b/elpher.el @@ -5,7 +5,7 @@ ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 3.4.3 +;; Version: 3.5.0 ;; Keywords: comm gopher gemini ;; Homepage: https://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "27.1")) @@ -71,7 +71,7 @@ ;;; Global constants ;; -(defconst elpher-version "3.4.3" +(defconst elpher-version "3.5.0" "Current version of elpher.") (defconst elpher-margin-width 6 @@ -241,11 +241,12 @@ meaningfully." "Label of button used to toggle formatted text." :type '(string)) -(defcustom elpher-client-certificate-map nil - "An alist representing a mapping between gemini URLs and the names -of client certificates which will be automatically activated for those -URLs. Beware that the certificates will also be active for all -subdirectories of the given URLs." +(defcustom elpher-certificate-map nil + "Register client certificates to be used for gemini URLs. +This variable contains an alist representing a mapping between gemini +URLs and the names of client certificates which will be automatically +activated for those URLs. Beware that the certificates will also be +active for all subdirectories of the given URLs." :type '(alist :key-type string :value-type string)) ;; Face customizations @@ -973,7 +974,8 @@ when the certificate is no longer needed for the current session. Otherwise, the certificate will be given a 100 year expiration period and the files will not be deleted. -The function returns a list containing the current host name, the +The function returns a list containing the URL-PREFIX of addresses +for which the certificate should be used in this session, the temporary flag, and the key and cert file names in the form required by `gnutls-boot-parameters`." (let ((exp-key-file (expand-file-name key-file)) @@ -995,7 +997,10 @@ by `gnutls-boot-parameters`." (defun elpher-generate-throwaway-certificate (url-prefix) "Generate and return details of a throwaway certificate. The key and certificate files will be deleted when they are no -longer needed for this session." +longer needed for this session. + +The certificate will be marked as applying to all addresses with URLs +starting with URL-PREFIX." (let* ((file-base (make-temp-name "elpher")) (key-file (concat temporary-file-directory file-base ".key")) (cert-file (concat temporary-file-directory file-base ".crt"))) @@ -1007,7 +1012,10 @@ The argument FILE-BASE is used as the base for the key and certificate files, while COMMON-NAME specifies the common name field of the certificate. -The key and certificate files are written to in `elpher-certificate-directory'." +The key and certificate files are written to in `elpher-certificate-directory'. + +In this session, the certificate will remain active for all addresses +having URLs starting with URL-PREFIX." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) (elpher-generate-certificate common-name key-file cert-file url-prefix))) @@ -1015,19 +1023,25 @@ The key and certificate files are written to in `elpher-certificate-directory'." (defun elpher-get-existing-certificate (file-base url-prefix) "Return a certificate object corresponding to an existing certificate. It is assumed that the key files FILE-BASE.key and FILE-BASE.crt exist in -the directory `elpher-certificate-directory'." +the directory `elpher-certificate-directory'. + +In this session, the certificate will remain active for all addresses +having URLs starting with URL-PREFIX." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) - (list (elpher-address-to-url (elpher-page-address elpher-current-page)) + (list url-prefix nil (expand-file-name key-file) (expand-file-name cert-file)))) -(defun elpher-install-certificate (key-file-src cert-file-src file-base) +(defun elpher-install-certificate (key-file-src cert-file-src file-base url-prefix) "Install a key+certificate file pair in `elpher-certificate-directory'. The strings KEY-FILE-SRC and CERT-FILE-SRC are the existing key and certificate files to install. The argument FILE-BASE is used as the -base for the installed key and certificate files." +base for the installed key and certificate files. + +In this session, the certificate will remain active for all addresses +having URLs starting with URL-PREFIX." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) (if (or (file-exists-p key-file) @@ -1038,7 +1052,7 @@ base for the installed key and certificate files." (error "Either of the key or certificate files do not exist")) (copy-file key-file-src key-file) (copy-file cert-file-src cert-file) - (list (elpher-address-to-url (elpher-page-address elpher-current-page)) + (list url-prefix nil (expand-file-name key-file) (expand-file-name cert-file)))) @@ -1064,7 +1078,7 @@ are also deleted." (when (cadr elpher-client-certificate) (delete-file (elt elpher-client-certificate 2)) (delete-file (elt elpher-client-certificate 3))) - (setq elpher-client-certificate nil) + (setq-local elpher-client-certificate nil) (if (called-interactively-p 'any) (message "Client certificate forgotten."))))) @@ -1072,10 +1086,10 @@ are also deleted." "Retrieve the `gnutls-boot-parameters'-compatable keylist. This is obtained from the client certificate described by -`elpher-current-certificate', if one is available and the host for -that certificate matches the host in ADDRESS. +`elpher-current-certificate', if one is available and the +URL prefix for that certificate matches ADDRESS. -If `elpher-current-certificate' is non-nil, and its host name doesn't +If `elpher-current-certificate' is non-nil, and its URL prefix doesn't match that of ADDRESS, the certificate is forgotten." (if elpher-client-certificate (if (string-prefix-p (car elpher-client-certificate) @@ -1407,7 +1421,7 @@ that the response was malformed." (elpher-address-to-url (elpher-page-address elpher-current-page)))))) (unless chosen-certificate (error "Gemini server requires a client certificate and none was provided")) - (setq elpher-client-certificate chosen-certificate)) + (setq-local elpher-client-certificate chosen-certificate)) (elpher-with-clean-buffer) (elpher-get-gemini-response (elpher-page-address elpher-current-page) renderer)) (_other @@ -1417,15 +1431,18 @@ that the response was malformed." (defun elpher-acquire-client-certificate (url-prefix) "Select a pre-defined client certificate or prompt for one. In this case, \"pre-defined\" means a certificate provided by -the `elpher-client-certificate-map' variable." +the `elpher-certificate-map' variable. + +For this session, the certificate will remain active for all addresses +having URLs begining with URL-PREFIX." (let ((entry (assoc url-prefix - elpher-client-certificate-map + elpher-certificate-map #'string-prefix-p))) (if entry (let ((cert-url-prefix (car entry)) (cert-name (cadr entry))) - (message "Using certificate \"%s\" specified in elpher-client-certificate-map" - cert-name) + (message "Using certificate \"%s\" specified in elpher-certificate-map with prefix \"%s\"" + cert-name cert-url-prefix) (elpher-get-existing-certificate cert-name cert-url-prefix)) (elpher-prompt-for-client-certificate url-prefix)))) @@ -1443,7 +1460,10 @@ are the possible answers." (defun elpher-prompt-for-client-certificate (url-prefix) - "Prompt for a client certificate to use to establish a TLS connection." + "Prompt for a client certificate to use to establish a TLS connection. + +In this session, the chosen certificate will remain active for all +addresses with URLs matching URL-PREFIX." (let* ((read-answer-short t)) (pcase (read-answer "What do you want to do? " '(("throwaway" ?t @@ -1453,7 +1473,7 @@ are the possible answers." ("abort" ?a "stop immediately"))) ("throwaway" - (setq elpher-client-certificate (elpher-generate-throwaway-certificate))) + (setq-local elpher-client-certificate (elpher-generate-throwaway-certificate url-prefix))) ("persistent" (let* ((existing-certificates (elpher-list-existing-certificates)) (file-base (completing-read @@ -1462,7 +1482,7 @@ are the possible answers." (if (string-empty-p (string-trim file-base)) nil (if (member file-base existing-certificates) - (setq elpher-client-certificate + (setq-local elpher-client-certificate (elpher-get-existing-certificate file-base url-prefix)) (pcase (read-answer "Generate new certificate or install externally-generated one? " '(("new" ?n diff --git a/elpher.texi b/elpher.texi index c9e3838..8b5c65d 100644 --- a/elpher.texi +++ b/elpher.texi @@ -1,7 +1,7 @@ \input texinfo @c -*-texinfo-*- @setfilename elpher.info -@settitle Elpher Manual v3.4.1 +@settitle Elpher Manual v3.5.0 @dircategory Emacs @direntry @@ -84,6 +84,7 @@ Gemini support News +* v3.5.0:: * v3.4.0:: * v3.3.0:: * v3.2.0:: @@ -146,7 +147,7 @@ have some ideas. * Installing by hand:: Installing directly from the source @end menu -@node Installing from ELPA or MELPA, , Installation, Installation +@node Installing from ELPA or MELPA, Installing by hand, Installation, Installation @section Installing from ELPA or MELPA Elpher is available on the non-GNU ELPA package archive. If you are @@ -604,7 +605,7 @@ change as the protocol develops further. * Hiding preformatted text in text/gemini documents:: An accessibility option @end menu -@node Client Certificates for Gemini, , Gemini support, Gemini support +@node Client Certificates for Gemini, Hiding preformatted text in text/gemini documents, Gemini support, Gemini support @section Client Certificates for Gemini Gemini makes explicit use of the client certificate mechanism that TLS @@ -658,10 +659,11 @@ Alternatively, pressing the @key{i} key will cause Elpher to ask for the locations of existing key and certificate files to add to @code{elpher-certificate-directory} under the chosen name. -Once a certificate is selected, it will be used for all subsequent TLS -transactions to the host for which the certificate was created. -It is immediately ``forgotten'' when a TLS connection to another host -is attempted, or the following command is issued: +Once a certificate is selected, it will be used for all subsequent +gemini requests involving URLs begining with the URL for for which the +certificate was created. It is immediately ``forgotten'' when a TLS +connection to a non-matching URL is attempted, or the following command +is issued: @table @asis @keycmd{@key{F},elpher-forget-certificate} @@ -672,6 +674,11 @@ In either case, ``forgetting'' means that the details of the key and certificate file pair are erased from memory. Furthermore, in the case of throw-away certificates, the corresponding files are deleted. +Persistant client certificates can be added to the alist contained in the +customization variable @code{elpher-certificate-map} so that they are +automatically activated whenever a gemini page with the matching URL +prefix is visited. + @node Hiding preformatted text in text/gemini documents, , Client Certificates for Gemini, Gemini support @section Hiding preformatted text in text/gemini documents @@ -851,6 +858,7 @@ See the customization group itself for details. This chapter documents the major changes introduced by Elpher releases. @menu +* v3.5.0:: * v3.4.0:: * v3.3.0:: * v3.2.0:: @@ -858,7 +866,19 @@ This chapter documents the major changes introduced by Elpher releases. * v3.0.0:: @end menu -@node v3.4.0, , News, News +@node v3.5.0, v3.4.0, News, News +@section v3.5.0 + +@subsection Automatic activation of client certificates in gemini + +This version introduces a new customization variable +@code{elpher-certificate-map} which allows you to pre-specify +a set of gemini URLs and the client certificates which should +be used when accessing them. + +@xref{Client Certificates for Gemini} for more details. + +@node v3.4.0, v3.3.0, v3.5.0, News @section v3.4.0 @subsection Toggling preformatted text visibility @@ -873,7 +893,7 @@ block. This feature is intended to make it easier for people using screen readers to read text/gemini documents. -@node v3.3.0, , v3.4.0, News +@node v3.3.0, v3.2.0, v3.4.0, News @section v3.3.0 This version includes lots of bug fixes, as well as a couple of new @@ -895,7 +915,7 @@ characters and displays the decoded IRI. (For security reasons, the @code{elpher-info-current} command (@kbd{I}) always displays both the decoded IRI and the URI when they differ.) -@node v3.2.0, , v3.3.0, News +@node v3.2.0, v3.1.0, v3.3.0, News @section v3.2.0 This version introduces several minor changes which, together, make it @@ -922,7 +942,7 @@ of the document to be loaded as elpher's ``start page''. By default this is set to @samp{about:welcome}, but any elpher-accessible URL is valid. @pxref{Customization} for suggestions. -@node v3.1.0, , v3.2.0, News +@node v3.1.0, v3.0.0, v3.2.0, News @section v3.1.0 @subsection Bookmarks system -- 2.20.1 From 22d2f81e6b829690463139a22ddd729019f23c95 Mon Sep 17 00:00:00 2001 From: plugd Date: Wed, 14 Feb 2024 10:49:24 +0100 Subject: [PATCH 10/12] Proper handling of query-only gemini links. --- elpher.el | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/elpher.el b/elpher.el index 608f09d..4a98cb3 100644 --- a/elpher.el +++ b/elpher.el @@ -1607,12 +1607,18 @@ treatment that a separate function is warranted." (if (string-empty-p (url-filename address)) (setf (url-filename address) "/")) ;ensure empty filename is marked as absolute (setf (url-host address) (url-host current-address)) - (setf (url-fullness address) (url-host address)) ; set fullness to t if host is set - (setf (url-portspec address) (url-portspec current-address)) ; (url-port) too slow! - (unless (string-prefix-p "/" (url-filename address)) ;deal with relative links + (setf (url-fullness address) (url-host address)) ;set fullness to t if host is set + (setf (url-portspec address) (url-portspec current-address)) ;(url-port) too slow! + (cond + ((string-prefix-p "/" (url-filename address))) ;do nothing for absolute case + ((string-prefix-p "?" (url-filename address)) ;handle query-only links + (setf (url-filename address) + (concat (url-filename current-address) + (url-filename address)))) + (t ;deal with relative links (setf (url-filename address) (concat (file-name-directory (url-filename current-address)) - (url-filename address))))) + (url-filename address)))))) (when (url-host address) (setf (url-host address) (puny-encode-domain (url-host address)))) (unless (url-type address) -- 2.20.1 From 3f53ed5b6550d25a66bc83f6f26d8cfb06b1dcce Mon Sep 17 00:00:00 2001 From: plugd Date: Wed, 14 Feb 2024 10:52:44 +0100 Subject: [PATCH 11/12] Patch release. --- config.mk | 2 +- elpher-pkg.el | 2 +- elpher.el | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config.mk b/config.mk index 11af4ef..0ca918a 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ PKG = elpher -VERSION = 3.5.0 +VERSION = 3.5.1 INSTALLINFO = install-info MAKEINFO = makeinfo diff --git a/elpher-pkg.el b/elpher-pkg.el index 5cdbef2..6a6a84d 100644 --- a/elpher-pkg.el +++ b/elpher-pkg.el @@ -1,4 +1,4 @@ -(define-package "elpher" "3.5.0" "A friendly gopher and gemini client" +(define-package "elpher" "3.5.1" "A friendly gopher and gemini client" '((emacs "27.1")) :keywords ("convenience") :authors (("Tim Vaughan" . "plugd@thelambdalab.xyz")) diff --git a/elpher.el b/elpher.el index 4a98cb3..3a80045 100644 --- a/elpher.el +++ b/elpher.el @@ -5,7 +5,7 @@ ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 3.5.0 +;; Version: 3.5.1 ;; Keywords: comm gopher gemini ;; Homepage: https://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "27.1")) @@ -71,7 +71,7 @@ ;;; Global constants ;; -(defconst elpher-version "3.5.0" +(defconst elpher-version "3.5.1" "Current version of elpher.") (defconst elpher-margin-width 6 -- 2.20.1 From 56bc74e224d9835c41b6e6b68c9705b60e6dbbe2 Mon Sep 17 00:00:00 2001 From: plugd Date: Sun, 24 Mar 2024 14:07:33 +0100 Subject: [PATCH 12/12] Release to allow opening links in new buffer. --- config.mk | 2 +- elpher-pkg.el | 2 +- elpher.el | 167 +++++++++++++++++++++++++++++--------------------- elpher.texi | 22 ++++++- 4 files changed, 119 insertions(+), 74 deletions(-) diff --git a/config.mk b/config.mk index 0ca918a..46598bf 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ PKG = elpher -VERSION = 3.5.1 +VERSION = 3.6.0 INSTALLINFO = install-info MAKEINFO = makeinfo diff --git a/elpher-pkg.el b/elpher-pkg.el index 6a6a84d..8c9c6a6 100644 --- a/elpher-pkg.el +++ b/elpher-pkg.el @@ -1,4 +1,4 @@ -(define-package "elpher" "3.5.1" "A friendly gopher and gemini client" +(define-package "elpher" "3.6.0" "A friendly gopher and gemini client" '((emacs "27.1")) :keywords ("convenience") :authors (("Tim Vaughan" . "plugd@thelambdalab.xyz")) diff --git a/elpher.el b/elpher.el index 3a80045..c3c3dc7 100644 --- a/elpher.el +++ b/elpher.el @@ -5,7 +5,7 @@ ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 3.5.1 +;; Version: 3.6.0 ;; Keywords: comm gopher gemini ;; Homepage: https://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "27.1")) @@ -71,7 +71,7 @@ ;;; Global constants ;; -(defconst elpher-version "3.5.1" +(defconst elpher-version "3.6.0" "Current version of elpher.") (defconst elpher-margin-width 6 @@ -376,7 +376,7 @@ is not explicitly given." (defun elpher-remove-redundant-ports (address) "Remove redundant port specifiers from ADDRESS. -Here 'redundant' means that the specified port matches the default +Here `redundant' means that the specified port matches the default for that protocol, eg 70 for gopher." (if (and (not (elpher-address-about-p address)) (eq (url-portspec address) ; (url-port) is too slow! @@ -699,6 +699,57 @@ If LINE is non-nil, replace that line instead." (replace-match string)) (set-match-data data)))))) +;;; Link button definitions +;; + +(defvar elpher-link-keymap + (let ((map (make-sparse-keymap))) + (keymap-set map "S-" 'ignore) ;Prevent buffer face popup + (keymap-set map "S-" #'elpher--open-link-new-buffer-mouse) + (keymap-set map "S-" #'elpher--open-link-new-buffer) + (set-keymap-parent map button-map) + map)) + +(defun elpher--click-link (button) + "Function called when the gopher link BUTTON is activated." + (let ((page (button-get button 'elpher-page))) + (elpher-visit-page page))) + +(defun elpher--open-link-new-buffer () + "Internal function used by Elpher to open links in a new buffer." + (interactive) + (let ((page (button-get (button-at (point)) 'elpher-page)) + (new-buf (generate-new-buffer (default-value 'elpher-buffer-name)))) + (pop-to-buffer new-buf) + (elpher-mode) + (elpher-visit-page page))) + +(defun elpher--open-link-new-buffer-mouse (event) + "Internal function used by Elpher to open links in a new buffer. +The EVENT argument is the mouse event which caused this function to be +called." + (interactive "e") + (mouse-set-point event) + (elpher--open-link-new-buffer)) + +(defun elpher--page-button-help (_window buffer pos) + "Function called by Emacs to generate mouse-over text. +The arguments specify the BUFFER and the POS within the buffer of the item +for which help is required. The function returns the help to be +displayed. The _WINDOW argument is currently unused." + (with-current-buffer buffer + (let ((button (button-at pos))) + (when button + (let* ((page (button-get button 'elpher-page)) + (address (elpher-page-address page))) + (format "mouse-1, RET: open '%s'" (elpher-address-to-url address))))))) + +(define-button-type 'elpher-link + 'action #'elpher--click-link + 'keymap elpher-link-keymap + 'follow-link t + 'help-echo #'elpher--page-button-help + 'face 'button) ;;; Text Processing ;; @@ -735,11 +786,8 @@ away CRs and any terminating period." (let ((page (elpher-page-from-url (substring-no-properties (match-string 0))))) (make-text-button (match-beginning 0) (match-end 0) - 'elpher-page page - 'action #'elpher-click-link - 'follow-link t - 'help-echo #'elpher--page-button-help - 'face 'button))) + 'elpher-page page + :type 'elpher-link))) (buffer-string))) @@ -1145,23 +1193,11 @@ once they are retrieved from the gopher server." (insert " ")) (insert (make-string elpher-margin-width ?\s)))) -(defun elpher--page-button-help (_window buffer pos) - "Function called by Emacs to generate mouse-over text. -The arguments specify the BUFFER and the POS within the buffer of the item -for which help is required. The function returns the help to be -displayed. The _WINDOW argument is currently unused." - (with-current-buffer buffer - (let ((button (button-at pos))) - (when button - (let* ((page (button-get button 'elpher-page)) - (address (elpher-page-address page))) - (format "mouse-1, RET: open '%s'" (elpher-address-to-url address))))))) - (defun elpher-insert-index-record (display-string &optional address) "Function to insert an index record into the current buffer. The contents of the record are dictated by DISPLAY-STRING and ADDRESS. If ADDRESS is not supplied or nil the record is rendered as an -'information' line." +`information' line." (let* ((type (if address (elpher-address-type address) nil)) (type-map-entry (cdr (assoc type elpher-type-map)))) (if type-map-entry @@ -1173,9 +1209,7 @@ If ADDRESS is not supplied or nil the record is rendered as an (insert-text-button filtered-display-string 'face face 'elpher-page page - 'action #'elpher-click-link - 'follow-link t - 'help-echo #'elpher--page-button-help)) + :type 'elpher-link)) (pcase type ('nil ;; Information (elpher-insert-margin) @@ -1188,11 +1222,6 @@ If ADDRESS is not supplied or nil the record is rendered as an 'face 'elpher-unknown))))) (insert "\n"))) -(defun elpher-click-link (button) - "Function called when the gopher link BUTTON is activated." - (let ((page (button-get button 'elpher-page))) - (elpher-visit-page page))) - (defun elpher-render-index (data &optional _mime-type-string) "Render DATA as an index. MIME-TYPE-STRING is unused." (elpher-with-clean-buffer @@ -1647,9 +1676,7 @@ treatment that a separate function is warranted." (insert-text-button display-string 'face face 'elpher-page page - 'action #'elpher-click-link - 'follow-link t - 'help-echo #'elpher--page-button-help)) + :type 'elpher-link)) (newline)))))) (defun elpher-gemini-insert-header (header-line) @@ -1910,7 +1937,7 @@ Assumes UTF-8 encoding for all text files." "Default bindings:\n" "\n" " - TAB/Shift-TAB: next/prev item on current page\n" - " - RET/mouse-1: open item under cursor\n" + " - RET/mouse-1: open item under cursor (with Shift to open in new buffer)\n" " - m: select an item on current page by name (autocompletes)\n" " - u/mouse-3/U: return to previous page or to the start page\n" " - g: go to a particular address (gopher, gemini, finger)\n" @@ -1932,7 +1959,7 @@ Assumes UTF-8 encoding for all text files." (elpher-insert-index-record "Floodgap Systems Gopher Server" (elpher-make-gopher-address ?1 "" "gopher.floodgap.com" 70)) (elpher-insert-index-record "Project Gemini home page" - (elpher-address-from-url "gemini://gemini.circumlunar.space/")) + (elpher-address-from-url "gemini://geminiprotocol.net/")) (insert "\n" "Alternatively, select a search engine and enter some search terms:\n") (elpher-insert-index-record "Gopher Search Engine (Veronica-2)" @@ -1943,12 +1970,10 @@ Assumes UTF-8 encoding for all text files." "Your bookmarks are stored in your ") (insert-text-button "bookmark list" 'face 'link - 'action #'elpher-click-link - 'follow-link t - 'help-echo #'elpher--page-button-help 'elpher-page (elpher-make-page "Elpher Bookmarks" - (elpher-make-about-address 'bookmarks))) + (elpher-make-about-address 'bookmarks)) + :type 'elpher-link) (insert ".\n") (insert (propertize "(Bookmarks from legacy elpher-bookmarks files will be automatically imported.)\n" @@ -2326,7 +2351,12 @@ supports the old protocol elpher, where the link is self-contained." (defun elpher-follow-current-link () "Open the link or url at point." (interactive) - (push-button)) + (elpher--click-link (button-at (point)))) + +(defun elpher-follow-current-link-new-buffer () + "Open the link or url at point." + (interactive) + (elpher--open-link-new-buffer)) ;;;###autoload (defun elpher-go (host-or-url) @@ -2556,36 +2586,35 @@ current page." (define-key map (kbd "F") 'elpher-forget-current-certificate) (when (fboundp 'evil-define-key*) (evil-define-key* - 'motion map - (kbd "TAB") 'elpher-next-link - (kbd "C-") 'elpher-follow-current-link - (kbd "C-t") 'elpher-back - (kbd "u") 'elpher-back - (kbd "-") 'elpher-back - (kbd "^") 'elpher-back - [mouse-3] 'elpher-back - (kbd "U") 'elpher-back-to-start - (kbd "g") 'elpher-go - (kbd "o") 'elpher-go-current - (kbd "O") 'elpher-root-dir - (kbd "s") 'elpher-show-history - (kbd "S") 'elpher-show-visited-pages - (kbd "r") 'elpher-redraw - (kbd "R") 'elpher-reload - (kbd "T") 'elpher-toggle-tls - (kbd ".") 'elpher-view-raw - (kbd "d") 'elpher-download - (kbd "D") 'elpher-download-current - (kbd "m") 'elpher-jump - (kbd "i") 'elpher-info-link - (kbd "I") 'elpher-info-current - (kbd "c") 'elpher-copy-link-url - (kbd "C") 'elpher-copy-current-url - (kbd "a") 'elpher-bookmark-link - (kbd "A") 'elpher-bookmark-current - (kbd "B") 'elpher-show-bookmarks - (kbd "!") 'elpher-set-gopher-coding-system - (kbd "F") 'elpher-forget-current-certificate)) + 'motion map + (kbd "TAB") 'elpher-next-link + (kbd "C-t") 'elpher-back + (kbd "u") 'elpher-back + (kbd "-") 'elpher-back + (kbd "^") 'elpher-back + [mouse-3] 'elpher-back + (kbd "U") 'elpher-back-to-start + (kbd "g") 'elpher-go + (kbd "o") 'elpher-go-current + (kbd "O") 'elpher-root-dir + (kbd "s") 'elpher-show-history + (kbd "S") 'elpher-show-visited-pages + (kbd "r") 'elpher-redraw + (kbd "R") 'elpher-reload + (kbd "T") 'elpher-toggle-tls + (kbd ".") 'elpher-view-raw + (kbd "d") 'elpher-download + (kbd "D") 'elpher-download-current + (kbd "m") 'elpher-jump + (kbd "i") 'elpher-info-link + (kbd "I") 'elpher-info-current + (kbd "c") 'elpher-copy-link-url + (kbd "C") 'elpher-copy-current-url + (kbd "a") 'elpher-bookmark-link + (kbd "A") 'elpher-bookmark-current + (kbd "B") 'elpher-show-bookmarks + (kbd "!") 'elpher-set-gopher-coding-system + (kbd "F") 'elpher-forget-current-certificate)) map) "Keymap for gopher client.") diff --git a/elpher.texi b/elpher.texi index 8b5c65d..56a5fcc 100644 --- a/elpher.texi +++ b/elpher.texi @@ -1,7 +1,7 @@ \input texinfo @c -*-texinfo-*- @setfilename elpher.info -@settitle Elpher Manual v3.5.0 +@settitle Elpher Manual v3.6.0 @dircategory Emacs @direntry @@ -84,6 +84,7 @@ Gemini support News +* v3.6.0:: * v3.5.0:: * v3.4.0:: * v3.3.0:: @@ -322,7 +323,7 @@ Moving to a different page can be accomplished in several ways, described by the following command: @table @asis -@keycmd{@key{RET}\, @key{mouse-1}, elpher-follow-link} +@keycmd{@key{RET}\, @key{mouse-1}, elpher-follow-current-link} Follow the menu item or link at point (or selected with the mouse). Exactly what is meant by ``follow'' depends on the kind of item selected: @@ -357,6 +358,10 @@ Emacs' own EWW browser. (See @pxref{Customization}.) Once a text, menu or query response page has been displayed, its contents are cached for the duration of the Emacs session. +@keycmd{S-@key{RET}\, S-@key{mouse-1}, elpher-follow-current-link-new-buffer} +Create a new Elpher buffer and follow the menu item or link at point +in the new buffer. + @keycmd{@key{g}, elpher-go} Open a particular page by specifying either its full URL or just entering a gopher host name. (The protocol defaults to gopher, so gemini @@ -858,6 +863,7 @@ See the customization group itself for details. This chapter documents the major changes introduced by Elpher releases. @menu +* v3.6.0:: * v3.5.0:: * v3.4.0:: * v3.3.0:: @@ -866,7 +872,17 @@ This chapter documents the major changes introduced by Elpher releases. * v3.0.0:: @end menu -@node v3.5.0, v3.4.0, News, News +@node v3.6.0, v3.5.0, News, News +@section v3.6.0 + +@subsection Easily open links in new buffer + +This version includes the ability to open all link types in +Elpher documents in a new buffer. By default, this is bound +to S-@key{RET} and S-@key{mouse-1}, but this can be modified +by adding adjusting the bindings in @code{elpher-link-keymap}. + +@node v3.5.0, v3.4.0, v3.6.0, News @section v3.5.0 @subsection Automatic activation of client certificates in gemini -- 2.20.1