]> code.delx.au - gnu-emacs/blobdiff - lisp/telnet.el
(write-contents-hooks): Call make-variable-buffer-local.
[gnu-emacs] / lisp / telnet.el
index 18546e99ce31a27b9fcbd378d20419e9bcf6a05d..0be43dc80b7479249b7ea556cefe8f8ac789dc9b 100644 (file)
@@ -1,10 +1,9 @@
 ;;; telnet.el --- run a telnet session from within an Emacs buffer
 
 ;;; telnet.el --- run a telnet session from within an Emacs buffer
 
+;;; Copyright (C) 1985, 1988, 1992, 1994 Free Software Foundation, Inc.
+
 ;; Author: William F. Schelter
 ;; Maintainer: FSF
 ;; Author: William F. Schelter
 ;; Maintainer: FSF
-;; Last-Modified: 16 Mar 1992
-
-;;; Copyright (C) 1985, 1988, 1992 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
 
 ;; This file is part of GNU Emacs.
 
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
+;;; Commentary:
+
+;; This mode is intended to be used for telnet or rsh to a remode host;
+;; `telnet' and `rsh' are the two entry points.  Multiple telnet or rsh
+;; sessions are supported.
+;;
+;; Normally, input is sent to the remote telnet/rsh line-by-line, as you
+;; type RET or LFD.  C-c C-c sends a C-c to the remote immediately; 
+;; C-c C-z sends C-z immediately.  C-c C-q followed by any character
+;; sends that character immediately.
+;;
+;; All RET characters are filtered out of the output coming back from the
+;; remote system.  The mode tries to do other useful translations based
+;; on what it sees coming back from the other system before the password
+;; query.  It knows about UNIX, ITS, TOPS-20 and Explorer systems.
+
 ;;; Code:
 
 ;;; Code:
 
-;;to do fix software types for lispm:
-;;to eval current expression.  Also to try to send escape keys correctly.
-;;essentially we'll want the rubout-handler off.
+;; to do fix software types for lispm:
+;; to eval current expression.  Also to try to send escape keys correctly.
+;; essentially we'll want the rubout-handler off.
 
 ;; filter is simplistic but should be okay for typical shell usage.
 ;; needs hacking if it is going to deal with asynchronous output in a sane
 
 ;; filter is simplistic but should be okay for typical shell usage.
 ;; needs hacking if it is going to deal with asynchronous output in a sane
@@ -36,7 +51,7 @@
 
 (defvar telnet-new-line "\r")
 (defvar telnet-mode-map nil)
 
 (defvar telnet-new-line "\r")
 (defvar telnet-mode-map nil)
-(defvar telnet-prompt-pattern "^[^#$%>]*[#$%>] *")
+(defvar telnet-prompt-pattern "^[^#$%>\n]*[#$%>] *")
 (defvar telnet-replace-c-g nil)
 (make-variable-buffer-local
  (defvar telnet-remote-echoes t
 (defvar telnet-replace-c-g nil)
 (make-variable-buffer-local
  (defvar telnet-remote-echoes t
  (defvar telnet-interrupt-string "\C-c" "String sent by C-c."))
 
 (defvar telnet-count 0
  (defvar telnet-interrupt-string "\C-c" "String sent by C-c."))
 
 (defvar telnet-count 0
-  "Number of output strings read from the telnet process
-while looking for the initial password.")
+  "Number of output strings from telnet process while looking for password.")
+(make-variable-buffer-local 'telnet-count)
+
+(defvar telnet-program "telnet"
+  "Program to run to open a telnet connection.")
 
 (defvar telnet-initial-count -50
 
 (defvar telnet-initial-count -50
-  "Initial value of telnet-count.  Should be set to the negative of the
+  "Initial value of `telnet-count'.  Should be set to the negative of the
 number of terminal writes telnet will make setting up the host connection.")
 
 (defvar telnet-maximum-count 4
 number of terminal writes telnet will make setting up the host connection.")
 
 (defvar telnet-maximum-count 4
-  "Maximum value telnet-count can have.
+  "Maximum value `telnet-count' can have.
 After this many passes, we stop looking for initial setup data.
 Should be set to the number of terminal writes telnet will make
 After this many passes, we stop looking for initial setup data.
 Should be set to the number of terminal writes telnet will make
-rejecting one login and prompting for the again for a username and password.")
+rejecting one login and prompting again for a username and password.")
 
 (defun telnet-interrupt-subjob ()
   (interactive)
 
 (defun telnet-interrupt-subjob ()
   (interactive)
@@ -78,7 +96,7 @@ rejecting one login and prompting for the again for a username and password.")
 ; initialization on first load.
 (if telnet-mode-map
     nil
 ; initialization on first load.
 (if telnet-mode-map
     nil
-  (setq telnet-mode-map (copy-keymap comint-mode-map))
+  (setq telnet-mode-map (nconc (make-sparse-keymap) comint-mode-map))
   (define-key telnet-mode-map "\C-m" 'telnet-send-input)
 ;  (define-key telnet-mode-map "\C-j" 'telnet-send-input)
   (define-key telnet-mode-map "\C-c\C-q" 'send-process-next-char)
   (define-key telnet-mode-map "\C-m" 'telnet-send-input)
 ;  (define-key telnet-mode-map "\C-j" 'telnet-send-input)
   (define-key telnet-mode-map "\C-c\C-q" 'send-process-next-char)
@@ -95,7 +113,7 @@ rejecting one login and prompting for the again for a username and password.")
        ((string-match "tops-20" string) ;;maybe add telnet-replace-c-g
         (setq telnet-prompt-pattern  "[@>]*"))
        ((string-match "its" string)
        ((string-match "tops-20" string) ;;maybe add telnet-replace-c-g
         (setq telnet-prompt-pattern  "[@>]*"))
        ((string-match "its" string)
-        (setq telnet-prompt-pattern  "^[^*>]*[*>] *"))
+        (setq telnet-prompt-pattern  "^[^*>\n]*[*>] *"))
        ((string-match "explorer" string)  ;;explorer telnet needs work
         (setq telnet-replace-c-g ?\n))))
   (setq comint-prompt-regexp telnet-prompt-pattern))
        ((string-match "explorer" string)  ;;explorer telnet needs work
         (setq telnet-replace-c-g ?\n))))
   (setq comint-prompt-regexp telnet-prompt-pattern))
@@ -107,39 +125,46 @@ rejecting one login and prompting for the again for a username and password.")
         (error "No such host."))
        ((string-match "passw" string)
         (telnet-filter proc string)
         (error "No such host."))
        ((string-match "passw" string)
         (telnet-filter proc string)
-        (let* ((echo-keystrokes 0)
-               (password (read-password)))
-          (setq telnet-count 0)
-          (send-string proc (concat password telnet-new-line))))
+        (setq telnet-count 0)
+        (send-string proc (concat (comint-read-noecho "Password: " t)
+                                  telnet-new-line)))
        (t (telnet-check-software-type-initialize string)
           (telnet-filter proc string)
           (cond ((> telnet-count telnet-maximum-count)
                  (set-process-filter proc 'telnet-filter))
                 (t (setq telnet-count (1+ telnet-count)))))))
 
        (t (telnet-check-software-type-initialize string)
           (telnet-filter proc string)
           (cond ((> telnet-count telnet-maximum-count)
                  (set-process-filter proc 'telnet-filter))
                 (t (setq telnet-count (1+ telnet-count)))))))
 
+;; Identical to comint-simple-send, except that it sends telnet-new-line
+;; instead of "\n".
+(defun telnet-simple-send (proc string)
+  (comint-send-string proc string)
+  (comint-send-string proc telnet-new-line))
+
 (defun telnet-filter (proc string)
 (defun telnet-filter (proc string)
-  (let ((at-end
-        (and (eq (process-buffer proc) (current-buffer))
-             (= (point) (point-max)))))
-    (save-excursion
-      (set-buffer (process-buffer proc))
+  (save-excursion
+    (set-buffer (process-buffer proc))
+    (let* ((last-insertion (marker-position (process-mark proc)))
+          (delta (- (point) last-insertion))
+          (ie (and comint-last-input-end
+                   (marker-position comint-last-input-end)))
+          (w (get-buffer-window (current-buffer)))
+          (ws (and w (window-start w))))
+      (goto-char last-insertion)
+      (insert-before-markers string)
+      (set-marker (process-mark proc) (point))
+      (if ws (set-window-start w ws t))
+      (if ie (set-marker comint-last-input-end ie))
+      (while (progn (skip-chars-backward "^\C-m" last-insertion)
+                   (> (point) last-insertion))
+       (delete-region (1- (point)) (point)))
       (goto-char (process-mark proc))
       (goto-char (process-mark proc))
-      (let ((now (point)))
-       ;; Insert STRING, omitting all C-m characters.
-       (let ((index 0) c-m)
-         (while (setq c-m (string-match "\C-m" string index))
-           (insert-before-markers (substring string index c-m))
-           (setq index (1+ c-m)))
-         (insert-before-markers (substring string index)))
-       (and telnet-replace-c-g
-            (subst-char-in-region now (point) ?\C-g telnet-replace-c-g)))
-;      (if (and (integer-or-marker-p last-input-start)
-;             (marker-position last-input-start)
-;             telnet-remote-echoes)
-;        (delete-region last-input-start last-input-end))
-      )
-    (if at-end
-       (goto-char (point-max)))))
+      (and telnet-replace-c-g
+          (subst-char-in-region last-insertion (point) ?\C-g
+                                telnet-replace-c-g t))
+      ;; If point is after the insertion place, move it
+      ;; along with the text.
+      (if (> delta 0)
+         (goto-char (+ (process-mark proc) delta))))))
 
 (defun telnet-send-input ()
   (interactive)
 
 (defun telnet-send-input ()
   (interactive)
@@ -149,31 +174,40 @@ rejecting one login and prompting for the again for a username and password.")
       (delete-region comint-last-input-start
                     comint-last-input-end)))
 
       (delete-region comint-last-input-start
                     comint-last-input-end)))
 
+;;;###autoload (add-hook 'same-window-regexps "\\*telnet-.*\\*\\(\\|<[0-9]+>\\)")
+
 ;;;###autoload
 ;;;###autoload
-(defun telnet (arg)
+(defun telnet (host)
   "Open a network login connection to host named HOST (a string).
   "Open a network login connection to host named HOST (a string).
-Communication with HOST is recorded in a buffer *HOST-telnet*.
+Communication with HOST is recorded in a buffer `*telnet-HOST*'.
 Normally input is edited in Emacs and sent a line at a time."
   (interactive "sOpen telnet connection to host: ")
 Normally input is edited in Emacs and sent a line at a time."
   (interactive "sOpen telnet connection to host: ")
-  (let ((name (concat arg "-telnet" )))
-    (switch-to-buffer (make-comint name "telnet"))
-    (set-process-filter (get-process name) 'telnet-initial-filter)
-    (erase-buffer)
-    (send-string  name (concat "open " arg "\n"))
-    (telnet-mode)
-    (setq telnet-count telnet-initial-count)))
+  (let* ((comint-delimiter-argument-list '(?\  ?\t))
+         (name (concat "telnet-" (comint-arguments host 0 nil) ))
+        (buffer (get-buffer (concat "*" name "*")))
+        process)
+    (if (and buffer (get-buffer-process buffer))
+       (pop-to-buffer (concat "*" name "*"))
+      (pop-to-buffer (make-comint name telnet-program))
+      (setq process (get-buffer-process (current-buffer)))
+      (set-process-filter process 'telnet-initial-filter)
+      ;; Don't send the `open' cmd till telnet is ready for it.
+      (accept-process-output process)
+      (erase-buffer)
+      (send-string process (concat "open " host "\n"))
+      (telnet-mode)
+      (setq comint-input-sender 'telnet-simple-send)
+      (setq telnet-count telnet-initial-count))))
 
 (defun telnet-mode ()
 
 (defun telnet-mode ()
-  "This mode is for use during telnet from a buffer to another
-host. It has most of the same commands as comint-mode.
+  "This mode is for using telnet (or rsh) from a buffer to another host.
+It has most of the same commands as comint-mode.
 There is a variable ``telnet-interrupt-string'' which is the character
 sent to try to stop execution of a job on the remote host.
 Data is sent to the remote host when RET is typed.
 
 \\{telnet-mode-map}
 There is a variable ``telnet-interrupt-string'' which is the character
 sent to try to stop execution of a job on the remote host.
 Data is sent to the remote host when RET is typed.
 
 \\{telnet-mode-map}
-
-Bugs:
---Replaces \r by a space, really should remove."
+"
   (interactive)
   (comint-mode)
   (setq major-mode 'telnet-mode
   (interactive)
   (comint-mode)
   (setq major-mode 'telnet-mode
@@ -182,13 +216,20 @@ Bugs:
   (use-local-map telnet-mode-map)
   (run-hooks 'telnet-mode-hook))
 
   (use-local-map telnet-mode-map)
   (run-hooks 'telnet-mode-hook))
 
-(defun read-password ()
-  (let ((answ "") tem)
-    (message "Reading password...")
-    (while (prog1 (not (memq (setq tem (read-char)) '(?\C-m ?\n ?\C-g)))
-            (setq quit-flag nil))
-      (setq answ (concat answ (char-to-string tem))))
-    answ))
+;;;###autoload (add-hook 'same-window-regexps "\\*rsh-[^-]*\\*\\(\\|<[0-9]*>\\)")
+
+;;;###autoload
+(defun rsh (host)
+  "Open a network login connection to host named HOST (a string).
+Communication with HOST is recorded in a buffer `*rsh-HOST*'.
+Normally input is edited in Emacs and sent a line at a time."
+  (interactive "sOpen rsh connection to host: ")
+  (require 'shell)
+  (let ((name (concat "rsh-" host )))
+    (pop-to-buffer (make-comint name remote-shell-program nil host))
+    (set-process-filter (get-process name) 'telnet-initial-filter)
+    (telnet-mode)
+    (setq telnet-count -16)))
 
 (provide 'telnet)
 
 
 (provide 'telnet)