[comp.emacs] Using Kermit from shell mode

jeff@colgate.CSNET (Jeff Norden) (03/22/88)

I'm not sure, but I think somebody asked about running kermit under shell
mode a while ago.  Anyway, here is some code that I find useful.  The result
is that I can log onto machines with primitive operating systems (VMS and
ATT system V :-), and still have the features of shell-mode available for
command history, etc.  It's also handy to be able to run a file transfer in
an emacs window.  The transfer is in the "background", but you can also
monitor or stop it easily.

The ^\ key is bound to a function for sending escape sequences to kermit,
and ^C^Q can be used to send any control characters needed thru to the
system you connect to.  A more serious problem is that some brain-dead
systems will not recognize a ^J as an end-of-line character.  So LFD is
bound to a new function which acts just like CR usually does in shell-mode,
but a ^M is sent as an end-of-line.  Funcions are also provied to swap the
bindings of CR and LFD.  I've also included a filter which will clean out
any ^M's or ^@'s that get typed at you, but I don't really recommend it.
There doesn't seem to be an acceptably fast way to do this via emacs-lisp.
Invoking kermit by the command " kermit | tr -d '\015' " seems to work
better (on my system anyway).

Put the code below in a file named  wherever/kermit-shell.el, and add
 (autoload 'kermit "wherever/kermit-shell.el" "" t) 
to your .emacs file.  Then use M-x kermit when you want to load in the new
functions and bindings.  ("kermit" is just a dummy function which causes the
file to be loaded.)

Here's how I've been using this setup.  We have several machines connected
thru a fairly stupid terminal switch.  If I want to connect to unix system,
then I use the LFD key to talk to the switch, and ignore any ^M's in the
buffer, and do a " stty -echo nl " after I log in.  Then the only real
differnce from being in local shell-mode is that it is you need to to type
^C^Q^C to send an interrupt, and ^C^Q^Z for a stop signal, etc.  (since ^C^C
just generates a local stop signal, which kermit ignores).
To connect to a VMS system, I use a shell script to invoke kermit thru the
tr filter, do "M-X cr-key", and then tell VMS that I'm on a half-duplex
terminal.

Please let me know if any bugs turn up.  Also, shell-send-input-cr is hacked
directly from the gnu source, so the GNU copyright and license apply.


				-Jeff Norden
				jeff@colgate.csnet
			Dept of Mathematics, Colgate University
			Hamilton, NY  13346.

--- cut here ----- do not fold, bend, or spindle ----- cut here -----------
;;Additions to shell mode for use with kermit, etc.
;;Feb 1988, Jeff Norden - jeff@colgate.csnet
;;This file is part of GNU Emacs, copying restrictions apply.
;;Please see the GNU Emacs General Public License for details.
;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.

(require 'shell)

(defvar kermit-esc-char "\C-\\" "*Kermit's escape char")

(defun kermit-esc ()
"For sending escape sequences to a kermit running in shell mode."
 (interactive)
 (process-send-string 
   (get-buffer-process (current-buffer))
   (concat kermit-esc-char (char-to-string (read-char)))))

(defun send-char ()
"Send an arbitrary character to a program in shell mode."
 (interactive)
 (process-send-string 
   (get-buffer-process (current-buffer))
   (char-to-string (read-char))))

(define-key shell-mode-map "\C-\\" 'kermit-esc)
(define-key shell-mode-map "\C-cq" 'send-char)
;; extra bindings for folks suffering form ^S/^Q braindamage:
(define-key shell-mode-map "\C-c\\" 'kermit-esc)
(define-key shell-mode-map "\C-c\C-q" 'send-char)

(defun shell-send-input-cr ()
  "Same as shell-send-input, but a return (^M) is sent at the end 
 instead of a newline (^J)."
  (interactive)
  (end-of-line)
    (if (eobp)
	(progn
	  (move-marker last-input-start
	       (process-mark (get-buffer-process (current-buffer))))
	  (insert ?\n)
	  (move-marker last-input-end (point)))
    (beginning-of-line)
    (re-search-forward shell-prompt-pattern nil t)
    (let ((copy (buffer-substring (point)
				  (progn (forward-line 1) (point)))))
      (goto-char (point-max))
      (move-marker last-input-start (point))
      (insert copy)
      (move-marker last-input-end (point))))
    (condition-case ()
	(save-excursion
	  (goto-char last-input-start)
	  (shell-set-directory))
      (error (funcall shell-set-directory-error-hook)))
  (let ((process (get-buffer-process (current-buffer))))
    (process-send-region process last-input-start (- last-input-end 1))
    (process-send-string process "\r")
    (set-marker (process-mark process) (point))))

;; This is backwards of what makes sense, but ...
(define-key shell-mode-map "\n" 'shell-send-input-cr)

(defun cr-key ()
"For shell mode - set the return key to actually send a return and
the line feed key actually send a newline."
 (interactive)
 (define-key shell-mode-map "\r" 'shell-send-input-cr)
 (define-key shell-mode-map "\n" 'shell-send-input))

(defun nl-key () "The opposite of cr-key."
 (interactive)
 (define-key shell-mode-map "\n" 'shell-send-input-cr)
 (define-key shell-mode-map "\r" 'shell-send-input))

;; This filter works, but I don't especially recommend it.
(defun clean-filter (process string)
"A process filter which kills off ^M's and ^@'s."
 (set-buffer (process-buffer process))
 (let 
     ((firstpos (string-match "[^\C-@\r]+" string))
      (buffermark (process-mark process))
      (oldpt (point))
      (newstring '"")
      goback)
   (while firstpos
     (setq newstring 
	   (concat newstring (substring string firstpos (match-end 0))))
     (setq firstpos (string-match "[^\C-@\r]+" string (match-end 0))))
   (goto-char (marker-position buffermark))
   (setq goback (< oldpt (point)))
   (insert newstring)
   (set-marker buffermark (point))
   (if goback (goto-char oldpt))))

(defun clean-shell-on ()
"Add a filter to the process running in the current buffer so that
 null's and ^M's will not appear.
A better alternative is to pipe the program you want to run thru
 tr -d '\\015' "
 (interactive)
 (set-process-filter (get-buffer-process (current-buffer)) 'clean-filter))

(defun clean-shell-off ()
"Cancel a previous clean-shell-on command"
 (interactive)
 (set-process-filter (get-buffer-process (current-buffer)) nil))

(define-key shell-mode-map "\C-cC" 'clean-shell-on)
(define-key shell-mode-map "\C-cc" 'clean-shell-off)

(defun kermit () "Extensions to shell mode for using kermit"
 (interactive) (message "Kermit shell extensions have been loaded"))