+ (condition-case the-error
+ (elpher-get-selector address
+ (lambda (proc event)
+ (let ((coding-system-for-write 'binary))
+ (with-temp-file elpher-download-filename
+ (insert elpher-selector-string)
+ (message (format "Download complate, saved to file %s."
+ elpher-download-filename)))))
+ t)
+ (error
+ (error "Error downloading %s" elpher-download-filename))))))
+
+;; HTML node retrieval
+
+(defun elpher-insert-rendered-html (string)
+ "Use shr to insert rendered view of html STRING into current buffer."
+ (let ((dom (with-temp-buffer
+ (insert string)
+ (libxml-parse-html-region (point-min) (point-max)))))
+ (shr-insert-document dom)))
+
+(defun elpher-get-html-node ()
+ "Getter which retrieves and renders an HTML node."
+ (let* ((address (elpher-node-address elpher-current-node))
+ (selector (elpher-gopher-address-selector address)))
+ (let ((content (elpher-get-cached-content address)))
+ (if content
+ (progn
+ (elpher-with-clean-buffer
+ (insert content)
+ (elpher-restore-pos)))
+ (elpher-with-clean-buffer
+ (insert "LOADING HTML... (use 'u' to cancel)"))
+ (elpher-get-selector address
+ (lambda (proc event)
+ (unless (string-prefix-p "deleted" event)
+ (elpher-with-clean-buffer
+ (elpher-insert-rendered-html elpher-selector-string)
+ (goto-char (point-min))
+ (elpher-cache-content
+ (elpher-node-address elpher-current-node)
+ (buffer-string))))))))))
+
+;; Gemini node retrieval
+
+(defvar elpher-gemini-response)
+
+(defun elpher-get-gemini (address after &optional propagate-error)
+ "Retrieve gemini ADDRESS, then execute AFTER.
+The result is stored as a string in the variable ‘elpher-selector-string’.
+
+Usually errors result in an error page being displayed. This is only
+appropriate if the selector is to be directly viewed. If PROPAGATE-ERROR
+is non-nil, this message is not displayed. Instead, the error propagates
+up to the calling function."
+ (setq elpher-gemini-response "")
+ (if (not (gnutls-available-p))
+ (error "Cannot retrieve TLS selector: GnuTLS not available"))
+ (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
+ (elpher-process-cleanup)
+ (if propagate-error
+ (error the-error)
+ (elpher-with-clean-buffer
+ (insert (propertize "\n---- ERROR -----\n\n" 'face 'error)
+ "Failed to connect to " (elpher-address-to-url address) ".\n"
+ (propertize "\n----------------\n\n" 'face 'error)
+ "Press 'u' to return to the previous page."))))))
+
+(defun elpher-get-gemini-node ()
+ "Getter which retrieves and renders a Gemini node."
+ (let* ((address (elpher-node-address elpher-current-node))
+ (content (elpher-get-cached-content address)))
+ (if content
+ (progn
+ (elpher-with-clean-buffer
+ (insert content)
+ (elpher-restore-pos)))
+ (elpher-with-clean-buffer
+ (insert "LOADING GEMINI... (use 'u' to cancel)"))
+ (elpher-get-gemini address
+ (lambda (proc event)
+ (unless (string-prefix-p "deleted" event)
+ (elpher-with-clean-buffer
+ (insert (elpher-buttonify-urls
+ (elpher-preprocess-text-response
+ elpher-gemini-response)))
+ (elpher-restore-pos)
+ (elpher-cache-content
+ (elpher-node-address elpher-current-node)
+ (buffer-string)))))))))
+
+
+;; Other URL node opening
+
+(defun elpher-get-other-url-node ()