;;; -*- Mode:Lisp; Readtable:CL; Package:USER; Base:10; Patch-File:T -*- ;;; Patch file for System version 123.159 ;;; Reason: ;;; Really make Server Telnet's H19 etc. support work. ;;; Written 9-Dec-87 15:13:12 by pld at site Gigamos Cambridge ;;; while running on Jack Flanders from band 2 ;;; with Experimental System 123.157, 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; TELNET.LISP#94 at 9-Dec-87 15:13:12 #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) (send terminal :initialize-terminal) (global:print-herald terminal) (format terminal "~%Type (help) for keyboard help~%~%") (send terminal :force-output) (subprocess :closure-variables cvars (loop (send terminal :force-output) (sys:process-sleep *telnet-asynchronous-force-output-period*))) (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 terminal)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:14:35 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defstruct (termcap (:conc-name termcap.) (:print-function (lambda (termcap stream ignore) (sys:printing-random-object (termcap stream :type :no-pointer) (format stream "of ~A" (termcap.name termcap)))))) name nicknames documentation add-blank-line (back-space #o10) clear-to-end-of-display clear-to-end-of-line clear-to-beginning-of-line clear-screen cursor-motion (number-of-columns 256) (number-of-lines 1000000) (carriage-return #o15) change-scrolling-region cursor-horizontal-motion cursor-vertical-motion delete-character delete-line enter-delete-mode down-one-line end-delete-mode enter-insert-mode end-insert-mode (form-feed #o14) hardcopy-p home-cursor insert-character initialization-string cursor-right (line-feed #o12) (tab-stops 8) (tab #o11) cursor-up visible-bell (audible-bell #o7) (linewrap-indicator #\!) auto-new-line cursor-down cursor-left) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:14:39 #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 :tyo-unlocked) (c) (cond ((< c #o40) (send self :string-out (aref *telnet-graphic-translations* c))) ((= c #\Return) (send self :terpri)) ((= c #\Tab) (send self :tab)) ((= c #\Overstrike) (when (plusp cursor-x) (send self :output-control-sequence (termcap.back-space termcap)) (decf cursor-x))) ((graphic-char-p c) (cond ((= cursor-x (- (termcap.number-of-columns termcap) 2)) (send output :tyo (termcap.linewrap-indicator termcap)) (send self :terpri) (send self :tyo c)) ('else (setq need-force-output t) (send output :tyo c) (incf cursor-x)))) ((and (zerop (char-bits c)) (> c #\Network)) ;; otherwise there will be a recursive call to this :TYO from FORMAT below. (format self "<~O>" c)) ('else (format self "~:C" c)))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:14:48 #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 :tab) () (let ((stops (termcap.tab-stops termcap))) (cond ((null stops) (send self :string-out " ")) ((numberp stops) (dotimes (i (mod cursor-x stops)) (send self :tyo #\Space))) ('else ;; a list of tab stops. write this some other time nil )))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:14:53 #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 :terpri) () (with-lock (output-lock) (cond ((= cursor-y (- (termcap.number-of-lines termcap) 2)) (cond ((not more-p) (send self :home-cursor) (send self :clear-eol)) ('else (send output :tyo (termcap.carriage-return termcap)) (send output :tyo (termcap.line-feed termcap)) (princ "**MORE**" output) (force-output output) (send input :tyi) (send output :tyo (termcap.carriage-return termcap)) (send self :clear-eol) (send self :home-cursor) (send self :clear-eol)))) ('else (setq cursor-x 0) (incf cursor-y) (send output :tyo (termcap.carriage-return termcap)) (send output :tyo (termcap.line-feed termcap)) (send self :clear-eol) (setq need-force-output t))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:14:58 #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 :clear-eol) () (let ((s (termcap.clear-to-end-of-line termcap))) (when s (send self :output-control-sequence s)))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:11 #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 self :force-output)) (do ((c) (action) (option) (quote)) ((not (setq c (or untyi-char (send input :tyi)))) nil) (cond (untyi-char (return (prog1 untyi-char (setq untyi-char nil)))) ((= c (get 'iac 'telnet-sym)) (setq flush-next-lf nil) (setq c (send input :tyi)) (case (setq action (cadr (assoc c *telsyms* :test #'eq))) (nil) (iac (return c)) (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)))) ((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#48 at 9-Dec-87 15:15:15 #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 :read-cursorpos) (&optional (type :pixel)) (ecase type (:pixel (values (* cursor-x 10) (* cursor-y 10))) (:character (values cursor-x cursor-y)))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:17 #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 :set-cursorpos) (x y &optional (type :pixel)) (ecase type (:pixel (send self :set-cursorpos (floor x 10) (floor y 10) :character)) (:character (setq cursor-x x) (setq cursor-y y) (dolist (item (termcap.cursor-motion termcap)) (send self :output-control-sequence (eval-cursorpos-item x y item))) ))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:23 #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 :set-cursor-x) (x) (send self :set-cursorpos x cursor-y :character)) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:25 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (defun eval-cursorpos-item (x y item) (cond ((eq item 'x) x) ((eq item 'y) y) ((symbolp item) (symbol-value item)) ((atom item) item) ('else (apply (car item) (mapcar #'(lambda (z) (eval-cursorpos-item x y z)) (cdr item)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:29 #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 :clear-screen) () (let ((s (termcap.clear-screen termcap))) (cond ((null s) (send self :fresh-line)) ('else (send self :output-control-sequence s) (setq cursor-x 0) (setq cursor-y 0)))) t) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:34 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (define-termcap h19 "Now manufactured by Zenith Data Systems. For Zenith-Mode functions" :nicknames '(h-19 z29 z-29 heath zenith) :add-blank-line '(*esc* "L") :clear-to-end-of-display '(*esc* "J") :clear-to-end-of-line '(*esc* "K") :clear-screen '(*esc* "E") :cursor-motion '(*esc* "Y" (+ y 32) (+ x 32)) :number-of-columns 80 :number-of-lines 24 :cursor-horizontal-motion nil :cursor-vertical-motion nil :delete-character '(*esc* "N") :delete-line '(*esc* "M") :enter-delete-mode nil :end-delete-mode nil :enter-insert-mode '(*esc* "@") :end-insert-mode '(*esc* "O") :home-cursor '(*esc* "H") :insert-character nil :initialization-string nil :cursor-up '(*esc* "A") :cursor-down '(*esc* "B") :cursor-right '(*esc* "C") :cursor-left '(*esc* "D") :tab nil :auto-new-line t ) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:40 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (define-termcap default "the default terminal capabilities" ) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:15:45 #10R TELNET#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TELNET"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; TERMCAP  " (define-termcap vt-100 "Another commonly used terminal" :nicknames '(vt100) :add-blank-line nil :clear-to-end-of-display '(*esc* "[J") :clear-to-end-of-line '(*esc* "[K") :clear-screen '(*esc* "[;H" *esc* "[2J") :cursor-motion '(*esc* "[" y ";" x "H") :number-of-columns 80 :number-of-lines 24 :cursor-horizontal-motion nil :cursor-vertical-motion nil :delete-character nil :delete-line nil :enter-delete-mode nil :down-one-line nil :end-delete-mode nil :enter-insert-mode nil :end-insert-mode nil :home-cursor '(*esc* "[H") :insert-character nil :initialization-string nil :cursor-right nil :cursor-up nil ) )) ; From modified file DJ: L.NETWORK.IP-TCP.SERVER; TERMCAP.LISP#48 at 9-Dec-87 15:19:50 #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 :any-tyi) (&optional ignore) (char-int-if-any (cond ((not tv:rubout-handler) (let ((c (if peek-chars (pop peek-chars) (send self :subtyi)))) (if (eq c *telnet-quote-character*) (send self :subtyi) c))) ('else (when (member status '(:restored :initial-entry) :test #'eq) (setq status nil) (send self :do-rubout-handler-prompting nil) (when echo-p (dolist (ch (reverse peek-chars)) (send self :tyo ch)))) (do ((ch) (quote) (rubout? nil) (activation-handler (assoc :activation tv:rubout-handler-options :test #'eq))) (peek-chars (car (push (pop peek-chars) buffer))) (setq ch (send self :subtyi)) (cond ((null ch) (return nil)) ((and (not quote) (eq ch *telnet-quote-character*)) (setq quote t)) ((and (not quote) (eq ch #\Rubout)) (when buffer (let ((x (pop buffer))) (dotimes (i (send self :tyo-print-length x)) (send self :tyo #\Overstrike) (send self :tyo #\Space) (send self :tyo #\Overstrike))) (and (null buffer) (assoc :full-rubout tv:rubout-handler-options :test #'eq) (throw 'tv:rubout-handler t)) (setq rubout? t))) ((and (not quote) (eq ch #\Control-U)) (when buffer (format self "~%") (setq tv:prompt-starting-x 0) (send self :force-output) (setq buffer nil) (setq peek-chars nil) (throw 'tv:rubout-handler t))) ((and (not quote) (eq ch #\Form)) (send self :clear-screen) (send self :redisplay ch)) ((and (not quote) (eq ch #\Control-R)) (send self :fresh-line) (send self :redisplay ch)) (t (push ch buffer) (cond ((and activation-handler (apply (cadr activation-handler) (char-int-if-any ch) (cddr activation-handler))) (setq ch `(:activation ,(char-int-if-any ch) 1)) (setq tv:rubout-handler-activation-character ch)) (echo-p (send self :tyo ch))) (when rubout? (setq peek-chars (reverse buffer)) (setq buffer nil) (throw 'tv:rubout-handler t)) (setq tv:rubout-handler-activation-character nil) (return ch))) ))))) ))