;-*- Mode:LISP; Package:MAIL; Base:8 -*-
;;; Mail server for the local file system

;;; For now only allow mail from one place at a time.
(DEFVAR *MAIL-SERVER-LOCK* NIL)

(DEFUN MAIL-SERVER (&AUX LOCK CONN STREAM (USER-ID USER-ID))
  (SETQ LOCK (LOCF *MAIL-SERVER-LOCK*))
  (CATCH-ERROR
    (UNWIND-PROTECT
      (PROG TOP ()
	    (AND (EQUAL USER-ID "") (SETQ USER-ID "Mail-server"))
	    (PROCESS-LOCK LOCK)
	    (SETQ CONN (CHAOS:LISTEN "MAIL"))
	    (CHAOS:ACCEPT CONN)
	    (FUNCALL TV:WHO-LINE-FILE-STATE-SHEET ':ADD-SERVER CONN "MAIL")
	    (SETQ STREAM (CHAOS:STREAM CONN))
	    (LET* ((RECIPIENTS (GET-MAIL-RECIPIENTS STREAM))
		   (TEXT (GET-MAIL-TEXT STREAM)))
	      (DOLIST (RECIPIENT RECIPIENTS)
		(WITH-OPEN-FILE (OUTFILE (FS:MAKE-PATHNAME ':HOST "LM"
							   ':DIRECTORY RECIPIENT
							   ':NAME RECIPIENT
							   ':TYPE "MAIL"
							   ':VERSION 0)
					 '(:OUT :NOERROR))
		  (COND ((STRINGP OUTFILE)
			 (FORMAT STREAM "-Unexpected error for ~A: ~A~%" RECIPIENT OUTFILE)
			 (FUNCALL STREAM ':FORCE-OUTPUT)
			 (RETURN-FROM TOP)))
		  ;; This always appends new mail.  ZMail knows how to reverse it after all.
		  (WITH-OPEN-FILE (INFILE (FS:MAKE-PATHNAME ':HOST "LM"
							    ':DIRECTORY RECIPIENT
							    ':NAME RECIPIENT
							    ':TYPE "MAIL"
							    ':VERSION ':NEWEST)
					  '(:IN :NOERROR))
		    (OR (STRINGP INFILE)
			(STREAM-COPY-UNTIL-EOF INFILE OUTFILE)))
		  (FUNCALL OUTFILE ':STRING-OUT TEXT)
		  (FUNCALL OUTFILE ':LINE-OUT ""))))
	    (FORMAT STREAM "+Message sent successfully.~%")
	    (FUNCALL STREAM ':FORCE-OUTPUT)
	    (FUNCALL STREAM ':FINISH)
	    (FUNCALL STREAM ':CLOSE))
      (AND CONN (CHAOS:REMOVE-CONN CONN))
      (PROCESS-UNLOCK LOCK))))

(DEFUN GET-MAIL-RECIPIENTS (STREAM)
  (DO ((LINE)
       (RECIPIENTS NIL))
      (NIL)
    (SETQ LINE (FUNCALL STREAM ':LINE-IN))
    (AND (EQUAL LINE "") (RETURN (NREVERSE RECIPIENTS)))
    (IF (NOT (FS:LM-DIRECTORY-EXISTS-P LINE))
	(FORMAT STREAM "-Unknown user ~A.~%" LINE)
	(PUSH LINE RECIPIENTS)
	(FORMAT STREAM "+Recipient name ~A ok.~%" LINE))
    (FUNCALL STREAM ':FORCE-OUTPUT)))

(DEFUN GET-MAIL-TEXT (STREAM)
  (WITH-OUTPUT-TO-STRING (SSTREAM)
    (STREAM-COPY-UNTIL-EOF STREAM SSTREAM)
    (FUNCALL SSTREAM ':FRESH-LINE)))

(ADD-INITIALIZATION "MAIL"
                    '(PROCESS-RUN-TEMPORARY-FUNCTION "MAIL Server" 'MAIL-SERVER)
                    NIL
                    'CHAOS:SERVER-ALIST)
