X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?a=blobdiff_plain;f=elpher.el;h=05f28233c8e7e60f50b697817d02992a7e98366c;hb=cfd6bea1a70a4d2fd7255bef66533aaec3b3fe3c;hp=19e78ef72e69d77fa86a9ce705fcf45ab3c06cea;hpb=39299728cafbcd98dc07cd45e4e5d11edc26f3a8;p=elpher.git diff --git a/elpher.el b/elpher.el index 19e78ef..05f2823 100644 --- a/elpher.el +++ b/elpher.el @@ -4,9 +4,9 @@ ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 2.3.6 +;; Version: 2.4.4 ;; Keywords: comm gopher -;; Homepage: https://github.com/tgvaughan/elpher +;; Homepage: http://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "26")) ;; This file is not part of GNU Emacs. @@ -37,7 +37,7 @@ ;; - direct visualisation of image files, ;; - a simple bookmark management system, ;; - connections using TLS encryption, -;; - basic support for the fledgling Gemini protocol. +;; - support for the fledgling Gemini protocol. ;; To launch Elpher, simply use 'M-x elpher'. This will open a start ;; page containing information on key bindings and suggested starting @@ -46,7 +46,8 @@ ;; Full instructions can be found in the Elpher info manual. ;; Elpher is under active development. Any suggestions for -;; improvements are welcome! +;; improvements are welcome, and can be made on the official +;; project page, gopher://thelambdalab.xyz/1/projects/elpher/. ;;; Code: @@ -66,7 +67,7 @@ ;;; Global constants ;; -(defconst elpher-version "2.3.6" +(defconst elpher-version "2.4.4" "Current version of elpher.") (defconst elpher-margin-width 6 @@ -482,6 +483,9 @@ ERROR can be either an error object or a string." ;;; Gopher selector retrieval ;; +(defvar elpher-network-timer nil + "Timer used for network connections.") + (defun elpher-process-cleanup () "Immediately shut down any extant elpher process and timers." (let ((p (get-process "elpher-process"))) @@ -492,8 +496,6 @@ ERROR can be either an error object or a string." (defvar elpher-use-tls nil "If non-nil, use TLS to communicate with gopher servers.") -(defvar elpher-network-timer) - (defun elpher-get-selector (address renderer &optional force-ipv4) "Retrieve selector specified by ADDRESS, then render it using RENDERER. If FORCE-IPV4 is non-nil, explicitly look up and use IPv4 address corresponding @@ -503,64 +505,66 @@ to ADDRESS." (when (not elpher-use-tls) (setq elpher-use-tls t) (message "Engaging TLS gopher mode.")) - (elpher-network-error "Cannot retrieve TLS gopher selector: GnuTLS not available"))) + (error "Cannot retrieve TLS gopher selector: GnuTLS not available"))) (unless (< (elpher-address-port address) 65536) - (elpher-network-error "Cannot retrieve gopher selector: port number > 65536")) - (let* ((kill-buffer-query-functions nil) - (port (elpher-address-port address)) - (host (elpher-address-host address)) - (selector-string "") - (proc (open-network-stream "elpher-process" - nil - (if force-ipv4 (dns-query host) host) - (if (> port 0) port 70) - :type (if elpher-use-tls 'tls 'plain) - :nowait t)) - (timer (run-at-time elpher-connection-timeout - nil - (lambda () - (pcase (process-status proc) - ('failed - (if (and (not (equal (elpher-address-protocol address) - "gophers")) - elpher-use-tls - (or elpher-auto-disengage-TLS - (yes-or-no-p "Could not establish encrypted connection. Disable TLS mode?"))) - (progn - (message "Disabling TLS mode.") - (setq elpher-use-tls nil) - (elpher-get-selector address renderer)) - (elpher-network-error "Could not establish encrypted connection."))) - ('connect - (elpher-process-cleanup) - (unless force-ipv4 - (message "Connection timed out. Retrying with IPv4 address.") - (elpher-get-selector address renderer t)))))))) - (setq elpher-network-timer timer) - (set-process-coding-system proc 'binary) - (set-process-filter proc - (lambda (_proc string) - (cancel-timer timer) - (setq selector-string - (concat selector-string string)))) - (set-process-sentinel proc - (lambda (_proc event) - (condition-case the-error - (cond - ((string-prefix-p "deleted" event)) - ((string-prefix-p "open" event) - (let ((inhibit-eol-conversion t)) - (process-send-string - proc - (concat (elpher-gopher-address-selector address) - "\r\n")))) - (t - (cancel-timer timer) - (funcall renderer selector-string) - (elpher-restore-pos))) - (error - (elpher-network-error address - (error-message-string the-error)))))))) + (error "Cannot retrieve gopher selector: port number > 65536")) + (condition-case nil + (let* ((kill-buffer-query-functions nil) + (port (elpher-address-port address)) + (host (elpher-address-host address)) + (selector-string "") + (proc (open-network-stream "elpher-process" + nil + (if force-ipv4 (dns-query host) host) + (if (> port 0) port 70) + :type (if elpher-use-tls 'tls 'plain) + :nowait t)) + (timer (run-at-time elpher-connection-timeout + nil + (lambda () + (pcase (process-status proc) + ('failed + (if (and (not (equal (elpher-address-protocol address) + "gophers")) + elpher-use-tls + (or elpher-auto-disengage-TLS + (yes-or-no-p "Could not establish encrypted connection. Disable TLS mode?"))) + (progn + (message "Disabling TLS mode.") + (setq elpher-use-tls nil) + (elpher-get-selector address renderer)) + (elpher-network-error address "Could not establish encrypted connection"))) + ('connect + (elpher-process-cleanup) + (unless force-ipv4 + (message "Connection timed out. Retrying with IPv4 address.") + (elpher-get-selector address renderer t)))))))) + (setq elpher-network-timer timer) + (set-process-coding-system proc 'binary) + (set-process-filter proc + (lambda (_proc string) + (cancel-timer timer) + (setq selector-string + (concat selector-string string)))) + (set-process-sentinel proc + (lambda (_proc event) + (condition-case the-error + (cond + ((string-prefix-p "deleted" event)) + ((string-prefix-p "open" event) + (let ((inhibit-eol-conversion t)) + (process-send-string + proc + (concat (elpher-gopher-address-selector address) + "\r\n")))) + (t + (cancel-timer timer) + (funcall renderer selector-string) + (elpher-restore-pos))) + (error + (elpher-network-error address the-error)))))) + (error + (error "Error initiating connection to server")))) (defun elpher-get-gopher-node (renderer) "Getter function for gopher nodes. @@ -574,7 +578,10 @@ once they are retrieved from the gopher server." (elpher-restore-pos)) (elpher-with-clean-buffer (insert "LOADING... (use 'u' to cancel)")) - (elpher-get-selector address renderer)))) + (condition-case the-error + (elpher-get-selector address renderer) + (error + (elpher-network-error address the-error)))))) ;; Index rendering @@ -665,7 +672,7 @@ If ADDRESS is not supplied or nil the record is rendered as an ;; Text rendering (defconst elpher-url-regex - "\\([a-zA-Z]+\\)://\\([a-zA-Z0-9.\-]*[a-zA-Z0-9\-]\\|\[[a-zA-Z0-9:]+\]\\)\\(:[0-9]+\\)?\\(/\\([0-9a-zA-Z\-_~?/@|:.]*[0-9a-zA-Z\-_~?/@|]\\)?\\)?" + "\\([a-zA-Z]+\\)://\\([a-zA-Z0-9.\-]*[a-zA-Z0-9\-]\\|\[[a-zA-Z0-9:]+\]\\)\\(:[0-9]+\\)?\\(/\\([0-9a-zA-Z\-_~?/@|:.%#]*[0-9a-zA-Z\-_~?/@|#]\\)?\\)?" "Regexp used to locate and buttniofy URLs in text files loaded by elpher.") (defun elpher-buttonify-urls (string) @@ -797,9 +804,8 @@ to ADDRESS." (error "Cannot establish gemini connection: GnuTLS not available") (unless (< (elpher-address-port address) 65536) (error "Cannot establish gemini connection: port number > 65536")) - (condition-case the-error + (condition-case nil (let* ((kill-buffer-query-functions nil) - (network-security-level 'medium) (port (elpher-address-port address)) (host (elpher-address-host address)) (response-string "") @@ -840,19 +846,19 @@ to ADDRESS." (message "Connection failed. Retrying with IPv4.") (cancel-timer timer) (elpher-get-gemini-response address renderer t)) - (t + (t (funcall #'elpher-process-gemini-response response-string renderer) (elpher-restore-pos))) - (error the-error + (error (elpher-network-error address the-error)))))) (error (error "Error initiating connection to server"))))) (defun elpher-parse-gemini-response (response) - "Parse the RESPONSE string and return a list of components -The list is of the form (code meta body). A response of nil implies + "Parse the RESPONSE string and return a list of components. +The list is of the form (code meta body). A response of nil implies that the response was malformed." (let ((header-end-idx (string-match "\r\n" response))) (if header-end-idx @@ -1101,6 +1107,13 @@ For instance, the filename /a/b/../c/./d will reduce to /a/c/d" (insert "\n" "This page contains your bookmarked sites (also visit with B):\n") (elpher-insert-index-record "Your Bookmarks" 'bookmarks) + (insert "\n" + "For Elpher release news or to leave feedback, visit:\n") + (elpher-insert-index-record "The Elpher Project Page" + (elpher-make-gopher-address ?1 + "/projects/elpher/" + "thelambdalab.xyz" + 70)) (insert "\n" "** Refer to the ") (let ((help-string "RET,mouse-1: Open Elpher info manual (if available)")) @@ -1114,7 +1127,7 @@ For instance, the filename /a/b/../c/./d will reduce to /a/c/d" (insert " for the full documentation. **\n") (insert (propertize (concat " (This should be available if you have installed Elpher using\n" - " MELPA. Otherwise you will have to install the manual yourself.)") + " MELPA. Otherwise you will have to install the manual yourself.)\n") 'face 'shadow)) (elpher-restore-pos)))