Improved URL regexp.
[elpher.git] / elpher.el
index f5bc3dc..d2d67f2 100644 (file)
--- a/elpher.el
+++ b/elpher.el
@@ -4,7 +4,7 @@
 
 ;; Author: Tim Vaughan <tgvaughan@gmail.com>
 ;; Created: 11 April 2019
-;; Version: 2.1.0
+;; Version: 2.3.1
 ;; Keywords: comm gopher
 ;; Homepage: https://github.com/tgvaughan/elpher
 ;; Package-Requires: ((emacs "26"))
@@ -65,7 +65,7 @@
 ;;; Global constants
 ;;
 
-(defconst elpher-version "2.1.0"
+(defconst elpher-version "2.3.1"
   "Current version of elpher.")
 
 (defconst elpher-margin-width 6
@@ -285,12 +285,13 @@ For gopher addresses this is a combination of the selector type and selector."
   "Retrieve port from ADDRESS object."
   (if (symbolp address)
       nil)
-  (or (> (url-port address) 0)
-      (and (or (equal (url-type address) "gopher")
-               (equal (url-type address) "gophers"))
-           70)
-      (and (equal (url-type address) "gemini")
-           1965)))
+  (if (> (url-port address) 0)
+      (url-port address)
+    (or (and (or (equal (url-type address) "gopher")
+                 (equal (url-type address) "gophers"))
+             70)
+        (and (equal (url-type address) "gemini")
+             1965))))
 
 (defun elpher-address-special-p (address)
   "Return non-nil if ADDRESS object is special (e.g. start page, bookmarks page)."
@@ -423,7 +424,14 @@ unless PRESERVE-PARENT is non-nil."
 (defun elpher-update-header ()
   "If `elpher-use-header' is true, display current node info in window header."
   (if elpher-use-header
-      (setq header-line-format (elpher-node-display-string elpher-current-node))))
+      (let* ((display-string (elpher-node-display-string elpher-current-node))
+             (address (elpher-node-address elpher-current-node))
+             (url-string (if (elpher-address-special-p address)
+                             ""
+                           (concat "  -  " (elpher-address-to-url address) "")))
+             (header (replace-regexp-in-string "%" "%%" (concat display-string
+                                                                url-string))))
+        (setq header-line-format header))))
 
 (defmacro elpher-with-clean-buffer (&rest args)
   "Evaluate ARGS with a clean *elpher* buffer as current."
@@ -636,7 +644,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:]+\]\\)\\(?3::[0-9]+\\)?\\(?4:/[^<> \r\n\t(),]*\\)?"
+  "\\([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)
@@ -768,21 +776,23 @@ The response is stored in the variable ‘elpher-gemini-response’."
   (setq elpher-gemini-response "")
   (if (not (gnutls-available-p))
       (error "Cannot retrieve TLS selector: GnuTLS not available")
-    (let* ((kill-buffer-query-functions nil)
-           (proc (open-network-stream "elpher-process"
-                                      nil
-                                      (elpher-address-host address)
-                                      (elpher-address-port address)
-                                      :type 'tls)))
-      (set-process-coding-system proc 'binary)
-      (set-process-filter proc
-                          (lambda (_proc string)
-                            (setq elpher-gemini-response
-                                  (concat elpher-gemini-response string))))
-      (set-process-sentinel proc after)
-      (process-send-string proc
-                           (concat (elpher-address-to-url address) "\r\n")))))
-
+    (condition-case the-error
+        (let* ((kill-buffer-query-functions nil)
+               (proc (open-network-stream "elpher-process"
+                                          nil
+                                          (elpher-address-host address)
+                                          (elpher-address-port address)
+                                          :type 'tls)))
+          (set-process-coding-system proc 'binary)
+          (set-process-filter proc
+                              (lambda (_proc string)
+                                (setq elpher-gemini-response
+                                      (concat elpher-gemini-response string))))
+          (set-process-sentinel proc after)
+          (process-send-string proc
+                               (concat (elpher-address-to-url address) "\r\n")))
+      (error
+       (error "Error initiating connection to server")))))
 
 (defun elpher-process-gemini-response (renderer)
   "Process the gemini response and pass the result to RENDERER.
@@ -821,14 +831,16 @@ The response is assumed to be in the variable `elpher-gemini-response'."
                                                       renderer)
                                              (elpher-restore-pos))))))
           (?4 ; Temporary failure
-           (error "Gemini server reports TEMPORARY FAILURE for this request"))
+           (error "Gemini server reports TEMPORARY FAILURE for this request: %S"
+                  response-header))
           (?5 ; Permanent failure
-           (error "Gemini server reports PERMANENT FAILURE for this request"))
+           (error "Gemini server reports PERMANENT FAILURE for this request: %S"
+                  response-header))
           (?6 ; Client certificate required
            (error "Gemini server requires client certificate (unsupported at this time)"))
           (_other
-           (error "Gemini server responded with unknown response code %S"
-                  response-code))))
+           (error "Gemini server response unknown: %S"
+                  response-header))))
     (error
      (elpher-network-error (elpher-node-address elpher-current-node) the-error))))