Reading [someodd](https://someodd.zip)'s manifesto convinced me that like how Alan Kay considers lisp a property of this universe the same way Maxwell's equations are, gopher protocol is a similar platonic solid of the rules our universe has for internetworked communication. If there are aliens, they program in lisp and phlog on the gopher.
Please accept this lispy gopher instead of my promised complicated neural network and condition distributino ones for the time being!
```
CL-USER> (dolist (s (list 'foo-specify 'dir-specify))
(handler-bind ((retrieve #'handle-directory)
(retrieve #'handle-file)
(t #'error))
(handler-bind
((got-request-for #'handle-got-request))
(as-gopher () () (signal 'got-request-for
:item-specifier
s))))
(terpri) (terpri))
BAR
0FOO-USER FOO-SPECIFY NIL 0
1DIR-USER DIR-SPECIFY NIL 0
.
NIL
```
On the other hand, I do not think TCP is a fundamental property of this universe, like how C++ and rust are clearly not fundamental properties of this universe in the same way.
I have implied (well, someodd.zip has) that gopher is a fundamental general view on communication. Taking this view I would like to view gopher as a general, run-time specified view on communication like lisp is for computing.
## Macro that provides `file` and `directory` gopher itemtypes
[RFC1436](https://www.rfc-editor.org/rfc/rfc1436) encourages adding itemtypes to an implementation gradually, with these two being the fundamental starting ones so I cooked their restarts into an `as-gopher` macro.
Here I am using `file` and `directory` in the RFC1436 sense of *textual thing* and *gophermap*.
```
(defmacro
as-gopher
((&optional
(output-stream *standard-output*))
(&body more-restarts)
&body body)
`(restart-case
(progn ,@body)
(file
(thing)
(princ thing ,output-stream))
(directory
(direntity-list)
(loop
:for r :in direntity-list :do
(format ,output-stream
"~:[.~;~{~c~@{~a~^ ~}~}~%~]"
r r)
:finally (princ ".")))
,@more-restarts))
```
## Two conditions for requests and retrievals
```
(define-condition
got-request-for
()
((item-specifier :initarg :item-specifier
:reader item-specifier)))
(define-condition
retrieve
()
((item :initarg :item
:reader item)))
```
## An item alist and handlers
So that we have a thing that we are talking about, I decided looking up a request would be an `assoc` in an association list, and that a *gophermap* (that is *directory* itemtype *1*) would be a `:gophermap` tagged list, and anything else would fall back to a *file* itemtype *0* (show as text).
It then seems natural for the gophermap to be a simple filter of the alist itself.
```
(setq *print-circle* t)
(defparameter *specifier.items*
'#1=(((#\\0 foo-user foo-specify nil 0) . bar)
((#\\1 dir-user dir-specify nil 0) :gophermap #1#)))
(defun handle-got-request (c)
(unless
(and (typep c 'got-request-for)
(slot-boundp c 'item-specifier))
(return-from handle-got-request))
(let ((item (cdr (assoc (item-specifier c)
*specifier.items*
:key 'caddr))))
(signal 'retrieve
:item (cond ((and (listp item)
(eq :gophermap (first item)))
(mapcar 'car (second item)))
(t item)))))
(defun handle-directory (c)
(unless
(and (typep c 'retrieve)
(slot-boundp c 'item)
(listp (item c)))
(return-from handle-directory))
(let ((r (find-restart 'directory c)))
(when
r
(invoke-restart r (item c)))))
(defun handle-file (c)
(unless
(and (typep c 'retrieve)
(slot-boundp c 'item))
(return-from handle-file))
(let ((r (find-restart 'file c)))
(when
r
(invoke-restart r (item c)))))
```
And so we can
```
(dolist (s (list 'foo-specify 'dir-specify))
(handler-bind ((retrieve #'handle-directory)
(retrieve #'handle-file)
(t #'error))
(handler-bind
((got-request-for #'handle-got-request))
(as-gopher () () (signal 'got-request-for
:item-specifier
s))))
(terpri) (terpri))
```
(see the top).
## Conclusions
I am pretty happy with this. It shows I can straightforwardly view anything kind of like an association list as being an expression of gopher protocol, then navigate and browse it according to rfc1436 in a runtime-computed way using the common lisp condition system in this non-TCP realisation.
Some obvious realisation targets are `signal`ling the literal view that lisp pathname stuff on my computer's directories and files is part of the gopher, lisp code as data in general is part of the gopher, the gopher (I will use [someodd.zip](https://someodd.zip)'s admittedly Haskellian server stuff) is part of the gopher, and if we imagine separating links-on-page and just-text-on-page in `lynx`, the web is part of the gopher.
Similar to how I gave [the great solderpunk](https://zaibatsu.circumlunar.space/~solderpunk/) of ROOPHLOCH and gemini protocol a hard time because I did not think transport layer security should be specified inside the communication protocol, here I have implemented RFC1436 without transmission control protocol neither.