diff -rN -C 2 '--exclude=.git' '--exclude=_darcs' ucw-ajax-last/ucw_ajax/examples/src/forms.lisp ../UCW-old/ucw-ajax-last/ucw_ajax/examples/src/forms.lisp *** ucw-ajax-last/ucw_ajax/examples/src/forms.lisp 2023-09-08 19:48:52.714634049 +0100 --- ../UCW-old/ucw-ajax-last/ucw_ajax/examples/src/forms.lisp 2011-04-03 17:01:01.000000000 +0100 *************** *** 63,72 **** (dojo-date-input :accessor dojo-date-input-of :initform (make-instance 'dojo-dropdown-date-picker :value (now) ! :validators (list (multiple-value-bind (usec sec min hour day month year day-of-week daylight-saving-time-p timezone) ! (decode-local-time (now)) ! (declare (ignore usec sec min hour day-of-week daylight-saving-time-p)) (make-instance 'time-range-validator ! :min-value (encode-local-time 0 0 0 0 (- day 10) month year :timezone timezone) ! :max-value (encode-local-time 0 59 59 23 (+ day 10) month year :timezone timezone)))))) (dojo-time-input :accessor dojo-time-input-of :initform (make-instance 'dojo-dropdown-time-picker :value (now))) --- 63,72 ---- (dojo-date-input :accessor dojo-date-input-of :initform (make-instance 'dojo-dropdown-date-picker :value (now) ! :validators (list (multiple-value-bind (usec sec min hour day month year day-of-week) ! (decode-timestamp (now)) ! (declare (ignore usec sec min hour day-of-week)) (make-instance 'time-range-validator ! :min-value (timestamp- (encode-timestamp 0 0 0 0 day month year) 10 :day) ! :max-value (timestamp+ (encode-timestamp 0 59 59 23 day month year) 10 :day)))))) (dojo-time-input :accessor dojo-time-input-of :initform (make-instance 'dojo-dropdown-time-picker :value (now))) diff -rN -C 2 '--exclude=.git' '--exclude=_darcs' ucw-ajax-last/ucw_ajax/src/admin/admin.lisp ../UCW-old/ucw-ajax-last/ucw_ajax/src/admin/admin.lisp *** ucw-ajax-last/ucw_ajax/src/admin/admin.lisp 2023-09-08 19:48:52.714634049 +0100 --- ../UCW-old/ucw-ajax-last/ucw_ajax/src/admin/admin.lisp 2011-04-03 17:01:01.000000000 +0100 *************** *** 5,9 **** (defvar *admin-application* (make-instance 'standard-application ! :url-prefix "/ucw/" :tal-generator (make-instance 'yaclml:file-system-generator :cachep t --- 5,9 ---- (defvar *admin-application* (make-instance 'standard-application ! :url-prefix "/admin/" :tal-generator (make-instance 'yaclml:file-system-generator :cachep t *************** *** 19,23 **** :accessor admin-app.body :component admin-login)) ! (:default-initargs :title "UCW Administration" :stylesheet "/admin/ucw/ucw.css")) (defmethod render-html-body ((app admin-app)) --- 19,23 ---- :accessor admin-app.body :component admin-login)) ! (:default-initargs :title "UCW Administration" :stylesheet '("/static/ucw/ucw.css"))) (defmethod render-html-body ((app admin-app)) *************** *** 50,54 **** (cons "Control Panel" control-panel) (cons "Server REPL" server-repl) ! (cons "Applications" applications)) :key-test #'string= :current-component-key "Control Panel"))) --- 50,54 ---- (cons "Control Panel" control-panel) (cons "Server REPL" server-repl) ! );;(cons "Applications" applications)) :key-test #'string= :current-component-key "Control Panel"))) *************** *** 72,77 **** (defmethod/cc toggle-inspectors ((self admin-control-panel)) ! (setf *inspect-components* (not *inspect-components*)) ! (call 'info-message :message (strcat "Inspectors " (if *inspect-components* "" --- 72,77 ---- (defmethod/cc toggle-inspectors ((self admin-control-panel)) ! ;;(setf *inspect-components* (not *inspect-components*)) ! (call 'info-message :message (strcat "(fake for security) Inspectors " (if *inspect-components* "" *************** *** 105,109 **** (ucw.admin.info "Starting slime server.") (call 'info-message ! :message (format nil "Swank server started on port ~D." (swank:create-server)))) ;;;; The REPL --- 105,111 ---- (ucw.admin.info "Starting slime server.") (call 'info-message ! :message (format nil "(fake for security) Swank server started on port ~D." 0 ! ;;(swank:create-server) ! ))) ;;;; The REPL *************** *** 124,128 **** :cols 60)) (form-value :accessor admin-repl.form-value :initarg :form-value :initform nil)) ! (:default-initargs :template-name "ucw/admin/admin-repl.tal")) (defun admin-do-eval (repl) --- 126,130 ---- :cols 60)) (form-value :accessor admin-repl.form-value :initarg :form-value :initform nil)) ! (:default-initargs :template-name "../admin/admin-repl.tal")) (defun admin-do-eval (repl) *************** *** 133,137 **** (let* ((*package* (value package-select)) (form (read-from-string (value input)))) ! (setf form-value (eval form))))) (defmethod/cc submit ((self admin-repl)) --- 135,141 ---- (let* ((*package* (value package-select)) (form (read-from-string (value input)))) ! (setf form-value "fake for security" ! ;;(eval form) ! )))) (defmethod/cc submit ((self admin-repl)) diff -rN -C 2 '--exclude=.git' '--exclude=_darcs' ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp ../UCW-old/ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp *** ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp 2023-09-08 19:48:52.714634049 +0100 --- ../UCW-old/ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp 2023-09-06 20:00:24.927399237 +0100 *************** *** 97,101 **** (remote-address (remote-address request)) (raw-uri (raw-uri request))) ! (ucw.backend.info "Handling request from ~S for ~S" remote-address raw-uri) (or (block handle (dolist* ((can-match handler url-base) (handlers backend)) --- 97,101 ---- (remote-address (remote-address request)) (raw-uri (raw-uri request))) ! (ucw.backend.info "Handling request from ~a for ~S" remote-address raw-uri) (or (block handle (dolist* ((can-match handler url-base) (handlers backend)) *************** *** 110,114 **** internal-time-units-per-second))) (when (> seconds 0.05) ! (ucw.backend.info "Handled request in ~,3f secs (request came from ~S for ~S)" seconds remote-address raw-uri))))) --- 110,114 ---- internal-time-units-per-second))) (when (> seconds 0.05) ! (ucw.backend.info "Handled request in ~,3f secs (request came from ~a for ~S)" seconds remote-address raw-uri))))) *************** *** 156,168 **** (declare (optimize speed) (inline localhost-ip-address-p ip-address-from-private-network-p)) ! (let ((physical-remote-address (call-next-method))) ! (if (and physical-remote-address ! (or (ip-address-from-private-network-p physical-remote-address) ! (localhost-ip-address-p physical-remote-address))) ;; check if we are in a proxy setup and extract the real remote address if provided. ;; but do so only if the physical remote address is coming from a machine from the local net. ;; please note that this is not a realiable source for ip addresses! (let ((ip-as-string (get-header message "X-Forwarded-For"))) ! (when ip-as-string (let* ((real-remote-address (first (cl-ppcre:split "," ip-as-string :sharedp t))) (pieces (cl-ppcre:split "\\." real-remote-address :sharedp t))) --- 156,169 ---- (declare (optimize speed) (inline localhost-ip-address-p ip-address-from-private-network-p)) ! (let* ((physical-remote-address (call-next-method)) ! (address-vector (iolib.sockets:address-to-vector physical-remote-address))) ! (if (and address-vector ! (or (ip-address-from-private-network-p address-vector) ! (localhost-ip-address-p address-vector))) ;; check if we are in a proxy setup and extract the real remote address if provided. ;; but do so only if the physical remote address is coming from a machine from the local net. ;; please note that this is not a realiable source for ip addresses! (let ((ip-as-string (get-header message "X-Forwarded-For"))) ! (if ip-as-string (let* ((real-remote-address (first (cl-ppcre:split "," ip-as-string :sharedp t))) (pieces (cl-ppcre:split "\\." real-remote-address :sharedp t))) *************** *** 177,181 **** (progn (ucw.backend.info "Returning NIL instead of an invalid ip address: ~S" ip-as-string) ! nil))))) physical-remote-address))) --- 178,183 ---- (progn (ucw.backend.info "Returning NIL instead of an invalid ip address: ~S" ip-as-string) ! nil))) ! physical-remote-address)) physical-remote-address))) diff -rN -C 2 '--exclude=.git' '--exclude=_darcs' ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp~ ../UCW-old/ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp~ *** ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp~ 1970-01-01 01:00:00.000000000 +0100 --- ../UCW-old/ucw-ajax-last/ucw_ajax/src/backend/basic-backend.lisp~ 2022-06-20 18:57:47.000000000 +0100 *************** *** 0 **** --- 1,414 ---- + ;; -*- lisp -*- + + (in-package :it.bese.ucw) + + (defclass basic-backend (backend) + ((host :accessor host :initarg :host) + (port :accessor port :initarg :port) + (socket :initform nil :accessor socket) + (server :accessor server :initarg :server) + (handlers :accessor handlers :initform '()) + (request-content-length-limit :initform *request-content-length-limit* + :accessor request-content-length-limit-of + :initarg :request-content-length-limit))) + + (defprint-object (self basic-backend) + (write-string ":host ") + (princ (host self)) + (write-string " :port ") + (princ (port self))) + + (defclass basic-message (message) + ((headers :accessor headers :initform '()) + (socket :accessor socket :initarg :socket))) + + (defclass basic-request (basic-message request) + ((cookies :accessor cookies) + (parameters :accessor parameters :initform '()) + (raw-uri :accessor raw-uri :initform nil) + (query-path :accessor query-path :initform nil) + (raw-body :accessor raw-body :initform nil) + (http-method :accessor http-method :initform nil))) + + (defclass basic-response (basic-message response) + ((headers-are-sent :accessor headers-are-sent-p :initform nil :type boolean) + (cookies :accessor cookies :initform '()) + (request :accessor request :initarg :request :initform nil) + (html-stream :accessor html-stream :initform (make-string-output-stream)) + (status :accessor status :initform +http-ok+) + (external-format :accessor external-format :initform nil) + (content :accessor content :initform nil))) + + (defclass lockable-backend-mixin () + ((lock + :initform (make-recursive-lock "backend lock") + :accessor lock-of))) + + (defmacro with-lock-held-on-backend (backend &body body) + `(with-recursive-lock-held ((lock-of ,backend)) + ,@body)) + + + ;;;; Cookies + + (defmethod cookies ((request basic-request)) + (if (slot-boundp request 'cookies) + (slot-value request 'cookies) + (setf (slot-value request 'cookies) + ;; TODO consider calling safe-parse-cookies, see rfc2109 comments + (rfc2109:parse-cookies (get-header request "Cookie"))))) + + (defmethod find-cookie ((request basic-request) cookie) + (find-cookie-using-request (context.request *context*) cookie)) + + (defmethod find-cookie-using-request ((request basic-request) cookie) + (let ((cookie-name (cond ((stringp cookie) cookie) + ((rfc2109:cookie-p cookie) (rfc2109:cookie-name cookie)) + (t (error "FIND-COOKIE only supports string and rfc2109:cookie struct as cookie name specifier"))))) + (find cookie-name (cookies request) :test #'string= :key #'rfc2109:cookie-name))) + + (defun cookie-value (cookie &optional default) + (cookie-value-using-request (context.request *context*) cookie default)) + + (defmethod cookie-value-using-request ((request basic-request) cookie &optional default) + (aif (find-cookie request cookie) + (unescape-as-uri (rfc2109:cookie-value it)) + default)) + + (defun add-cookie (cookie) + "Add cookie to the current response." + (add-cookie-using-response (context.response *context*) cookie)) + + (defmethod add-cookie-using-response ((response basic-response) cookie) + (assert (rfc2109:cookie-p cookie)) + (push cookie (cookies response))) + + + ;;;; Backend methods + (defmethod initialize-backend ((backend basic-backend) &key server &allow-other-keys) + (when (and (null *mime-types*) + (probe-file *default-mime-types-file*)) + (read-mime-types *default-mime-types-file*)) + (setf (server backend) server) + backend) + + (defmethod handle-request ((backend basic-backend) (request basic-request) (response basic-response)) + (let ((start-time (get-internal-real-time)) + (remote-address (remote-address request)) + (raw-uri (raw-uri request))) + (ucw.backend.info "Handling request from ~a for ~S" remote-address raw-uri) + (or (block handle + (dolist* ((can-match handler url-base) (handlers backend)) + (declare (ignore url-base)) + (when (funcall can-match (query-path request)) + (funcall handler request response) + (return-from handle t))) + nil) + (handle-request (server backend) request response) + (error 'no-handler-for-request :raw-uri raw-uri :request request)) + (let ((seconds (/ (- (get-internal-real-time) start-time) + internal-time-units-per-second))) + (when (> seconds 0.05) + (ucw.backend.info "Handled request in ~,3f secs (request came from ~a for ~S)" + seconds remote-address raw-uri))))) + + (defmethod publish-directory ((backend basic-backend) directory-pathname url-base) + (push (list (lambda (request-url) + (ucw.backend.dribble "Trying to match '~S' under url-base '~S' to serve it as a file from '~S'" + request-url url-base directory-pathname) + (starts-with request-url url-base)) + (lambda (request response) + (aif (map-query-path-to-file (query-path request) + url-base + directory-pathname) + (progn + (ucw.backend.debug "Serving [~S] as a file under url-base [~S]" it url-base) + (serve-file it :request request :response response)) + (progn + (ucw.backend.debug "Failed to serve [~S] as a file under url-base [~S]" (query-path request) url-base) + (error 'no-handler-for-request :raw-uri (raw-uri request) :request request)))) + url-base) + (handlers backend))) + + ;;;; Message headers methods + + (defmethod get-header ((message basic-message) header-name) + (cdr (assoc header-name (headers message) :test #'string-equal))) + + (defmethod (setf get-header) (value (message basic-message) header-name) + (aif (assoc header-name (headers message) :test #'string-equal) + (setf (cdr it) value) + (push (cons header-name value) (headers message))) + value) + + (defmethod add-header ((message basic-message) header-name value) + (push (cons header-name value) (headers message)) + value) + + (defmethod delete-header ((message basic-message) header-name) + (setf (headers message) + (delete-if #'(lambda (item) + (string-equal (car item) + header-name)) + (headers message)))) + + (defmethod remote-address :around ((message basic-message)) + (declare (optimize speed) + (inline localhost-ip-address-p ip-address-from-private-network-p)) + (let ((physical-remote-address (call-next-method))) + (if (and physical-remote-address + (or (ip-address-from-private-network-p physical-remote-address) + (localhost-ip-address-p physical-remote-address))) + ;; check if we are in a proxy setup and extract the real remote address if provided. + ;; but do so only if the physical remote address is coming from a machine from the local net. + ;; please note that this is not a realiable source for ip addresses! + (let ((ip-as-string (get-header message "X-Forwarded-For"))) + (if ip-as-string + (let* ((real-remote-address (first (cl-ppcre:split "," ip-as-string :sharedp t))) + (pieces (cl-ppcre:split "\\." real-remote-address :sharedp t))) + (declare (type list pieces)) + (if (= (length pieces) 4) + (iter (with result = (make-array 4 :element-type '(unsigned-byte 8))) + (for idx :from 0 :below 4) + (for ip-address-part = (parse-integer (pop pieces))) + (assert (<= 0 ip-address-part 255)) + (setf (aref result idx) ip-address-part) + (finally (return result))) + (progn + (ucw.backend.info "Returning NIL instead of an invalid ip address: ~S" ip-as-string) + nil))) + physical-remote-address)) + physical-remote-address))) + + ;;;; Request handling + + (defun read-line-from-network (stream &optional (eof-error-p t)) + "A simple state machine which reads chars from STREAM until it + gets a CR-LF sequence or the end of the stream." + (declare (optimize (speed 3))) + (let ((buffer (make-array 50 + :element-type '(unsigned-byte 8) + :adjustable t + :fill-pointer 0))) + (labels ((read-next-char () + (let ((byte (read-byte stream eof-error-p stream))) + (if (eq stream byte) + (return-from read-line-from-network buffer) + (return-from read-next-char byte)))) + (cr () + (let ((next-byte (read-next-char))) + (case next-byte + (#.+linefeed+ ;; LF + (return-from read-line-from-network buffer)) + (t ;; add both the cr and this char to the buffer + (vector-push-extend #.+carriage-return+ buffer) + (vector-push-extend next-byte buffer) + (next))))) + (next () + (let ((next-byte (read-next-char))) + (case next-byte + (#.+carriage-return+ ;; CR + (cr)) + (#.+linefeed+ ;; LF + (return-from read-line-from-network buffer)) + (t + (vector-push-extend next-byte buffer) + (next)))))) + (next)))) + + (defun accumulate-parameters (assoc-list) + "Accumulates same parameters into lists. Otherwise + multiple-selection lists won't have a list value and + seconds 0.05) + (ucw.backend.info "Handled request in ~,3f secs (request came from ~a for ~S)" + seconds remote-address raw-uri))))) + + (defmethod publish-directory ((backend basic-backend) directory-pathname url-base) + (push (list (lambda (request-url) + (ucw.backend.dribble "Trying to match '~S' under url-base '~S' to serve it as a file from '~S'" + request-url url-base directory-pathname) + (starts-with request-url url-base)) + (lambda (request response) + (aif (map-query-path-to-file (query-path request) + url-base + directory-pathname) + (progn + (ucw.backend.debug "Serving [~S] as a file under url-base [~S]" it url-base) + (serve-file it :request request :response response)) + (progn + (ucw.backend.debug "Failed to serve [~S] as a file under url-base [~S]" (query-path request) url-base) + (error 'no-handler-for-request :raw-uri (raw-uri request) :request request)))) + url-base) + (handlers backend))) + + ;;;; Message headers methods + + (defmethod get-header ((message basic-message) header-name) + (cdr (assoc header-name (headers message) :test #'string-equal))) + + (defmethod (setf get-header) (value (message basic-message) header-name) + (aif (assoc header-name (headers message) :test #'string-equal) + (setf (cdr it) value) + (push (cons header-name value) (headers message))) + value) + + (defmethod add-header ((message basic-message) header-name value) + (push (cons header-name value) (headers message)) + value) + + (defmethod delete-header ((message basic-message) header-name) + (setf (headers message) + (delete-if #'(lambda (item) + (string-equal (car item) + header-name)) + (headers message)))) + + (defmethod remote-address :around ((message basic-message)) + (declare (optimize speed) + (inline localhost-ip-address-p ip-address-from-private-network-p)) + (let ((physical-remote-address (call-next-method))) + (if (and physical-remote-address + (or (ip-address-from-private-network-p physical-remote-address) + (localhost-ip-address-p physical-remote-address))) + ;; check if we are in a proxy setup and extract the real remote address if provided. + ;; but do so only if the physical remote address is coming from a machine from the local net. + ;; please note that this is not a realiable source for ip addresses! + (let ((ip-as-string (get-header message "X-Forwarded-For"))) + (if ip-as-string + (let* ((real-remote-address (first (cl-ppcre:split "," ip-as-string :sharedp t))) + (pieces (cl-ppcre:split "\\." real-remote-address :sharedp t))) + (declare (type list pieces)) + (if (= (length pieces) 4) + (iter (with result = (make-array 4 :element-type '(unsigned-byte 8))) + (for idx :from 0 :below 4) + (for ip-address-part = (parse-integer (pop pieces))) + (assert (<= 0 ip-address-part 255)) + (setf (aref result idx) ip-address-part) + (finally (return result))) + (progn + (ucw.backend.info "Returning NIL instead of an invalid ip address: ~S" ip-as-string) + nil))) + physical-remote-address)) + physical-remote-address))) + + ;;;; Request handling + + (defun read-line-from-network (stream &optional (eof-error-p t)) + "A simple state machine which reads chars from STREAM until it + gets a CR-LF sequence or the end of the stream." + (declare (optimize (speed 3))) + (let ((buffer (make-array 50 + :element-type '(unsigned-byte 8) + :adjustable t + :fill-pointer 0))) + (labels ((read-next-char () + (let ((byte (read-byte stream eof-error-p stream))) + (if (eq stream byte) + (return-from read-line-from-network buffer) + (return-from read-next-char byte)))) + (cr () + (let ((next-byte (read-next-char))) + (case next-byte + (#.+linefeed+ ;; LF + (return-from read-line-from-network buffer)) + (t ;; add both the cr and this char to the buffer + (vector-push-extend #.+carriage-return+ buffer) + (vector-push-extend next-byte buffer) + (next))))) + (next () + (let ((next-byte (read-next-char))) + (case next-byte + (#.+carriage-return+ ;; CR + (cr)) + (#.+linefeed+ ;; LF + (return-from read-line-from-network buffer)) + (t + (vector-push-extend next-byte buffer) + (next)))))) + (next)))) + + (defun accumulate-parameters (assoc-list) + "Accumulates same parameters into lists. Otherwise + multiple-selection lists won't have a list value and + seconds 0.05) + (ucw.backend.info "Handled request in ~,3f secs (request came from ~S for ~S)" + seconds remote-address raw-uri))))) + + (defmethod publish-directory ((backend basic-backend) directory-pathname url-base) + (push (list (lambda (request-url) + (ucw.backend.dribble "Trying to match '~S' under url-base '~S' to serve it as a file from '~S'" + request-url url-base directory-pathname) + (starts-with request-url url-base)) + (lambda (request response) + (aif (map-query-path-to-file (query-path request) + url-base + directory-pathname) + (progn + (ucw.backend.debug "Serving [~S] as a file under url-base [~S]" it url-base) + (serve-file it :request request :response response)) + (progn + (ucw.backend.debug "Failed to serve [~S] as a file under url-base [~S]" (query-path request) url-base) + (error 'no-handler-for-request :raw-uri (raw-uri request) :request request)))) + url-base) + (handlers backend))) + + ;;;; Message headers methods + + (defmethod get-header ((message basic-message) header-name) + (cdr (assoc header-name (headers message) :test #'string-equal))) + + (defmethod (setf get-header) (value (message basic-message) header-name) + (aif (assoc header-name (headers message) :test #'string-equal) + (setf (cdr it) value) + (push (cons header-name value) (headers message))) + value) + + (defmethod add-header ((message basic-message) header-name value) + (push (cons header-name value) (headers message)) + value) + + (defmethod delete-header ((message basic-message) header-name) + (setf (headers message) + (delete-if #'(lambda (item) + (string-equal (car item) + header-name)) + (headers message)))) + + (defmethod remote-address :around ((message basic-message)) + (declare (optimize speed) + (inline localhost-ip-address-p ip-address-from-private-network-p)) + (let ((physical-remote-address (call-next-method))) + (if (and physical-remote-address + (or (ip-address-from-private-network-p physical-remote-address) + (localhost-ip-address-p physical-remote-address))) + ;; check if we are in a proxy setup and extract the real remote address if provided. + ;; but do so only if the physical remote address is coming from a machine from the local net. + ;; please note that this is not a realiable source for ip addresses! + (let ((ip-as-string (get-header message "X-Forwarded-For"))) + (when ip-as-string + (let* ((real-remote-address (first (cl-ppcre:split "," ip-as-string :sharedp t))) + (pieces (cl-ppcre:split "\\." real-remote-address :sharedp t))) + (declare (type list pieces)) + (if (= (length pieces) 4) + (iter (with result = (make-array 4 :element-type '(unsigned-byte 8))) + (for idx :from 0 :below 4) + (for ip-address-part = (parse-integer (pop pieces))) + (assert (<= 0 ip-address-part 255)) + (setf (aref result idx) ip-address-part) + (finally (return result))) + (progn + (ucw.backend.info "Returning NIL instead of an invalid ip address: ~S" ip-as-string) + nil))))) + physical-remote-address))) + + ;;;; Request handling + + (defun read-line-from-network (stream &optional (eof-error-p t)) + "A simple state machine which reads chars from STREAM until it + gets a CR-LF sequence or the end of the stream." + (declare (optimize (speed 3))) + (let ((buffer (make-array 50 + :element-type '(unsigned-byte 8) + :adjustable t + :fill-pointer 0))) + (labels ((read-next-char () + (let ((byte (read-byte stream eof-error-p stream))) + (if (eq stream byte) + (return-from read-line-from-network buffer) + (return-from read-next-char byte)))) + (cr () + (let ((next-byte (read-next-char))) + (case next-byte + (#.+linefeed+ ;; LF + (return-from read-line-from-network buffer)) + (t ;; add both the cr and this char to the buffer + (vector-push-extend #.+carriage-return+ buffer) + (vector-push-extend next-byte buffer) + (next))))) + (next () + (let ((next-byte (read-next-char))) + (case next-byte + (#.+carriage-return+ ;; CR + (cr)) + (#.+linefeed+ ;; LF + (return-from read-line-from-network buffer)) + (t + (vector-push-extend next-byte buffer) + (next)))))) + (next)))) + + (defun accumulate-parameters (assoc-list) + "Accumulates same parameters into lists. Otherwise + multiple-selection lists won't have a list value and +