Allow option to force ipv4
[elpher.git] / elpher.el
index 2f39db6..09fdb6f 100644 (file)
--- a/elpher.el
+++ b/elpher.el
@@ -4,7 +4,7 @@
 
 ;; Author: Tim Vaughan <plugd@thelambdalab.xyz>
 ;; Created: 11 April 2019
-;; Version: 2.7.4
+;; Version: 2.7.8
 ;; Keywords: comm gopher
 ;; Homepage: http://thelambdalab.xyz/elpher
 ;; Package-Requires: ((emacs "26"))
@@ -70,7 +70,7 @@
 ;;; Global constants
 ;;
 
-(defconst elpher-version "2.7.4"
+(defconst elpher-version "2.7.8"
   "Current version of elpher.")
 
 (defconst elpher-margin-width 6
@@ -152,6 +152,11 @@ the time when the text is rendered."
   "Specify the name of the file where elpher bookmarks will be saved."
   :type '(file))
 
+(defcustom elpher-force-ipv4 nil
+  "If non-nil, force elpher to use ipv4 instead of trying an ipv6 address
+and falling back to an ipv4 address"
+  :type '(boolean))
+
 ;; Face customizations
 
 (defgroup elpher-faces nil
@@ -222,6 +227,10 @@ the time when the text is rendered."
   '((t :inherit bold :height 1.2))
   "Face used for gemini heading level 3.")
 
+(defface elpher-gemini-preformatted
+  '((t :inherit fixed-pitch))
+  "Face used for pre-formatted gemini text blocks.")
+
 ;;; Model
 ;;
 
@@ -354,7 +363,7 @@ If no address is defined, returns 0.  (This is for compatibility with the URL li
   "Retrieve gopher selector from ADDRESS object."
   (if (member (url-filename address) '("" "/"))
       ""
-    (substring (url-filename address) 2)))
+    (url-unhex-string (substring (url-filename address) 2))))
 
 
 ;; Cache
@@ -547,6 +556,7 @@ to ADDRESS."
     (error "Cannot retrieve gopher selector: port number > 65536"))
   (condition-case nil
       (let* ((kill-buffer-query-functions nil)
+             (gnutls-verify-error nil) ; We use the NSM for verification
              (port (elpher-address-port address))
              (host (elpher-address-host address))
              (selector-string-parts nil)
@@ -571,7 +581,7 @@ to ADDRESS."
                                           (progn
                                             (message "Disabling TLS mode.")
                                             (setq elpher-use-tls nil)
-                                            (elpher-get-selector address renderer))
+                                            (elpher-get-selector address renderer elpher-force-ipv4))
                                         (elpher-network-error address "Could not establish encrypted connection")))
                                      ('connect
                                       (elpher-process-cleanup)
@@ -635,7 +645,7 @@ once they are retrieved from the gopher server."
       (elpher-with-clean-buffer
        (insert "LOADING... (use 'u' to cancel)\n"))
       (condition-case the-error
-          (elpher-get-selector address renderer)
+          (elpher-get-selector address renderer elpher-force-ipv4)
         (error
          (elpher-network-error address the-error))))))
 
@@ -808,7 +818,7 @@ The response is rendered using the rendering function RENDERER."
 
             (elpher-with-clean-buffer
              (insert "LOADING RESULTS... (use 'u' to cancel)"))
-            (elpher-get-selector search-address renderer))
+            (elpher-get-selector search-address renderer elpher-force-ipv4))
         (if aborted
             (elpher-visit-previous-page))))))
  
@@ -875,6 +885,7 @@ to ADDRESS."
       (error "Cannot establish gemini connection: port number > 65536"))
     (condition-case nil
         (let* ((kill-buffer-query-functions nil)
+               (gnutls-verify-error nil) ; We use the NSM for verification
                (port (elpher-address-port address))
                (host (elpher-address-host address))
                (response-string-parts nil)
@@ -954,7 +965,7 @@ that the response was malformed."
                     (meta (string-trim (substring header 2))))
                 (list code meta body))
             (error "Malformed response: No response status found in header %s" header)))
-      (error "Malformed response: No CRLF-delimited header found"))))
+      (error "Malformed response: No CRLF-delimited header found in response %s" response))))
 
 (defun elpher-process-gemini-response (response-string renderer)
   "Process the gemini response RESPONSE-STRING and pass the result to RENDERER."
@@ -1140,6 +1151,18 @@ by HEADER-LINE."
                             (_ 'default)))
               "\n"))))
 
+(defun elpher-gemini-insert-text (text-line)
+  "Insert a plain non-preformatted TEXT-LINE into a text/gemini document.
+This function uses Emacs' auto-fill to wrap text sensibly to a maximum
+width defined by elpher-gemini-max-fill-width."
+  (insert (elpher-process-text-for-display text-line))
+  (let* ((prefix-end-idx (string-match "[^ \t*]" text-line))
+         (fill-prefix (if prefix-end-idx
+                          (let ((raw-prefix (substring text-line 0 prefix-end-idx)))
+                            (replace-regexp-in-string "\*" " " raw-prefix))
+                        nil)))
+    (newline)))
+
 (defun elpher-render-gemini-map (data _parameters)
   "Render DATA as a gemini map file, PARAMETERS is currently unused."
   (elpher-with-clean-buffer
@@ -1149,10 +1172,12 @@ by HEADER-LINE."
      (dolist (line (split-string data "\n"))
        (cond
         ((string-prefix-p "```" line) (setq preformatted (not preformatted)))
-        (preformatted (insert (elpher-process-text-for-display line) "\n"))
+        (preformatted (insert (elpher-process-text-for-display
+                               (propertize line 'face 'elpher-gemini-preformatted))
+                              "\n"))
         ((string-prefix-p "=>" line) (elpher-gemini-insert-link line))
         ((string-prefix-p "#" line) (elpher-gemini-insert-header line))
-        (t (insert (elpher-process-text-for-display line)) (newline)))))
+        (t (elpher-gemini-insert-text line)))))
    (elpher-cache-content
     (elpher-page-address elpher-current-page)
     (buffer-string))))
@@ -1771,6 +1796,7 @@ functions which initialize the gopher client, namely
       (switch-to-buffer "*elpher*")
     (switch-to-buffer "*elpher*")
     (setq elpher-current-page nil)
+    (setq elpher-history nil)
     (let ((start-page (elpher-make-page "Elpher Start Page"
                                         (elpher-make-special-address 'start))))
       (elpher-visit-page start-page)))