;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: modlisp -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          base.lisp
;;;; Purpose:       Utility functions for modlisp package
;;;; Programmer:    Kevin M. Rosenberg
;;;; Date Started:  Dec 2002
;;;;
;;;; $Id: base.lisp 7061 2003-09-07 06:34:45Z kevin $
;;;; *************************************************************************

(in-package #:modlisp)

(defun modlisp-start (&key (port +default-modlisp-port+)
			   (processor 'demo-modlisp-command-processor)
			   (processor-args nil)
			   (catch-errors t)
			   timeout
			   number-fixed-workers
			   remote-host-checker)
  (let* ((server (make-instance 'ml-server
		   :processor processor
		   :processor-args processor-args
		   :port port))
	 (listener (make-instance 'listener :port port
				  :base-name "modlisp"			 
				  :function 'modlisp-command-issuer
				  :function-args (list server)
				  :format :text
				  :wait nil
				  :catch-errors catch-errors
				  :timeout timeout
				  :number-fixed-workers number-fixed-workers
				  :remote-host-checker remote-host-checker)))
    (setf (listener server) listener)
    (init/listener listener :start)
    (setf *ml-server* server)
    server))


(defun modlisp-stop (server)
  (init/listener (listener server) :stop)
  (setf (listener server) nil)
  server)

(defun modlisp-stop-all ()
  (stop-all/listener))

;; Internal functions

(defun modlisp-command-issuer (*modlisp-socket* server)
  "generates commands from modlisp, issues commands to processor-fun"
  (unwind-protect
       (progn
	 (let ((*number-worker-requests* 0)
	       (*close-modlisp-socket* t)
	       (*ml-server* server))
	   (do ((command (read-modlisp-command) (read-modlisp-command)))
	       ((null command))
	     (apply (processor server) command (processor-args server))
	     (finish-output *modlisp-socket*)
	     (incf *number-worker-requests*)
	     (incf *number-server-requests*)
	     (when *close-modlisp-socket*
	       (return)))))
    (close-active-socket *modlisp-socket*)))
  
(defun header-value (header key)
  "Returns the value of a modlisp header"
  (cdr (assoc key header :test #'eq)))

(defun read-modlisp-command ()
  (ignore-errors
    (let* ((header (read-modlisp-header))
	   (content-length (header-value header :content-length))
	   (content (when content-length 
		      (make-string
		       (parse-integer content-length :junk-allowed t)))))
	  (when content
	    (read-sequence content *modlisp-socket*)
	    (push (cons :posted-content content) header))
	  header)))


(defun read-modlisp-line ()
  (kmrcl:string-right-trim-one-char
   #\return
   (read-line *modlisp-socket* nil nil)))      


(defun read-modlisp-header ()
  (loop for key = (read-modlisp-line)
      while (and key (string-not-equal key "end"))
      for value = (read-modlisp-line)
      collect (cons (ensure-keyword key) value)))

(defun write-header-line (key value)
  (write-string (string key) *modlisp-socket*)
  (write-char #\NewLine *modlisp-socket*)
  (write-string value *modlisp-socket*)
  (write-char #\NewLine *modlisp-socket*))


