;;; -*- Mode:Lisp; Readtable:CL; Package:USER; Base:10; Patch-File:T -*- ;;; Patch file for System version 123.161 ;;; Reason: ;;; Server Telnet now does option negotiation per spec: all options assumed initially ;;; OFF, if command received to change to a state we are already in, no response is ;;; sent. Unless Go-aheads are suppressed, we now send one when enter :input-wait. ;;; Written 17-Dec-87 11:46:52 by pld at site Gigamos Cambridge ;;; while running on Jack Flanders from band 2 ;;; with Experimental System 123.160, Experimental Local-File 73.3, Experimental FILE-Server 22.1, Experimental Unix-Interface 11.0, Experimental Tape 18.0, Experimental KERMIT 34.2, Experimental ZMail 71.0, Experimental Lambda-Diag 15.0, microcode 1754, SDU Boot Tape 3.12, SDU ROM 8. ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 11:47:29 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defmethod (telnet-server :send-initial-telnet-frobs) () (send-option 'will 'telopt_echo) (send-option 'will 'telopt_sga) (send-option 'do 'telopt_sga)) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 11:47:31 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defun send-option (command option) (declare (:self-flavor telnet-server)) (let ((item (find-option telnet-options-sent option (case command ((do dont) '(do dont)) ((will wont) '(will wont)))))) (cond ((null item) (unless (member command '(dont wont)) (push (cons option command) telnet-options-sent) (send-iac command option))) ((eq (cdr item) command)) (t (setf (cdr item) command) (send-iac command option))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 11:47:32 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defun receive-option (command option) (declare (:self-flavor telnet-server)) (let ((item (find-option telnet-options-received option (case command ((do dont) '(do dont)) ((will wont) '(will wont)))))) (unless (eq (cdr item) command) (if (null item) (push (cons option command) telnet-options-received) (setf (cdr item) command)) (case command (do (send-option 'will option)) (dont (send-option 'wont option)) (will (send-option 'do option)) (wont (send-option 'dont option)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 11:47:34 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defun find-option (list option commands) (loop (setq list (member option list :key #'car :test #'eq)) (cond ((null list) (return nil)) ((member (cdar list) commands) (return (car list))) (t (setq list (cdr list)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 11:47:35 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defun send-iac (&rest commands) (declare (:self-flavor telnet-server)) (send output :tyo (get 'iac 'telnet-sym)) (dolist (char commands) (send output :tyo (cond ((not (symbolp char)) char) ((string-equal char "TELOPT_" :end1 7) (get char 'telnet-opt)) ('else (get char 'telnet-sym))))) (send output :force-output)) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 11:47:41 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defmethod (telnet-server :subtyi) () (if need-force-output (send self :force-output)) (flet ((getc (tcp stream) (unless (send tcp :listen) (send stream :notice :input-wait)) (send tcp :tyi))) (do ((c) (quote)) ((not (setq c (or untyi-char (getc input self)))) nil) (cond (untyi-char (return (prog1 untyi-char (setq untyi-char nil)))) ((= c (get 'iac 'telnet-sym)) (multiple-value-bind (return value) (receive-iac) (when return (return value)))) ((and (not quote) (= c *telnet-ascii-quote-character*)) (setq quote t)) ((and (not quote) (= c (glass-tty-ascii-code #\Altmode))) (setq c (send self :subtyi)) (return (set-char-bit (make-char (if (plusp (char-bits c)) c (global:char-flipcase (char-code c))) (char-bits c)) :meta t))) ((and (not quote) (= c (glass-tty-ascii-code #\Control-\\))) (setq c (send self :subtyi)) (return (set-char-bit (make-char (if (plusp (char-bits c)) c (global:char-flipcase (char-code c))) (char-bits c)) :super t))) ((= (setq c (translate-char c)) #\Return) (setq flush-next-lf t) (return #\Return)) ((and (= c #\Line) flush-next-lf) (setq flush-next-lf nil)) ('else (setq flush-next-lf nil) (when quote (setq untyi-char c) (setq c *telnet-quote-character*)) (return c)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 11:47:44 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defun receive-iac (&aux c action option) (declare (:self-flavor telnet-server)) (setq flush-next-lf nil) (setq c (send input :tyi)) (case (setq action (cadr (assoc c *telsyms* :test #'eq))) (iac (values t c)) (do (setq c (send input :tyi)) (setq option (cadr (assoc c *telopts* :test #'eq))) (case option ((telopt_echo telopt_sga) (receive-option action option)) (telopt_logout (receive-option action option) (return-from receive-iac (values t nil))) (t (send-option 'wont option))) nil) (dont (setq c (send input :tyi)) (setq option (cadr (assoc c *telopts* :test #'eq))) (case option ((telopt_echo telopt_sga) (receive-option action option))) nil) (will (setq c (send input :tyi)) (setq option (cadr (assoc c *telopts* :test #'eq))) (case option (telopt_sga (receive-option action option)) (t (send-option 'dont option))) nil) (wont (setq c (send input :tyi)) (setq option (cadr (assoc c *telopts* :test #'eq))) (case option (telopt_sga (receive-option action option))) nil) (sb (do ((se (get 'se 'telnet-sym))) ((= (send input :tyi) se))) nil) (t nil))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 12:02:03 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defmethod (telnet-server :notice) (event &rest args) (declare (ignore args)) (case event ((:input :output) ;Deexposed window needs some attention t) (:input-wait ;Hanging up waiting for input. (setf (tv:sheet-more-flag self) 0) (unless (find-option telnet-options-received 'telopt_sga '(do)) ;;Unless remote side said Do Suppress Go-aheads, send a Go-ahead (send-iac 'ga)) t) (:error ;Error in process using this window as its *TERMINAL-IO*. t) (otherwise nil))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#75 at 17-Dec-87 12:17:31 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defvar *telopts* '( ( 0 telopt_binary "8-bit data path") ( 1 telopt_echo "echo") ( 2 telopt_rcp "prepare to reconnect") ( 3 telopt_sga "suppress go ahead") ( 4 telopt_nams "approximate message size") ( 5 telopt_status "give status") ( 6 telopt_tm "timing mark") ( 7 telopt_rcte "remote controlled transmission and echo") ( 8 telopt_naol "negotiate about output line width") ( 9 telopt_naop "negotiate about output page size") ( 10 telopt_naocrd "negotiate about CR disposition") ( 11 telopt_naohts "negotiate about horizontal tabstops") ( 12 telopt_naohtd "negotiate about horizontal tab disposition") ( 13 telopt_naoffd "negotiate about formfeed disposition") ( 14 telopt_naovts "negotiate about vertical tab stops") ( 15 telopt_naovtd "negotiate about vertical tab disposition") ( 16 telopt_naolfd "negotiate about output LF disposition") ( 17 telopt_xascii "extended ascic character set") ( 18 telopt_logout "force logout") ( 19 telopt_bm "byte macro") ( 20 telopt_det "data entry terminal") ( 21 telopt_supdup "supdup protocol") ( 22 telopt_supdup-output "supdup output allowed") ( 255 telopt_exopl "extended-options-list"))) (dolist (x *telopts*) (setf (get (cadr x) 'telnet-opt) (car x))) ))