;;;; cl-phantasmagoria.lisp
;;;Requires:
;;; #:cl-ppcre #:usocket
;;;(in-package #:cl-phantasmagoria)
(defvar *threads* (list))
(defvar *last-post* 0)
(defvar *port* 8070)
(defvar *domain* "localhost")
(defun create-server ()
(let ((socket (usocket:socket-listen "127.0.0.1" *port* :reuse-address t)))
(unwind-protect
(loop for connection = (usocket:socket-accept socket :element-type 'character)
do (unwind-protect
(progn
(gopher-respond connection)
(force-output (usocket:socket-stream connection)))
(progn
(when connection
(usocket:socket-close connection)))))
(when socket usocket:socket-close socket))))
(defun add-thread (name)
(push (list (incf *last-post*) name "") *threads*))
(defun filter-posts (lambda)
(delete-if lambda *threads*))
(defun blank-from (cutoff postno)
(setf (third (assoc postno *threads*))
(subseq (third (assoc postno *threads*))
0
(nth-value
0
(cl-ppcre:scan
cutoff
(third (assoc postno *threads*)))))))
(defun append-to-thread (thrno words)
(setf (third (assoc thrno *threads*))
(format nil "~a~%~%~a:~%~a~%"
(third (assoc thrno *threads*))
(incf *last-post*)
words)))
(defun print-gophermap (stream)
(format stream "phantasmagoria~%~%")
(format stream "~a~a ~a ~a ~a~%"
7 "add thread" "add thread" *domain* *port*)
(format stream "~a~a ~a ~a ~a~%"
7 "respond thread" "respond thread" *domain* *port*)
(dolist (s *threads*)
(format stream "0~a: ~a ~a ~a ~a~%"
(first s) (second s) (first s) *domain* *port*)))
(defun print-thread (thrno stream)
(format stream "phantasmagoria~%~a: ~a~%~a"
thrno
(second (assoc thrno *threads*))
(third (assoc thrno *threads*))))
(defun gopher-respond (connection)
"lynx
gopher://localhost:8070/1/"
(let* ((safety 0)
(terms (mapcar
(lambda (x) (coerce x 'string))
(loop
for done = nil
collect
(loop
for y = (read-char (usocket:socket-stream connection))
do (when (char= y #\return) (setf done t))
do (when (> (incf safety) 400)
(setf done t)
(return))
while (not (or (char= y #\tab) (char= y #\return)))
collect y)
while (not done)))))
(cond ((and (= 1 (length terms))
(string= "/" (car terms)))
(print-gophermap (usocket:socket-stream connection)))
((and (= 1 (length terms))
(assoc (parse-integer (first terms))
*threads*))
(print-thread (parse-integer (first terms))
(usocket:socket-stream connection)))
((and (= 2 (length terms))
(string= "add thread" (car terms)))
(add-thread (second terms))
(print-thread *last-post* (usocket:socket-stream connection)))
((and (= 2 (length terms))
(string= "respond thread" (car terms)))
(let* ((idx (parse-integer (subseq
(second terms)
0
(nth-value
0
(cl-ppcre:scan
'(:POSITIVE-LOOKAHEAD ":")
(second terms)))))))
(append-to-thread idx
(second terms))
(print-thread idx
(usocket:socket-stream connection))))
(t (error ":-(")))))