Can now open gophermap files with file:.
[elpher.git] / elpher.el
index bd9cbb5..c6627df 100644 (file)
--- a/elpher.el
+++ b/elpher.el
@@ -340,6 +340,8 @@ the start page."
                       (if (cdr p)
                           (concat "/" (mapconcat #'identity (cdr p) "/"))
                         ""))))
+            (when (url-host url)
+              (setf (url-host url) (puny-encode-domain (url-host url))))
             (when (or (equal "gopher" (url-type url))
                       (equal "gophers" (url-type url)))
               ;; Gopher defaults
@@ -502,9 +504,25 @@ If no address is defined, returns 0.  (This is for compatibility with the URL li
   "Create a page with address and display string defined by URL.
 The URL is unhexed prior to its use as a display string to improve
 readability."
-  (elpher-make-page (elpher-decode (url-unhex-string url))
+  (elpher-make-page (elpher-url-to-iri url)
                     (elpher-address-from-url url)))
 
+(defun elpher-url-to-iri (url)
+  "Return an IRI for URL.
+Decode percent-escapes and handle punycode in the domain name.
+Drop the password, if any."
+  (let ((data (match-data))) ; Prevent parsing clobbering match data
+    (unwind-protect
+        (let* ((address (elpher-address-from-url (elpher-decode (url-unhex-string url))))
+               (host (url-host address))
+               (pass (url-password address)))
+          (when host
+            (setf (url-host address) (puny-decode-domain host)))
+          (when pass                            ; RFC 3986 says we should not render
+            (setf (url-password address) nil)) ; the password as clear text
+          (url-recreate-url address))
+      (set-match-data data))))
+
 (defvar elpher-current-page nil
   "The current page for this Elpher buffer.")
 
@@ -1432,6 +1450,7 @@ Returns the url portion in the event that the display-string portion is empty."
   "Collapse dot sequences in the (absolute) FILENAME.
 For instance, the filename \"/a/b/../c/./d\" will reduce to \"/a/c/d\""
   (let* ((path (split-string filename "/" t))
+         (is-directory (string-match-p (rx (: (or "." ".." "/") line-end)) filename))
          (path-reversed-normalized
           (seq-reduce (lambda (a b)
                         (cond ((equal b "..") (cdr a))
@@ -1440,10 +1459,7 @@ For instance, the filename \"/a/b/../c/./d\" will reduce to \"/a/c/d\""
                       path nil))
          (path-normalized (reverse path-reversed-normalized)))
     (if path-normalized
-        (concat
-         "/"
-         (string-join (reverse path-reversed-normalized) "/")
-         (if (string-match-p (rx (: (or "." ".." "/") line-end)) filename) "/") "")
+        (concat "/" (string-join path-normalized "/") (and is-directory "/"))
       "/")))
 
 (defun elpher-address-from-gemini-url (url)
@@ -1464,6 +1480,8 @@ treatment that a separate function is warranted."
           (setf (url-filename address)
                 (concat (file-name-directory (url-filename current-address))
                         (url-filename address)))))
+      (when (url-host address)
+        (setf (url-host address) (puny-encode-domain (url-host address))))
       (unless (url-type address)
         (setf (url-type address) (url-type current-address)))
       (when (equal (url-type address) "gemini")
@@ -1669,6 +1687,8 @@ Assumes UTF-8 encoding for all text files."
             (elpher-render-text (decode-coding-string body 'utf-8)))
            ((or "jpg" "jpeg" "gif" "png" "bmp" "tif" "tiff")
             (elpher-render-image body))
+           ((or "gopher" "gophermap")
+            (elpher-render-index (elpher-decode body)))
            (_
             (elpher-render-download body))))
        (elpher-restore-pos))))