1 ;;; elopher.el --- gopher client
5 ;; Simple gopher client in elisp.
9 ;; (defvar elopher-mode-map nil "Keymap for gopher client.")
11 ;; (define-derived-mode elopher-mode special-mode "elopher"
12 ;; "Major mode for elopher, an elisp gopher client.")
14 (defvar elopher-margin-width 5)
16 (defun elopher-insert-margin (&optional type-name)
19 (format (concat "%" (number-to-string elopher-margin-width) "s")
20 (concat "[" type-name "] "))
21 'face '(foreground-color . "yellow")))
22 (insert (make-string elopher-margin-width ?\s))))
24 (defun elopher-follow-index-link (button)
25 (apply #'elopher-get-index (button-get button 'link-address)))
27 (defun elopher-follow-text-link (button)
28 (apply #'elopher-get-text (button-get button 'link-address)))
30 (defun elopher-follow-image-link (button)
31 (apply #'elopher-get-image (button-get button 'link-address)))
33 (defun elopher-process-record (line)
34 (let* ((type (elt line 0))
35 (fields (split-string (substring line 1) "\t"))
36 (display-string (elt fields 0))
37 (selector (elt fields 1))
38 (hostname (elt fields 2))
40 (address (list selector hostname port)))
42 (?i (elopher-insert-margin)
43 (insert (propertize display-string
44 'face '(foreground-color. "white"))))
45 (?0 (elopher-insert-margin "T")
46 (insert-text-button display-string
47 'face '(foreground-color . "gray")
49 'action #'elopher-follow-text-link
51 (?1 (elopher-insert-margin "/")
52 (insert-text-button display-string
53 'face '(foreground-color . "cyan")
55 'action #'elopher-follow-index-link
57 (?p (elopher-insert-margin "img")
58 (insert-text-button display-string
59 'face '(foreground-color . "gray")
61 'action #'elopher-follow-image-link
63 (?.) ; Occurs at end of index, can safely ignore.
64 (tp (elopher-insert-margin (concat (char-to-string tp) "?"))
65 (insert (propertize display-string
66 'face '(foreground-color . "red")))))
69 (defvar elopher-incomplete-record "")
71 (defun elopher-process-complete-records (string)
72 (let* ((til-now (string-join (list elopher-incomplete-record string)))
73 (lines (split-string til-now "\r\n")))
74 (dotimes (idx (length lines))
75 (if (< idx (- (length lines) 1))
76 (let ((line (elt lines idx)))
77 (unless (string-empty-p line)
78 (elopher-process-record line)))
79 (setq elopher-incomplete-record (elt lines idx))))))
81 (defun elopher-index-filter (proc string)
82 (with-current-buffer (get-buffer "*elopher*")
83 (let ((marker (process-mark proc)))
84 (if (not (marker-position marker))
85 (set-marker marker 0 (current-buffer)))
88 (elopher-process-complete-records string)
89 (set-marker marker (point))))))
91 (defun elopher-get-index (selector host port)
92 (switch-to-buffer "*elopher*")
94 (setq elopher-incomplete-record "")
96 :name "elopher-process"
98 :service (if port port 70)
99 :filter #'elopher-index-filter)
100 (process-send-string "elopher-process" (concat selector "\n")))
102 (defun elopher-text-filter (proc string)
103 (with-current-buffer (get-buffer "*elopher*")
104 (let ((marker (process-mark proc)))
105 (if (not (marker-position marker))
106 (set-marker marker 0 (current-buffer)))
109 (dolist (line (split-string string "\r"))
111 (set-marker marker (point))))))
113 (defun elopher-get-text (selector host port)
114 (switch-to-buffer "*elopher*")
116 (make-network-process
117 :name "elopher-process"
120 :filter #'elopher-text-filter)
121 (process-send-string "elopher-process" (concat selector "\n")))
123 (defvar elopher-image-buffer "")
125 (defun elopher-image-filter (proc string)
126 (setq elopher-image-buffer (concat elopher-image-buffer string)))
128 (defun elopher-get-image (selector host port)
129 (switch-to-buffer "*elopher*")
131 (setq elopher-image-buffer "")
132 (make-network-process
133 :name "elopher-process"
136 :filter #'elopher-image-filter)
137 (process-send-string "elopher-process" (concat selector "\n"))
138 (insert-image (create-image elopher-image-buffer)))
141 "Start gopher client."
143 (elopher-get-index "" (read-from-minibuffer "Gopher host: ") 70))
145 (elopher-get-index "" "cosmic.voyage" 70)
146 ;; (elopher-get-image "/fun/xkcd/comics/2130/2137/text_entry.png" "gopher.floodgap.com" 70)
148 ;;; elopher.el ends here