;;; -*- Mode:Lisp; Readtable:CL; Package:USER; Base:10; Patch-File:T -*-
;;; Patch file for System version 123.138
;;; Reason:
;;;  Telnet Server input process now catches telnet Interrupt Process command and
;;;  sends an abort to the lisp listener.  Telnet Server now does proper option
;;;  negotiation -- you can successfully toggle remote echo.
;;; Written 3-Dec-87 16:29:08 by pld at site Gigamos Cambridge
;;; while running on Jack Flanders from band 2
;;; with Experimental System 123.136, Experimental Local-File 73.3, Experimental FILE-Server 22.1, Experimental Unix-Interface 11.0, Experimental Tape 18.0, Experimental KERMIT 34.0, 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#36 at 3-Dec-87 16:29:08
#10R TELNET#: 
(COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET")))
  (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  "

(defmethod (simple-ascii-stream-terminal :subtyi) ()
  (if need-force-output (send global:self :force-output))
  (do ((c))
      ((not (setq c (send input :tyi)))
       nil)
    (setq c (or (cadr (assoc c *special-ascii-lispm-translations* :test #'eq)) c))
    (cond ((= c (get 'iac 'telnet-sym))
	   (setq flush-next-lf nil)
	   (let (action option)
	     (setq c (send input :tyi))
	     (setq action (cadr (assoc c *telsyms* :test #'eq)))
	     (case action
	       (nil)
	       (do
		(setq c (send input :tyi))
		(setq option (cadr (assoc c *telopts* :test #'eq)))
		(push (list action option) telnet-commands-received)
		(case option
		  (telopt_echo
		   (unless (send self :echo-p)
		     (send self :set-echo-p t)
		     (send-iac output 'will option)))
		  (telopt_sga)
		  (telopt_logout
		   (return nil))
		  (t
		   (send-iac output 'wont option))))
	       (dont
		(setq c (send input :tyi))
		(setq option (cadr (assoc c *telopts* :test #'eq)))
		(push (list action option) telnet-commands-received)
		(case option
		  (telopt_echo
		   (when (send self :echo-p)
		     (send self :set-echo-p nil)
		     (send-iac output 'wont option)))
		  (telopt_sga
		   (send-iac output 'wont option))))
	       (will
		(setq c (send input :tyi))
		(setq option (cadr (assoc c *telopts* :test #'eq)))
		(push (list action option) telnet-commands-received)
		(case option
		  (telopt_sga
		   (send-iac output 'do option))
		  (t
		   (send-iac output 'dont option))))
	       (wont
		(setq c (send input :tyi))
		(setq option (cadr (assoc c *telopts* :test #'eq)))
		(push (list action option) telnet-commands-received)
		(case option
		  (telopt_sga
		   (send-iac output 'dont option))))
	       (sb
		(do ()
		    ((= (send input :tyi) (get 'se 'telnet-sym))))
		(push action telnet-commands-received))
	       (t
		(push action telnet-commands-received)))))
	  ((= c #\Return)
	   (setq flush-next-lf t)
	   (return #\Return))
	  ((and (= c #\Line) flush-next-lf)
	   (setq flush-next-lf nil))
	  ((= c #\Altmode)
	   (return (set-char-bit (send global:self :subtyi) :meta t)))
	  ((= c (glass-tty-ascii-code #\Control-\\))
	   (setq c (send global:self :subtyi))
	   (return (set-char-bit (make-char (global:char-flipcase (char-code c))
					    (char-bits c))
				 :super t)))
	  ((< c #o40)
	   (setq flush-next-lf nil)
	   (return (set-char-bit (logior #o100 c) :control 1)))
	  ('else
	   (setq flush-next-lf nil)
	   (return c)))))

))

; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TELNET.LISP#89 at 3-Dec-87 16:41:53
#10R TELNET#: 
(COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET")))
  (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TELNET  "


(defun telnet-server-function (remote-stream)
  (let* ((safe-input-stream (make-eof-throwing-stream remote-stream))
	 (terminal (make-stream-terminal nil remote-stream safe-input-stream))
	 (si:user-id nil)
	 (telnet-user:*term* nil)
	 (cvars '(telnet-user:*term* si:user-id)))
    (catch 'eof
      (send terminal :send-if-handles :send-initial-telnet-frobs)
      (format terminal "~%Welcome to ~A Server Telnet." (send si:local-host :name))
      (send terminal :force-output)
      (telnet-user-login terminal)
      (global:print-herald terminal)
      (terpri terminal)
      (send terminal :force-output)
      (multiple-value-bind (buffer-stream buffer)
	  (make-simple-io-buffer-stream)
	(send terminal :set-input-stream buffer-stream)
	(send terminal :set-more-p t)
	(send sys:current-process :set-priority 1)
	(catch 'telnet-server-logout
	  (telnet-server-input (subprocess :closure-variables cvars
					   (global:progw (append *telnet-user-process-bindings* si:*break-bindings*)
					     (catch 'telnet-server-logout
					       (si:lisp-top-level1 terminal))
					     (send (network-server-process *server*)
						   :interrupt #'telnet-user:logout)))
			       buffer
			       remote-stream))))))

))

; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TELNET.LISP#89 at 3-Dec-87 16:41:54
#10R TELNET#: 
(COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET")))
  (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TELNET  "


(defun telnet-server-input (user-process buffer remote-stream)
  (do (c int)
      ((null (setq c (send remote-stream :tyi))))
    (cond ((= c (get 'iac 'telnet-sym))
	   (let* ((c1 (send remote-stream :tyi))
		  (action (cadr (assoc c1 *telsyms* :test #'eq))))
	     (cond ((eq action 'ip)
		    (send user-process :interrupt 'telnet-user:abortion-interrupt))
		   (t
		    (simple-io-buffer-put buffer c)
		    (simple-io-buffer-put buffer c1)))))
	  ((setq int (assoc c *telnet-interrupt-characters* :test #'eq))
	   (cond ((third int)
		  (send user-process :interrupt 
			(second int)
			(funcall (third int) user-process)))
		 (t
		  (send user-process :interrupt (second int)))))
	  ((simple-io-buffer-full-p buffer)
	   ;; GOOD QUESTION. LETS JUST THROW AWAY CHARACTERS, OTHERWISE
	   ;; WE WILL MISS ANY #\CONTROL-G'S COMING DOWN.
	   (send remote-stream :tyo (glass-tty-ascii-code #\Control-g)))
	  (t
	   (simple-io-buffer-put buffer c)))))

))
