#!/bin/sh
echo "Loading..."

exec scsh -lel SSAX-4.9/load.scm -lel module-system/load.scm -lel sunet-2.1/load.scm -dm -o surflet-server -e main -s "$0" "$@"
!#

(define-structure surflet-server
  (export main				; sh jump entry point
	  server)			; scsh entry point
  (open httpd-core
	httpd-make-options
	httpd-basic-handlers
	httpd-file-directory-handlers
	httpd-cgi-handlers
	httpd-seval-handlers
	surflet-handler
	surflet-handler/options
	let-opt
        scsh      
        scheme
	srfi-37
	signals)
                         
  (begin
    
    (define (usage)
      (format #f 
"Usage: start-surflet-server 
             [-h DIR | --htdocs-dir=DIR] [-s DIR | --surflet-dir=DIR]
             [--cgi-bin-dir=DIR]
             [-i DIR | --images-dir=DIR] [-p NUM | --port=NUM] 
             [-l FILE | --log-file-name=FILE] [-r NUM | --requests=NUM]
             [--help]

 with
 htdocs-dir     directory of html files (default: root/htdocs)
 surflet-dir    directory of SUrflet files  (default: root/surflets)
 cgi-bin-dir    directory of cgi files  (default: root/cgi-bin)
 images-dir     directory of images files (default: root/img)
 port           port server is listening to (default: 8080)
 log-file-name  directory where to store the logfile in CLF
                 (default: /tmp/httpd.log)
 requests       maximal amount of simultaneous requests (default 5)
 --help         show this help
"))

    (define (display-usage)
      (display (usage) (current-error-port))
      (exit 1))

    (define (raise-usage-error msg . info)
      (display msg (current-error-port))
      (display " --- " (current-error-port))
      (for-each 
       (lambda (i)
	 (display i (current-error-port))
	 (display " " (current-error-port)))
       info)
      (display "\n" (current-error-port))
      (exit 1))

    (define (parse-arguments arg-list)
      (let ((number-option-proc
	     (lambda (alist-key)
	       (lambda (option name arg ops)
		 (cond 
		  ((not arg) 
		   (raise-usage-error "Option requires a number" name arg))
		  ((string->number arg)
		   => (lambda (n) (cons (cons alist-key n) ops)))
		  (else 
		   (raise-usage-error "Not a number" arg))))))
	    (absolute-file-option-proc
	     (lambda (alist-key)
	       (lambda (option name arg ops)
		 (cons (cons alist-key
			     (absolute-file-name arg)) ops)))))

	(let ((htdocs-dir-option
	       (option '(#\h "htdocs-dir") #t #f 
		       (absolute-file-option-proc 'htdocs-dir)))
	      (surflet-dir-option
	       (option '(#\s "surflet-dir") #t #f
		       (absolute-file-option-proc 'surflet-dir)))
	      (cgi-bin-dir-option
	       (option '(#\c "cgi-bin-dir") #t #f
		       (absolute-file-option-proc 'cgi-bin-dir)))
	      (images-dir-option
	       (option '(#\i "images-dir") #t #f
		       (absolute-file-option-proc 'images-dir)))
	      (port-option
	       (option '(#\p "port") #t #f
		       (number-option-proc 'port)))
	      (log-file-name-option
	       (option '(#\l "log-file-name") #t #f
		       (absolute-file-option-proc 'log-file-name)))
	      (requests-option
	       (option '(#\r "requests") #t #f
		       (number-option-proc 'requests)))
	      (help-option
	       (option '(#f "help") #f #f
		       (lambda (option name arg ops)
			 (display-usage)))))
	  (args-fold arg-list
		     (list htdocs-dir-option surflet-dir-option
                           cgi-bin-dir-option
			   images-dir-option port-option
			   log-file-name-option requests-option
			   help-option)
		     (lambda (op name arg ops)
		       (raise-usage-error 
			"Unknown command line argument: " op))
		     cons
		     '()))))

    (define (make-options-from-args cmd-line-args default-options)
      (let ((given (parse-arguments cmd-line-args)))
	(map (lambda (p)
	       (or (assoc (car p) given) p))
	     default-options)))

    (define (lookup-option alist option)
      (cond 
       ((assoc option alist)
	=> cdr)
       (else
	(error "Internal error, option not found" option alist))))

    (define (server . args)
      (if (pair? args)
	  (main `(main ,@(car args)))
	  (main (list (cwd)))))
    
    (define (become-nobody-if-root)
      (cond ((zero? (user-uid))
	     (set-gid (->gid "nobody"))
	     (set-uid (->uid "nobody")))))

    (define (main args)
      (with-cwd 
	  (file-name-directory (car args))
	(let* ((default-options
                 `((htdocs-dir	. ,(absolute-file-name "root/htdocs"))
                   (surflet-dir	. ,(absolute-file-name "root/surflets"))
                   (cgi-bin-dir	. ,(absolute-file-name "root/cgi-bin"))
                   (images-dir	. ,(absolute-file-name "root/img"))
                   (port		. 8080)
                   (log-file-name	. "/tmp/httpd.log")
                   (requests	. 5)))
               (options (make-options-from-args (cdr args) default-options)))

	 (format #t "Going to run SUrflet server with:
 htdocs-dir:    ~a
 surflet-dir:   ~a
 cgi-bin-dir:   ~a
 images-dir:    ~a
 port:          ~a
 log-file-name: ~a
 a maximum of ~a simultaneous requests, syslogging activated, 
 and home-dir-handler (public_html) activated.

"
		 (lookup-option options 'htdocs-dir)
		 (lookup-option options 'surflet-dir)
		  (lookup-option options 'cgi-bin-dir)
		 (lookup-option options 'images-dir)
		 (lookup-option options 'port)
		 (lookup-option options 'log-file-name)
		 (lookup-option options 'requests))

	 (httpd 
	  (make-httpd-options
	   with-port			(lookup-option options 'port)
	   with-root-directory		(cwd)
	   with-simultaneous-requests	(lookup-option options 'requests)
	   with-syslog?			#t
	   with-log-file		(lookup-option options 'log-file-name)
           with-post-bind-thunk          become-nobody-if-root
	   ;; The following settings are made to avoid dns lookups.
	   with-reported-port		(lookup-option options 'port)
	   with-fqdn			"localhost"
	   with-resolve-ips?		#f
	   with-request-handler 
	   (alist-path-dispatcher
	    (list
             (cons "cgi-bin" (cgi-handler (lookup-option options 'cgi-bin-dir)))
             (cons "seval" seval-handler)
	     (cons "source"	(rooted-file-or-directory-handler 
				 (lookup-option options 'surflet-dir)
				 (with-file-name->content-type
				  (lambda (file-name)
				    (if (string-ci=? 
					 (file-name-extension file-name) ".scm")
					"text/plain"))
				  (make-file-directory-options))))
	     (cons "img"	(rooted-file-handler 
				 (lookup-option options 'images-dir)))
	     (cons "surflet"	(surflet-handler 
				 (with-surflet-path 
				  (lookup-option options 'surflet-dir)))))
            (tilde-home-dir-handler "public_html"
                                    (rooted-file-or-directory-handler
                                     (lookup-option options 'htdocs-dir)))))))))
    ))
;; EOF

;;; Local Variables:
;;; mode:scheme
;;; End: