;;; -*- Mode:LISP; Package:SERIAL; Base:8; Fonts:(CPTFONT TR12I) -*- ;1;;This file contains the serial server program.* (defvar remotely-readable-directories '("Dulcey" "remote-info" "remote-patch" "remote-temporary") "Directories which can be used as sources for file transfers.") (defvar remotely-writeable-directories '("remote-temporary" "Dulcey") "Directories which can be used as destinations for file transfers.") (defvar remote-mail-reader-users '("Dulcey" "Naha" "Dexter") "Users who can read their mail from the server.") (defvar server-stream nil "The serial stream in use by the server.") (defvar server-transfer-flavor 'lmodem-connection "Flavor of file transfer to be used.") (sstatus nofeature real-serial-server) (defun remote-serial-server () (let* ((server-stream (make-server-stream)) (standard-input server-stream) (standard-output server-stream) (query-io server-stream)) (do-forever (serial-server-top-level)))) (defun enable-serial-server () (process-run-function "Serial server" 'remote-serial-server)) (defun serial-server-top-level (&aux (server-transfer-flavor 'lmodem-connection)) #+real-serial-server (send standard-output ':reset) #+real-serial-server (send standard-output ':put ':data-terminal-ready T) #+real-serial-server (dotimes (dummy 10.) (send standard-input ':tyi)) (format standard-output "~%~%LMI serial server~%~%") (let ((user-id (prompt-and-read ':string "User name: "))) (do-forever (format standard-output "~%Operation? ") (let ((char (char-upcase (tyi)))) (selectq char ((#Return #Control-L) nil) (#B (server-send-bug)) (#D (server-list-directory)) ((#H #? #Control-_) (server-help)) (#M (server-send-mail)) (#P (server-select-file-protocol)) (#Q (when (y-or-n-p "Do you really want to quit? ") (return nil))) (#R (server-transmit-file)) (#T (server-receive-file)) (#V (server-view-mail)) (t (format standard-output "~%Unknown operation. Type H for help."))))) #+real-serial-server (send standard-output ':eval-inside-yourself '(si:serial-write-command (logand 7775 si:uart-command))) )) #+real-serial-server (defun make-server-stream () (make-instance 'si:serial-stream ':baud 1200. ':number-of-data-bits 8. ':number-of-stop-bits 1 ':parity nil ':ascii-characters nil)) #-real-serial-server (defun make-server-stream () terminal-io) (defun server-help () (format standard-output " You are using the LMI serial server. Commands: B Send a bug report D List a directory H Print this message M Send mail P Select file transfer protocol Q Quit R Receive a file (file goes from the server to you) T Transmit a file (file goes from you to the server) V View your mail ")) (defun server-list-directory () (let ((directory (prompt-and-read `(:pathname :defaults ,(send (fs:user-homedir "fs") ':new-pathname ':name ':wild ':type ':wild ':version ':wild)) "~%~%Directory: "))) (terpri standard-output) (cond ((server-verify-file-for-transmit directory) (condition-case () (let ((dir-list (fs:directory-list directory))) (mapc #'(lambda (path) (zwei:default-list-one-file path standard-output)) dir-list)) (fs:file-lookup-error (format standard-output "The directory ~A does not exist.~%" directory)))) (t (format standard-output "The directory ~A is not listable remotely.~%" directory)))) nil) ;1;; Note that the names of the next two functions are egocentric, but the command names are* ;1;; defined from the point of view of the user.* (defun server-transmit-file () (let ((file (prompt-and-read `(:pathname :defaults ,(fs:user-homedir)) "~%~%File to receive: "))) (cond ((not (server-verify-file-for-transmit file)) (format standard-output "Remote access to file ~A is not permitted.~%" file)) (t (condition-case () (send (make-instance server-transfer-flavor ':modem-stream server-stream) ':send-file file) (fs:file-lookup-error (format standard-output "The file ~A does not exist.~%" file))))))) (defun server-receive-file () (let ((file (prompt-and-read `(:pathname :defaults ,(fs:user-homedir)) "~%~%File to transmit: "))) (cond ((not (server-verify-file-for-receive file)) (format standard-output "Remote access to file ~A is not permitted.~%" file)) (t (send (make-instance server-transfer-flavor ':modem-stream server-stream) ':get-file file))))) (defun server-verify-file-for-transmit (path) (member (send path ':directory) remotely-readable-directories)) (defun server-verify-file-for-receive (path) (member (send path ':directory) remotely-writeable-directories)) (defun server-verify-mail-reader (name) (member name remote-mail-reader-users)) (defunp server-view-mail () (when (not (server-verify-mail-reader user-id)) (format standard-output "~%Sorry, you do not have remote mail reading privileges.~%") (return nil)) (let* ((home-dir (fs:user-homedir "FS")) (out-message-count 0) (mail-file (send home-dir ':new-pathname ':name "mail" ':type "text" ':version ':newest)) (old-mail-file (send mail-file ':new-pathname ':name "_serial_server_mail_input_" ':type "_temporary_file_")) (out-file (send old-mail-file ':new-pathname ':name "_serial_server_mail_output_")) (rmail-file (send mail-file ':new-pathname ':name user-id ':type "rmail"))) (cond ((not (probef mail-file)) (format standard-output "~%~%No new mail.~%")) (t (terpri standard-output) (terpri standard-output) (renamef mail-file old-mail-file) (with-open-file (mail-out out-file ':direction ':output) (with-open-file (mail-in old-mail-file ':direction ':input) (loop while (loop with line-list = nil with line with end-flag do (multiple-value (line end-flag) (send mail-in ':line-in)) until end-flag while line until (string-equal line "") do (send standard-output ':line-out line) (push line line-list) finally (when (y-or-n-p "Save this message? ") (loop for out-line in (nreverse line-list) do (send mail-out ':line-out out-line)) (incf out-message-count)) (terpri standard-output) (terpri standard-output) (send mail-out ':line-out "") (return (and (not end-flag) line)))) (deletef mail-in)) (when (and (not (zerop out-message-count)) (probef rmail-file)) (format standard-output "Copying old saved messages...") (with-open-file (rmail-in rmail-file ':direction ':input) (fs:stream-copy-until-eof rmail-in mail-out)) (format standard-output " done.~%"))) (renamef out-file rmail-file)))))