changeset 45861:7b663a89ef2a

*** empty log message ***
author Kai Großjohann <kgrossjo@eu.uu.net>
date Mon, 17 Jun 2002 11:47:23 +0000
parents 0dcc2162a55f
children 1bcf7f390ca2
files lisp/net/tramp-vc.el lisp/net/tramp.el man/tramp.texi
diffstat 3 files changed, 7258 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/net/tramp-vc.el	Mon Jun 17 11:47:23 2002 +0000
@@ -0,0 +1,480 @@
+;;; tramp-vc.el --- Version control integration for TRAMP.el
+
+;; Copyright (C) 2000 by Free Software Foundation, Inc.
+
+;; Author: Daniel Pittman <daniel@danann.net>
+;; Keywords: comm, processes
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; See the main module, 'tramp.el' for discussion of the purpose of TRAMP.
+;; This module provides integration between remote files accessed by TRAMP and
+;; the Emacs version control system.
+
+;;; Code:
+
+(eval-when-compile
+  (require 'cl))
+(require 'vc)
+;; Old VC defines vc-rcs-release in vc.el, new VC requires extra module.
+(unless (boundp 'vc-rcs-release)
+  (require 'vc-rcs))
+(require 'tramp)
+
+;; -- vc --
+
+;; This used to blow away the file-name-handler-alist and reinstall
+;; TRAMP into it. This was intended to let VC work remotely. It didn't,
+;; at least not in my XEmacs 21.2 install.
+;; 
+;; In any case, tramp-run-real-handler now deals correctly with disabling
+;; the things that should be, making this a no-op.
+;;
+;; I have removed it from the tramp-file-name-handler-alist because the
+;; shortened version does nothing. This is for reference only now.
+;;
+;; Daniel Pittman <daniel@danann.net>
+;;
+;; (defun tramp-handle-vc-registered (file)
+;;   "Like `vc-registered' for tramp files."
+;;   (tramp-run-real-handler 'vc-registered (list file)))
+
+;; `vc-do-command'
+;; This function does not deal well with remote files, so we define
+;; our own version and make a backup of the original function and
+;; call our version for tramp files and the original version for
+;; normal files.
+
+;; The following function is pretty much copied from vc.el, but
+;; the part that actually executes a command is changed.
+;; CCC: this probably works for Emacs 21, too.
+(defun tramp-vc-do-command (buffer okstatus command file last &rest flags)
+  "Like `vc-do-command' but invoked for tramp files.
+See `vc-do-command' for more information."
+  (save-match-data
+    (and file (setq file (tramp-handle-expand-file-name file)))
+    (if (not buffer) (setq buffer "*vc*"))
+    (if vc-command-messages
+	(message "Running `%s' on `%s'..." command file))
+    (let ((obuf (current-buffer)) (camefrom (current-buffer))
+	  (squeezed nil)
+	  (olddir default-directory)
+	  vc-file status)
+      (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name file)))
+	     (multi-method (tramp-file-name-multi-method v))
+	     (method (tramp-file-name-method v))
+	     (user (tramp-file-name-user v))
+	     (host (tramp-file-name-host v))
+	     (path (tramp-file-name-path v)))
+	(set-buffer (get-buffer-create buffer))
+	(set (make-local-variable 'vc-parent-buffer) camefrom)
+	(set (make-local-variable 'vc-parent-buffer-name)
+	     (concat " from " (buffer-name camefrom)))
+	(setq default-directory olddir)
+    
+	(erase-buffer)
+
+	(mapcar
+	 (function
+	  (lambda (s) (and s (setq squeezed (append squeezed (list s))))))
+	 flags)
+	(if (and (eq last 'MASTER) file
+		 (setq vc-file (vc-name file)))
+	    (setq squeezed
+		  (append squeezed
+			  (list (tramp-file-name-path
+				 (tramp-dissect-file-name vc-file))))))
+	(if (and file (eq last 'WORKFILE))
+	    (progn
+	      (let* ((pwd (expand-file-name default-directory))
+		     (preflen (length pwd)))
+		(if (string= (substring file 0 preflen) pwd)
+		    (setq file (substring file preflen))))
+	      (setq squeezed (append squeezed (list file)))))
+	;; Unless we (save-window-excursion) the layout of windows in
+	;; the current frame changes. This is painful, at best.
+	;;
+	;; As a point of note, (save-excursion) is still here only because
+	;; it preserves (point) in the current buffer. (save-window-excursion)
+	;; does not, at least under XEmacs 21.2.
+	;;
+	;; I trust that the FSF support this as well. I can't find useful
+	;; documentation to check :(
+	;;
+	;; Daniel Pittman <daniel@danann.net>
+	(save-excursion
+	  (save-window-excursion
+	    ;; Actually execute remote command
+	    (tramp-handle-shell-command
+	     (mapconcat 'tramp-shell-quote-argument
+			(cons command squeezed) " ") t)
+	    ;;(tramp-wait-for-output)
+	    ;; Get status from command
+	    (tramp-send-command multi-method method user host "echo $?")
+	    (tramp-wait-for-output)
+	    ;; Make sure to get status from last line of output.
+	    (goto-char (point-max)) (forward-line -1)
+	    (setq status (read (current-buffer)))
+	    (message "Command %s returned status %d." command status)))
+	(goto-char (point-max))
+	(set-buffer-modified-p nil)
+	(forward-line -1)
+	(if (or (not (integerp status)) (and okstatus (< okstatus status)))
+	    (progn
+	      (pop-to-buffer buffer)
+	      (goto-char (point-min))
+	      (shrink-window-if-larger-than-buffer)
+	      (error "Running `%s'...FAILED (%s)" command
+		     (if (integerp status)
+			 (format "status %d" status)
+		       status))
+	      )
+	  (if vc-command-messages
+	      (message "Running %s...OK" command))
+	  )
+	(set-buffer obuf)
+	status))
+    ))
+
+;; Following code snarfed from Emacs 21 vc.el and slightly tweaked.
+(defun tramp-vc-do-command-new (buffer okstatus command file &rest flags)
+  "Like `vc-do-command' but for TRAMP files.
+This function is for the new VC which comes with Emacs 21.
+Since TRAMP doesn't do async commands yet, this function doesn't, either."
+  (and file (setq file (expand-file-name file)))
+  (if vc-command-messages
+      (message "Running %s on %s..." command file))
+  (save-current-buffer
+    (unless (eq buffer t) (vc-setup-buffer buffer))
+    (let ((squeezed nil)
+	  (inhibit-read-only t)
+	  (status 0))
+      (let* ((v (when file (tramp-dissect-file-name file)))
+             (multi-method (when file (tramp-file-name-multi-method v)))
+             (method (when file (tramp-file-name-method v)))
+             (user (when file (tramp-file-name-user v)))
+             (host (when file (tramp-file-name-host v)))
+             (path (when file (tramp-file-name-path v))))
+      (setq squeezed (delq nil (copy-sequence flags)))
+      (when file
+	(setq squeezed (append squeezed (list path))))
+      (let ((w32-quote-process-args t))
+        (when (eq okstatus 'async)
+          (message "Tramp doesn't do async commands, running synchronously."))
+        (setq status (tramp-handle-shell-command
+                      (mapconcat 'tramp-shell-quote-argument
+                                 (cons command squeezed) " ") t))
+        (when (or (not (integerp status)) (and okstatus (< okstatus status)))
+          (pop-to-buffer (current-buffer))
+          (goto-char (point-min))
+          (shrink-window-if-larger-than-buffer)
+          (error "Running %s...FAILED (%s)" command
+                 (if (integerp status) (format "status %d" status) status))))
+      (if vc-command-messages
+          (message "Running %s...OK" command))
+      (vc-exec-after
+       `(run-hook-with-args
+         'vc-post-command-functions ',command ',path ',flags))
+      status))))
+
+
+;; The context for a VC command is the current buffer.
+;; That makes a test on the buffers file more reliable than a test on the
+;; arguments.
+;; This is needed to handle remote VC correctly - else we test against the
+;; local VC system and get things wrong...
+;; Daniel Pittman <daniel@danann.net>
+;;-(if (fboundp 'vc-call-backend)
+;;-    () ;; This is the new VC for which we don't have an appropriate advice yet
+(if (fboundp 'vc-call-backend)
+    (defadvice vc-do-command
+      (around tramp-advice-vc-do-command
+              (buffer okstatus command file &rest flags)
+              activate)
+      "Invoke tramp-vc-do-command for tramp files."
+      (let ((file (symbol-value 'file)))    ;pacify byte-compiler
+        (if (or (and (stringp file)     (tramp-tramp-file-p file))
+                (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name))))
+            (setq ad-return-value
+                  (apply 'tramp-vc-do-command-new buffer okstatus command 
+                         file ;(or file (buffer-file-name))
+                         flags))
+          ad-do-it)))
+  (defadvice vc-do-command
+    (around tramp-advice-vc-do-command
+            (buffer okstatus command file last &rest flags)
+            activate)
+    "Invoke tramp-vc-do-command for tramp files."
+    (let ((file (symbol-value 'file)))  ;pacify byte-compiler
+      (if (or (and (stringp file)     (tramp-tramp-file-p file))
+              (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name))))
+          (setq ad-return-value
+                (apply 'tramp-vc-do-command buffer okstatus command 
+                       (or file (buffer-file-name)) last flags))
+        ad-do-it))))
+;;-)
+
+
+;; XEmacs uses this to do some of its work. Like vc-do-command, we
+;; need to enhance it to make VC work via TRAMP-mode.
+;;
+;; Like the previous function, this is a cut-and-paste job from the VC
+;; file. It's based on the vc-do-command code.
+;; CCC: this isn't used in Emacs 21, so do as before.
+(defun tramp-vc-simple-command (okstatus command file &rest args)
+  ;; Simple version of vc-do-command, for use in vc-hooks only.
+  ;; Don't switch to the *vc-info* buffer before running the
+  ;; command, because that would change its default directory
+  (save-match-data
+    (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name file)))
+	   (multi-method (tramp-file-name-multi-method v))
+	   (method (tramp-file-name-method v))
+	   (user (tramp-file-name-user v))
+	   (host (tramp-file-name-host v))
+	   (path (tramp-file-name-path v)))
+      (save-excursion (set-buffer (get-buffer-create "*vc-info*"))
+		      (erase-buffer))
+      (let ((exec-path (append vc-path exec-path)) exec-status
+	    ;; Add vc-path to PATH for the execution of this command.
+	    (process-environment
+	     (cons (concat "PATH=" (getenv "PATH")
+			   path-separator
+			   (mapconcat 'identity vc-path path-separator))
+		   process-environment)))
+	;; Call the actual process. See tramp-vc-do-command for discussion of
+	;; why this does both (save-window-excursion) and (save-excursion).
+	;;
+	;; As a note, I don't think that the process-environment stuff above
+	;; has any effect on the remote system. This is a hard one though as
+	;; there is no real reason to expect local and remote paths to be
+	;; identical...
+	;;
+	;; Daniel Pittman <daniel@danann.net>
+	(save-excursion
+	  (save-window-excursion
+	    ;; Actually execute remote command
+	    (tramp-handle-shell-command
+	     (mapconcat 'tramp-shell-quote-argument
+			(append (list command) args (list path)) " ")
+	     (get-buffer-create"*vc-info*"))
+					;(tramp-wait-for-output)
+	    ;; Get status from command
+	    (tramp-send-command multi-method method user host "echo $?")
+	    (tramp-wait-for-output)
+	    (setq exec-status (read (current-buffer)))
+	    (message "Command %s returned status %d." command exec-status)))
+      
+	(cond ((> exec-status okstatus)
+	       (switch-to-buffer (get-file-buffer file))
+	       (shrink-window-if-larger-than-buffer
+		(display-buffer "*vc-info*"))
+	       (error "Couldn't find version control information")))
+	exec-status))))
+
+;; This function does not exist any more in Emacs-21's VC
+(defadvice vc-simple-command
+  (around tramp-advice-vc-simple-command
+	  (okstatus command file &rest args)
+	  activate)
+  "Invoke tramp-vc-simple-command for tramp files."
+  (let ((file (symbol-value 'file)))    ;pacify byte-compiler
+    (if (or (and (stringp file)     (tramp-tramp-file-p file))
+            (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name))))
+        (setq ad-return-value
+              (apply 'tramp-vc-simple-command okstatus command 
+                     (or file (buffer-file-name)) args))
+      ad-do-it)))
+
+
+;; `vc-workfile-unchanged-p'
+;; This function does not deal well with remote files, so we do the
+;; same as for `vc-do-command'.
+
+;; `vc-workfile-unchanged-p' checks the modification time, we cannot
+;; do that for remote files, so here's a version which relies on diff.
+;; CCC: this one probably works for Emacs 21, too.
+(defun tramp-vc-workfile-unchanged-p
+  (filename &optional want-differences-if-changed)
+  (if (fboundp 'vc-backend-diff)
+      ;; Old VC.  Call `vc-backend-diff'.
+      (let ((status (funcall (symbol-function 'vc-backend-diff)
+                             filename nil nil
+                             (not want-differences-if-changed))))
+        (zerop status))
+    ;; New VC.  Call `vc-default-workfile-unchanged-p'.
+    (vc-default-workfile-unchanged-p (vc-backend file) filename)))
+
+(defadvice vc-workfile-unchanged-p
+  (around tramp-advice-vc-workfile-unchanged-p
+          (filename &optional want-differences-if-changed)
+          activate)
+  "Invoke tramp-vc-workfile-unchanged-p for tramp files."
+  (if (and (stringp filename)
+	   (tramp-tramp-file-p filename)
+	   (not
+	    (let ((v	(tramp-dissect-file-name filename)))
+	      (tramp-get-remote-perl (tramp-file-name-multi-method v)
+				   (tramp-file-name-method v)
+				   (tramp-file-name-user v)
+				   (tramp-file-name-host v)))))
+      (setq ad-return-value
+            (tramp-vc-workfile-unchanged-p filename want-differences-if-changed))
+    ad-do-it))
+
+
+;; Redefine a function from vc.el -- allow tramp files.
+;; `save-match-data' seems not to be required -- it isn't in
+;; the original version, either.
+;; CCC: this might need some work -- how does the Emacs 21 version
+;; work, anyway?  Does it work over ange-ftp?  Hm.
+(if (not (fboundp 'vc-backend-checkout))
+    () ;; our replacement won't work and is unnecessary anyway
+(defun vc-checkout (filename &optional writable rev)
+  "Retrieve a copy of the latest version of the given file."
+  ;; If ftp is on this system and the name matches the ange-ftp format
+  ;; for a remote file, the user is trying something that won't work.
+  (funcall (symbol-function 'vc-backend-checkout) filename writable rev)
+  (vc-resynch-buffer filename t t))
+)
+
+
+;; Do we need to advise the vc-user-login-name function anyway?
+;; This will return the correct login name for the owner of a 
+;; file. It does not deal with the default remote user name...
+;;
+;; That is, when vc calls (vc-user-login-name), we return the 
+;; local login name, something that may be different to the remote
+;; default. 
+;;
+;; The remote VC operations will occur as the user that we logged
+;; in with however - not always the same as the local user.
+;;
+;; In the end, I did advise the function. This is because, well, 
+;; the thing didn't work right otherwise ;)
+;;
+;; Daniel Pittman <daniel@danann.net>
+
+(defun tramp-handle-vc-user-login-name (&optional uid)
+  "Return the default user name on the remote machine.
+Whenever VC calls this function, `file' is bound to the file name
+in question.  If no uid is provided or the uid is equal to the uid
+owning the file, then we return the user name given in the file name.
+
+This should only be called when `file' is bound to the
+filename we are thinking about..."
+  ;; Pacify byte-compiler; this symbol is bound in the calling
+  ;; function.  CCC: Maybe it would be better to move the
+  ;; boundness-checking into this function?
+  (let ((file (symbol-value 'file)))
+    (if (and uid (/= uid (nth 2 (file-attributes file))))
+	(error "tramp-handle-vc-user-login-name cannot map a uid to a name")
+      (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name file)))
+	     (u (tramp-file-name-user v)))
+	(cond ((stringp u) u)
+	      ((vectorp u) (elt u (1- (length u))))
+	      ((null    u) (user-login-name))
+	      (t	   (error "tramp-handle-vc-user-login-name cannot cope!")))))))
+
+
+(defadvice vc-user-login-name
+  (around tramp-vc-user-login-name activate)
+  "Support for files on remote machines accessed by TRAMP."
+  ;; We rely on the fact that `file' is bound when this is called.
+  ;; This appears to be the case everywhere in vc.el and vc-hooks.el
+  ;; as of Emacs 20.5.
+  ;;
+  ;; CCC TODO there should be a real solution!  Talk to Andre Spiegel
+  ;; about this.
+  (let ((file (when (boundp 'file)
+                (symbol-value 'file))))    ;pacify byte-compiler
+    (or (and (stringp file)
+             (tramp-tramp-file-p file)	; tramp file
+             (setq ad-return-value
+		   (save-match-data
+		     (tramp-handle-vc-user-login-name uid)))) ; get the owner name
+        ad-do-it)))                     ; else call the original
+
+  
+;; Determine the name of the user owning a file.
+(defun tramp-file-owner (filename)
+  "Return who owns FILE (user name, as a string)."
+  (let ((v (tramp-dissect-file-name 
+	    (tramp-handle-expand-file-name filename))))
+    (if (not (tramp-handle-file-exists-p filename))
+        nil                             ; file cannot be opened
+      ;; file exists, find out stuff
+      (save-excursion
+        (tramp-send-command
+         (tramp-file-name-multi-method v) (tramp-file-name-method v)
+         (tramp-file-name-user v) (tramp-file-name-host v)
+         (format "%s -Lld %s"
+                 (tramp-get-ls-command (tramp-file-name-multi-method v)
+                                     (tramp-file-name-method v)
+                                     (tramp-file-name-user v)
+                                     (tramp-file-name-host v))
+                 (tramp-shell-quote-argument (tramp-file-name-path v))))
+        (tramp-wait-for-output)
+        ;; parse `ls -l' output ...
+        ;; ... file mode flags
+        (read (current-buffer))
+        ;; ... number links
+        (read (current-buffer))
+        ;; ... uid (as a string)
+        (symbol-name (read (current-buffer)))))))
+
+;; Wire ourselves into the VC infrastructure...
+;; This function does not exist any more in Emacs-21's VC
+;; CCC: it appears that no substitute is needed for Emacs 21.
+(defadvice vc-file-owner
+  (around tramp-vc-file-owner activate)
+  "Support for files on remote machines accessed by TRAMP."
+  (let ((filename (ad-get-arg 0)))
+    (or (and (tramp-file-name-p filename) ; tramp file
+             (setq ad-return-value
+		   (save-match-data
+		     (tramp-file-owner filename)))) ; get the owner name
+        ad-do-it)))                     ; else call the original
+
+
+;; We need to make the version control software backend version
+;; information local to the current buffer. This is because each TRAMP
+;; buffer can (theoretically) have a different VC version and I am
+;; *way* too lazy to try and push the correct value into each new
+;; buffer.
+;;
+;; Remote VC costs will just have to be paid, at least for the moment.
+;; Well, at least, they will right until I feel guilty about doing a
+;; botch job here and fix it. :/
+;;
+;; Daniel Pittman <daniel@danann.net>
+;; CCC: this is probably still needed for Emacs 21.
+(defun tramp-vc-setup-for-remote ()
+  "Make the backend release variables buffer local.
+This makes remote VC work correctly at the cost of some processing time."
+  (when (and (buffer-file-name)
+             (tramp-tramp-file-p (buffer-file-name)))
+    (make-local-variable 'vc-rcs-release)
+    (setq vc-rcs-release nil)))
+(add-hook 'find-file-hooks 'tramp-vc-setup-for-remote t)
+
+;; No need to load this again if anyone asks.
+(provide 'tramp-vc)
+
+;;; tramp-vc.el ends here
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/net/tramp.el	Mon Jun 17 11:47:23 2002 +0000
@@ -0,0 +1,5152 @@
+;;; tramp.el --- Transparent Remote Access, Multiple Protocol -*- coding: iso-8859-1; -*- 
+
+;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+;; Author: Kai.Grossjohann@CS.Uni-Dortmund.DE 
+;; Keywords: comm, processes
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; This package provides remote file editing, similar to ange-ftp.
+;; The difference is that ange-ftp uses FTP to transfer files between
+;; the local and the remote host, whereas tramp.el uses a combination
+;; of rsh and rcp or other work-alike programs, such as ssh/scp.
+;;
+;; For more detailed instructions, please see the info file, which is
+;; included in the file `tramp.tar.gz' mentioned below.
+;;
+;; Notes:
+;; -----
+;; 
+;; This package only works for Emacs 20 and higher, and for XEmacs 21
+;; and higher.  (XEmacs 20 is missing the `with-timeout' macro.  Emacs
+;; 19 is reported to have other problems.  For XEmacs 21, you need the
+;; package `fsf-compat' for the `with-timeout' macro.)
+;;
+;; This version might not work with pre-Emacs 21 VC unless VC is
+;; loaded before tramp.el.  Could you please test this and tell me about
+;; the result?  Thanks.
+;;
+;; Also see the todo list at the bottom of this file.
+;;
+;; The current version of tramp.el can be retrieved from the following
+;; URL:  ftp://ls6-ftp.cs.uni-dortmund.de/pub/src/emacs/tramp.tar.gz
+;; For your convenience, the *.el file is available separately from
+;; the same directory.
+;;
+;; There's a mailing list for this, as well.  Its name is:
+;;                tramp-devel@lists.sourceforge.net
+;; Send a mail with `help' in the subject (!) to the administration
+;; address for instructions on joining the list.  The administration
+;; address is:
+;;            tramp-devel-request@lists.sourceforge.net
+;; You can also use the Web to subscribe, under the following URL:
+;;            http://lists.sourceforge.net/lists/listinfo/tramp-devel
+;;
+;; For the adventurous, the current development sources are available
+;; via CVS.  You can find instructions about this at the following URL:
+;;            http://sourceforge.net/projects/tramp/
+;; Click on "CVS" in the navigation bar near the top.
+;;
+;; Don't forget to put on your asbestos longjohns, first!
+
+;;; Code:
+
+(defconst tramp-version "2.0.0"
+  "This version of tramp.")
+(defconst tramp-bug-report-address "tramp-devel@mail.freesoftware.fsf.org"
+  "Email address to send bug reports to.")
+
+(require 'timer)
+(require 'format-spec)                  ;from Gnus 5.8, also in tar ball
+(require 'base64)                       ;for the mimencode methods
+(require 'shell)
+(require 'advice)
+
+;; ;; It does not work to load EFS after loading TRAMP.  
+;; (when (fboundp 'efs-file-handler-function)
+;;   (require 'efs))
+
+(eval-when-compile
+  (require 'cl)
+  (require 'custom)
+  ;; Emacs 19.34 compatibility hack -- is this needed?
+  (or (>= emacs-major-version 20)
+      (load "cl-seq")))
+
+(unless (boundp 'custom-print-functions)
+  (defvar custom-print-functions nil))	; not autoloaded before Emacs 20.4
+
+;;; User Customizable Internal Variables:
+
+(defgroup tramp nil
+  "Edit remote files with a combination of rsh and rcp or similar programs."
+  :group 'files)
+
+(defcustom tramp-verbose 10
+  "*Verbosity level for tramp.el.  0 means be silent, 10 is most verbose."
+  :group 'tramp
+  :type 'integer)
+
+(defcustom tramp-debug-buffer nil
+  "*Whether to send all commands and responses to a debug buffer."
+  :group 'tramp
+  :type 'boolean)
+
+(defcustom tramp-auto-save-directory nil
+  "*Put auto-save files in this directory, if set.
+The idea is to use a local directory so that auto-saving is faster."
+  :group 'tramp
+  :type '(choice (const nil)
+                 string))
+
+(defcustom tramp-sh-program "/bin/sh"
+  "*Use this program for shell commands on the local host.
+This MUST be a Bourne-like shell.  This shell is used to execute
+the encoding and decoding command on the local host, so if you
+want to use `~' in those commands, you should choose a shell here
+which groks tilde expansion.  `/bin/sh' normally does not
+understand tilde expansion.
+
+Note that this variable is not used for remote commands.  There are
+mechanisms in tramp.el which automatically determine the right shell to
+use for the remote host."
+  :group 'tramp
+  :type '(file :must-match t))
+
+;; CCC I have changed all occurrences of comint-quote-filename with
+;; tramp-shell-quote-argument, except in tramp-handle-expand-many-files.
+;; There, comint-quote-filename was removed altogether.  If it turns
+;; out to be necessary there, something will need to be done.
+;;-(defcustom tramp-file-name-quote-list
+;;-  '(?] ?[ ?\| ?& ?< ?> ?\( ?\) ?\; ?\  ?\* ?\? ?\! ?\" ?\' ?\` ?# ?\@ ?\+ )
+;;-  "*Protect these characters from the remote shell.
+;;-Any character in this list is quoted (preceded with a backslash)
+;;-because it means something special to the shell.  This takes effect
+;;-when sending file and directory names to the remote shell.
+;;-
+;;-See `comint-file-name-quote-list' for details."
+;;-  :group 'tramp
+;;-  :type '(repeat character))
+
+(defcustom tramp-methods
+  '( ("rcp"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "rsh")
+              (tramp-rcp-program          "rcp")
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    "-p")
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     nil)
+              (tramp-decoding-command     nil)
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    nil)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("scp"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh")
+              (tramp-rcp-program          "scp")
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    "-p")
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     nil)
+              (tramp-decoding-command     nil)
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    nil)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("scp1"  (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh1")
+              (tramp-rcp-program          "scp1")
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    "-p")
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     nil)
+              (tramp-decoding-command     nil)
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    nil)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("scp2"  (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh2")
+              (tramp-rcp-program          "scp2")
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    "-p")
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     nil)
+              (tramp-decoding-command     nil)
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    nil)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("rsync" (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh")
+              (tramp-rcp-program          "rsync")
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             ("-e" "ssh"))
+              (tramp-rcp-keep-date-arg    "-t")
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     nil)
+              (tramp-decoding-command     nil)
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    nil)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("ru"    (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "rsh")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("su"    (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("su1"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh1")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("su2"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh2")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("rm"    (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "rsh")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("sm"    (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("smp"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "tramp_mimencode")
+              (tramp-decoding-command     "tramp_mimedecode")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil))
+     ("sm1"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh1")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("sm2"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh2")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("tm"    (tramp-connection-function  tramp-open-connection-telnet)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       "telnet")
+              (tramp-telnet-args          nil))
+     ("tu"    (tramp-connection-function  tramp-open-connection-telnet)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       "telnet")
+              (tramp-telnet-args          nil))
+     ("sum"   (tramp-connection-function  tramp-open-connection-su)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           "su")
+              (tramp-su-args              ("-" "%u"))
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("suu"   (tramp-connection-function  tramp-open-connection-su)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           "su")
+              (tramp-su-args              ("-" "%u"))
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("sudm"  (tramp-connection-function  tramp-open-connection-su)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           "sudo")
+              (tramp-su-args              ("-u" "%u" "-s"))
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("sudu"  (tramp-connection-function  tramp-open-connection-su)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           "sudo")
+              (tramp-su-args              ("-u" "%u" "-s"))
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("multi" (tramp-connection-function  tramp-open-connection-multi)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("multiu" (tramp-connection-function  tramp-open-connection-multi)
+              (tramp-rsh-program          nil)
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             nil)
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    uudecode-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("scpx"  (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh")
+              (tramp-rcp-program          "scp")
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none" "-t" "-t" "/bin/sh"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    "-p")
+              (tramp-encoding-command     nil)
+              (tramp-decoding-command     nil)
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    nil)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("smx"   (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "ssh")
+              (tramp-rcp-program          nil)
+              (tramp-remote-sh            "/bin/sh")
+              (tramp-rsh-args             ("-e" "none" "-t" "-t" "/bin/sh"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    nil)
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     "mimencode -b")
+              (tramp-decoding-command     "mimencode -u -b")
+              (tramp-encoding-function    base64-encode-region)
+              (tramp-decoding-function    base64-decode-region)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("km"
+              (tramp-connection-function  tramp-open-connection-rsh)
+	      (tramp-rsh-program          "krlogin")
+	      (tramp-rcp-program          nil)
+	      (tramp-remote-sh            "/bin/sh")
+	      (tramp-rsh-args             ("-x"))
+	      (tramp-rcp-args             nil)
+	      (tramp-rcp-keep-date-arg    nil)
+	      (tramp-su-program           nil)
+	      (tramp-su-args              nil)
+	      (tramp-encoding-command     "mimencode -b")
+	      (tramp-decoding-command     "mimencode -u -b")
+	      (tramp-encoding-function    base64-encode-region)
+	      (tramp-decoding-function    base64-decode-region)
+	      (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("plinku"
+              (tramp-connection-function  tramp-open-connection-rsh)
+	      (tramp-rsh-program          "plink")
+	      (tramp-rcp-program          nil)
+	      (tramp-remote-sh            "/bin/sh")
+	      (tramp-rsh-args             ("-ssh")) ;optionally add "-v"
+	      (tramp-rcp-args             nil)
+	      (tramp-rcp-keep-date-arg    nil)
+	      (tramp-su-program           nil)
+	      (tramp-su-args              nil)
+              (tramp-encoding-command     "uuencode xxx")
+              (tramp-decoding-command
+               "( uudecode -o - 2>/dev/null || uudecode -p 2>/dev/null )")
+	      (tramp-encoding-function    nil)
+	      (tramp-decoding-function    uudecode-decode-region)
+	      (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("plinkm"
+              (tramp-connection-function  tramp-open-connection-rsh)
+	      (tramp-rsh-program          "plink")
+	      (tramp-rcp-program          nil)
+	      (tramp-remote-sh            "/bin/sh")
+	      (tramp-rsh-args             ("-ssh")) ;optionally add "-v"
+	      (tramp-rcp-args             nil)
+	      (tramp-rcp-keep-date-arg    nil)
+	      (tramp-su-program           nil)
+	      (tramp-su-args              nil)
+	      (tramp-encoding-command     "mimencode -b")
+	      (tramp-decoding-command     "mimencode -u -b")
+	      (tramp-encoding-function    base64-encode-region)
+	      (tramp-decoding-function    base64-decode-region)
+	      (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("pscp"
+              (tramp-connection-function  tramp-open-connection-rsh)
+	      (tramp-rsh-program          "plink")
+	      (tramp-rcp-program          "pscp")
+	      (tramp-remote-sh            "/bin/sh")
+	      (tramp-rsh-args             ("-ssh"))
+	      (tramp-rcp-args             nil)
+	      (tramp-rcp-keep-date-arg    "-p")
+	      (tramp-su-program           nil)
+	      (tramp-su-args              nil)
+	      (tramp-encoding-command     nil)
+	      (tramp-decoding-command     nil)
+	      (tramp-encoding-function    nil)
+	      (tramp-decoding-function    nil)
+	      (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     ("fcp"   
+	      (tramp-connection-function  tramp-open-connection-rsh)
+              (tramp-rsh-program          "fsh")
+              (tramp-rcp-program          "fcp")
+              (tramp-remote-sh            "/bin/sh -i")
+              (tramp-rsh-args             ("sh" "-i"))
+              (tramp-rcp-args             nil)
+              (tramp-rcp-keep-date-arg    "-p")
+              (tramp-su-program           nil)
+              (tramp-su-args              nil)
+              (tramp-encoding-command     nil)
+              (tramp-decoding-command     nil)
+              (tramp-encoding-function    nil)
+              (tramp-decoding-function    nil)
+              (tramp-telnet-program       nil)
+              (tramp-telnet-args          nil))
+     )
+  "*Alist of methods for remote files.
+This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
+Each NAME stands for a remote access method.  Each PARAM is a
+pair of the form (KEY VALUE).  The following KEYs are defined:
+  * `tramp-connection-function'
+    This specifies the function to use to connect to the remote host.
+    Currently, `tramp-open-connection-rsh', `tramp-open-connection-telnet'
+    and `tramp-open-connection-su' are defined.  See the documentation
+    of these functions for more details.
+  * `tramp-remote-sh'
+    This specifies the Bourne shell to use on the remote host.  This
+    MUST be a Bourne-like shell.  It is normally not necessary to set
+    this to any value other than \"/bin/sh\": tramp wants to use a shell
+    which groks tilde expansion, but it can search for it.  Also note
+    that \"/bin/sh\" exists on all Unixen, this might not be true for
+    the value that you decide to use.  You Have Been Warned.
+  * `tramp-rsh-program'
+    This specifies the name of the program to use for rsh; this might be
+    the full path to rsh or the name of a workalike program.
+  * `tramp-rsh-args'
+    This specifies the list of arguments to pass to the above
+    mentioned program.  Please note that this is a list of arguments,
+    that is, normally you don't want to put \"-a -b\" or \"-f foo\"
+    here.  Instead, you want two list elements, one for \"-a\" and one
+    for \"-b\", or one for \"-f\" and one for \"foo\".
+  * `tramp-rcp-program'
+    This specifies the name of the program to use for rcp; this might be
+    the full path to rcp or the name of a workalike program.
+  * `tramp-rcp-args'
+    This specifies the list of parameters to pass to the above mentioned
+    program, the hints for `tramp-rsh-args' also apply here.
+  * `tramp-rcp-keep-date-arg'
+    This specifies the parameter to use for `rcp' when the timestamp
+    of the original file should be kept.  For `rcp', use `-p', for
+    `rsync', use `-t'.
+  * `tramp-su-program'
+    This specifies the name of the program to use for `su'.
+  * `tramp-su-args'
+    This specifies the list of arguments to pass to `su'.
+    \"%u\" is replaced by the user name, use \"%%\" for a literal
+    percent character.
+  * `tramp-encoding-command'
+    This specifies a command to use to encode the file contents for
+    transfer.  The command should read the raw file contents from
+    standard input and write the encoded file contents to standard
+    output.  In this string, the percent escape \"%f\" should be used
+    to indicate the file to convert.  Use \"%%\" if you need a literal
+    percent character in your command.
+  * `tramp-decoding-command'
+    This specifies a command to use to decode file contents encoded
+    with `tramp-encoding-command'.  The command should read from standard
+    input and write to standard output.
+  * `tramp-encoding-function'
+    This specifies a function to be called to encode the file contents
+    on the local side.  This function should accept two arguments
+    START and END, the beginning and end of the region to encode.  The
+    region should be replaced with the encoded contents.
+  * `tramp-decoding-function'
+    Same for decoding on the local side.
+  * `tramp-telnet-program'
+    Specifies the telnet program to use when using
+    `tramp-open-connection-telnet' to log in.
+  * `tramp-telnet-args'
+    Specifies list of arguments to pass to `telnet'.  The hints for
+    `tramp-rsh-args' also apply here.
+
+What does all this mean?  Well, you should specify `tramp-rsh-program',
+`tramp-telnet-program' or `tramp-su-program' for all methods; this program
+is used to log in to the remote site.  Then, there are two ways to
+actually transfer the files between the local and the remote side.
+One way is using an additional rcp-like program.  If you want to do
+this, set `tramp-rcp-program' in the method.
+
+Another possibility for file transfer is inline transfer, i.e. the
+file is passed through the same buffer used by `tramp-rsh-program'.  In
+this case, the file contents need to be protected since the
+`tramp-rsh-program' might use escape codes or the connection might not
+be eight-bit clean.  Therefore, file contents are encoded for transit.
+
+Two possibilities for encoding are uuencode/uudecode and mimencode.
+For uuencode/uudecode you want to set `tramp-encoding-command' to
+something like \"uuencode\" and `tramp-decoding-command' to \"uudecode
+-p\".  For mimencode you want to set `tramp-encoding-command' to
+something like \"mimencode -b\" and `tramp-decoding-command' to
+\"mimencode -b -u\".
+
+When using inline transfer, you can use a program or a Lisp function
+on the local side to encode or decode the file contents.  Set the
+`tramp-encoding-function' and `tramp-decoding-function' parameters to nil
+in order to use the commands or to the function to use.  It is
+possible to specify one function and the other parameter as nil.
+
+So, to summarize: if the method is an inline method, you must specify
+`tramp-encoding-command' and `tramp-decoding-command', and
+`tramp-rcp-program' must be nil.  If the method is out of band, then
+you must specify `tramp-rcp-program' and `tramp-rcp-args' and
+`tramp-encoding-command' and `tramp-decoding-command' must be nil.
+Every method, inline or out of band, must specify
+`tramp-connection-function' plus the associated arguments (for
+example, the telnet program if you chose
+`tramp-open-connection-telnet').
+
+Notes:
+
+When using `tramp-open-connection-su' the phrase `open connection to a
+remote host' sounds strange, but it is used nevertheless, for
+consistency.  No connection is opened to a remote host, but `su' is
+started on the local host.  You are not allowed to specify a remote
+host other than `localhost' or the name of the local host.
+
+Using a uuencode/uudecode inline method is discouraged, please use one
+of the base64 methods instead since base64 encoding is much more
+reliable and the commands are more standardized between the different
+Unix versions.  But if you can't use base64 for some reason, please
+note that the default uudecode command does not work well for some
+Unices, in particular AIX and Irix.  For AIX, you might want to use
+the following command for uudecode:
+
+    sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
+
+For Irix, no solution is known yet."
+  :group 'tramp
+  :type '(repeat
+          (cons string
+                (set (list (const tramp-connection-function) function)
+                     (list (const tramp-rsh-program)
+			   (choice (const nil) string))
+                     (list (const tramp-rcp-program)
+			   (choice (const nil) string))
+                     (list (const tramp-remote-sh)
+			   (choice (const nil) string))
+                     (list (const tramp-rsh-args) (repeat string))
+                     (list (const tramp-rcp-args) (repeat string))
+                     (list (const tramp-rcp-keep-date-arg)
+			   (choice (const nil) string))
+                     (list (const tramp-su-program)
+			   (choice (const nil) string))
+                     (list (const tramp-su-args) (repeat string))
+                     (list (const tramp-encoding-command)
+			   (choice (const nil) string))
+                     (list (const tramp-decoding-command)
+			   (choice (const nil) string))
+                     (list (const tramp-encoding-function)
+			   (choice (const nil) function))
+                     (list (const tramp-decoding-function)
+			   (choice (const nil) function))
+                     (list (const tramp-telnet-program)
+			   (choice (const nil) string))
+                     (list (const tramp-telnet-args) (repeat string))))))
+
+(defcustom tramp-multi-methods '("multi" "multiu")
+  "*List of multi-hop methods.
+Each entry in this list should be a method name as mentioned in the
+variable `tramp-methods'."
+  :group 'tramp
+  :type '(repeat string))
+
+(defcustom tramp-multi-connection-function-alist
+  '(("telnet" tramp-multi-connect-telnet "telnet %h%n")
+    ("rsh"    tramp-multi-connect-rlogin "rsh %h -l %u%n")
+    ("ssh"    tramp-multi-connect-rlogin "ssh %h -l %u%n")
+    ("su"     tramp-multi-connect-su     "su - %u%n")
+    ("sudo"   tramp-multi-connect-su     "sudo -u %u -s%n"))
+  "*List of connection functions for multi-hop methods.
+Each list item is a list of three items (METHOD FUNCTION COMMAND),
+where METHOD is the name as used in the file name, FUNCTION is the
+function to be executed, and COMMAND is the shell command used for
+connecting.
+
+COMMAND may contain percent escapes.  `%u' will be replaced with the
+user name, `%h' will be replaced with the host name, and `%n' will be
+replaced with an end-of-line character, as specified in the variable
+`tramp-rsh-end-of-line'.  Use `%%' for a literal percent character.
+Note that the interpretation of the percent escapes also depends on
+the FUNCTION.  For example, the `%u' escape is forbidden with the
+function `tramp-multi-connect-telnet'.  See the documentation of the
+various functions for details."
+  :group 'tramp
+  :type '(repeat (list string function string)))
+
+(defcustom tramp-default-method "rcp"
+  "*Default method to use for transferring files.
+See `tramp-methods' for possibilities."
+  :group 'tramp
+  :type 'string)
+
+(defcustom tramp-rsh-end-of-line "\n"
+  "*String used for end of line in rsh connections.
+I don't think this ever needs to be changed, so please tell me about it
+if you need to change this."
+  :group 'tramp
+  :type 'string)
+
+(defcustom tramp-remote-path
+  '("/bin" "/usr/bin" "/usr/sbin" "/usr/local/bin" "/usr/ccs/bin"
+    "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
+    "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
+  "*List of directories to search for executables on remote host.
+Please notify me about other semi-standard directories to include here.
+
+You can use `~' in this list, but when searching for a shell which groks
+tilde expansion, all directory names starting with `~' will be ignored."
+  :group 'tramp
+  :type '(repeat string))
+
+(defcustom tramp-login-prompt-regexp
+  ".*ogin: *$"
+  "*Regexp matching login-like prompts.
+The regexp should match the whole line."
+  :group 'tramp
+  :type 'regexp)
+
+(defcustom tramp-password-prompt-regexp
+  "^.*\\([pP]assword\\|passphrase.*\\):\^@? *$"
+  "*Regexp matching password-like prompts.
+The regexp should match the whole line.
+
+The `sudo' program appears to insert a `^@' character into the prompt."
+  :group 'tramp
+  :type 'regexp)
+
+(defcustom tramp-wrong-passwd-regexp
+  (concat "^.*\\(Permission denied.\\|Login [Ii]ncorrect\\|"
+          "Received signal [0-9]+\\|Connection \\(refused\\|closed\\)\\|"
+          "Sorry, try again.\\|Name or service not known\\).*$")
+  "*Regexp matching a `login failed' message.
+The regexp should match the whole line."
+  :group 'tramp
+  :type 'regexp)
+
+(defcustom tramp-temp-name-prefix "tramp."
+  "*Prefix to use for temporary files.
+If this is a relative file name (such as \"tramp.\"), it is considered
+relative to the directory name returned by the function
+`tramp-temporary-file-directory' (which see).  It may also be an
+absolute file name; don't forget to include a prefix for the filename
+part, though."
+  :group 'tramp
+  :type 'string)
+
+(defcustom tramp-discard-garbage nil
+  "*If non-nil, try to discard garbage sent by remote shell.
+Some shells send such garbage upon connection setup."
+  :group 'tramp
+  :type 'boolean)
+
+;; File name format.
+
+(defcustom tramp-file-name-structure
+  (list "\\`/\\[\\(\\([a-zA-Z0-9]+\\)/\\)?\\(\\([-a-zA-Z0-9_#/:]+\\)@\\)?\\([-a-zA-Z0-9_#/:@.]+\\)\\]\\(.*\\)\\'"
+        2 4 5 6)
+  "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
+the tramp file name structure.
+
+The first element REGEXP is a regular expression matching a tramp file
+name.  The regex should contain parentheses around the method name,
+the user name, the host name, and the file name parts.
+
+The second element METHOD is a number, saying which pair of
+parentheses matches the method name.  The third element USER is
+similar, but for the user name.  The fourth element HOST is similar,
+but for the host name.  The fifth element FILE is for the file name.
+These numbers are passed directly to `match-string', which see.  That
+means the opening parentheses are counted to identify the pair.
+
+See also `tramp-file-name-regexp' and `tramp-make-tramp-file-format'."
+  :group 'tramp
+  :type '(list (regexp :tag "File name regexp")
+               (integer :tag "Paren pair for method name")
+               (integer :tag "Paren pair for user name  ")
+               (integer :tag "Paren pair for host name  ")
+               (integer :tag "Paren pair for file name  ")))
+
+;;;###autoload
+(defcustom tramp-file-name-regexp "\\`/\\[.*\\]"
+  "*Regular expression matching file names handled by tramp.
+This regexp should match tramp file names but no other file names.
+\(When tramp.el is loaded, this regular expression is prepended to
+`file-name-handler-alist', and that is searched sequentially.  Thus,
+if the tramp entry appears rather early in the `file-name-handler-alist'
+and is a bit too general, then some files might be considered tramp
+files which are not really tramp files.
+
+Please note that the entry in `file-name-handler-alist' is made when
+this file (tramp.el) is loaded.  This means that this variable must be set
+before loading tramp.el.  Alternatively, `file-name-handler-alist' can be
+updated after changing this variable.
+
+Also see `tramp-file-name-structure' and `tramp-make-tramp-file-format'."
+  :group 'tramp
+  :type 'regexp)
+
+(defcustom tramp-make-tramp-file-format "/[%m/%u@%h]%p"
+  "*Format string saying how to construct tramp file name.
+`%m' is replaced by the method name.
+`%u' is replaced by the user name.
+`%h' is replaced by the host name.
+`%p' is replaced by the file name.
+`%%' is replaced by %.
+
+Also see `tramp-file-name-structure' and `tramp-file-name-regexp'."
+  :group 'tramp
+  :type 'string)
+
+;; HHH: New.  This format spec is made to handle the cases where the
+;;      user does not provide a user name for the connection.
+(defcustom tramp-make-tramp-file-user-nil-format "/[%m/%h]%p"
+  "*Format string saying how to construct tramp file name when the user name is not known.
+`%m' is replaced by the method name.
+`%h' is replaced by the host name.
+`%p' is replaced by the file name.
+`%%' is replaced by %.
+
+Also see `tramp-make-tramp-file-format', `tramp-file-name-structure', and `tramp-file-name-regexp'."
+  :group 'tramp
+  :type 'string)
+
+(defcustom tramp-multi-file-name-structure
+  (list (concat
+         ;; prefix
+         "\\`/\\[\\(\\([a-z0-9]+\\)\\)?"
+         ;; regexp specifying a hop
+         "\\(\\(%s\\)+\\)"
+         ;; path name
+         "\\]\\(.*\\)\\'")
+        2                               ;number of pair to match method
+        3                               ;number of pair to match hops
+        -1)                             ;number of pair to match path
+
+  "*Describes the file name structure of `multi' files.
+Multi files allow you to contact a remote host in several hops.
+This is a list of four elements (REGEXP METHOD HOP PATH).
+
+The first element, REGEXP, gives a regular expression to match against
+the file name.  In this regular expression, `%s' is replaced with the
+value of `tramp-multi-file-name-hop-structure'.  (Note: in order to
+allow multiple hops, you normally want to use something like
+\"\\\\(\\\\(%s\\\\)+\\\\)\" in the regular expression.  The outer pair
+of parentheses is used for the HOP element, see below.)
+
+All remaining elements are numbers.  METHOD gives the number of the
+paren pair which matches the method name.  HOP gives the number of the
+paren pair which matches the hop sequence.  PATH gives the number of
+the paren pair which matches the path name on the remote host.
+
+PATH can also be negative, which means to count from the end.  Ie, a
+value of -1 means the last paren pair.
+
+I think it would be good if the regexp matches the whole of the
+string, but I haven't actually tried what happens if it doesn't..."
+  :group 'tramp
+  :type '(list (regexp :tag "File name regexp")
+               (integer :tag "Paren pair for method name")
+               (integer :tag "Paren pair for hops")
+               (integer :tag "Paren pair to match path")))
+
+(defcustom tramp-multi-file-name-hop-structure
+  (list "/\\([a-z0-9_]+\\):\\([a-z0-9_]+\\)@\\([a-z0-9.-]+\\)"
+        1 2 3)
+  "*Describes the structure of a hop in multi files.
+This is a list of four elements (REGEXP METHOD USER HOST).  First
+element REGEXP is used to match against the hop.  Pair number METHOD
+matches the method of one hop, pair number USER matches the user of
+one hop, pair number HOST matches the host of one hop.
+
+This regular expression should match exactly all of one hop."
+  :group 'tramp
+  :type '(list (regexp :tag "Hop regexp")
+               (integer :tag "Paren pair for method name")
+               (integer :tag "Paren pair for user name")
+               (integer :tag "Paren pair for host name")))
+
+(defcustom tramp-make-multi-tramp-file-format
+  (list "/[%m" "/%m:%u@%h" "]%p")
+  "*Describes how to construct a `multi' file name.
+This is a list of three elements PREFIX, HOP and PATH.
+
+The first element PREFIX says how to construct the prefix, the second
+element HOP specifies what each hop looks like, and the final element
+PATH says how to construct the path name.
+
+In PREFIX, `%%' means `%' and `%m' means the method name.
+
+In HOP, `%%' means `%' and `%m', `%u', `%h' mean the hop method, hop
+user and hop host, respectively.
+
+In PATH, `%%' means `%' and `%p' means the path name.
+
+The resulting file name always contains one copy of PREFIX and one
+copy of PATH, but there is one copy of HOP for each hop in the file
+name.
+
+Note: the current implementation requires the prefix to contain the
+method name, followed by all the hops, and the path name must come
+last."
+  :group 'tramp
+  :type '(list string string string))
+
+(defcustom tramp-terminal-type "dumb"
+  "*Value of TERM environment variable for logging in to remote host.
+Because Tramp wants to parse the output of the remote shell, it is easily
+confused by ANSI color escape sequences and suchlike.  Often, shell init
+files conditionalize this setup based on the TERM environment variable."
+  :group 'tramp
+  :type 'string)
+
+(defcustom tramp-completion-without-shell-p nil
+  "*If nil, use shell wildcards for completion, else rely on Lisp only.
+Using shell wildcards for completions has the advantage that it can be
+fast even in large directories, but completion is always
+case-sensitive.  Relying on Lisp only means that case-insensitive
+completion is possible (subject to the variable `completion-ignore-case'),
+but it might be slow on large directories."
+  :group 'tramp
+  :type 'boolean)
+
+;;; Internal Variables:
+
+(defvar tramp-buffer-file-attributes nil
+  "Holds the `ls -ild' output for the current buffer.
+This variable is local to each buffer.  It is not used if the remote
+machine groks Perl.  If it is used, it's used as an emulation for
+the visited file modtime.")
+(make-variable-buffer-local 'tramp-buffer-file-attributes)
+
+(defvar tramp-end-of-output "/////"
+  "String used to recognize end of output.")
+
+(defvar tramp-connection-function nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-remote-sh nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-rsh-program nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-rsh-args nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-rcp-program nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-rcp-args nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-rcp-keep-date-arg nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-encoding-command nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-decoding-command nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-encoding-function nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-decoding-function nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-telnet-program nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+(defvar tramp-telnet-args nil
+  "This internal variable holds a parameter for `tramp-methods'.
+In the connection buffer, this variable has the value of the like-named
+method parameter, as specified in `tramp-methods' (which see).")
+
+;; CCC `local in each buffer'?
+(defvar tramp-ls-command nil
+  "This command is used to get a long listing with numeric user and group ids.
+This variable is automatically made buffer-local to each rsh process buffer
+upon opening the connection.")
+
+(defvar tramp-current-multi-method nil
+  "Name of `multi' connection method for this *tramp* buffer, or nil if not multi.
+This variable is automatically made buffer-local to each rsh process buffer
+upon opening the connection.")
+
+(defvar tramp-current-method nil
+  "Connection method for this *tramp* buffer.
+This variable is automatically made buffer-local to each rsh process buffer
+upon opening the connection.")
+
+(defvar tramp-current-user nil
+  "Remote login name for this *tramp* buffer.
+This variable is automatically made buffer-local to each rsh process buffer
+upon opening the connection.")
+
+(defvar tramp-current-host nil
+  "Remote host for this *tramp* buffer.
+This variable is automatically made buffer-local to each rsh process buffer
+upon opening the connection.")
+
+(defvar tramp-test-groks-nt nil
+  "Whether the `test' command groks the `-nt' switch.
+\(`test A -nt B' tests if file A is newer than file B.)
+This variable is automatically made buffer-local to each rsh process buffer
+upon opening the connection.")
+
+(defvar tramp-file-exists-command nil
+  "Command to use for checking if a file exists.
+This variable is automatically made buffer-local to each rsh process buffer
+upon opening the connection.")
+
+;; Perl script to implement `file-attributes' in a Lisp `read'able output.
+;; If you are hacking on this, note that you get *no* output unless this
+;; spits out a complete line, including the '\n' at the end.
+(defconst tramp-perl-file-attributes (concat
+ "$f = $ARGV[0];
+@s = lstat($f);
+if (($s[2] & 0170000) == 0120000) { $l = readlink($f); $l = \"\\\"$l\\\"\"; }
+elsif (($s[2] & 0170000) == 040000) { $l = \"t\"; }
+else { $l = \"nil\" };
+printf(\"(%s %u %u %u (%u %u) (%u %u) (%u %u) %u %u t (%u . %u) (%u %u))\\n\",
+$l, $s[3], $s[4], $s[5], $s[8] >> 16 & 0xffff, $s[8] & 0xffff,
+$s[9] >> 16 & 0xffff, $s[9] & 0xffff, $s[10] >> 16 & 0xffff, $s[10] & 0xffff,
+$s[7], $s[2], $s[1] >> 16 & 0xffff, $s[1] & 0xffff, $s[0] >> 16 & 0xffff, $s[0] & 0xffff);"
+ )
+  "Perl script to produce output suitable for use with `file-attributes'
+on the remote file system.")
+
+;; Perl script to implement `mime-encode'
+(defvar tramp-perl-mime-encode (concat
+ "sub encode_base64 ($);
+  my $buf;
+  while(read(STDIN, $buf, 60*57)) { print encode_base64($buf) }
+  sub encode_base64 ($) {
+    my $res = \"\";
+    my $eol = \"\n\";
+    pos($_[0]) = 0;                          # ensure start at the beginning
+    while ($_[0] =~ /(.{1,45})/gs) {
+	$res .= substr(pack(\"u\", $1), 1);
+	chop($res);
+    }
+    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
+    # fix padding at the end
+    my $padding = (3 - length($_[0]) % 3) % 3;
+    $res =~ s/.{$padding}$/\"=\" x $padding/e if $padding;
+    # break encoded string into lines of no more than 76 characters each
+    if (length $eol) {
+	$res =~ s/(.{1,76})/$1$eol/g;
+    }
+    $res;}"))
+
+;; Perl script to implement `mime-decode'
+(defvar tramp-perl-mime-decode (concat
+ "sub decode_base64 ($);
+  my $buf;
+  while(read(STDIN, $buf, 60*57)) { print decode_base64($buf) }
+  sub decode_base64 ($) {
+    local($^W) = 0; # unpack(\"u\",...) gives bogus warning in 5.00[123]
+
+    my $str = shift;
+    my $res = \"\";
+
+    $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
+    if (length($str) % 4) {
+	warn(\"Length of base64 data not a multiple of 4\")
+    }
+    $str =~ s/=+$//;                        # remove padding
+    $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
+    while ($str =~ /(.{1,60})/gs) {
+	my $len = chr(32 + length($1)*3/4); # compute length byte
+	$res .= unpack(\"u\", $len . $1 );    # uudecode
+    }
+    $res;}"))
+
+; These values conform to `file-attributes' from XEmacs 21.2.
+; GNU Emacs and other tools not checked.
+(defconst tramp-file-mode-type-map '((0  . "-")  ; Normal file (SVID-v2 and XPG2)
+				     (1  . "p")  ; fifo
+				     (2  . "c")  ; character device
+				     (3  . "m")  ; multiplexed character device (v7)
+				     (4  . "d")  ; directory
+				     (5  . "?")  ; Named special file (XENIX)
+				     (6  . "b")  ; block device
+				     (7  . "?")  ; multiplexed block device (v7)
+				     (8  . "-")  ; regular file
+				     (9  . "n")  ; network special file (HP-UX)
+				     (10 . "l")  ; symlink
+				     (11 . "?")  ; ACL shadow inode (Solaris, not userspace)
+				     (12 . "s")  ; socket
+				     (13 . "D")  ; door special (Solaris)
+				     (14 . "w")) ; whiteout (BSD)
+  "A list of file types returned from the `stat' system call.
+This is used to map a mode number to a permission string.")
+
+(defvar tramp-dos-coding-system
+  (if (and (fboundp 'coding-system-p)
+           (funcall 'coding-system-p '(dos)))
+      'dos
+    'undecided-dos)
+  "Some Emacsen know the `dos' coding system, others need `undecided-dos'.")
+
+
+;; New handlers should be added here.  The following operations can be
+;; handled using the normal primitives: file-name-as-directory,
+;; file-name-directory, file-name-nondirectory,
+;; file-name-sans-versions, get-file-buffer.
+(defconst tramp-file-name-handler-alist
+  '(
+    (load . tramp-handle-load)
+    (make-symbolic-link . tramp-handle-make-symbolic-link)
+    (file-name-directory . tramp-handle-file-name-directory)
+    (file-name-nondirectory . tramp-handle-file-name-nondirectory)
+    (file-truename . tramp-handle-file-truename)
+    (file-exists-p . tramp-handle-file-exists-p)
+    (file-directory-p . tramp-handle-file-directory-p)
+    (file-executable-p . tramp-handle-file-executable-p)
+    (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
+    (file-readable-p . tramp-handle-file-readable-p)
+    (file-regular-p . tramp-handle-file-regular-p)
+    (file-symlink-p . tramp-handle-file-symlink-p)
+    (file-writable-p . tramp-handle-file-writable-p)
+    (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
+    (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
+    (file-attributes . tramp-handle-file-attributes)
+    (file-modes . tramp-handle-file-modes)
+    (file-directory-files . tramp-handle-file-directory-files)
+    (directory-files . tramp-handle-directory-files)
+    (file-name-all-completions . tramp-handle-file-name-all-completions)
+    (file-name-completion . tramp-handle-file-name-completion)
+    (add-name-to-file . tramp-handle-add-name-to-file)
+    (copy-file . tramp-handle-copy-file)
+    (rename-file . tramp-handle-rename-file)
+    (set-file-modes . tramp-handle-set-file-modes)
+    (make-directory . tramp-handle-make-directory)
+    (delete-directory . tramp-handle-delete-directory)
+    (delete-file . tramp-handle-delete-file)
+    (directory-file-name . tramp-handle-directory-file-name)
+    (shell-command . tramp-handle-shell-command)
+    (insert-directory . tramp-handle-insert-directory)
+    (expand-file-name . tramp-handle-expand-file-name)
+    (file-local-copy . tramp-handle-file-local-copy)
+    (insert-file-contents . tramp-handle-insert-file-contents)
+    (write-region . tramp-handle-write-region)
+    (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
+    (dired-call-process . tramp-handle-dired-call-process)
+    (dired-recursive-delete-directory
+     . tramp-handle-dired-recursive-delete-directory)
+    (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
+    (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime))
+        "Alist of handler functions.
+Operations not mentioned here will be handled by the normal Emacs functions.")
+
+;;; For better error reporting.
+
+(defun tramp-version (arg)
+  "Print version number of tramp.el in minibuffer or current buffer."
+  (interactive "P")
+  (if arg (insert tramp-version) (message tramp-version)))
+
+;;; Internal functions which must come first.
+
+(defsubst tramp-message (level fmt-string &rest args)
+  "Emit a message depending on verbosity level.
+First arg LEVEL says to be quiet if `tramp-verbose' is less than LEVEL.  The
+message is emitted only if `tramp-verbose' is greater than or equal to LEVEL.
+Calls function `message' with FMT-STRING as control string and the remaining
+ARGS to actually emit the message (if applicable).
+
+This function expects to be called from the tramp buffer only!"
+  (when (<= level tramp-verbose)
+    (apply #'message (concat "tramp: " fmt-string) args)
+    (when tramp-debug-buffer
+      (save-excursion
+        (set-buffer
+         (tramp-get-debug-buffer
+	  tramp-current-multi-method tramp-current-method
+	  tramp-current-user tramp-current-host))
+        (goto-char (point-max))
+        (tramp-insert-with-face
+         'italic
+         (concat "# " (apply #'format fmt-string args) "\n"))))))
+
+(defun tramp-message-for-buffer
+  (multi-method method user host level fmt-string &rest args)
+  "Like `tramp-message' but temporarily switches to the tramp buffer.
+First three args METHOD, USER, and HOST identify the tramp buffer to use,
+remaining args passed to `tramp-message'."
+  (save-excursion
+    (set-buffer (tramp-get-buffer multi-method method user host))
+    (apply 'tramp-message level fmt-string args)))
+
+(defsubst tramp-line-end-position nil
+  "Return point at end of line.
+Calls `line-end-position' or `point-at-eol' if defined, else
+own implementation."
+  (cond
+   ((fboundp 'line-end-position) (funcall 'line-end-position))
+   ((fboundp 'point-at-eol) 	 (funcall 'point-at-eol))
+   (t (save-excursion (end-of-line) (point)))))
+
+;;; File Name Handler Functions:
+
+;; The following file name handler ops are not implemented (yet?).
+
+(defun tramp-handle-make-symbolic-link
+  (filename linkname &optional ok-if-already-exists)
+  "Like `make-symbolic-link' for tramp files.
+This function will raise an error if FILENAME and LINKNAME are not
+on the same remote host."
+  (unless (or (tramp-tramp-file-p filename)
+              (tramp-tramp-file-p linkname))
+    (tramp-run-real-handler 'make-symbolic-link
+			    (list filename linkname ok-if-already-exists)))
+  (let* ((file	 (tramp-dissect-file-name 	filename))
+	 (link   (tramp-dissect-file-name 	linkname))
+	 (multi	 (tramp-file-name-multi-method	file))
+	 (method (tramp-file-name-method	file))
+	 (user   (tramp-file-name-user		file))
+	 (host   (tramp-file-name-host		file))
+         (l-multi (tramp-file-name-multi-method link))
+         (l-meth  (tramp-file-name-method       link))
+         (l-user  (tramp-file-name-user         link))
+         (l-host  (tramp-file-name-host         link))
+	 (ln	 (tramp-get-remote-ln 		multi method user host))
+	 (cwd	 (file-name-directory		(tramp-file-name-path file))))
+    (unless ln
+      (signal 'file-error (list "Making a symbolic link."
+				"ln(1) does not exist on the remote host.")))
+
+    ;; Check that method, user, host are the same.
+    (unless (equal host l-host)
+      (signal 'file-error (list "Can't make symlink across hosts" host l-host)))
+    (unless (equal user l-user)
+      (signal 'file-error (list "Can't make symlink for different users"
+                                user l-user)))
+    (unless (and (equal multi l-multi)
+                 (equal method l-meth))
+      (signal 'file-error (list "Method must be the same for making symlinks"
+                                multi l-multi method l-meth)))
+
+    ;; Do the 'confirm if exists' thing.
+    (when (file-exists-p (tramp-file-name-path link))
+      ;; What to do?
+      (if (or (null ok-if-already-exists) ; not allowed to exist
+	      (and (numberp ok-if-already-exists)
+		   (not (yes-or-no-p
+			 (format "File %s already exists; make it a link anyway? "
+				 (tramp-file-name-path link))))))
+	  (signal 'file-already-exists (list "File already exists"
+					     (tramp-file-name-path link)))))
+    
+    ;; Right, they are on the same host, regardless of user, method, etc.
+    ;; We now make the link on the remote machine. This will occur as the user
+    ;; that FILENAME belongs to.
+    (zerop
+     (tramp-send-command-and-check
+      multi method user host
+      (format "cd %s && %s -sf %s %s"
+              cwd ln
+              (tramp-file-name-path file) ; target
+              (tramp-file-name-path link)) ; link name
+      t))))				
+
+
+(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
+  "Like `load' for tramp files.  Not implemented!"
+  (unless (file-name-absolute-p file)
+    (error "Tramp cannot `load' files without absolute path name"))
+  (unless nosuffix
+    (cond ((file-exists-p (concat file ".elc"))
+           (setq file (concat file ".elc")))
+          ((file-exists-p (concat file ".el"))
+           (setq file (concat file ".el")))))
+  (when must-suffix
+    ;; The first condition is always true for absolute file names.
+    ;; Included for safety's sake.
+    (unless (or (file-name-directory file)
+                (string-match "\\.elc?\\'" file))
+      (error "File `%s' does not include a `.el' or `.elc' suffix"
+             file)))
+  (unless noerror
+    (when (not (file-exists-p file))
+      (error "Cannot load nonexistant file `%s'" file)))
+  (if (not (file-exists-p file))
+      nil
+    (unless nomessage
+      (message "Loading %s..." file))
+    (let ((local-copy (file-local-copy file)))
+      ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
+      (load local-copy noerror t t)
+      (delete-file local-copy))
+    (unless nomessage
+      (message "Loading %s...done" file))
+    t))
+
+;; Path manipulation functions that grok TRAMP paths...
+(defun tramp-handle-file-name-directory (file)
+  "Like `file-name-directory' but aware of TRAMP files."
+  ;; everything except the last filename thing is the directory
+  (let* ((v	 (tramp-dissect-file-name file))
+         (multi-method (tramp-file-name-multi-method v))
+	 (method (tramp-file-name-method v))
+	 (user   (tramp-file-name-user v))
+	 (host   (tramp-file-name-host v))
+	 (path   (tramp-file-name-path v)))
+    (if (or (string= path "") (string= path "/"))
+	;; For a filename like "/[foo]", we return "/".  The `else'
+	;; case would return "/[foo]" unchanged.  But if we do that,
+	;; then `file-expand-wildcards' ceases to work.  It's not
+	;; quite clear to me what's the intuition that tells that this
+	;; behavior is the right behavior, but oh, well.
+	"/"
+      ;; run the command on the path portion only
+      ;; CCC: This should take into account the remote machine type, no?
+      ;;  --daniel <daniel@danann.net>
+      (tramp-make-tramp-file-name multi-method method user host
+				  ;; This will not recurse...
+				  (or (file-name-directory path) "")))))
+
+(defun tramp-handle-file-name-nondirectory (file)
+  "Like `file-name-nondirectory' but aware of TRAMP files."
+  (let ((v (tramp-dissect-file-name file)))
+    (file-name-nondirectory (tramp-file-name-path v))))
+
+(defun tramp-handle-file-truename (filename &optional counter prev-dirs)
+  "Like `file-truename' for tramp files."
+  (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))
+	 (multi-method (tramp-file-name-multi-method v))
+	 (method       (tramp-file-name-method v))
+	 (user         (tramp-file-name-user v))
+	 (host         (tramp-file-name-host v))
+	 (path         (tramp-file-name-path v))
+	 (steps        (tramp-split-string path "/"))
+	 (pathdir (let ((directory-sep-char ?/))
+		    (file-name-as-directory path)))
+	 (is-dir (string= path pathdir))
+	 (thisstep nil)
+	 (numchase 0)
+	 ;; Don't make the following value larger than necessary.
+	 ;; People expect an error message in a timely fashion when
+	 ;; something is wrong; otherwise they might think that Emacs
+	 ;; is hung.  Of course, correctness has to come first.
+	 (numchase-limit 20)
+	 (result nil)			;result steps in reverse order
+	 (curstri "")
+	 symlink-target)
+    (tramp-message-for-buffer
+     multi-method method user host
+     10 "Finding true name for `%s'" filename)
+    (while (and steps (< numchase numchase-limit))
+      (setq thisstep (pop steps))
+      (tramp-message-for-buffer
+       multi-method method user host
+       10 "Check %s"
+       (mapconcat 'identity
+		  (append '("") (reverse result) (list thisstep))
+		  "/"))
+      (setq symlink-target
+	    (nth 0 (tramp-handle-file-attributes
+		    (tramp-make-tramp-file-name
+		     multi-method method user host
+		     (mapconcat 'identity
+				(append '("") (reverse result) (list thisstep))
+				"/")))))
+      (cond ((string= "." thisstep)
+	     (tramp-message-for-buffer multi-method method user host
+				       10 "Ignoring step `.'"))
+	    ((string= ".." thisstep)
+	     (tramp-message-for-buffer multi-method method user host
+				       10 "Processing step `..'")
+	     (pop result))
+	    ((stringp symlink-target)
+	     ;; It's a symlink, follow it.
+	     (tramp-message-for-buffer
+	      multi-method method user host
+	      10 "Follow symlink to %s" symlink-target)
+	     (setq numchase (1+ numchase))
+	     (when (file-name-absolute-p symlink-target)
+	       (setq result nil))
+	     (setq steps
+		   (append (tramp-split-string symlink-target "/") steps)))
+	    (t
+	     ;; It's a file.
+	     (setq result (cons thisstep result)))))
+    (when (>= numchase numchase-limit)
+      (error "Maximum number (%d) of symlinks exceeded" numchase-limit))
+    (setq result (reverse result))
+    (tramp-message-for-buffer
+     multi-method method user host
+     10 "True name of `%s' is `%s'"
+     filename (mapconcat 'identity (cons "" result) "/"))
+    (tramp-make-tramp-file-name
+     multi-method method user host
+     (concat (mapconcat 'identity (cons "" result) "/")
+	     (if is-dir "/" "")))))
+
+;; Basic functions.
+
+(defun tramp-handle-file-exists-p (filename)
+  "Like `file-exists-p' for tramp files."
+  (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))
+        multi-method method user host path)
+    (setq multi-method (tramp-file-name-multi-method v))
+    (setq method (tramp-file-name-method v))
+    (setq user (tramp-file-name-user v))
+    (setq host (tramp-file-name-host v))
+    (setq path (tramp-file-name-path v))
+    (save-excursion
+      (zerop (tramp-send-command-and-check
+	      multi-method method user host
+	      (format
+               (tramp-get-file-exists-command multi-method method user host)
+               (tramp-shell-quote-argument path)))))))
+
+;; CCC: This should check for an error condition and signal failure
+;;      when something goes wrong.
+;; Daniel Pittman <daniel@danann.net>
+(defun tramp-handle-file-attributes (filename &optional nonnumeric)
+  "Like `file-attributes' for tramp files.
+Optional argument NONNUMERIC means return user and group name
+rather than as numbers."
+  (if (tramp-handle-file-exists-p filename)
+      ;; file exists, find out stuff
+      (save-excursion
+	(let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))
+	       (multi-method (tramp-file-name-multi-method v))
+	       (method (tramp-file-name-method v))
+	       (user (tramp-file-name-user v))
+	       (host (tramp-file-name-host v))
+	       (path (tramp-file-name-path v)))
+	  (if (tramp-get-remote-perl multi-method method user host)
+	      (tramp-handle-file-attributes-with-perl multi-method method user host path nonnumeric)
+	    (tramp-handle-file-attributes-with-ls multi-method method user host path nonnumeric))))
+    nil))				; no file
+
+
+(defun tramp-handle-file-attributes-with-ls
+  (multi-method method user host path &optional nonnumeric)
+  "Implement `file-attributes' for tramp files using the ls(1) command."
+  (let (symlinkp dirp
+		 res-inode res-filemodes res-numlinks
+		 res-uid res-gid res-size res-symlink-target)
+    (tramp-send-command
+     multi-method method user host
+     (format "%s %s %s"
+	     (tramp-get-ls-command multi-method method user host)
+	     (if nonnumeric "-ild" "-ildn")
+	     (tramp-shell-quote-argument path)))
+    (tramp-wait-for-output)
+    ;; parse `ls -l' output ...
+    ;; ... inode
+    (setq res-inode
+	  (condition-case err
+	      (read (current-buffer))
+	    (invalid-read-syntax
+	     (when (and (equal (cadr err)
+			       "Integer constant overflow in reader")
+			(string-match
+			 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
+			 (caddr err)))
+	       (let* ((big (read (substring (caddr err) 0
+					    (match-beginning 1))))
+		      (small (read (match-string 1 (caddr err))))
+		      (twiddle (/ small 65536)))
+		 (cons (+ big twiddle)
+		       (- small (* twiddle 65536))))))))
+    ;; ... file mode flags
+    (setq res-filemodes (symbol-name (read (current-buffer))))
+    ;; ... number links
+    (setq res-numlinks (read (current-buffer)))
+    ;; ... uid and gid
+    (setq res-uid (read (current-buffer)))
+    (setq res-gid (read (current-buffer)))
+    (unless nonnumeric
+      (unless (numberp res-uid) (setq res-uid -1))
+      (unless (numberp res-gid) (setq res-gid -1)))
+    ;; ... size
+    (setq res-size (read (current-buffer)))
+    ;; From the file modes, figure out other stuff.
+    (setq symlinkp (eq ?l (aref res-filemodes 0)))
+    (setq dirp (eq ?d (aref res-filemodes 0)))
+    ;; if symlink, find out file name pointed to
+    (when symlinkp
+      (search-forward "-> ")
+      (setq res-symlink-target
+	    (buffer-substring (point)
+			      (tramp-line-end-position))))
+    ;; return data gathered
+    (list
+     ;; 0. t for directory, string (name linked to) for symbolic
+     ;; link, or nil.
+     (or dirp res-symlink-target nil)
+     ;; 1. Number of links to file.
+     res-numlinks
+     ;; 2. File uid.
+     res-uid
+     ;; 3. File gid.
+     res-gid
+     ;; 4. Last access time, as a list of two integers. First
+     ;; integer has high-order 16 bits of time, second has low 16
+     ;; bits.
+     ;; 5. Last modification time, likewise.
+     ;; 6. Last status change time, likewise.
+     '(0 0) '(0 0) '(0 0)		;CCC how to find out?
+     ;; 7. Size in bytes (-1, if number is out of range).
+     res-size
+     ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
+     res-filemodes
+     ;; 9. t iff file's gid would change if file were deleted and
+     ;; recreated.
+     nil				;hm?
+     ;; 10. inode number.
+     res-inode
+     ;; 11. Device number.
+     -1					;hm?
+     )))
+
+(defun tramp-handle-file-attributes-with-perl
+  (multi-method method user host path &optional nonnumeric)
+  "Implement `file-attributes' for tramp files using a Perl script.
+
+The Perl command is sent to the remote machine when the connection
+is initially created and is kept cached by the remote shell."
+  (tramp-send-command
+   multi-method method user host
+   (format "tramp_file_attributes %s" 
+	   (tramp-shell-quote-argument path)))
+  (tramp-wait-for-output)
+  (let ((result (read (current-buffer))))
+    (setcar (nthcdr 8 result)
+	    (tramp-file-mode-from-int (nth 8 result)))
+    result))
+
+(defun tramp-handle-set-visited-file-modtime (&optional time-list)
+  "Like `set-visited-file-modtime' for tramp files."
+  (unless (buffer-file-name)
+    (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
+	   (buffer-name)))
+  (when time-list
+    (tramp-run-real-handler 'set-visited-file-modtime (list time-list)))
+  (let* ((coding-system-used nil)
+	 (f (buffer-file-name))
+	 (v (tramp-dissect-file-name f))
+	 (multi-method (tramp-file-name-multi-method v))
+	 (method (tramp-file-name-method v))
+	 (user (tramp-file-name-user v))
+	 (host (tramp-file-name-host v))
+	 (path (tramp-file-name-path v))
+	 (attr (file-attributes f))
+	 (modtime (nth 5 attr)))
+    ;; We use '(0 0) as a don't-know value.  See also
+    ;; `tramp-handle-file-attributes-with-ls'.
+    (when (boundp 'last-coding-system-used)
+      (setq coding-system-used last-coding-system-used))
+    (if (not (equal modtime '(0 0)))
+	(tramp-run-real-handler 'set-visited-file-modtime (list modtime))
+      (save-excursion
+	(tramp-send-command
+	 multi-method method user host
+	 (format "%s -ild %s"
+		 (tramp-get-ls-command multi-method method user host)
+		 (tramp-shell-quote-argument path)))
+	(tramp-wait-for-output)
+	(setq attr (buffer-substring (point)
+				     (progn (end-of-line) (point)))))
+      (setq tramp-buffer-file-attributes attr))
+    (when (boundp 'last-coding-system-used)
+      (setq last-coding-system-used coding-system-used))
+    nil))
+
+;; This function makes the same assumption as
+;; `tramp-handle-set-visited-file-modtime'.
+(defun tramp-handle-verify-visited-file-modtime (buf)
+  "Like `verify-visited-file-modtime' for tramp files."
+  (with-current-buffer buf
+    (let* ((f (buffer-file-name))
+	   (v (tramp-dissect-file-name f))
+	   (multi-method (tramp-file-name-multi-method v))
+	   (method (tramp-file-name-method v))
+	   (user (tramp-file-name-user v))
+	   (host (tramp-file-name-host v))
+	   (path (tramp-file-name-path v))
+	   (attr (file-attributes f))
+	   (modtime (nth 5 attr)))
+      (if attr
+	(if (not (equal modtime '(0 0)))
+	    ;; Why does `file-attributes' return a list (HIGH LOW), but
+	    ;; `visited-file-modtime' returns a cons (HIGH . LOW)?
+	    (let ((mt (visited-file-modtime)))
+	      (< (abs (tramp-time-diff modtime (list (car mt) (cdr mt)))) 2))
+	  (save-excursion
+	    (tramp-send-command
+	     multi-method method user host
+	     (format "%s -ild %s"
+		     (tramp-get-ls-command multi-method method user host)
+		     (tramp-shell-quote-argument path)))
+	    (tramp-wait-for-output)
+	    (setq attr (buffer-substring (point)
+					 (progn (end-of-line) (point)))))
+	  (equal tramp-buffer-file-attributes attr))
+	;; If file does not exist, say it is not modified.
+	nil))))
+
+(defadvice clear-visited-file-modtime (after tramp activate)
+  "Set `tramp-buffer-file-attributes' back to nil.
+Tramp uses this variable as an emulation for the actual modtime of the file,
+if the remote host can't provide the modtime."
+  (setq tramp-buffer-file-attributes nil))
+
+(defun tramp-handle-set-file-modes (filename mode)
+  "Like `set-file-modes' for tramp files."
+  (let ((v (tramp-dissect-file-name filename)))
+    (save-excursion
+      (unless (zerop (tramp-send-command-and-check
+                      (tramp-file-name-multi-method v)
+                      (tramp-file-name-method v)
+                      (tramp-file-name-user v)
+                      (tramp-file-name-host v)
+                      (format "chmod %s %s"
+                              (tramp-decimal-to-octal mode)
+                              (tramp-shell-quote-argument
+                               (tramp-file-name-path v)))))
+	(signal 'file-error
+		(list "Doing chmod"
+		      ;; FIXME: extract the proper text from chmod's stderr.
+		      "error while changing file's mode"
+		      filename))))))
+
+;; Simple functions using the `test' command.
+
+(defun tramp-handle-file-executable-p (filename)
+  "Like `file-executable-p' for tramp files."
+  (zerop (tramp-run-test "-x" filename)))
+
+(defun tramp-handle-file-readable-p (filename)
+  "Like `file-readable-p' for tramp files."
+  (zerop (tramp-run-test "-r" filename)))
+
+(defun tramp-handle-file-accessible-directory-p (filename)
+  "Like `file-accessible-directory-p' for tramp files."
+  (and (zerop (tramp-run-test "-d" filename))
+       (zerop (tramp-run-test "-r" filename))
+       (zerop (tramp-run-test "-x" filename))))
+
+;; When the remote shell is started, it looks for a shell which groks
+;; tilde expansion.  Here, we assume that all shells which grok tilde
+;; expansion will also provide a `test' command which groks `-nt' (for
+;; newer than).  If this breaks, tell me about it and I'll try to do
+;; something smarter about it.
+(defun tramp-handle-file-newer-than-file-p (file1 file2)
+  "Like `file-newer-than-file-p' for tramp files."
+  (cond ((not (file-exists-p file1))
+         nil)
+        ((not (file-exists-p file2))
+         t)
+        ;; We are sure both files exist at this point.
+        (t
+         (save-excursion
+           (let* ((v1 (tramp-dissect-file-name file1))
+                  (mm1 (tramp-file-name-multi-method v1))
+                  (m1 (tramp-file-name-method v1))
+                  (u1 (tramp-file-name-user v1))
+                  (h1 (tramp-file-name-host v1))
+                  (v2 (tramp-dissect-file-name file2))
+                  (mm2 (tramp-file-name-multi-method v2))
+                  (m2 (tramp-file-name-method v2))
+                  (u2 (tramp-file-name-user v2))
+                  (h2 (tramp-file-name-host v2)))
+             (unless (and (equal mm1 mm2)
+                          (equal m1 m2)
+                          (equal u1 u2)
+                          (equal h1 h2))
+               (signal 'file-error
+                       (list "Files must have same method, user, host"
+                             file1 file2)))
+             (unless (and (tramp-tramp-file-p file1)
+                          (tramp-tramp-file-p file2))
+               (signal 'file-error
+                       (list "Files must be tramp files on same host"
+                             file1 file2)))
+             (if (tramp-get-test-groks-nt mm1 m1 u1 h1)
+                 (zerop (tramp-run-test2 "test" file1 file2 "-nt"))
+               (zerop (tramp-run-test2 "tramp_test_nt" file1 file2))))))))
+
+;; Functions implemented using the basic functions above.
+
+(defun tramp-handle-file-modes (filename)
+  "Like `file-modes' for tramp files."
+  (when (file-exists-p filename)
+    (tramp-mode-string-to-int
+     (nth 8 (tramp-handle-file-attributes filename)))))
+
+(defun tramp-handle-file-directory-p (filename)
+  "Like `file-directory-p' for tramp files."
+  ;; Care must be taken that this function returns `t' for symlinks
+  ;; pointing to directories.  Surely the most obvious implementation
+  ;; would be `test -d', but that returns false for such symlinks.
+  ;; CCC: Stefan Monnier says that `test -d' follows symlinks.  And
+  ;; I now think he's right.  So we could be using `test -d', couldn't
+  ;; we?
+  ;;
+  ;; Alternatives: `cd %s', `test -d %s'
+  (save-excursion
+    (let ((v (tramp-dissect-file-name filename)))
+      (zerop
+       (tramp-send-command-and-check
+        (tramp-file-name-multi-method v) (tramp-file-name-method v)
+        (tramp-file-name-user v) (tramp-file-name-host v)
+        (format "test -d %s"
+                (tramp-shell-quote-argument (tramp-file-name-path v)))
+        t)))))                          ;run command in subshell
+
+(defun tramp-handle-file-regular-p (filename)
+  "Like `file-regular-p' for tramp files."
+  (and (tramp-handle-file-exists-p filename)
+       (eq ?- (aref (nth 8 (tramp-handle-file-attributes filename)) 0))))
+
+(defun tramp-handle-file-symlink-p (filename)
+  "Like `file-symlink-p' for tramp files."
+  (let ((x (car (tramp-handle-file-attributes filename))))
+    (when (stringp x) x)))
+
+(defun tramp-handle-file-writable-p (filename)
+  "Like `file-writable-p' for tramp files."
+  (if (tramp-handle-file-exists-p filename)
+      ;; Existing files must be writable.
+      (zerop (tramp-run-test "-w" filename))
+    ;; If file doesn't exist, check if directory is writable.
+    (and (zerop (tramp-run-test "-d" (tramp-handle-file-name-directory filename)))
+         (zerop (tramp-run-test "-w" (tramp-handle-file-name-directory filename))))))
+
+(defun tramp-handle-file-ownership-preserved-p (filename)
+  "Like `file-ownership-preserved-p' for tramp files."
+  (or (not (tramp-handle-file-exists-p filename))
+      ;; Existing files must be writable.
+      (zerop (tramp-run-test "-O" filename))))
+
+;; Other file name ops.
+
+;; ;; Matthias Köppe <mkoeppe@mail.math.uni-magdeburg.de>
+;; (defun tramp-handle-directory-file-name (directory)
+;;   "Like `directory-file-name' for tramp files."
+;;   (if (and (eq (aref directory (- (length directory) 1)) ?/)
+;; 	   (not (eq (aref directory (- (length directory) 2)) ?:)))
+;;       (substring directory 0 (- (length directory) 1))
+;;     directory))
+
+;; Philippe Troin <phil@fifi.org>
+(defun tramp-handle-directory-file-name (directory)
+  "Like `directory-file-name' for tramp files."
+  (let ((directory-length-1 (1- (length directory))))
+    (save-match-data
+      (if (and (eq (aref directory directory-length-1) ?/)
+  	       (eq (string-match tramp-file-name-regexp directory) 0)
+  	       (/= (match-end 0) directory-length-1))
+	  (substring directory 0 directory-length-1)
+	directory))))
+
+;; Directory listings.
+
+(defun tramp-handle-directory-files (directory &optional full match nosort)
+  "Like `directory-files' for tramp files."
+  (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name directory)))
+        multi-method method user host path result x)
+    (setq multi-method (tramp-file-name-multi-method v))
+    (setq method (tramp-file-name-method v))
+    (setq user (tramp-file-name-user v))
+    (setq host (tramp-file-name-host v))
+    (setq path (tramp-file-name-path v))
+    (save-excursion
+      (tramp-barf-unless-okay multi-method method user host
+			      (concat "cd " (tramp-shell-quote-argument path))
+			      nil
+			      'file-error
+			      "tramp-handle-directory-files: couldn't `cd %s'"
+			      (tramp-shell-quote-argument path))
+      (tramp-send-command
+       multi-method method user host
+       (concat (tramp-get-ls-command multi-method method user host)
+	       " -a | cat"))
+      (tramp-wait-for-output)
+      (goto-char (point-max))
+      (while (zerop (forward-line -1))
+	(setq x (buffer-substring (point)
+				  (tramp-line-end-position)))
+	(when (or (not match) (string-match match x))
+	  (if full
+	      (push (concat (file-name-as-directory directory)
+			    x)
+		    result)
+	    (push x result))))
+      (tramp-send-command multi-method method user host "cd")
+      (tramp-wait-for-output))
+    result))
+
+;; This function should return "foo/" for directories and "bar" for
+;; files.  We use `ls -ad' to get a list of files (including
+;; directories), and `find . -type d \! -name . -prune' to get a list
+;; of directories.
+(defun tramp-handle-file-name-all-completions (filename directory)
+  "Like `file-name-all-completions' for tramp files."
+  (unless (save-match-data (string-match "/" filename))
+    (let* ((v 		(tramp-dissect-file-name directory))
+	   (multi-method 	(tramp-file-name-multi-method v))
+	   (method 	(tramp-file-name-method v))
+	   (user 		(tramp-file-name-user v))
+	   (host 		(tramp-file-name-host v))
+	   (path 		(tramp-file-name-path v))
+	   (nowild        tramp-completion-without-shell-p)
+	   result)
+      (save-excursion
+	(tramp-barf-unless-okay
+	 multi-method method user host
+	 (format "cd %s" (tramp-shell-quote-argument path))
+	 nil 'file-error
+	 "tramp-handle-file-name-all-completions: Couldn't `cd %s'"
+	 (tramp-shell-quote-argument path))
+
+	;; Get a list of directories and files, including reliably
+	;; tagging the directories with a trailing '/'.  Because I
+	;; rock.  --daniel@danann.net
+	(tramp-send-command
+	 multi-method method user host
+	 (format (concat "%s -a %s 2>/dev/null | while read f; do "
+			 "if test -d \"$f\" 2>/dev/null; "
+			 "then echo \"$f/\"; else echo \"$f\"; fi; done")
+		 (tramp-get-ls-command multi-method method user host)
+		 (if (or nowild (zerop (length filename)))
+		     ""
+		   (format "-d %s*" (tramp-shell-quote-argument filename)))))
+
+	;; Now grab the output.
+	(tramp-wait-for-output)
+	(goto-char (point-max))
+	(while (zerop (forward-line -1))
+	  (push (buffer-substring (point)
+				  (tramp-line-end-position))
+		result))
+	
+	(tramp-send-command multi-method method user host "cd")
+	(tramp-wait-for-output)
+
+	;; Return the list.
+	(if nowild
+	    (all-completions filename (mapcar 'list result))
+	  result)))))
+
+
+;; The following isn't needed for Emacs 20 but for 19.34?
+(defun tramp-handle-file-name-completion (filename directory)
+  "Like `file-name-completion' for tramp files."
+  (unless (tramp-tramp-file-p directory)
+    (error
+     "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
+     directory))
+  ;(setq directory (tramp-handle-expand-file-name directory))
+  (try-completion
+   filename
+   (mapcar (lambda (x) (cons x nil))
+           (tramp-handle-file-name-all-completions filename directory))))
+
+;; cp, mv and ln
+
+(defun tramp-handle-add-name-to-file
+  (filename newname &optional ok-if-already-exists)
+  "Like `add-name-to-file' for tramp files."
+  (let* ((v1 (when (tramp-tramp-file-p filename)
+               (tramp-dissect-file-name (tramp-handle-expand-file-name filename))))
+         (v2 (when (tramp-tramp-file-p newname)
+               (tramp-dissect-file-name (tramp-handle-expand-file-name newname))))
+         (mmeth1 (when v1 (tramp-file-name-multi-method v1)))
+         (mmeth2 (when v2 (tramp-file-name-multi-method v2)))
+         (meth1  (when v1 (tramp-file-name-method v1)))
+         (meth2  (when v2 (tramp-file-name-method v2)))
+         (user1  (when v1 (tramp-file-name-user v1)))
+         (user2  (when v2 (tramp-file-name-user v2)))
+         (host1  (when v1 (tramp-file-name-host v1)))
+         (host2  (when v2 (tramp-file-name-host v2)))
+         (path1  (when v1 (tramp-file-name-path v1)))
+         (path2  (when v2 (tramp-file-name-path v2)))
+	 (ln     (when v1 (tramp-get-remote-ln mmeth1 meth1 user1 host1))))
+    (unless (and meth1 meth2 user1 user2 host1 host2
+                 (equal mmeth1 mmeth2)
+                 (equal meth1 meth2)
+                 (equal user1 user2)
+                 (equal host1 host2))
+      (error "add-name-to-file: %s"
+             "only implemented for same method, same user, same host"))
+    (when (and (not ok-if-already-exists)
+               (file-exists-p newname)
+               (not (numberp ok-if-already-exists))
+               (y-or-n-p
+                (format
+                 "File %s already exists; make it a new name anyway? "
+                 newname)))
+      (error "add-name-to-file: file %s already exists" newname))
+    (tramp-barf-unless-okay
+     mmeth1 meth1 user1 host1
+     (format "%s %s %s" ln (tramp-shell-quote-argument path1)
+             (tramp-shell-quote-argument path2))
+     nil 'file-error
+     "error with add-name-to-file, see buffer `%s' for details"
+     (buffer-name))))
+
+(defun tramp-handle-copy-file
+  (filename newname &optional ok-if-already-exists keep-date)
+  "Like `copy-file' for tramp files."
+  ;; Check if both files are local -- invoke normal copy-file.
+  ;; Otherwise, use tramp from local system.
+  (setq filename (expand-file-name filename))
+  (setq newname (expand-file-name newname))
+  ;; At least one file a tramp file?
+  (if (or (tramp-tramp-file-p filename)
+          (tramp-tramp-file-p newname))
+      (tramp-do-copy-or-rename-file
+       'copy filename newname ok-if-already-exists keep-date)
+    (tramp-run-real-handler
+     'copy-file
+     (list filename newname ok-if-already-exists keep-date))))
+
+(defun tramp-handle-rename-file
+  (filename newname &optional ok-if-already-exists)
+  "Like `rename-file' for tramp files."
+  ;; Check if both files are local -- invoke normal rename-file.
+  ;; Otherwise, use tramp from local system.
+  (setq filename (expand-file-name filename))
+  (setq newname (expand-file-name newname))
+  ;; At least one file a tramp file?
+  (if (or (tramp-tramp-file-p filename)
+          (tramp-tramp-file-p newname))
+      (tramp-do-copy-or-rename-file
+       'rename filename newname ok-if-already-exists)
+    (tramp-run-real-handler 'rename-file
+                          (list filename newname ok-if-already-exists))))
+
+(defun tramp-do-copy-or-rename-file
+  (op filename newname &optional ok-if-already-exists keep-date)
+  "Copy or rename a remote file.
+OP must be `copy' or `rename' and indicates the operation to perform.
+FILENAME specifies the file to copy or rename, NEWNAME is the name of
+the new file (for copy) or the new name of the file (for rename).
+OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
+KEEP-DATE means to make sure that NEWNAME has the same timestamp
+as FILENAME.
+
+This function is invoked by `tramp-handle-copy-file' and
+`tramp-handle-rename-file'.  It is an error if OP is neither of `copy'
+and `rename'.  FILENAME and NEWNAME must be absolute file names."
+  (unless (memq op '(copy rename))
+    (error "Unknown operation `%s', must be `copy' or `rename'" op))
+  (unless ok-if-already-exists
+    (when (file-exists-p newname)
+      (signal 'file-already-exists
+              (list newname))))
+  (let* ((v1 (when (tramp-tramp-file-p filename)
+               (tramp-dissect-file-name (tramp-handle-expand-file-name filename))))
+         (v2 (when (tramp-tramp-file-p newname)
+               (tramp-dissect-file-name (tramp-handle-expand-file-name newname))))
+         (mmeth1 (when v1 (tramp-file-name-multi-method v1)))
+         (mmeth2 (when v2 (tramp-file-name-multi-method v2)))
+         (meth1 (when v1 (tramp-file-name-method v1)))
+         (meth2 (when v2 (tramp-file-name-method v2)))
+         (mmeth (tramp-file-name-multi-method (or v1 v2)))
+         (meth (tramp-file-name-method (or v1 v2)))
+         (rcp-program (tramp-get-rcp-program mmeth meth))
+         (rcp-args (tramp-get-rcp-args mmeth meth))
+         (trampbuf (get-buffer-create "*tramp output*")))
+    ;; Check if we can use a shortcut.
+    (if (and meth1 meth2 (equal mmeth1 mmeth2) (equal meth1 meth2)
+             (equal (tramp-file-name-host v1)
+                    (tramp-file-name-host v2))
+             (equal (tramp-file-name-user v1)
+                    (tramp-file-name-user v2)))
+        ;; Shortcut: if method, host, user are the same for both
+        ;; files, we invoke `cp' or `mv' on the remote host directly.
+        (tramp-do-copy-or-rename-file-directly
+         op
+         (tramp-file-name-multi-method v1)
+         (tramp-file-name-method v1)
+         (tramp-file-name-user v1)
+         (tramp-file-name-host v1)
+         (tramp-file-name-path v1) (tramp-file-name-path v2)
+         keep-date)
+      ;; New algorithm: copy file first.  Then, if operation is
+      ;; `rename', go back and delete the original file if the copy
+      ;; was successful.
+      (if rcp-program
+          ;; The following code uses a tramp program to copy the file.
+          (let ((f1 (if (not v1)
+                        filename
+                      (tramp-make-rcp-program-file-name
+                       (tramp-file-name-user v1)
+                       (tramp-file-name-host v1)
+                       (tramp-shell-quote-argument (tramp-file-name-path v1)))))
+                (f2 (if (not v2)
+                        newname
+                      (tramp-make-rcp-program-file-name
+                       (tramp-file-name-user v2)
+                       (tramp-file-name-host v2)
+                       (tramp-shell-quote-argument (tramp-file-name-path v2)))))
+                (default-directory
+                  (if (tramp-tramp-file-p default-directory)
+                      (tramp-temporary-file-directory)
+                    default-directory)))
+            (when keep-date
+              (add-to-list 'rcp-args (tramp-get-rcp-keep-date-arg mmeth meth)))
+            (save-excursion (set-buffer trampbuf) (erase-buffer))
+            (unless
+                (equal 0 (apply #'call-process (tramp-get-rcp-program mmeth meth)
+                                nil trampbuf nil (append rcp-args (list f1 f2))))
+              (pop-to-buffer trampbuf)
+              (error (concat "tramp-do-copy-or-rename-file: %s"
+                             " didn't work, see buffer `%s' for details")
+                     (tramp-get-rcp-program mmeth meth) trampbuf)))
+        ;; The following code uses an inline method for copying.
+        ;; Let's start with a simple-minded approach: we create a new
+        ;; buffer, insert the contents of the source file into it,
+        ;; then write out the buffer.  This should work fine, whether
+        ;; the source or the target files are tramp files.
+        ;; CCC TODO: error checking
+        (when keep-date
+          (tramp-message 1 (concat "Warning: cannot preserve file time stamp"
+				 " with inline copying across machines")))
+        (save-excursion
+          (set-buffer trampbuf) (erase-buffer)
+          (insert-file-contents-literally filename)
+	  (let ((coding-system-for-write 'no-conversion))
+	    (write-region (point-min) (point-max) newname))))
+
+      ;; If the operation was `rename', delete the original file.
+      (unless (eq op 'copy)
+        (delete-file filename)))))
+
+(defun tramp-do-copy-or-rename-file-directly
+  (op multi-method method user host path1 path2 keep-date)
+  "Invokes `cp' or `mv' on the remote system.
+OP must be one of `copy' or `rename', indicating `cp' or `mv',
+respectively.  METHOD, USER, and HOST specify the connection.
+PATH1 and PATH2 specify the two arguments of `cp' or `mv'.
+If KEEP-DATE is non-nil, preserve the time stamp when copying."
+  ;; CCC: What happens to the timestamp when renaming?
+  (let ((cmd (cond ((and (eq op 'copy) keep-date) "cp -f -p")
+                   ((eq op 'copy) "cp -f")
+                   ((eq op 'rename) "mv -f")
+                   (t (error
+                       "Unknown operation `%s', must be `copy' or `rename'"
+                       op)))))
+    (save-excursion
+      (tramp-barf-unless-okay
+       multi-method method user host
+       (format "%s %s %s"
+               cmd
+               (tramp-shell-quote-argument path1)
+               (tramp-shell-quote-argument path2))
+       nil 'file-error
+       "Copying directly failed, see buffer `%s' for details."
+       (buffer-name)))))
+
+;; mkdir
+(defun tramp-handle-make-directory (dir &optional parents)
+  "Like `make-directory' for tramp files."
+  (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name dir))))
+    (tramp-barf-unless-okay
+     (tramp-file-name-multi-method v) (tramp-file-name-method v)
+     (tramp-file-name-user v) (tramp-file-name-host v)
+     (format " %s %s"
+             (if parents "mkdir -p" "mkdir")
+             (tramp-shell-quote-argument (tramp-file-name-path v)))
+     nil 'file-error
+     "Couldn't make directory %s" dir)))
+
+;; CCC error checking?
+(defun tramp-handle-delete-directory (directory)
+  "Like `delete-directory' for tramp files."
+  (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name directory))))
+    (save-excursion
+      (tramp-send-command
+       (tramp-file-name-multi-method v) (tramp-file-name-method v)
+       (tramp-file-name-user v) (tramp-file-name-host v)
+       (format "rmdir %s ; echo ok"
+               (tramp-shell-quote-argument (tramp-file-name-path v))))
+      (tramp-wait-for-output))))
+
+(defun tramp-handle-delete-file (filename)
+  "Like `delete-file' for tramp files."
+  (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename))))
+    (save-excursion
+      (unless (zerop (tramp-send-command-and-check
+                      (tramp-file-name-multi-method v)
+                      (tramp-file-name-method v)
+                      (tramp-file-name-user v)
+                      (tramp-file-name-host v)
+                      (format "rm -f %s"
+                              (tramp-shell-quote-argument
+                               (tramp-file-name-path v)))))
+        (signal 'file-error "Couldn't delete Tramp file")))))
+
+;; Dired.
+
+;; CCC: This does not seem to be enough. Something dies when
+;;      we try and delete two directories under TRAMP :/
+(defun tramp-handle-dired-recursive-delete-directory (filename)
+  "Recursively delete the directory given.
+This is like `dired-recursive-delete-directory' for tramp files."
+  (let* ((v	 (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))
+         (multi-method (tramp-file-name-multi-method v))
+	 (method (tramp-file-name-method v))
+	 (user   (tramp-file-name-user v))
+	 (host   (tramp-file-name-host v))
+	 (path   (tramp-file-name-path v)))
+    ;; run a shell command 'rm -r <path>'
+    ;; Code shamelessly stolen for the dired implementation and, um, hacked :)
+    (or (tramp-handle-file-exists-p filename)
+	(signal
+	 'file-error
+	 (list "Removing old file name" "no such directory" filename)))
+    ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
+    (tramp-send-command multi-method method user host 
+		      (format "rm -r %s" (tramp-shell-quote-argument path)))
+    ;; Wait for the remote system to return to us...
+    ;; This might take a while, allow it plenty of time.
+    (tramp-wait-for-output 120)
+    ;; Make sure that it worked...
+    (and (tramp-handle-file-exists-p filename)
+	 (error "Failed to recusively delete %s" filename))))
+	 
+
+(defun tramp-handle-dired-call-process (program discard &rest arguments)
+  "Like `dired-call-process' for tramp files."
+  (let ((v (tramp-dissect-file-name
+            (tramp-handle-expand-file-name default-directory)))
+        multi-method method user host path)
+    (setq multi-method (tramp-file-name-multi-method v))
+    (setq method (tramp-file-name-method v))
+    (setq user (tramp-file-name-user v))
+    (setq host (tramp-file-name-host v))
+    (setq path (tramp-file-name-path v))
+    (save-excursion
+      (tramp-barf-unless-okay
+       multi-method method user host
+       (format "cd %s" (tramp-shell-quote-argument path))
+       nil 'file-error
+       "tramp-handle-dired-call-process: Couldn't `cd %s'"
+       (tramp-shell-quote-argument path))
+      (tramp-send-command
+       multi-method method user host
+       (mapconcat #'tramp-shell-quote-argument (cons program arguments) " "))
+      (tramp-wait-for-output))
+    (unless discard
+      (insert-buffer (tramp-get-buffer multi-method method user host)))
+    (save-excursion
+      (prog1
+	  (tramp-send-command-and-check multi-method method user host nil)
+	(tramp-send-command multi-method method user host "cd")
+	(tramp-wait-for-output)))))
+
+;; Pacify byte-compiler.  The function is needed on XEmacs only.  I'm
+;; not sure at all that this is the right way to do it, but let's hope
+;; it works for now, and wait for a guru to point out the Right Way to
+;; achieve this.
+;;(eval-when-compile
+;;  (unless (fboundp 'dired-insert-set-properties)
+;;    (fset 'dired-insert-set-properties 'ignore)))
+;; Gerd suggests this:
+(eval-when-compile (require 'dired))
+;; Note that dired is required at run-time, too, when it is needed.
+;; It is only needed on XEmacs for the function
+;; `dired-insert-set-properties'.
+
+(defun tramp-handle-insert-directory
+  (filename switches &optional wildcard full-directory-p)
+  "Like `insert-directory' for tramp files."
+  (let ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))
+         multi-method method user host path)
+    (setq multi-method (tramp-file-name-multi-method v))
+    (setq method (tramp-file-name-method v))
+    (setq user (tramp-file-name-user v))
+    (setq host (tramp-file-name-host v))
+    (setq path (tramp-file-name-path v))
+    (tramp-message-for-buffer
+     multi-method method user host 10
+     "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
+     switches filename (if wildcard "yes" "no")
+     (if full-directory-p "yes" "no"))
+    (when wildcard
+      (setq wildcard (file-name-nondirectory path))
+      (setq path (file-name-directory path)))
+    (when (listp switches)
+      (setq switches (mapconcat 'identity switches " ")))
+    (unless full-directory-p
+      (setq switches (concat "-d " switches)))
+    (when wildcard
+      (setq switches (concat switches " " wildcard)))
+    (save-excursion
+      ;; If `full-directory-p', we just say `ls -l FILENAME'.
+      ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
+      (if full-directory-p
+          (tramp-send-command
+           multi-method method user host
+           (format "%s %s %s"
+                   (tramp-get-ls-command multi-method method user host)
+                   switches
+                   (if wildcard
+                       path
+                     (tramp-shell-quote-argument (concat path ".")))))
+        (tramp-barf-unless-okay
+         multi-method method user host
+         (format "cd %s" (tramp-shell-quote-argument
+                          (file-name-directory path)))
+         nil 'file-error
+         "Couldn't `cd %s'"
+         (tramp-shell-quote-argument (file-name-directory path)))
+        (tramp-send-command
+         multi-method method user host
+         (format "%s %s %s"
+                 (tramp-get-ls-command multi-method method user host)
+                 switches
+                 (if full-directory-p
+                     ;; Add "/." to make sure we got complete dir
+                     ;; listing for symlinks, too.
+                     (concat (file-name-as-directory
+                              (file-name-nondirectory path)) ".")
+                   (file-name-nondirectory path)))))
+      (sit-for 1)                       ;needed for rsh but not ssh?
+      (tramp-wait-for-output))
+    (insert-buffer (tramp-get-buffer multi-method method user host))
+    ;; On XEmacs, we want to call (exchange-point-and-mark t), but
+    ;; that doesn't exist on Emacs, so we use this workaround instead.
+    ;; Since zmacs-region-stays doesn't exist in Emacs, this ought to
+    ;; be safe.  Thanks to Daniel Pittman <daniel@danann.net>.
+    (let ((zmacs-region-stays t))
+      (exchange-point-and-mark))
+    (save-excursion
+      (tramp-send-command multi-method method user host "cd")
+      (tramp-wait-for-output))
+    ;; Another XEmacs specialty follows.  What's the right way to do
+    ;; it?
+    (when (and (featurep 'xemacs)
+               (eq major-mode 'dired-mode))
+      (save-excursion
+        (require 'dired)
+        (dired-insert-set-properties (point) (mark t))))))
+
+;; Continuation of kluge to pacify byte-compiler.
+;;(eval-when-compile
+;;  (when (eq (symbol-function 'dired-insert-set-properties) 'ignore)
+;;    (fmakunbound 'dired-insert-set-properties)))
+
+;; CCC is this the right thing to do?
+(defun tramp-handle-unhandled-file-name-directory (filename)
+  "Like `unhandled-file-name-directory' for tramp files."
+  (expand-file-name "~/"))
+
+;; Canonicalization of file names.
+
+(defun tramp-drop-volume-letter (name)
+  "Cut off unnecessary drive letter from file NAME.
+The function `tramp-handle-expand-file-name' calls `expand-file-name'
+locally on a remote file name.  When the local system is a W32 system
+but the remote system is Unix, this introduces a superfluous drive
+letter into the file name.  This function removes it.
+
+Doesn't do anything if the NAME does not start with a drive letter."
+  (if (and (> (length name) 1)
+           (char-equal (aref name 1) ?:)
+           (let ((c1 (aref name 0)))
+             (or (and (>= c1 ?A) (<= c1 ?Z))
+                 (and (>= c1 ?a) (<= c1 ?z)))))
+      (substring name 2)
+    name))
+
+(defun tramp-handle-expand-file-name (name &optional dir)
+  "Like `expand-file-name' for tramp files."
+  ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
+  (setq dir (or dir default-directory "/"))
+  ;; Unless NAME is absolute, concat DIR and NAME.
+  (unless (file-name-absolute-p name)
+    (setq name (concat (file-name-as-directory dir) name)))
+  ;; If NAME is not a tramp file, run the real handler
+  (if (not (tramp-tramp-file-p name))
+      (tramp-run-real-handler 'expand-file-name
+                              (list name nil))
+    ;; Dissect NAME.
+    (let* ((v (tramp-dissect-file-name name))
+	   (multi-method (tramp-file-name-multi-method v))
+	   (method (tramp-file-name-method v))
+	   (user (tramp-file-name-user v))
+	   (host (tramp-file-name-host v))
+	   (path (tramp-file-name-path v)))
+      (unless (file-name-absolute-p path)
+	(setq path (concat "~/" path)))
+      (save-excursion
+	;; Tilde expansion if necessary.  This needs a shell which
+	;; groks tilde expansion!  The function `tramp-find-shell' is
+	;; supposed to find such a shell on the remote host.  Please
+	;; tell me about it when this doesn't work on your system.
+	(when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" path)
+	  (let ((uname (match-string 1 path))
+		(fname (match-string 2 path)))
+	    ;; CCC fanatic error checking?
+	    (set-buffer (tramp-get-buffer multi-method method user host))
+	    (erase-buffer)
+	    (tramp-send-command
+	     multi-method method user host
+	     (format "cd %s; pwd" uname)
+	     t)
+	    (tramp-wait-for-output)
+	    (goto-char (point-min))
+	    (setq uname (buffer-substring (point) (tramp-line-end-position)))
+	    (setq path (concat uname fname))
+	    (erase-buffer)))
+	;; No tilde characters in file name, do normal
+	;; expand-file-name (this does "/./" and "/../").  We bind
+	;; directory-sep-char here for XEmacs on Windows, which would
+	;; otherwise use backslash.
+	(let ((directory-sep-char ?/))
+	  (tramp-make-tramp-file-name
+	   multi-method method user host
+	   (tramp-drop-volume-letter
+	    (tramp-run-real-handler 'expand-file-name (list path)))))))))
+
+;; Remote commands.
+
+(defun tramp-handle-shell-command (command &optional output-buffer error-buffer)
+  "Like `shell-command' for tramp files.
+This will break if COMMAND prints a newline, followed by the value of
+`tramp-end-of-output', followed by another newline."
+  (if (tramp-tramp-file-p default-directory)
+      (let* ((v (tramp-dissect-file-name
+                 (tramp-handle-expand-file-name default-directory)))
+             (multi-method (tramp-file-name-multi-method v))
+             (method (tramp-file-name-method v))
+             (user (tramp-file-name-user v))
+             (host (tramp-file-name-host v))
+             (path (tramp-file-name-path v))
+             status)
+	(when (string-match "&[ \t]*\\'" command)
+	  (error "Tramp doesn't grok asynchronous shell commands, yet"))
+        (when error-buffer
+          (error "Tramp doesn't grok optional third arg ERROR-BUFFER, yet"))
+        (save-excursion
+          (tramp-barf-unless-okay
+           multi-method method user host
+           (format "cd %s" (tramp-shell-quote-argument path))
+           nil 'file-error
+           "tramp-handle-shell-command: Couldn't `cd %s'"
+           (tramp-shell-quote-argument path))
+          (tramp-send-command multi-method method user host
+			      (concat command "; tramp_old_status=$?"))
+          ;; This will break if the shell command prints "/////"
+          ;; somewhere.  Let's just hope for the best...
+          (tramp-wait-for-output))
+        (unless output-buffer
+          (setq output-buffer (get-buffer-create "*Shell Command Output*"))
+          (set-buffer output-buffer)
+          (erase-buffer))
+        (unless (bufferp output-buffer)
+          (setq output-buffer (current-buffer)))
+        (set-buffer output-buffer)
+        (insert-buffer (tramp-get-buffer multi-method method user host))
+        (save-excursion
+	  (tramp-send-command multi-method method user host "cd")
+	  (tramp-wait-for-output)
+          (tramp-send-command
+           multi-method method user host
+           "tramp_set_exit_status $tramp_old_status; echo tramp_exit_status $?")
+          (tramp-wait-for-output)
+          (goto-char (point-max))
+          (unless (search-backward "tramp_exit_status " nil t)
+            (error "Couldn't find exit status of `%s'" command))
+          (skip-chars-forward "^ ")
+          (setq status (read (current-buffer))))
+        (unless (zerop (buffer-size))
+          (pop-to-buffer output-buffer))
+        status)
+    ;; The following is only executed if something strange was
+    ;; happening.  Emit a helpful message and do it anyway.
+    (message "tramp-handle-shell-command called with non-tramp directory: `%s'"
+             default-directory)
+    (tramp-run-real-handler 'shell-command
+			    (list command output-buffer error-buffer))))
+
+;; File Editing.
+
+(defsubst tramp-make-temp-file ()
+  (funcall (if (fboundp 'make-temp-file) 'make-temp-file 'make-temp-name)
+	   (expand-file-name tramp-temp-name-prefix
+			     (tramp-temporary-file-directory))))
+
+(defun tramp-handle-file-local-copy (filename)
+  "Like `file-local-copy' for tramp files."
+  (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))
+         (multi-method (tramp-file-name-multi-method v))
+         (method (tramp-file-name-method v))
+         (user (tramp-file-name-user v))
+         (host (tramp-file-name-host v))
+         (path (tramp-file-name-path v))
+         (trampbuf (get-buffer-create "*tramp output*"))
+         tmpfil)
+    (unless (file-exists-p filename)
+      (error "Cannot make local copy of non-existing file `%s'"
+             filename))
+    (setq tmpfil (tramp-make-temp-file))
+    (cond ((tramp-get-rcp-program multi-method method)
+           ;; Use tramp-like program for file transfer.
+           (tramp-message-for-buffer
+	    multi-method method user host
+	    5 "Fetching %s to tmp file %s..." filename tmpfil)
+           (save-excursion (set-buffer trampbuf) (erase-buffer))
+           (unless (equal 0
+                          (apply #'call-process
+                                 (tramp-get-rcp-program multi-method method)
+                                 nil trampbuf nil
+                                 (append (tramp-get-rcp-args multi-method method)
+                                         (list
+                                          (tramp-make-rcp-program-file-name
+                                           user host
+                                           (tramp-shell-quote-argument path))
+                                          tmpfil))))
+             (pop-to-buffer trampbuf)
+             (error (concat "tramp-handle-file-local-copy: `%s' didn't work, "
+                            "see buffer `%s' for details")
+                    (tramp-get-rcp-program multi-method method) trampbuf))
+           (tramp-message-for-buffer
+	    multi-method method user host
+	    5 "Fetching %s to tmp file %s...done" filename tmpfil))
+          ((and (tramp-get-encoding-command multi-method method)
+                (tramp-get-decoding-command multi-method method))
+           ;; Use inline encoding for file transfer.
+           (save-excursion
+             ;; Following line for setting tramp-current-method,
+             ;; tramp-current-user, tramp-current-host.
+             (set-buffer (tramp-get-buffer multi-method method user host))
+             (tramp-message 5 "Encoding remote file %s..." filename)
+             (tramp-barf-unless-okay
+              multi-method method user host
+              (concat (tramp-get-encoding-command multi-method method)
+                      " < " (tramp-shell-quote-argument path))
+              nil 'file-error
+              "Encoding remote file failed, see buffer `%s' for details"
+              (tramp-get-buffer multi-method method user host))
+             ;; Remove trailing status code
+             (goto-char (point-max))
+             (delete-region (point) (progn (forward-line -1) (point)))
+
+             (tramp-message 5 "Decoding remote file %s..." filename)
+             (if (and (tramp-get-decoding-function multi-method method)
+                      (fboundp (tramp-get-decoding-function multi-method method)))
+                 ;; If tramp-decoding-function is defined for this
+                 ;; method, we call it.
+                 (let ((tmpbuf (get-buffer-create " *tramp tmp*")))
+                   (set-buffer tmpbuf)
+                   (erase-buffer)
+                   (insert-buffer (tramp-get-buffer multi-method method
+						    user host))
+                   (tramp-message-for-buffer
+                    multi-method method user host
+                    6 "Decoding remote file %s with function %s..."
+                    filename
+                    (tramp-get-decoding-function multi-method method))
+                   (set-buffer tmpbuf)
+                   (let ((coding-system-for-write 'no-conversion))
+		     (funcall (tramp-get-decoding-function multi-method method)
+			      (point-min)
+			      (point-max))
+		     (write-region (point-min) (point-max) tmpfil))
+                   (kill-buffer tmpbuf))
+               ;; If tramp-decoding-function is not defined for this
+               ;; method, we invoke tramp-decoding-command instead.
+	       (let ((tmpfil2 (tramp-make-temp-file)))
+		 (write-region (point-min) (point-max) tmpfil2)
+		 (tramp-message
+		  6 "Decoding remote file %s with command %s..."
+		  filename
+		  (tramp-get-decoding-command multi-method method))
+		 (call-process
+		  tramp-sh-program
+		  tmpfil2		;input
+		  nil			;output
+		  nil			;display
+		  "-c" (concat (tramp-get-decoding-command multi-method method)
+			       " > " tmpfil))
+		 (delete-file tmpfil2)))
+             (tramp-message-for-buffer
+              multi-method method user host
+              5 "Decoding remote file %s...done" filename)))
+
+          (t (error "Wrong method specification for `%s'" method)))
+    tmpfil))
+
+
+(defun tramp-handle-insert-file-contents
+  (filename &optional visit beg end replace)
+  "Like `insert-file-contents' for tramp files."
+  (barf-if-buffer-read-only)
+  (setq filename (expand-file-name filename))
+  (let* ((v (tramp-dissect-file-name (tramp-handle-expand-file-name filename)))
+         (multi-method (tramp-file-name-multi-method v))
+         (method (tramp-file-name-method v))
+         (user (tramp-file-name-user v))
+         (host (tramp-file-name-host v))
+         (path (tramp-file-name-path v)))
+    (if (not (tramp-handle-file-exists-p filename))
+	(progn
+	  (when visit
+	    (setq buffer-file-name filename)
+	    (set-visited-file-modtime)
+	    (set-buffer-modified-p nil))
+	  (signal 'file-error
+		  (format "File `%s' not found on remote host" filename))
+	  (list (tramp-handle-expand-file-name filename) 0))
+      (let ((local-copy (tramp-handle-file-local-copy filename))
+	    (coding-system-used nil)
+	    (result nil))
+	(when visit
+	  (setq buffer-file-name filename)
+	  (set-visited-file-modtime)
+	  (set-buffer-modified-p nil))
+	(tramp-message-for-buffer
+	 multi-method method user host
+	 9 "Inserting local temp file `%s'..." local-copy)
+	(setq result
+	      (tramp-run-real-handler 'insert-file-contents
+				      (list local-copy nil beg end replace)))
+	;; Now `last-coding-system-used' has right value.  Remember it.
+	(when (boundp 'last-coding-system-used)
+	  (setq coding-system-used last-coding-system-used))
+	(tramp-message 9 "Inserting local temp file `%s'...done" local-copy)
+	(delete-file local-copy)
+	(when (boundp 'last-coding-system-used)
+	  (setq last-coding-system-used coding-system-used))
+	(list (expand-file-name filename)
+	      (second result))))))
+
+;; CCC grok APPEND, LOCKNAME, CONFIRM
+(defun tramp-handle-write-region
+  (start end filename &optional append visit lockname confirm)
+  "Like `write-region' for tramp files."
+  (unless (eq append nil)
+    (error "Cannot append to file using tramp (`%s')" filename))
+  (setq filename (expand-file-name filename))
+;; Following part commented out because we don't know what to do about
+;; file locking, and it does not appear to be a problem to ignore it.
+;; Ange-ftp ignores it, too.
+;  (when (and lockname (stringp lockname))
+;    (setq lockname (expand-file-name lockname)))
+;  (unless (or (eq lockname nil)
+;              (string= lockname filename))
+;    (error "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
+  ;; XEmacs takes a coding system as the sevent argument, not `confirm'
+  (when (and (not (featurep 'xemacs))
+		  confirm (file-exists-p filename))
+    (unless (y-or-n-p (format "File %s exists; overwrite anyway? "
+                              filename))
+      (error "File not overwritten")))
+  (let* ((curbuf (current-buffer))
+	 (v (tramp-dissect-file-name filename))
+         (multi-method (tramp-file-name-multi-method v))
+         (method (tramp-file-name-method v))
+         (user (tramp-file-name-user v))
+         (host (tramp-file-name-host v))
+         (path (tramp-file-name-path v))
+         (rcp-program (tramp-get-rcp-program multi-method method))
+         (rcp-args (tramp-get-rcp-args multi-method method))
+         (encoding-command (tramp-get-encoding-command multi-method  method))
+         (encoding-function (tramp-get-encoding-function multi-method method))
+         (decoding-command (tramp-get-decoding-command multi-method method))
+         (trampbuf (get-buffer-create "*tramp output*"))
+         ;; We use this to save the value of `last-coding-system-used'
+         ;; after writing the tmp file.  At the end of the function,
+         ;; we set `last-coding-system-used' to this saved value.
+         ;; This way, any intermediary coding systems used while
+         ;; talking to the remote shell or suchlike won't hose this
+         ;; variable.  This approach was snarfed from ange-ftp.el.
+         coding-system-used
+         tmpfil)
+    ;; Write region into a tmp file.  This isn't really needed if we
+    ;; use an encoding function, but currently we use it always
+    ;; because this makes the logic simpler.
+    (setq tmpfil (tramp-make-temp-file))
+    ;; We say `no-message' here because we don't want the visited file
+    ;; modtime data to be clobbered from the temp file.  We call
+    ;; `set-visited-file-modtime' ourselves later on.
+    (tramp-run-real-handler
+     'write-region
+     (if confirm ; don't pass this arg unless defined for backward compat.
+         (list start end tmpfil append 'no-message lockname confirm)
+       (list start end tmpfil append 'no-message lockname)))
+    ;; Now, `last-coding-system-used' has the right value.  Remember it.
+    (when (boundp 'last-coding-system-used)
+      (setq coding-system-used last-coding-system-used))
+    ;; This is a bit lengthy due to the different methods possible for
+    ;; file transfer.  First, we check whether the method uses an rcp
+    ;; program.  If so, we call it.  Otherwise, both encoding and
+    ;; decoding command must be specified.  However, if the method
+    ;; _also_ specifies an encoding function, then that is used for
+    ;; encoding the contents of the tmp file.
+    (cond (rcp-program
+           ;; use rcp-like program for file transfer
+           (let ((argl (append rcp-args
+                               (list
+                                tmpfil
+                                (tramp-make-rcp-program-file-name
+                                 user host
+                                 (tramp-shell-quote-argument path))))))
+             (tramp-message-for-buffer
+              multi-method method user host
+              6 "Writing tmp file using `%s'..." rcp-program)
+             (save-excursion (set-buffer trampbuf) (erase-buffer))
+             (when tramp-debug-buffer
+               (save-excursion
+                 (set-buffer (tramp-get-debug-buffer multi-method
+                                                   method user host))
+                 (goto-char (point-max))
+                 (tramp-insert-with-face
+                  'bold (format "$ %s %s\n" rcp-program
+                                (mapconcat 'identity argl " ")))))
+             (unless (equal 0
+                            (apply #'call-process
+                                   rcp-program nil trampbuf nil argl))
+               (pop-to-buffer trampbuf)
+               (error "Cannot write region to file `%s', command `%s' failed"
+                      filename rcp-program))
+             (tramp-message-for-buffer multi-method method user host
+                                     6 "Transferring file using `%s'...done"
+                                     rcp-program)))
+          ((and encoding-command decoding-command)
+           ;; Use inline file transfer
+           (let ((tmpbuf (get-buffer-create " *tramp file transfer*")))
+             (save-excursion
+               ;; Encode tmpfil into tmpbuf
+               (tramp-message-for-buffer multi-method method user host
+                                       5 "Encoding region...")
+               (set-buffer tmpbuf)
+               (erase-buffer)
+               ;; Use encoding function or command.
+               (if (and encoding-function
+                        (fboundp encoding-function))
+                   (progn
+                     (tramp-message-for-buffer
+                      multi-method method user host
+                      6 "Encoding region using function...")
+                     (insert-file-contents-literally tmpfil)
+                     ;; CCC.  The following `let' is a workaround for
+                     ;; the base64.el that comes with pgnus-0.84.  If
+                     ;; both of the following conditions are
+                     ;; satisfied, it tries to write to a local file
+                     ;; in default-directory, but at this point,
+                     ;; default-directory is remote.
+                     ;; (CALL-PROCESS-REGION can't write to remote
+                     ;; files, it seems.)  The file in question is a
+                     ;; tmp file anyway.
+                     (let ((default-directory (tramp-temporary-file-directory)))
+                       (funcall encoding-function (point-min) (point-max)))
+                     (goto-char (point-max))
+                     (unless (bolp)
+                       (newline)))
+                 (tramp-message-for-buffer multi-method method user host
+                                         6 "Encoding region using command...")
+                 (unless (equal 0
+                                (call-process
+                                 tramp-sh-program
+                                 tmpfil ;input = local tmp file
+                                 t      ;output is current buffer
+                                 nil    ;don't redisplay
+                                 "-c"
+                                 encoding-command))
+                   (pop-to-buffer trampbuf)
+                   (error (concat "Cannot write to `%s', local encoding"
+                                  " command `%s' failed")
+                          filename encoding-command)))
+               ;; Send tmpbuf into remote decoding command which
+               ;; writes to remote file.  Because this happens on the
+               ;; remote host, we cannot use the function.
+               (tramp-message-for-buffer
+                multi-method method user host
+                5 "Decoding region into remote file %s..." filename)
+               (tramp-send-command
+                multi-method method user host
+                (format "%s >%s <<'EOF'"
+                        decoding-command
+                        (tramp-shell-quote-argument path)))
+               (set-buffer tmpbuf)
+               (tramp-message-for-buffer
+                multi-method method user host
+                6 "Sending data to remote host...")
+               (tramp-send-region multi-method method user host
+                                (point-min) (point-max))
+               ;; wait for remote decoding to complete
+               (tramp-message-for-buffer
+                multi-method method user host 6 "Sending end of data token...")
+               (tramp-send-command
+                multi-method method user host "EOF")
+               (tramp-message-for-buffer
+                multi-method method user host 6
+                "Waiting for remote host to process data...")
+               (set-buffer (tramp-get-buffer multi-method method user host))
+               (tramp-wait-for-output)
+               (tramp-barf-unless-okay
+                multi-method method user host nil nil 'file-error
+                (concat "Couldn't write region to `%s',"
+                        " decode using `%s' failed")
+                filename decoding-command)
+               (tramp-message 5 "Decoding region into remote file %s...done"
+                            filename)
+               (kill-buffer tmpbuf))))
+          (t
+           (error
+            (concat "Method `%s' should specify both encoding and "
+                    "decoding command or an rcp program")
+            method)))
+    (delete-file tmpfil)
+    (unless (equal curbuf (current-buffer))
+      (error "Buffer has changed from `%s' to `%s'"
+	     curbuf (current-buffer)))
+    (when (eq visit t)
+      (set-visited-file-modtime))
+    ;; Make `last-coding-system-used' have the right value.
+    (when (boundp 'last-coding-system-used)
+      (setq last-coding-system-used coding-system-used))
+    (when (or (eq visit t)
+              (eq visit nil)
+              (stringp visit))
+      (message "Wrote %s" filename))))
+
+;; Call down to the real handler.
+;; Because EFS does not play nicely with TRAMP (both systems match an
+;; TRAMP path) it is needed to disable efs as well as tramp for the
+;; operation.
+;;
+;; Other than that, this is the canon file-handler code that the doco
+;; says should be used here. Which is nice.
+;;
+;; Under XEmacs current, EFS also hooks in as
+;; efs-sifn-handler-function to handle any path with environment
+;; variables. This has two implications:
+;; 1) That EFS may not be completely dead (yet) for TRAMP paths
+;; 2) That TRAMP might want to do the same thing.
+;; Details as they come in.
+;;
+;; Daniel Pittman <daniel@danann.net>
+
+;; (defun tramp-run-real-handler (operation args)
+;;   "Invoke normal file name handler for OPERATION.
+;; This inhibits EFS and Ange-FTP, too, because they conflict with tramp.
+;; First arg specifies the OPERATION, remaining ARGS are passed to the
+;; OPERATION."
+;;   (let ((inhibit-file-name-handlers
+;;          (list 'tramp-file-name-handler
+;; 	       'efs-file-handler-function
+;;                'ange-ftp-hook-function
+;;                (and (eq inhibit-file-name-operation operation)
+;;                     inhibit-file-name-handlers)))
+;;         (inhibit-file-name-operation operation))
+;;     (apply operation args)))
+
+(defun tramp-run-real-handler (operation args)
+  "Invoke normal file name handler for OPERATION.
+First arg specifies the OPERATION, remaining ARGS are passed to the
+OPERATION."
+  (let ((inhibit-file-name-handlers
+         (list 'tramp-file-name-handler
+               (and (eq inhibit-file-name-operation operation)
+                    inhibit-file-name-handlers)))
+        (inhibit-file-name-operation operation))
+    (apply operation args)))
+
+
+;; Main function.
+;;;###autoload
+(defun tramp-file-name-handler (operation &rest args)
+  "Invoke tramp file name handler.
+Falls back to normal file name handler if no tramp file name handler exists."
+  (let ((fn (assoc operation tramp-file-name-handler-alist)))
+    ;(message "Handling %s using %s" operation fn)
+    (if fn
+	(save-match-data
+	  (apply (cdr fn) args))
+      (tramp-run-real-handler operation args))))
+
+;; Register in file name handler alist
+;;;###autoload
+(add-to-list 'file-name-handler-alist
+	     (cons tramp-file-name-regexp 'tramp-file-name-handler))
+
+;; If jka-compr is already loaded, move it to the front of
+;; `file-name-handler-alist'.  On Emacs 21.3 or so this will not be
+;; necessary anymore.
+(let ((jka (rassoc 'jka-compr-handler file-name-handler-alist)))
+  (when jka
+    (setq file-name-handler-alist
+	  (cons jka (delete jka file-name-handler-alist)))))
+
+;;; Interactions with other packages:
+
+;; -- complete.el --
+
+;; This function contributed by Ed Sabol
+(defun tramp-handle-expand-many-files (name)
+  "Like `PC-expand-many-files' for tramp files."
+  (save-match-data
+    (if (or (string-match "\\*" name)
+            (string-match "\\?" name)
+            (string-match "\\[.*\\]" name))
+        (save-excursion
+          ;; Dissect NAME.
+          (let* ((v (tramp-dissect-file-name name))
+                 (multi-method (tramp-file-name-multi-method v))
+                 (method (tramp-file-name-method v))
+                 (user (tramp-file-name-user v))
+                 (host (tramp-file-name-host v))
+                 (path (tramp-file-name-path v))
+                 bufstr)
+            ;; CCC: To do it right, we should quote certain characters
+            ;; in the file name, but since the echo command is going to
+            ;; break anyway when there are spaces in the file names, we
+            ;; don't bother.
+            ;;-(let ((comint-file-name-quote-list
+            ;;-       (set-difference tramp-file-name-quote-list
+            ;;-                       '(?\* ?\? ?[ ?]))))
+            ;;-  (tramp-send-command
+            ;;-   multi-method method user host
+            ;;-   (format "echo %s" (comint-quote-filename path)))
+            ;;-  (tramp-wait-for-output))
+            (tramp-send-command multi-method method user host
+                              (format "echo %s" path))
+            (tramp-wait-for-output)
+            (setq bufstr (buffer-substring (point-min)
+                                           (tramp-line-end-position)))
+            (goto-char (point-min))
+            (if (string-equal path bufstr)
+                nil
+              (insert "(\"")
+              (while (search-forward " " nil t)
+                (delete-backward-char 1)
+                (insert "\" \""))
+              (goto-char (point-max))
+              (delete-backward-char 1)
+              (insert "\")")
+              (goto-char (point-min))
+              (mapcar
+               (function (lambda (x)
+                           (tramp-make-tramp-file-name multi-method method
+                                                   user host x)))
+               (read (current-buffer))))))
+      (list (tramp-handle-expand-file-name name)))))
+
+;; Check for complete.el and override PC-expand-many-files if appropriate.
+(eval-when-compile
+  (defun tramp-save-PC-expand-many-files (name))); avoid compiler warning
+
+(defun tramp-setup-complete ()
+  (fset 'tramp-save-PC-expand-many-files
+        (symbol-function 'PC-expand-many-files))
+  (defun PC-expand-many-files (name)
+    (if (tramp-tramp-file-p name)
+        (tramp-handle-expand-many-files name)
+      (tramp-save-PC-expand-many-files name))))
+
+;; Why isn't eval-after-load sufficient?
+(if (fboundp 'PC-expand-many-files)
+    (tramp-setup-complete)
+  (eval-after-load "complete" '(tramp-setup-complete)))
+
+
+
+
+;;; Internal Functions:
+
+(defun tramp-set-auto-save ()
+  (when (and (buffer-file-name)
+             (tramp-tramp-file-p (buffer-file-name))
+             auto-save-default)
+    (auto-save-mode 1)))
+(add-hook 'find-file-hooks 'tramp-set-auto-save t)
+
+(defun tramp-run-test (switch filename)
+  "Run `test' on the remote system, given a SWITCH and a FILENAME.
+Returns the exit code of the `test' program."
+  (let ((v (tramp-dissect-file-name filename)))
+    (save-excursion
+      (tramp-send-command-and-check
+       (tramp-file-name-multi-method v) (tramp-file-name-method v)
+       (tramp-file-name-user v) (tramp-file-name-host v)
+       (format "test %s %s" switch
+               (tramp-shell-quote-argument (tramp-file-name-path v)))))))
+
+(defun tramp-run-test2 (program file1 file2 &optional switch)
+  "Run `test'-like PROGRAM on the remote system, given FILE1, FILE2.
+The optional SWITCH is inserted between the two files.
+Returns the exit code of the `test' PROGRAM.  Barfs if the methods,
+hosts, or files, disagree."
+  (let* ((v1 (tramp-dissect-file-name file1))
+         (v2 (tramp-dissect-file-name file2))
+         (mmethod1 (tramp-file-name-multi-method v1))
+         (mmethod2 (tramp-file-name-multi-method v2))
+         (method1 (tramp-file-name-method v1))
+         (method2 (tramp-file-name-method v2))
+         (user1 (tramp-file-name-user v1))
+         (user2 (tramp-file-name-user v2))
+         (host1 (tramp-file-name-host v1))
+         (host2 (tramp-file-name-host v2))
+         (path1 (tramp-file-name-path v1))
+         (path2 (tramp-file-name-path v2)))
+    (unless (and method1 method2 host1 host2
+                 (equal mmethod1 mmethod2)
+                 (equal method1 method2)
+                 (equal user1 user2)
+                 (equal host1 host2))
+      (error "tramp-run-test2: %s"
+             "only implemented for same method, same user, same host"))
+    (save-excursion
+      (tramp-send-command-and-check
+       mmethod1 method1 user1 host1
+       (format "%s %s %s %s"
+               program
+               (tramp-shell-quote-argument path1)
+               (or switch "")
+               (tramp-shell-quote-argument path2))))))
+
+(defun tramp-buffer-name (multi-method method user host)
+  "A name for the connection buffer for USER at HOST using METHOD."
+  (cond (multi-method
+         (tramp-buffer-name-multi-method "tramp" multi-method method user host))
+        (user
+         (format "*tramp/%s %s@%s*" method user host))
+        (t
+         (format "*tramp/%s %s*" method host))))
+
+(defun tramp-buffer-name-multi-method (prefix multi-method method user host)
+  "A name for the multi method connection buffer.
+MULTI-METHOD gives the multi method, METHOD the array of methods,
+USER the array of user names, HOST the array of host names."
+  (unless (and (= (length method) (length user))
+               (= (length method) (length host)))
+    (error "Syntax error in multi method (implementation error)"))
+  (let ((len (length method))
+        (i 0)
+        string-list)
+    (while (< i len)
+      (setq string-list
+            (cons (if (aref user i)
+                      (format "%s#%s@%s:" (aref method i)
+                              (aref user i) (aref host i))
+                    (format "%s@%s:" (aref method i) (aref host i)))
+                  string-list))
+      (incf i))
+    (format "*%s/%s %s*"
+            prefix multi-method
+            (apply 'concat (reverse string-list)))))
+
+(defun tramp-get-buffer (multi-method method user host)
+  "Get the connection buffer to be used for USER at HOST using METHOD."
+  (get-buffer-create (tramp-buffer-name multi-method method user host)))
+
+(defun tramp-debug-buffer-name (multi-method method user host)
+  "A name for the debug buffer for USER at HOST using METHOD."
+  (cond (multi-method
+         (tramp-buffer-name-multi-method "debug tramp"
+                                         multi-method method user host))
+        (user
+         (format "*debug tramp/%s %s@%s*" method user host))
+        (t
+         (format "*debug tramp/%s %s*" method host))))
+
+(defun tramp-get-debug-buffer (multi-method method user host)
+  "Get the debug buffer for USER at HOST using METHOD."
+  (get-buffer-create (tramp-debug-buffer-name multi-method method user host)))
+
+(defun tramp-find-executable (multi-method method user host
+                                         progname dirlist ignore-tilde)
+  "Searches for PROGNAME in all directories mentioned in DIRLIST.
+First args METHOD, USER and HOST specify the connection, PROGNAME
+is the program to search for, and DIRLIST gives the list of directories
+to search.  If IGNORE-TILDE is non-nil, directory names starting
+with `~' will be ignored.
+
+Returns the full path name of PROGNAME, if found, and nil otherwise.
+
+This function expects to be in the right *tramp* buffer."
+  (let (result)
+    (when ignore-tilde
+      ;; Remove all ~/foo directories from dirlist.  In Emacs 20,
+      ;; `remove' is in CL, and we want to avoid CL dependencies.
+      (let (newdl d)
+        (while dirlist
+          (setq d (car dirlist))
+          (setq dirlist (cdr dirlist))
+          (unless (char-equal ?~ (aref d 0))
+            (setq newdl (cons d newdl))))
+        (setq dirlist (nreverse newdl))))
+    (tramp-send-command
+     multi-method method user host
+     (format (concat "while read d; "
+                     "do if test -x $d/%s -a -f $d/%s; "
+                     "then echo tramp_executable $d/%s; "
+                     "break; fi; done <<'EOF'")
+             progname progname progname))
+    (mapcar (lambda (d)
+              (tramp-send-command multi-method method user host d))
+            dirlist)
+    (tramp-send-command multi-method method user host "EOF")
+    (tramp-wait-for-output)
+    (goto-char (point-max))
+    (when (search-backward "tramp_executable " nil t)
+      (skip-chars-forward "^ ")
+      (skip-chars-forward " ")
+      (buffer-substring (point) (tramp-line-end-position)))))
+
+(defun tramp-set-remote-path (multi-method method user host var dirlist)
+  "Sets the remote environment VAR to existing directories from DIRLIST.
+I.e., for each directory in DIRLIST, it is tested whether it exists and if
+so, it is added to the environment variable VAR."
+  (let ((existing-dirs
+         (mapcar
+          (lambda (x)
+            (when (and
+                   (file-exists-p
+                    (tramp-make-tramp-file-name multi-method method user host x))
+                   (file-directory-p
+                    (tramp-make-tramp-file-name multi-method method user host x)))
+              x))
+          dirlist)))
+    (tramp-send-command
+     multi-method method user host
+     (concat var "="
+             (mapconcat 'identity (delq nil existing-dirs) ":")
+             "; export " var))
+  (tramp-wait-for-output)))
+
+;; -- communication with external shell --
+
+(defun tramp-find-file-exists-command (multi-method method user host)
+  "Find a command on the remote host for checking if a file exists.
+Here, we are looking for a command which has zero exit status if the
+file exists and nonzero exit status otherwise."
+  (make-local-variable 'tramp-file-exists-command)
+  (tramp-message 10 "Finding command to check if file exists")
+  (let ((existing
+         (tramp-make-tramp-file-name
+          multi-method method user host
+          "/"))                         ;assume this file always exists
+        (nonexisting
+         (tramp-make-tramp-file-name
+          multi-method method user host
+          "/ this file does not exist "))) ;assume this never exists
+    ;; The algorithm is as follows: we try a list of several commands.
+    ;; For each command, we first run `$cmd /' -- this should return
+    ;; true, as the root directory always exists.  And then we run
+    ;; `$cmd /this\ file\ does\ not\ exist', hoping that the file indeed
+    ;; does not exist.  This should return false.  We use the first
+    ;; command we find that seems to work.
+    ;; The list of commands to try is as follows:
+    ;; `ls -d'          This works on most systems, but NetBSD 1.4
+    ;;                  has a bug: `ls' always returns zero exit
+    ;;                  status, even for files which don't exist.
+    ;; `test -e'        Some Bourne shells have a `test' builtin
+    ;;                  which does not know the `-e' option.
+    ;; `/bin/test -e'   For those, the `test' binary on disk normally
+    ;;                  provides the option.  Alas, the binary
+    ;;                  is sometimes `/bin/test' and sometimes it's
+    ;;                  `/usr/bin/test'.
+    ;; `/usr/bin/test -e'       In case `/bin/test' does not exist.
+    (unless (or
+             (and (setq tramp-file-exists-command "ls -d %s")
+                  (tramp-handle-file-exists-p existing)
+                  (not (tramp-handle-file-exists-p nonexisting)))
+             (and (setq tramp-file-exists-command "test -e %s")
+                  (tramp-handle-file-exists-p existing)
+                  (not (tramp-handle-file-exists-p nonexisting)))
+             (and (setq tramp-file-exists-command "/bin/test -e %s")
+                  (tramp-handle-file-exists-p existing)
+                  (not (tramp-handle-file-exists-p nonexisting)))
+             (and (setq tramp-file-exists-command "/usr/bin/test -e %s")
+                  (tramp-handle-file-exists-p existing)
+                  (not (tramp-handle-file-exists-p nonexisting))))
+      (error "Couldn't find command to check if file exists."))))
+    
+
+;; CCC test ksh or bash found for tilde expansion?
+(defun tramp-find-shell (multi-method method user host)
+  "Find a shell on the remote host which groks tilde expansion."
+  (let ((shell nil))
+    (tramp-send-command multi-method method user host "echo ~root")
+    (tramp-wait-for-output)
+    (cond
+     ((string-match "^~root$" (buffer-string))
+      (setq shell
+            (or (tramp-find-executable multi-method method user host
+                                     "bash"  tramp-remote-path t)
+                (tramp-find-executable multi-method method user host
+                                     "ksh" tramp-remote-path t)))
+      (unless shell
+        (error "Couldn't find a shell which groks tilde expansion"))
+      ;; Hack: avoid reading of ~/.bashrc.  What we should do is have an
+      ;; alist for extra args to give to each shell...
+      (when (string-match "/bash\\'" shell)
+	(setq shell (concat shell " --norc")))
+      (tramp-message
+       5 "Starting remote shell `%s' for tilde expansion..." shell)
+      (tramp-send-command
+       multi-method method user host
+       (concat "PS1='$ ' ; exec " shell))
+      (unless (tramp-wait-for-regexp
+               (get-buffer-process (current-buffer))
+               60 (format "\\(\\$ *\\|\\(%s\\)\\'\\)" shell-prompt-pattern))
+        (pop-to-buffer (buffer-name))
+        (error "Couldn't find remote `%s' prompt." shell))
+      (process-send-string nil (format "PS1='%s%s%s'; PS2=''; PS3=''%s"
+                                       tramp-rsh-end-of-line
+                                       tramp-end-of-output
+                                       tramp-rsh-end-of-line
+                                       tramp-rsh-end-of-line))
+      (tramp-wait-for-output)
+      (tramp-send-command multi-method method user host "echo hello")
+      (tramp-message 5 "Waiting for remote `%s' to start up..." shell)
+      (unless (tramp-wait-for-output 5)
+        (unless (tramp-wait-for-output 5)
+          (pop-to-buffer (buffer-name))
+          (error "Couldn't start remote `%s', see buffer `%s' for details"
+                 shell (buffer-name))))
+      (tramp-message 5 "Waiting for remote `%s' to start up...done" shell))
+     (t (tramp-message 5 "Remote `%s' groks tilde expansion, good"
+                     (tramp-get-remote-sh multi-method method))))))
+
+(defun tramp-check-ls-command (multi-method method user host cmd)
+  "Checks whether the given `ls' executable groks `-n'.
+METHOD, USER and HOST specify the connection, CMD (the full path name of)
+the `ls' executable.  Returns t if CMD supports the `-n' option, nil
+otherwise."
+  (tramp-message 9 "Checking remote `%s' command for `-n' option"
+               cmd)
+  (when (tramp-handle-file-executable-p
+         (tramp-make-tramp-file-name multi-method method user host cmd))
+    (let ((result nil))
+      (tramp-message 7 "Testing remote command `%s' for -n..." cmd)
+      (setq result
+            (tramp-send-command-and-check
+             multi-method method user host
+             (format "%s -lnd / >/dev/null"
+                     cmd)))
+      (tramp-message 7 "Testing remote command `%s' for -n...%s"
+                   cmd
+                   (if (zerop result) "okay" "failed"))
+      (zerop result))))
+
+(defun tramp-check-ls-commands (multi-method method user host cmd dirlist)
+  "Checks whether the given `ls' executable in one of the dirs groks `-n'.
+Returns nil if none was found, else the command is returned."
+  (let ((dl dirlist)
+        (result nil))
+    ;; It would be better to use the CL function `find', but
+    ;; we don't want run-time dependencies on CL.
+    (while (and dl (not result))
+      (let ((x (concat (file-name-as-directory (car dl)) cmd)))
+        (when (tramp-check-ls-command multi-method method user host x)
+          (setq result x)))
+      (setq dl (cdr dl)))
+    result))
+
+(defun tramp-find-ls-command (multi-method method user host)
+  "Finds an `ls' command which groks the `-n' option, returning nil if failed.
+\(This option prints numeric user and group ids in a long listing.)"
+  (tramp-message 9 "Finding a suitable `ls' command")
+  (or
+   (tramp-check-ls-commands multi-method method user host "ls" tramp-remote-path)
+   (tramp-check-ls-commands multi-method method user host "gnuls" tramp-remote-path)
+   (tramp-check-ls-commands multi-method method user host "gls" tramp-remote-path)))
+
+;; ------------------------------------------------------------ 
+;; -- Functions for establishing connection -- 
+;; ------------------------------------------------------------ 
+
+(defun tramp-process-actions
+  (multi-method method user host actions &optional timeout)
+  "Process given ACTIONS for login specified via first four args.
+ACTIONS is a list of items (REGEXP FUN), where REGEXP specifies what
+output from the remote end to look for, and FUN specifies the action
+to take when the regexp matches."
+  nil)
+
+(defun tramp-open-connection-telnet (multi-method method user host)
+  "Open a connection using a telnet METHOD.
+This starts the command `telnet HOST ARGS'[*], then waits for a remote
+login prompt, then sends the user name USER, then waits for a remote
+password prompt.  It queries the user for the password, then sends the
+password to the remote host.
+
+If USER is nil, uses value returned by `(user-login-name)' instead.
+
+Recognition of the remote shell prompt is based on the variable
+`shell-prompt-pattern' which must be set up correctly.
+
+Please note that it is NOT possible to use this connection method
+together with an out-of-band transfer method!  You must use an inline
+transfer method.
+
+Maybe the different regular expressions need to be tuned.
+
+* Actually, the telnet program as well as the args to be used can be
+  specified in the method parameters, see the variable `tramp-methods'."
+  (save-match-data
+    (when (tramp-method-out-of-band-p multi-method method)
+      (error "Cannot use out-of-band method `%s' with telnet connection method"
+             method))
+    (when multi-method
+      (error "Cannot multi-connect using telnet connection method"))
+    (tramp-pre-connection multi-method method user host)
+    (tramp-message 7 "Opening connection for %s@%s using %s..." 
+		   (or user (user-login-name)) host method)
+    (let ((process-environment (copy-sequence process-environment)))
+      (setenv "TERM" tramp-terminal-type)
+      (let* ((default-directory (tramp-temporary-file-directory))
+             (coding-system-for-read (unless (and (not (featurep 'xemacs))
+                                                  (> emacs-major-version 20))
+                                       tramp-dos-coding-system))
+             (p (apply 'start-process
+                       (tramp-buffer-name multi-method method user host)
+                       (tramp-get-buffer multi-method method user host)
+                       (tramp-get-telnet-program multi-method method)
+                       host
+                       (tramp-get-telnet-args multi-method method)))
+             (found nil)
+             (pw nil))
+        (process-kill-without-query p)
+        (tramp-message 9 "Waiting for login prompt...")
+        (unless (tramp-wait-for-regexp p nil tramp-login-prompt-regexp)
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Couldn't find remote login prompt"))
+        (erase-buffer)
+        ;; Remote login defaults to local one.
+        (tramp-message 9 "Sending login name %s" (or user (user-login-name)))
+        (process-send-string p (concat (or user (user-login-name)) 
+                                       tramp-rsh-end-of-line))
+        (tramp-message 9 "Waiting for password prompt...")
+        (unless (setq found (tramp-wait-for-regexp
+                             p nil tramp-password-prompt-regexp))
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Couldn't find remote password prompt"))
+        (erase-buffer)
+        (setq pw (tramp-read-passwd (car found)))
+        (tramp-message 9 "Sending password")
+        (process-send-string p (concat pw tramp-rsh-end-of-line))
+        (tramp-message 9 "Waiting 30s for remote shell to come up...")
+        (unless (setq found
+                      (tramp-wait-for-regexp
+                       p 30 (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                    tramp-wrong-passwd-regexp
+                                    shell-prompt-pattern)))
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Couldn't find remote shell prompt"))
+        (when (nth 1 found)
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Login failed: %s" (nth 1 found)))
+        (tramp-open-connection-setup-interactive-shell
+         p multi-method method user host)
+        (tramp-post-connection multi-method method user host)))))
+
+;; HHH: Changed to handle the case when USER is nil.
+(defun tramp-open-connection-rsh (multi-method method user host)
+  "Open a connection using an rsh METHOD.
+This starts the command `rsh HOST -l USER'[*], then waits for a remote
+password or shell prompt.  If a password prompt is seen, the user is
+queried for a password, this function sends the password to the remote
+host and waits for a shell prompt.
+
+If USER is nil, start the command `rsh HOST'[*] instead
+
+Recognition of the remote shell prompt is based on the variable
+`shell-prompt-pattern' which must be set up correctly.
+
+Please note that it is NOT possible to use this connection method with
+an out-of-band transfer method if this function asks the user for a
+password!  You must use an inline transfer method in this case.
+Sadly, the transfer method cannot be switched on the fly, instead you
+must specify the right method in the file name.
+
+* Actually, the rsh program to be used can be specified in the
+  method parameters, see the variable `tramp-methods'."
+  (save-match-data
+    (when multi-method
+      (error "Cannot multi-connect using rsh connection method"))
+    (tramp-pre-connection multi-method method user host)
+    (if user 
+	(tramp-message 7 "Opening connection for %s@%s using %s..." 
+		       user host method)
+      (tramp-message 7 "Opening connection at %s using %s..." host method))
+    (let ((process-environment (copy-sequence process-environment)))
+      (setenv "TERM" tramp-terminal-type)
+      (let* ((default-directory (tramp-temporary-file-directory))
+             (coding-system-for-read (unless (and (not (featurep 'xemacs))
+                                                  (> emacs-major-version 20))
+                                       tramp-dos-coding-system))
+             (p (if user
+                    (apply #'start-process
+                           (tramp-buffer-name multi-method method user host)
+                           (tramp-get-buffer multi-method method user host)
+                           (tramp-get-rsh-program multi-method method) 
+                           host "-l" user
+                           (tramp-get-rsh-args multi-method method))
+                  (apply #'start-process
+                         (tramp-buffer-name multi-method method user host)
+                         (tramp-get-buffer multi-method method user host)
+                         (tramp-get-rsh-program multi-method method) 
+                         host
+                         (tramp-get-rsh-args multi-method method))))
+             (found nil))
+        (process-kill-without-query p)
+        (tramp-message 9 "Waiting 60s for shell or passwd prompt from %s" host)
+        (setq found
+              (tramp-wait-for-regexp
+               p 60
+               (format
+                "\\(%s\\)\\|\\(%s\\)\\'"
+                tramp-password-prompt-regexp
+                shell-prompt-pattern)))
+        (unless found
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Couldn't find remote shell or passwd prompt"))
+        (when (nth 1 found)
+          (when (tramp-method-out-of-band-p multi-method method)
+            (pop-to-buffer (buffer-name))
+            (kill-process p)
+            (error (concat "Out of band method `%s' not applicable"
+                           " for remote shell asking for a password")
+                   method))
+          (erase-buffer)
+          (tramp-message 9 "Sending password...")
+          (tramp-enter-password p (nth 1 found))
+          (tramp-message 9 "Sent password, waiting 60s for remote shell prompt")
+          (setq found (tramp-wait-for-regexp p 60
+                                             (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                                     tramp-wrong-passwd-regexp
+                                                     shell-prompt-pattern))))
+        (unless found
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Couldn't find remote shell prompt"))
+        (when (nth 1 found)
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Login failed: %s" (nth 1 found)))
+        (tramp-message 7 "Initializing remote shell")
+        (tramp-open-connection-setup-interactive-shell
+         p multi-method method user host)
+        (tramp-post-connection multi-method method user host)))))
+
+;; HHH: Changed.  Now utilizes (or user (user-login-name)) instead of USER.
+(defun tramp-open-connection-su (multi-method method user host)
+  "Open a connection using the `su' program with METHOD.
+This starts `su - USER', then waits for a password prompt.  The HOST
+name must be equal to the local host name or to `localhost'.
+
+If USER is nil, uses value returned by user-login-name instead.
+
+Recognition of the remote shell prompt is based on the variable
+`shell-prompt-pattern' which must be set up correctly.  Note that the
+other user may have a different shell prompt than you do, so it is not
+at all unlikely that this variable is set up wrongly!"
+  (save-match-data
+    (when (tramp-method-out-of-band-p multi-method method)
+      (error "Cannot use out-of-band method `%s' with `su' connection method"
+             method))
+    (unless (or (string-match (concat "^" (regexp-quote host))
+                              (system-name))
+                (string= "localhost" host))
+      (error
+       "Cannot connect to different host `%s' with `su' connection method"
+       host))
+    (when (not user)
+      (error "Must give user name for `su' connection method"))
+    (tramp-pre-connection multi-method method user host)
+    (tramp-message 7 "Opening connection for `%s' using `%s'..." 
+		   (or user (user-login-name)) method)
+    (let ((process-environment (copy-sequence process-environment)))
+      (setenv "TERM" tramp-terminal-type)
+      (let* ((default-directory (tramp-temporary-file-directory))
+             (coding-system-for-read (unless (and (not (featurep 'xemacs))
+                                                  (> emacs-major-version 20))
+                                       tramp-dos-coding-system))
+             (p (apply 'start-process
+                       (tramp-buffer-name multi-method method 
+                                          user host)
+                       (tramp-get-buffer multi-method method 
+                                         user host)
+                       (tramp-get-su-program multi-method method)
+                       (mapcar
+                        '(lambda (x)
+                           (format-spec
+                            x (list (cons ?u user))))
+                        (tramp-get-su-args multi-method method))))
+             (found nil)
+             (pw nil))
+        (process-kill-without-query p)
+        (tramp-message 9 "Waiting 30s for shell or password prompt...")
+        (unless (setq found (tramp-wait-for-regexp
+                             p 30
+                             (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                     tramp-password-prompt-regexp
+                                     shell-prompt-pattern)))
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Couldn't find shell or password prompt"))
+        (when (nth 1 found)
+          (erase-buffer)
+          (setq pw (tramp-read-passwd (car found)))
+          (tramp-message 9 "Sending password")
+          (process-send-string p (concat pw tramp-rsh-end-of-line))
+          (tramp-message 9 "Waiting 30s for remote shell to come up...")
+          (unless (setq found
+                        (tramp-wait-for-regexp
+                         p 30 (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                      tramp-wrong-passwd-regexp
+                                      shell-prompt-pattern)))
+            (pop-to-buffer (buffer-name))
+            (kill-process p)
+            (error "Couldn't find remote shell prompt"))
+          (when (nth 1 found)
+            (pop-to-buffer (buffer-name))
+            (kill-process p)
+            (error "`su' failed: %s" (nth 1 found))))
+        (tramp-open-connection-setup-interactive-shell
+         p multi-method method user host)
+        (tramp-post-connection multi-method method 
+                               user host)))))
+
+;; HHH: Not Changed.  Multi method.  It is not clear to me how this can 
+;;      handle not giving a user name in the "file name".
+;;
+;;      This is more difficult than for the single-hop method.  In the
+;;      multi-hop-method, the desired behaviour should be that the
+;;      user must specify names for the telnet hops of which the user
+;;      name is different than the "original" name (or different from
+;;      the previous hop.
+(defun tramp-open-connection-multi (multi-method method user host)
+  "Open a multi-hop connection using METHOD.
+This uses a slightly changed file name syntax.  The idea is to say
+    [multi/telnet:u1@h1/rsh:u2@h2]/path/to/file
+This will use telnet to log in as u1 to h1, then use rsh from there to
+log in as u2 to h2."
+  (save-match-data
+    (unless multi-method
+      (error "Multi-hop open connection function called on non-multi method"))
+    (when (tramp-method-out-of-band-p multi-method method)
+      (error "No out of band multi-hop connections"))
+    (unless (and (arrayp method) (not (stringp method)))
+      (error "METHOD must be an array of strings for multi methods"))
+    (unless (and (arrayp user) (not (stringp user)))
+      (error "USER must be an array of strings for multi methods"))
+    (unless (and (arrayp host) (not (stringp host)))
+      (error "HOST must be an array of strings for multi methods"))
+    (unless (and (= (length method) (length user))
+                 (= (length method) (length host)))
+      (error "Arrays METHOD, USER, HOST must have equal length"))
+    (tramp-pre-connection multi-method method user host)
+    (tramp-message 7 "Opening `%s' connection..." multi-method)
+    (let ((process-environment (copy-sequence process-environment)))
+      (setenv "TERM" tramp-terminal-type)
+      (let* ((default-directory (tramp-temporary-file-directory))
+             (coding-system-for-read (unless (and (not (featurep 'xemacs))
+                                                  (> emacs-major-version 20))
+                                       tramp-dos-coding-system))
+             (p (start-process (tramp-buffer-name multi-method method user host)
+                               (tramp-get-buffer multi-method method user host)
+                               tramp-sh-program))
+             (num-hops (length method))
+             (i 0))
+        (process-kill-without-query p)
+        (tramp-message 9 "Waiting 60s for local shell to come up...")
+        (unless (tramp-wait-for-regexp
+		 p 60 (format "%s\\'" shell-prompt-pattern))
+          (pop-to-buffer (buffer-name))
+          (kill-process p)
+          (error "Couldn't find local shell prompt"))
+        ;; Now do all the connections as specified.
+        (while (< i num-hops)
+          (let* ((m (aref method i))
+                 (u (aref user i))
+                 (h (aref host i))
+                 (entry (assoc m tramp-multi-connection-function-alist))
+                 (multi-func (nth 1 entry))
+                 (command (nth 2 entry)))
+          ;; The multi-funcs don't need to do save-match-data, as that
+            ;; is done here.
+            (funcall multi-func p m u h command)
+            (erase-buffer)
+            (incf i)))
+        (tramp-open-connection-setup-interactive-shell
+         p multi-method method user host)
+        (tramp-post-connection multi-method method user host)))))
+
+;; HHH: Changed.  Multi method.  Don't know how to handle this in the case
+;;      of no user name provided.  Hack to make it work as it did before:  
+;;      changed `user' to `(or user (user-login-name))' in the places where
+;;      the value is actually used.
+(defun tramp-multi-connect-telnet (p method user host command)
+  "Issue `telnet' command.
+Uses shell COMMAND to issue a `telnet' command to log in as USER to
+HOST.  You can use percent escapes in COMMAND: `%h' is replaced with
+the host name, and `%n' is replaced with an end of line character, as
+set in `tramp-rsh-end-of-line'.  Use `%%' if you want a literal percent
+character.
+
+If USER is nil, uses the return value of (user-login-name) instead."
+  (let ((cmd (format-spec command (list (cons ?h host)
+                                        (cons ?n tramp-rsh-end-of-line))))
+        (cmd1 (format-spec command (list (cons ?h host)
+                                         (cons ?n ""))))
+        found pw)
+    (erase-buffer)
+    (tramp-message 9 "Sending telnet command `%s'" cmd1)
+    (process-send-string p cmd)
+    (tramp-message 9 "Waiting 30s for login prompt from %s" host)
+    (unless (tramp-wait-for-regexp p 30 tramp-login-prompt-regexp)
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Couldn't find login prompt from host %s" host))
+    (erase-buffer)
+    (tramp-message 9 "Sending login name %s" (or user (user-login-name)))
+    (process-send-string p (concat (or user (user-login-name)) tramp-rsh-end-of-line))
+    (tramp-message 9 "Waiting for password prompt")
+    (unless (setq found (tramp-wait-for-regexp p nil tramp-password-prompt-regexp))
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Couldn't find password prompt from host %s" host))
+    (erase-buffer)
+    (setq pw (tramp-read-passwd
+              (format "Password for %s@%s, %s" (or user (user-login-name)) host found)))
+    (tramp-message 9 "Sending password")
+    (process-send-string p (concat pw tramp-rsh-end-of-line))
+    (tramp-message 9 "Waiting 60s for remote shell to come up...")
+    (unless (setq found (tramp-wait-for-regexp
+                         p 60 (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                      tramp-wrong-passwd-regexp
+                                      shell-prompt-pattern)))
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Couldn't find shell prompt from host %s" host))
+    (when (nth 1 found)
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Login to %s failed: %s" (nth 2 found)))))
+
+;; HHH: Changed.  Multi method.  Don't know how to handle this in the case 
+;;      of no user name provided.  Hack to make it work as it did before:  
+;;      changed `user' to `(or user (user-login-name))' in the places where
+;;      the value is actually used.
+(defun tramp-multi-connect-rlogin (p method user host command)
+  "Issue `rlogin' command.
+Uses shell COMMAND to issue an `rlogin' command to log in as USER to
+HOST.  You can use percent escapes in COMMAND.  `%u' will be replaced
+with the user name, `%h' will be replaced with the host name, and `%n'
+will be replaced with the value of `tramp-rsh-end-of-line'.  You can use
+`%%' if you want to use a literal percent character.
+
+If USER is nil, uses the return value of (user-login-name) instead."
+  (let ((cmd (format-spec command (list (cons ?h host)
+                                        (cons ?u (or user (user-login-name)))
+                                        (cons ?n tramp-rsh-end-of-line))))
+        (cmd1 (format-spec command (list (cons ?h host)
+                                         (cons ?u (or user (user-login-name)))
+                                         (cons ?n ""))))
+        found)
+    (erase-buffer)
+    (tramp-message 9 "Sending rlogin command `%s'" cmd1)
+    (process-send-string p cmd)
+    (tramp-message 9 "Waiting 60s for shell or passwd prompt from %s" host)
+    (unless (setq found
+                  (tramp-wait-for-regexp p 60
+                                       (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                               tramp-password-prompt-regexp
+                                               shell-prompt-pattern)))
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Couldn't find remote shell or passwd prompt"))
+    (when (nth 1 found)
+      (erase-buffer)
+      (tramp-message 9 "Sending password...")
+      (tramp-enter-password p (nth 1 found))
+      (tramp-message 9 "Sent password, waiting 60s for remote shell prompt")
+      (setq found (tramp-wait-for-regexp p 60
+                                         (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                                 tramp-wrong-passwd-regexp
+                                                 shell-prompt-pattern))))
+    (unless found
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Couldn't find remote shell prompt"))
+    (when (nth 1 found)
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Login failed: %s" (nth 1 found)))))
+
+;; HHH: Changed.  Multi method.  Don't know how to handle this in the case 
+;;      of no user name provided.  Hack to make it work as it did before:  
+;;      changed `user' to `(or user (user-login-name))' in the places where
+;;      the value is actually used.
+(defun tramp-multi-connect-su (p method user host command)
+  "Issue `su' command.
+Uses shell COMMAND to issue a `su' command to log in as USER on
+HOST.  The HOST name is ignored, this just changes the user id on the
+host currently logged in to.
+
+If USER is nil, uses the return value of (user-login-name) instead.
+
+You can use percent escapes in the COMMAND.  `%u' is replaced with the
+user name, and `%n' is replaced with the value of
+`tramp-rsh-end-of-line'.  Use `%%' if you want a literal percent
+character."
+  (let ((cmd (format-spec command (list (cons ?u (or user (user-login-name)))
+                                        (cons ?n tramp-rsh-end-of-line))))
+        (cmd1 (format-spec command (list (cons ?u (or user (user-login-name)))
+                                         (cons ?n ""))))
+        found)
+    (erase-buffer)
+    (tramp-message 9 "Sending su command `%s'" cmd1)
+    (process-send-string p cmd)
+    (tramp-message 9 "Waiting 60s for shell or passwd prompt for %s" (or user (user-login-name)))
+    (unless (setq found (tramp-wait-for-regexp
+                         p 60 (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                      tramp-password-prompt-regexp
+                                      shell-prompt-pattern)))
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Couldn't find shell or passwd prompt for %s" 
+	     (or user (user-login-name))))
+    (when (nth 1 found)
+      (tramp-message 9 "Sending password...")
+      (tramp-enter-password p (nth 1 found))
+      (erase-buffer)
+      (tramp-message 9 "Sent password, waiting 60s for remote shell prompt")
+      (setq found (tramp-wait-for-regexp p 60
+                                       (format "\\(%s\\)\\|\\(%s\\)\\'"
+                                               tramp-wrong-passwd-regexp
+                                               shell-prompt-pattern))))
+    (unless found
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Couldn't find remote shell prompt"))
+    (when (nth 1 found)
+      (pop-to-buffer (buffer-name))
+      (kill-process p)
+      (error "Login failed: %s" (nth 1 found)))))
+
+;; Utility functions.
+
+(defun tramp-wait-for-regexp (proc timeout regexp)
+  "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
+Expects the output of PROC to be sent to the current buffer.  Returns
+the string that matched, or nil.  Waits indefinitely if TIMEOUT is
+nil."
+  (let ((found nil)
+        (start-time (current-time)))
+    (cond (timeout
+           ;; Work around a bug in XEmacs 21, where the timeout
+           ;; expires faster than it should.  This degenerates
+           ;; to polling for buggy XEmacsen, but oh, well.
+           (while (and (not found)
+                       (< (tramp-time-diff (current-time) start-time)
+                          timeout))
+             (with-timeout (timeout)
+               (while (not found)
+                 (accept-process-output proc 1)
+                 (goto-char (point-min))
+                 (setq found (when (re-search-forward regexp nil t)
+                               (tramp-match-string-list)))))))
+          (t
+           (while (not found)
+             (accept-process-output proc 1)
+             (goto-char (point-min))
+             (setq found (when (re-search-forward regexp nil t)
+                           (tramp-match-string-list))))))
+    (when tramp-debug-buffer
+      (append-to-buffer
+       (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
+                             tramp-current-user tramp-current-host)
+       (point-min) (point-max))
+      (when (not found)
+        (save-excursion
+          (set-buffer
+           (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
+                             tramp-current-user tramp-current-host))
+          (goto-char (point-max))
+          (insert "[[Regexp `" regexp "' not found"
+                  (if timeout (concat " in " timeout " secs") "")
+                  "]]"))))
+    found))
+
+(defun tramp-enter-password (p prompt)
+  "Prompt for a password and send it to the remote end.
+Uses PROMPT as a prompt and sends the password to process P."
+  (let ((pw (tramp-read-passwd prompt)))
+    (process-send-string p (concat pw tramp-rsh-end-of-line))))
+
+;; HHH: Not Changed.  This might handle the case where USER is not
+;;      given in the "File name" very poorly.  Then, the local
+;;      variable tramp-current user will be set to nil.
+(defun tramp-pre-connection (multi-method method user host)
+  "Do some setup before actually logging in.
+METHOD, USER and HOST specify the connection."
+  (set-buffer (tramp-get-buffer multi-method method user host))
+  (set (make-local-variable 'tramp-current-multi-method) multi-method)
+  (set (make-local-variable 'tramp-current-method) method)
+  (set (make-local-variable 'tramp-current-user)   user)
+  (set (make-local-variable 'tramp-current-host)   host)
+  (set (make-local-variable 'inhibit-eol-conversion) nil)
+  (erase-buffer))
+
+(defun tramp-open-connection-setup-interactive-shell
+  (p multi-method method user host)
+  "Set up an interactive shell.
+Mainly sets the prompt and the echo correctly.  P is the shell process
+to set up.  METHOD, USER and HOST specify the connection."
+  ;; Wait a bit in case the remote end feels like sending a little
+  ;; junk first.  It seems that fencepost.gnu.org does this when doing
+  ;; a Kerberos login.
+  (sit-for 1)
+  (tramp-discard-garbage-erase-buffer p multi-method method user host)
+  (process-send-string nil (format "exec %s%s"
+                                   (tramp-get-remote-sh multi-method method)
+                                   tramp-rsh-end-of-line))
+  (when tramp-debug-buffer
+    (save-excursion
+      (set-buffer (tramp-get-debug-buffer multi-method method user host))
+      (goto-char (point-max))
+      (tramp-insert-with-face
+       'bold (format "$ exec %s\n" (tramp-get-remote-sh multi-method method)))))
+  (tramp-message 9 "Waiting 30s for remote `%s' to come up..."
+               (tramp-get-remote-sh multi-method method))
+  (unless (tramp-wait-for-regexp
+	   p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+    (pop-to-buffer (buffer-name))
+    (error "Remote `%s' didn't come up.  See buffer `%s' for details"
+           (tramp-get-remote-sh multi-method method) (buffer-name)))
+  (tramp-message 9 "Setting up remote shell environment")
+  (tramp-discard-garbage-erase-buffer p multi-method method user host)
+  (process-send-string
+   nil (format "stty -inlcr -echo kill '^U'%s" tramp-rsh-end-of-line))
+  (unless (tramp-wait-for-regexp
+	   p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+    (pop-to-buffer (buffer-name))
+    (error "Couldn't `stty -echo', see buffer `%s'" (buffer-name)))
+  (erase-buffer)
+  (process-send-string nil (format "TERM=dumb; export TERM%s"
+                                   tramp-rsh-end-of-line))
+  (unless (tramp-wait-for-regexp
+	   p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+    (pop-to-buffer (buffer-name))
+    (error "Couldn't `TERM=dumb; export TERM', see buffer `%s'" (buffer-name)))
+  ;; Try to set up the coding system correctly.
+  ;; CCC this can't be the right way to do it.  Hm.
+  (save-excursion
+    (erase-buffer)
+    (tramp-message 9 "Determining coding system")
+    (process-send-string nil (format "echo foo ; echo bar %s"
+                                     tramp-rsh-end-of-line))
+    (unless (tramp-wait-for-regexp
+             p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+      (pop-to-buffer (buffer-name))
+      (error "Couldn't `echo foo; echo bar' to determine line endings'"))
+    (goto-char (point-min))
+    (if (featurep 'mule)
+        ;; Use MULE to select the right EOL convention for communicating
+        ;; with the process.
+        (let* ((cs (or (process-coding-system p) (cons 'undecided 'undecided)))
+               cs-decode cs-encode)
+          (when (symbolp cs) (setq cs (cons cs cs)))
+          (setq cs-decode (car cs))
+          (setq cs-encode (cdr cs))
+          (unless cs-decode (setq cs-decode 'undecided))
+          (unless cs-encode (setq cs-encode 'undecided))
+          (setq cs-encode (tramp-coding-system-change-eol-conversion
+                           cs-encode 'unix))
+          (when (search-forward "\r" nil t)
+            (setq cs-decode (tramp-coding-system-change-eol-conversion
+                             cs-decode 'dos)))
+          (set-buffer-process-coding-system cs-decode cs-encode))
+      ;; Look for ^M and do something useful if found.
+      (when (search-forward "\r" nil t)
+        ;; We have found a ^M but cannot frob the process coding system
+        ;; because we're running on a non-MULE Emacs.  Let's try
+        ;; stty, instead.
+        (tramp-message 9 "Trying `stty -onlcr'")
+        (process-send-string nil (format "stty -onlcr%s" tramp-rsh-end-of-line))
+        (unless (tramp-wait-for-regexp
+                 p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+          (pop-to-buffer (buffer-name))
+          (error "Couldn't `stty -onlcr', see buffer `%s'" (buffer-name))))))
+  (erase-buffer)
+  (tramp-message
+   9 "Waiting 30s for `HISTFILE=$HOME/.tramp_history; HISTSIZE=1'")
+  (process-send-string
+   nil (format "HISTFILE=$HOME/.tramp_history; HISTSIZE=1%s"
+               tramp-rsh-end-of-line))
+  (unless (tramp-wait-for-regexp
+           p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+    (pop-to-buffer (buffer-name))
+    (error (concat "Couldn't `HISTFILE=$HOME/.tramp_history; "
+                   "HISTSIZE=1', see buffer `%s'")
+           (buffer-name)))
+  (erase-buffer)
+  (tramp-message 9 "Waiting 30s for `set +o vi +o emacs'")
+  (process-send-string
+   nil (format "set +o vi +o emacs%s"      ;mustn't `>/dev/null' with AIX?
+               tramp-rsh-end-of-line))
+  (unless (tramp-wait-for-regexp
+           p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+    (pop-to-buffer (buffer-name))
+    (error "Couldn't `set +o vi +o emacs', see buffer `%s'"
+           (buffer-name)))
+  (erase-buffer)
+  (tramp-message 9 "Waiting 30s for `unset MAIL MAILCHECK MAILPATH'")
+  (process-send-string
+   nil (format "unset MAIL MAILCHECK MAILPATH 1>/dev/null 2>/dev/null%s"
+               tramp-rsh-end-of-line))
+  (unless (tramp-wait-for-regexp
+           p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+    (pop-to-buffer (buffer-name))
+    (error "Couldn't `unset MAIL MAILCHECK MAILPATH', see buffer `%s'"
+           (buffer-name)))
+  (erase-buffer)
+  (tramp-message 9 "Waiting 30s for `unset CDPATH'")
+  (process-send-string
+   nil (format "unset CDPATH%s" tramp-rsh-end-of-line))
+  (unless (tramp-wait-for-regexp
+           p 30 (format "\\(\\$ *\\|%s\\)\\'" shell-prompt-pattern))
+    (pop-to-buffer (buffer-name))
+    (error "Couldn't `unset CDPATH', see buffer `%s'"
+           (buffer-name)))
+  (erase-buffer)
+  (tramp-message 9 "Setting shell prompt")
+  (tramp-send-command
+   multi-method method user host
+   (format "PS1='%s%s%s'; PS2=''; PS3=''"
+           tramp-rsh-end-of-line
+           tramp-end-of-output
+           tramp-rsh-end-of-line))
+  (tramp-wait-for-output)
+  (tramp-send-command multi-method method user host "echo hello")
+  (tramp-message 9 "Waiting for remote `%s' to come up..."
+               (tramp-get-remote-sh multi-method method))
+  (unless (tramp-wait-for-output 5)
+    (unless (tramp-wait-for-output 5)
+      (pop-to-buffer (buffer-name))
+      (error "Couldn't set remote shell prompt.  See buffer `%s' for details"
+             (buffer-name))))
+  (tramp-message 7 "Waiting for remote `%s' to come up...done"
+               (tramp-get-remote-sh multi-method method)))
+
+(defun tramp-post-connection (multi-method method user host)
+  "Prepare a remote shell before being able to work on it.
+METHOD, USER and HOST specify the connection.
+Among other things, this finds a shell which groks tilde expansion,
+tries to find an `ls' command which groks the `-n' option, sets the
+locale to C and sets up the remote shell search path."
+  ;; Search for a good shell before searching for a command which
+  ;; checks if a file exists. This is done because Tramp wants to use
+  ;; "test foo; echo $?" to check if various conditions hold, and
+  ;; there are buggy /bin/sh implementations which don't execute the
+  ;; "echo $?"  part if the "test" part has an error.  In particular,
+  ;; the Solaris /bin/sh is a problem.  I'm betting that all systems
+  ;; with buggy /bin/sh implementations will have a working bash or
+  ;; ksh.  Whee...
+  (tramp-find-shell multi-method method user host)
+  (tramp-find-file-exists-command multi-method method user host)
+  (sit-for 1)
+  ;; Without (sit-for 0.1) at least, my machine will almost always blow
+  ;; up on 'not numberp /root' - a race that causes the 'echo ~root'
+  ;; output of (tramp-find-shell) to show up along with the output of
+  ;; (tramp-find-ls-command) testing.
+  ;;
+  ;; I can't work out why this is a problem though. The (tramp-wait-for-output)
+  ;; call in (tramp-find-shell) *should* make this not happen, I thought.
+  ;;
+  ;; After much debugging I couldn't find any problem with the implementation
+  ;; of that function though. The workaround stays for me at least. :/
+  ;;
+  ;; Daniel Pittman <daniel@danann.net>
+  (make-local-variable 'tramp-ls-command)
+  (setq tramp-ls-command (tramp-find-ls-command multi-method method user host))
+  (unless tramp-ls-command
+    (tramp-message
+     1
+     "Danger!  Couldn't find ls which groks -n.  Muddling through anyway")
+    (setq tramp-ls-command
+          (tramp-find-executable multi-method method user host
+                               "ls" tramp-remote-path nil)))
+  (unless tramp-ls-command
+    (error "Fatal error: Couldn't find remote executable `ls'"))
+  (tramp-message 5 "Using remote command `%s' for getting directory listings"
+               tramp-ls-command)
+  (tramp-send-command multi-method method user host
+                    (concat "tramp_set_exit_status () {" tramp-rsh-end-of-line
+                            "return $1" tramp-rsh-end-of-line
+                            "}"))
+  (tramp-wait-for-output)
+  ;; Set remote PATH variable.
+  (tramp-set-remote-path multi-method method user host "PATH" tramp-remote-path)
+  ;; Tell remote shell to use standard time format, needed for
+  ;; parsing `ls -l' output.
+  (tramp-send-command multi-method method user host
+                    "LC_TIME=C; export LC_TIME; echo huhu")
+  (tramp-wait-for-output)
+  (tramp-send-command multi-method method user host
+                    "mesg n; echo huhu")
+  (tramp-wait-for-output)
+  (tramp-send-command multi-method method user host
+                    "biff n ; echo huhu")
+  (tramp-wait-for-output)
+  ;; Unalias ls(1) to work around issues with those silly people who make it
+  ;; spit out ANSI escapes or whatever.
+  (tramp-send-command multi-method method user host
+                    "unalias ls; echo huhu")
+  (tramp-wait-for-output)
+  ;; Does `test A -nt B' work?  Use abominable `find' construct if it
+  ;; doesn't.  BSD/OS 4.0 wants the parentheses around the command,
+  ;; for otherwise the shell crashes.
+  (erase-buffer)
+  (make-local-variable 'tramp-test-groks-nt)
+  (tramp-send-command multi-method method user host
+                    "( test / -nt / )")
+  (tramp-wait-for-output)
+  (goto-char (point-min))
+  (setq tramp-test-groks-nt
+        (looking-at (format "\n%s\n" (regexp-quote tramp-end-of-output))))
+  (unless tramp-test-groks-nt
+    (tramp-send-command
+     multi-method method user host
+     (concat "tramp_test_nt () {" tramp-rsh-end-of-line
+             "test -n \"`find $1 -prune -newer $2 -print`\"" tramp-rsh-end-of-line
+             "}")))
+  (tramp-wait-for-output)
+  ;; Find a `perl'.
+  (erase-buffer)
+  (let ((tramp-remote-perl
+	 (or (tramp-find-executable multi-method method user host
+				  "perl5" tramp-remote-path nil)
+	     (tramp-find-executable multi-method method user host
+				  "perl" tramp-remote-path nil))))
+    (when tramp-remote-perl
+      (tramp-set-connection-property "perl" tramp-remote-perl multi-method method user host)
+      ;; Set up stat in Perl if we can.
+      (when tramp-remote-perl
+	(tramp-message 5 "Sending the Perl `file-attributes' implementation.")
+	(tramp-send-linewise
+	 multi-method method user host
+	 (concat "tramp_file_attributes () {\n"
+		 tramp-remote-perl
+		 " -e '" tramp-perl-file-attributes "' $1 2>/dev/null\n"
+		 "}"))
+	(tramp-wait-for-output)
+	(when (string= (tramp-get-encoding-command multi-method method)
+		       "tramp_mimencode")
+	  (tramp-message 5 "Sending the Perl `mime-encode' implementation.")
+	  (tramp-send-linewise
+	   multi-method method user host
+	   (concat "tramp_mimencode () {\n"
+		   (if (tramp-find-executable multi-method method user host
+					      "mimencode"  tramp-remote-path t)
+		       "mimencode -b $1" 
+		     (concat tramp-remote-perl
+			     " -e '" tramp-perl-mime-encode "' $1 2>/dev/null"))
+		   "\n}"))
+	  (tramp-wait-for-output))
+	(when (string= (tramp-get-decoding-command multi-method method)
+		       "tramp_mimedecode")
+	  (tramp-message 5 "Sending the Perl `mime-decode' implementation.")
+	  (tramp-send-linewise
+	   multi-method method user host
+	   (concat "tramp_mimedecode () {\n"
+		   (if (tramp-find-executable multi-method method user host
+					      "mimencode"  tramp-remote-path t)
+		       "mimencode -u -b $1" 
+		     (concat tramp-remote-perl
+			     " -e '" tramp-perl-mime-decode "' $1 2>/dev/null"))
+		   "\n}"))
+	  (tramp-wait-for-output)))))
+  ;; Find ln(1)
+  (erase-buffer)
+  (let ((ln (tramp-find-executable multi-method method user host
+				   "ln" tramp-remote-path nil)))
+    (when ln
+      (tramp-set-connection-property "ln" ln multi-method method user host)))
+  (erase-buffer)
+  ;; If encoding/decoding command are given, test to see if they work.
+  ;; CCC: Maybe it would be useful to run the encoder both locally and
+  ;; remotely to see if they produce the same result.
+  (let ((decoding (tramp-get-decoding-command multi-method method))
+	(encoding (tramp-get-encoding-command multi-method method))
+	(magic-string "xyzzy"))
+    (when (and (or decoding encoding) (not (and decoding encoding)))
+      (tramp-kill-process multi-method method user host)
+      (error
+       "Must give both decoding and encoding command in method definition"))
+    (when (and decoding encoding)
+      (tramp-message
+       5
+       "Checking to see if encoding/decoding commands work on remote host...")
+      (tramp-send-command
+       multi-method method user host
+       (format "echo %s | %s | %s"
+	       (tramp-shell-quote-argument magic-string) encoding decoding))
+      (tramp-wait-for-output)
+      (unless (looking-at (regexp-quote magic-string))
+	(tramp-kill-process multi-method method user host)
+	(error "Remote host cannot execute de/encoding commands.  See buffer `%s' for details"
+	       (buffer-name)))
+      (erase-buffer)
+      (tramp-message
+       5 "Checking to see if encoding/decoding commands work on remote host...done"))))
+
+
+(defun tramp-maybe-open-connection (multi-method method user host)
+  "Maybe open a connection to HOST, logging in as USER, using METHOD.
+Does not do anything if a connection is already open, but re-opens the
+connection if a previous connection has died for some reason."
+  (let ((p (get-buffer-process (tramp-get-buffer multi-method method user host))))
+    (unless (and p
+                 (processp p)
+                 (memq (process-status p) '(run open)))
+      (when (and p (processp p))
+        (delete-process p))
+      (funcall (tramp-get-connection-function multi-method method)
+               multi-method method user host))))
+
+(defun tramp-send-command
+  (multi-method method user host command &optional noerase)
+  "Send the COMMAND to USER at HOST (logged in using METHOD).
+Erases temporary buffer before sending the command (unless NOERASE
+is true)."
+  (tramp-maybe-open-connection multi-method method user host)
+  (when tramp-debug-buffer
+    (save-excursion
+      (set-buffer (tramp-get-debug-buffer multi-method method user host))
+      (goto-char (point-max))
+      (tramp-insert-with-face 'bold (format "$ %s\n" command))))
+  (let ((proc nil))
+    (set-buffer (tramp-get-buffer multi-method method user host))
+    (unless noerase (erase-buffer))
+    (setq proc (get-buffer-process (current-buffer)))
+    (process-send-string proc
+                         (concat command tramp-rsh-end-of-line))))
+
+;; It seems that Tru64 Unix does not like it if long strings are sent
+;; to it in one go.  (This happens when sending the Perl
+;; `file-attributes' implementation, for instance.)  Therefore, we
+;; have this function which waits a bit at each line.
+(defun tramp-send-linewise
+  (multi-method method user host string &optional noerase)
+  "Send the STRING to USER at HOST linewise.
+Erases temporary buffer before sending the STRING (unless NOERASE
+is true).
+
+The STRING is expected to use Unix line-endings, but the lines sent to
+the remote host use line-endings as defined in the variable
+`tramp-rsh-end-of-line'."
+  (tramp-maybe-open-connection multi-method method user host)
+  (when tramp-debug-buffer
+    (save-excursion
+      (set-buffer (tramp-get-debug-buffer multi-method method user host))
+      (goto-char (point-max))
+      (tramp-insert-with-face 'bold (format "$ %s\n" string))))
+  (let ((proc nil)
+	(lines (split-string string "\n")))
+    (set-buffer (tramp-get-buffer multi-method method user host))
+    (unless noerase (erase-buffer))
+    (setq proc (get-buffer-process (current-buffer)))
+    (mapcar (lambda (x)
+	      (sleep-for 0.1)
+	      (process-send-string proc
+				   (concat x tramp-rsh-end-of-line)))
+	    lines)))
+
+(defun tramp-wait-for-output (&optional timeout)
+  "Wait for output from remote rsh command."
+  (let ((proc (get-buffer-process (current-buffer)))
+        (found nil)
+        (start-time (current-time))
+        (end-of-output (concat "^"
+                               (regexp-quote tramp-end-of-output)
+                               "$")))
+    ;; Algorithm: get waiting output.  See if last line contains
+    ;; end-of-output sentinel.  If not, wait a bit and again get
+    ;; waiting output.  Repeat until timeout expires or end-of-output
+    ;; sentinel is seen.  Will hang if timeout is nil and
+    ;; end-of-output sentinel never appears.
+    (save-match-data
+      (cond (timeout
+             ;; Work around an XEmacs bug, where the timeout expires
+             ;; faster than it should.  This degenerates into polling
+             ;; for buggy XEmacsen, but oh, well.
+             (while (and (not found)
+                         (< (tramp-time-diff (current-time) start-time)
+                            timeout))
+               (with-timeout (timeout)
+                 (while (not found)
+                   (accept-process-output proc 1)
+                   (goto-char (point-max))
+                   (forward-line -1)
+                   (setq found (looking-at end-of-output))))))
+            (t
+             (while (not found)
+               (accept-process-output proc 1)
+               (goto-char (point-max))
+               (forward-line -1)
+               (setq found (looking-at end-of-output))))))
+    ;; At this point, either the timeout has expired or we have found
+    ;; the end-of-output sentinel.
+    (when found
+      (goto-char (point-max))
+      (forward-line -2)
+      (delete-region (point) (point-max)))
+    ;; Add output to debug buffer if appropriate.
+    (when tramp-debug-buffer
+      (append-to-buffer
+       (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
+                             tramp-current-user tramp-current-host)
+       (point-min) (point-max))
+      (when (not found)
+        (save-excursion
+          (set-buffer
+           (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
+                                 tramp-current-user tramp-current-host))
+          (goto-char (point-max))
+          (insert "[[Remote prompt `" end-of-output "' not found"
+                  (if timeout (concat " in " timeout " secs") "")
+                  "]]"))))
+    (goto-char (point-min))
+    ;; Return value is whether end-of-output sentinel was found.
+    found))
+
+(defun tramp-match-string-list (&optional string)
+  "Returns list of all match strings.
+That is, (list (match-string 0) (match-string 1) ...), according to the
+number of matches."
+  (let* ((nmatches (/ (length (match-data)) 2))
+         (i (- nmatches 1))
+         (res nil))
+    (while (>= i 0)
+      (setq res (cons (match-string i string) res))
+      (setq i (- i 1)))
+    res))
+
+(defun tramp-send-command-and-check (multi-method method user host command
+                                                  &optional subshell)
+  "Run COMMAND and check its exit status.
+MULTI-METHOD and METHOD specify how to log in (as USER) to the remote HOST.
+Sends `echo $?' along with the COMMAND for checking the exit status.  If
+COMMAND is nil, just sends `echo $?'.  Returns the exit status found.
+
+If the optional argument SUBSHELL is non-nil, the command is executed in
+a subshell, ie surrounded by parentheses."
+  (tramp-send-command multi-method method user host
+                      (concat (if subshell "( " "")
+                              command
+                              (if command " 2>/dev/null; " "")
+                              "echo tramp_exit_status $?"
+                              (if subshell " )" " ")))
+  (tramp-wait-for-output)
+  (goto-char (point-max))
+  (unless (search-backward "tramp_exit_status " nil t)
+    (error "Couldn't find exit status of `%s'" command))
+  (skip-chars-forward "^ ")
+  (read (current-buffer)))
+
+(defun tramp-barf-unless-okay (multi-method method user host command subshell
+                                            signal fmt &rest args)
+  "Run COMMAND, check exit status, throw error if exit status not okay.
+Similar to `tramp-send-command-and-check' but accepts two more arguments
+FMT and ARGS which are passed to `error'."
+  (unless (zerop (tramp-send-command-and-check
+                  multi-method method user host command subshell))
+    ;; CCC: really pop-to-buffer?  Maybe it's appropriate to be more
+    ;; silent.
+    (pop-to-buffer (current-buffer))
+    (funcall 'signal signal (apply 'format fmt args))))
+
+(defun tramp-send-region (multi-method method user host start end)
+  "Send the region from START to END to remote command
+running as USER on HOST using METHOD."
+  (let ((proc (get-buffer-process
+               (tramp-get-buffer multi-method method user host))))
+    (unless proc
+      (error "Can't send region to remote host -- not logged in"))
+    (process-send-region proc start end)
+    (when tramp-debug-buffer
+      (append-to-buffer
+       (tramp-get-debug-buffer multi-method method user host)
+       start end))))
+
+(defun tramp-send-eof (multi-method method user host)
+  "Send EOF to the remote end.
+METHOD, HOST and USER specify the the connection."
+  (let ((proc (get-buffer-process
+               (tramp-get-buffer multi-method method user host))))
+    (unless proc
+      (error "Can't send EOF to remote host -- not logged in"))
+    (process-send-eof proc)))
+;    (process-send-string proc "\^D")))
+
+(defun tramp-kill-process (multi-method method user host)
+  "Kill the connection process used by Tramp.
+MULTI-METHOD, METHOD, USER, and HOST, specify the connection."
+  (let ((proc (get-buffer-process
+	       (tramp-get-buffer multi-method method user host))))
+    (kill-process proc)))
+
+(defun tramp-discard-garbage-erase-buffer (p multi-method method user host)
+  "Erase buffer, then discard subsequent garbage.
+If `tramp-discard-garbage' is nil, just erase buffer."
+  (if (not tramp-discard-garbage)
+      (erase-buffer)
+    (while (prog1 (erase-buffer) (accept-process-output p 0.25))
+      (when tramp-debug-buffer
+        (save-excursion
+          (set-buffer (tramp-get-debug-buffer multi-method method user host))
+          (goto-char (point-max))
+          (tramp-insert-with-face
+           'bold (format "Additional characters detected\n")))))))
+
+(defun tramp-mode-string-to-int (mode-string)
+  "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
+  (let* ((mode-chars (string-to-vector mode-string))
+         (owner-read (aref mode-chars 1))
+         (owner-write (aref mode-chars 2))
+         (owner-execute-or-setid (aref mode-chars 3))
+         (group-read (aref mode-chars 4))
+         (group-write (aref mode-chars 5))
+         (group-execute-or-setid (aref mode-chars 6))
+         (other-read (aref mode-chars 7))
+         (other-write (aref mode-chars 8))
+         (other-execute-or-sticky (aref mode-chars 9)))
+    (save-match-data
+      (logior
+       (case owner-read
+         (?r (tramp-octal-to-decimal "00400")) (?- 0)
+         (t (error "Second char `%c' must be one of `r-'" owner-read)))
+       (case owner-write
+         (?w (tramp-octal-to-decimal "00200")) (?- 0)
+         (t (error "Third char `%c' must be one of `w-'" owner-write)))
+       (case owner-execute-or-setid
+         (?x (tramp-octal-to-decimal "00100"))
+         (?S (tramp-octal-to-decimal "04000"))
+         (?s (tramp-octal-to-decimal "04100"))
+         (?- 0)
+         (t (error "Fourth char `%c' must be one of `xsS-'"
+                   owner-execute-or-setid)))
+       (case group-read
+         (?r (tramp-octal-to-decimal "00040")) (?- 0)
+         (t (error "Fifth char `%c' must be one of `r-'" group-read)))
+       (case group-write
+         (?w (tramp-octal-to-decimal "00020")) (?- 0)
+         (t (error "Sixth char `%c' must be one of `w-'" group-write)))
+       (case group-execute-or-setid
+         (?x (tramp-octal-to-decimal "00010"))
+         (?S (tramp-octal-to-decimal "02000"))
+         (?s (tramp-octal-to-decimal "02010"))
+         (?- 0)
+         (t (error "Seventh char `%c' must be one of `xsS-'"
+                   group-execute-or-setid)))
+       (case other-read
+         (?r (tramp-octal-to-decimal "00004")) (?- 0)
+         (t (error "Eighth char `%c' must be one of `r-'" other-read)))
+       (case other-write
+         (?w (tramp-octal-to-decimal "00002")) (?- 0)
+         (t (error "Nineth char `%c' must be one of `w-'" other-write)))
+       (case other-execute-or-sticky
+         (?x (tramp-octal-to-decimal "00001"))
+         (?T (tramp-octal-to-decimal "01000"))
+         (?t (tramp-octal-to-decimal "01001"))
+         (?- 0)
+         (t (error "Tenth char `%c' must be one of `xtT-'"
+                   other-execute-or-sticky)))))))
+
+
+(defun tramp-file-mode-from-int (mode)
+  "Turn an integer representing a file mode into an ls(1)-like string."
+  (let ((type	(cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
+	(user	(logand (lsh mode -6) 7))
+	(group	(logand (lsh mode -3) 7))
+	(other	(logand (lsh mode -0) 7))
+	(suid	(> (logand (lsh mode -9) 4) 0))
+	(sgid	(> (logand (lsh mode -9) 2) 0))
+	(sticky	(> (logand (lsh mode -9) 1) 0)))
+    (setq user  (tramp-file-mode-permissions user  suid "s"))
+    (setq group (tramp-file-mode-permissions group sgid "s"))
+    (setq other (tramp-file-mode-permissions other sticky "t"))
+    (concat type user group other)))
+
+
+(defun tramp-file-mode-permissions (perm suid suid-text)
+  "Convert a permission bitset into a string.
+This is used internally by `tramp-file-mode-from-int'."
+  (let ((r (> (logand perm 4) 0))
+	(w (> (logand perm 2) 0))
+	(x (> (logand perm 1) 0)))
+    (concat (or (and r "r") "-")
+	    (or (and w "w") "-")
+	    (or (and suid x suid-text)	; suid, execute
+		(and suid (upcase suid-text)) ; suid, !execute
+		(and x "x") "-"))))	; !suid
+
+
+(defun tramp-decimal-to-octal (i)
+  "Return a string consisting of the octal digits of I.
+Not actually used.  Use `(format \"%o\" i)' instead?"
+  (cond ((< i 0) (error "Cannot convert negative number to octal"))
+        ((not (integerp i)) (error "Cannot convert non-integer to octal"))
+        ((zerop i) "0")
+        (t (concat (tramp-decimal-to-octal (/ i 8))
+                   (number-to-string (% i 8))))))
+
+
+;;(defun tramp-octal-to-decimal (ostr)
+;;  "Given a string of octal digits, return a decimal number."
+;;  (cond ((null ostr) 0)
+;;        ((string= "" ostr) 0)
+;;        (t (let ((last (aref ostr (1- (length ostr))))
+;;                 (rest (substring ostr 0 (1- (length ostr)))))
+;;             (unless (and (>= last ?0)
+;;                          (<= last ?7))
+;;               (error "Not an octal digit: %c" last))
+;;             (+ (- last ?0) (* 8 (tramp-octal-to-decimal rest)))))))
+;; Kudos to Gerd Moellmann for this suggestion.
+(defun tramp-octal-to-decimal (ostr)
+  "Given a string of octal digits, return a decimal number."
+  (let ((x (or ostr "")))
+    ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
+    (unless (string-match "\\`[0-7]*\\'" x)
+      (error "Non-octal junk in string `%s'" x))
+    (string-to-number ostr 8)))
+
+(defun tramp-shell-case-fold (string)
+  "Converts STRING to shell glob pattern which ignores case."
+  (mapconcat
+   (lambda (c)
+     (if (equal (downcase c) (upcase c))
+         (vector c)
+       (format "[%c%c]" (downcase c) (upcase c))))
+   string
+   ""))
+
+
+;; ------------------------------------------------------------ 
+;; -- TRAMP file names -- 
+;; ------------------------------------------------------------ 
+;; Conversion functions between external representation and
+;; internal data structure.  Convenience functions for internal
+;; data structure.
+
+(defstruct tramp-file-name multi-method method user host path)
+
+(defun tramp-tramp-file-p (name)
+  "Return t iff NAME is a tramp file."
+  (save-match-data
+    (string-match tramp-file-name-regexp name)))
+ 
+;; HHH: Changed.  Used to assign the return value of (user-login-name)
+;;      to the `user' part of the structure if a user name was not
+;;      provided, now it assigns nil.
+(defun tramp-dissect-file-name (name)
+  "Return an `tramp-file-name' structure.
+The structure consists of remote method, remote user, remote host and
+remote path name."
+  (let (method)
+    (save-match-data
+      (unless (string-match (nth 0 tramp-file-name-structure) name)
+        (error "Not a tramp file name: %s" name))
+      (setq method (or (match-string (nth 1 tramp-file-name-structure) name)
+                       tramp-default-method))
+      (if (member method tramp-multi-methods)
+          ;; If it's a multi method, the file name structure contains
+          ;; arrays of method, user and host.
+          (tramp-dissect-multi-file-name name)
+        ;; Normal method.
+        (make-tramp-file-name
+         :multi-method nil
+         :method method
+         :user (or (match-string (nth 2 tramp-file-name-structure) name)
+                   nil)
+         :host (match-string (nth 3 tramp-file-name-structure) name)
+         :path (match-string (nth 4 tramp-file-name-structure) name))))))
+
+;; HHH: Not Changed.  Multi method.  Will probably not handle the case where
+;;      a user name is not provided in the "file name" very well.
+(defun tramp-dissect-multi-file-name (name)
+  "Not implemented yet."
+  (let ((regexp           (nth 0 tramp-multi-file-name-structure))
+        (method-index     (nth 1 tramp-multi-file-name-structure))
+        (hops-index       (nth 2 tramp-multi-file-name-structure))
+        (path-index       (nth 3 tramp-multi-file-name-structure))
+        (hop-regexp       (nth 0 tramp-multi-file-name-hop-structure))
+        (hop-method-index (nth 1 tramp-multi-file-name-hop-structure))
+        (hop-user-index   (nth 2 tramp-multi-file-name-hop-structure))
+        (hop-host-index   (nth 3 tramp-multi-file-name-hop-structure))
+        method hops len hop-methods hop-users hop-hosts path)
+    (unless (string-match (format regexp hop-regexp) name)
+      (error "Not a multi tramp file name: %s" name))
+    (setq method (match-string method-index name))
+    (setq hops (match-string hops-index name))
+    (setq len (/ (length (match-data t)) 2))
+    (when (< path-index 0) (incf path-index len))
+    (setq path (match-string path-index name))
+    (let ((index 0))
+      (while (string-match hop-regexp hops index)
+        (setq index (match-end 0))
+        (setq hop-methods
+              (cons (match-string hop-method-index hops) hop-methods))
+        (setq hop-users
+              (cons (match-string hop-user-index hops) hop-users))
+        (setq hop-hosts
+              (cons (match-string hop-host-index hops) hop-hosts))))
+    (make-tramp-file-name
+     :multi-method method
+     :method       (apply 'vector (reverse hop-methods))
+     :user         (apply 'vector (reverse hop-users))
+     :host         (apply 'vector (reverse hop-hosts))
+     :path         path)))
+
+(defun tramp-make-tramp-file-name (multi-method method user host path)
+  "Constructs a tramp file name from METHOD, USER, HOST and PATH."
+  (unless tramp-make-tramp-file-format
+    (error "`tramp-make-tramp-file-format' is nil"))
+  (if multi-method
+      (tramp-make-tramp-multi-file-name multi-method method user host path)
+    (if user
+        (format-spec tramp-make-tramp-file-format
+                     (list (cons ?m method)
+                           (cons ?u user)
+                           (cons ?h host)
+                           (cons ?p path)))
+      (format-spec tramp-make-tramp-file-user-nil-format
+                   (list (cons ?m method)
+                         (cons ?h host)
+                         (cons ?p path))))))
+
+;; CCC: Henrik Holm: Not Changed.  Multi Method.  What should be done
+;; with this when USER is nil?
+(defun tramp-make-tramp-multi-file-name (multi-method method user host path)
+  "Constructs a tramp file name for a multi-hop method."
+  (unless tramp-make-multi-tramp-file-format
+    (error "`tramp-make-multi-tramp-file-format' is nil"))
+  (let* ((prefix-format (nth 0 tramp-make-multi-tramp-file-format))
+         (hop-format    (nth 1 tramp-make-multi-tramp-file-format))
+         (path-format   (nth 2 tramp-make-multi-tramp-file-format))
+         (prefix (format-spec prefix-format (list (cons ?m multi-method))))
+         (hops "")
+         (path (format-spec path-format (list (cons ?p path))))
+         (i 0)
+         (len (length method)))
+    (while (< i len)
+      (let ((m (aref method i))
+            (u (aref user i))
+            (h (aref host i)))
+        (setq hops (concat hops
+                           (format-spec
+                            hop-format
+                            (list (cons ?m m)
+                                  (cons ?u u)
+                                  (cons ?h h)))))
+        (incf i)))
+    (concat prefix hops path)))
+
+;; HHH: Changed.  Handles the case where no user name is given in the
+;;      file name.
+(defun tramp-make-rcp-program-file-name (user host path)
+  "Create a file name suitable to be passed to `rcp'."
+  (if user
+      (format "%s@%s:%s" user host path)
+    (format "%s:%s" host path)))
+
+(defun tramp-method-out-of-band-p (multi-method method)
+  "Return t if this is an out-of-band method, nil otherwise.
+It is important to check for this condition, since it is not possible
+to enter a password for the `tramp-rcp-program'."
+  (tramp-get-rcp-program multi-method method))
+
+;; Variables local to connection.
+
+(defun tramp-get-ls-command (multi-method method user host)
+  (save-excursion
+    (tramp-maybe-open-connection multi-method method user host)
+    (set-buffer (tramp-get-buffer multi-method method user host))
+    tramp-ls-command))
+
+(defun tramp-get-test-groks-nt (multi-method method user host)
+  (save-excursion
+    (tramp-maybe-open-connection multi-method method user host)
+    (set-buffer (tramp-get-buffer multi-method method user host))
+    tramp-test-groks-nt))
+
+(defun tramp-get-file-exists-command (multi-method method user host)
+  (save-excursion
+    (tramp-maybe-open-connection multi-method method user host)
+    (set-buffer (tramp-get-buffer multi-method method user host))
+    tramp-file-exists-command))
+
+(defun tramp-get-remote-perl (multi-method method user host)
+  (tramp-get-connection-property "perl" nil multi-method method user host))
+
+(defun tramp-get-remote-ln (multi-method method user host)
+  (tramp-get-connection-property "ln" nil multi-method method user host))
+
+;; Get a property of a TRAMP connection.
+(defun tramp-get-connection-property (property default multi-method method user host)
+  "Get the named property for the connection.
+If the value is not set for the connection, return `default'"
+  (tramp-maybe-open-connection multi-method method user host)
+  (with-current-buffer (tramp-get-buffer multi-method method user host)
+    (let (error)
+      (condition-case nil
+	  (symbol-value (intern (concat "tramp-connection-property-" property)))
+	(error	default)))))
+
+;; Set a property of a TRAMP connection.
+(defun tramp-set-connection-property (property value multi-method method user host)
+  "Set the named property of a TRAMP connection."
+  (tramp-maybe-open-connection multi-method method user host)
+  (with-current-buffer (tramp-get-buffer multi-method method user host)
+    (set (make-local-variable
+	  (intern (concat "tramp-connection-property-" property)))
+	  value)))
+
+
+
+(defun tramp-get-connection-function (multi-method method)
+  (second (or (assoc 'tramp-connection-function
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify a connection function"
+                     (or multi-method method)))))
+
+(defun tramp-get-remote-sh (multi-method method)
+  (second (or (assoc 'tramp-remote-sh
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify a remote shell"
+                     (or multi-method method)))))
+
+(defun tramp-get-rsh-program (multi-method method)
+  (second (or (assoc 'tramp-rsh-program
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify an rsh program"
+                     (or multi-method method)))))
+
+(defun tramp-get-rsh-args (multi-method method)
+  (second (or (assoc 'tramp-rsh-args
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify rsh args"
+                     (or multi-method method)))))
+
+(defun tramp-get-rcp-program (multi-method method)
+  (second (or (assoc 'tramp-rcp-program
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify an rcp program"
+                     (or multi-method method)))))
+
+(defun tramp-get-rcp-args (multi-method method)
+  (second (or (assoc 'tramp-rcp-args
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify rcp args"
+                     (or multi-method method)))))
+
+(defun tramp-get-rcp-keep-date-arg (multi-method method)
+  (second (or (assoc 'tramp-rcp-keep-date-arg
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify `keep-date' arg for tramp"
+                     (or multi-method method)))))
+
+(defun tramp-get-su-program (multi-method method)
+  (second (or (assoc 'tramp-su-program
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify a su program"
+                     (or multi-method method)))))
+
+(defun tramp-get-su-args (multi-method method)
+  (second (or (assoc 'tramp-su-args
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify su args"
+                     (or multi-method method)))))
+
+(defun tramp-get-encoding-command (multi-method method)
+  (second (or (assoc 'tramp-encoding-command
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify an encoding command"
+                     (or multi-method method)))))
+
+(defun tramp-get-decoding-command (multi-method method)
+  (second (or (assoc 'tramp-decoding-command
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify a decoding command"
+                     (or multi-method method)))))
+
+(defun tramp-get-encoding-function (multi-method method)
+  (second (or (assoc 'tramp-encoding-function
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify an encoding function"
+                     (or multi-method method)))))
+
+(defun tramp-get-decoding-function (multi-method method)
+  (second (or (assoc 'tramp-decoding-function
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify a decoding function"
+                     (or multi-method method)))))
+
+(defun tramp-get-telnet-program (multi-method method)
+  (second (or (assoc 'tramp-telnet-program
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify a telnet program"
+                     (or multi-method method)))))
+
+(defun tramp-get-telnet-args (multi-method method)
+  (second (or (assoc 'tramp-telnet-args
+                     (assoc (or multi-method method tramp-default-method)
+                            tramp-methods))
+              (error "Method `%s' didn't specify telnet args"
+                     (or multi-method method)))))
+
+;; Auto saving to a special directory.
+
+(defun tramp-make-auto-save-file-name (fn)
+  "Returns a file name in `tramp-auto-save-directory' for autosaving this file."
+  (when tramp-auto-save-directory
+    (unless (file-exists-p tramp-auto-save-directory)
+      (make-directory tramp-auto-save-directory t)))
+  ;; jka-compr doesn't like auto-saving, so by appending "~" to the
+  ;; file name we make sure that jka-compr isn't used for the
+  ;; auto-save file.
+  (let ((buffer-file-name (expand-file-name
+			   (tramp-subst-strs-in-string '(("_" . "|")
+							 ("/" . "_a")
+							 (":" . "_b")
+							 ("|" . "__")
+							 ("[" . "_l")
+							 ("]" . "_r"))
+						       fn)
+			   tramp-auto-save-directory)))
+    (make-auto-save-file-name)))
+
+(defadvice make-auto-save-file-name
+  (around tramp-advice-make-auto-save-file-name () activate)
+  "Invoke `tramp-make-auto-save-file-name' for tramp files."
+  (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name))
+	   tramp-auto-save-directory)
+      (setq ad-return-value
+            (tramp-make-auto-save-file-name (buffer-file-name)))
+    ad-do-it))
+
+(defun tramp-subst-strs-in-string (alist string)
+  "Replace all occurrences of the string FROM with TO in STRING.
+ALIST is of the form ((FROM . TO) ...)."
+  (save-match-data
+    (while alist
+      (let* ((pr (car alist))
+             (from (car pr))
+             (to (cdr pr)))
+        (while (string-match (regexp-quote from) string)
+          (setq string (replace-match to t t string)))
+        (setq alist (cdr alist))))
+    string))
+
+(defun tramp-insert-with-face (face string)
+  "Insert text with a specific face."
+  (let ((start (point)))
+    (insert string)
+    (add-text-properties start (point) (list 'face face))))
+
+;; ------------------------------------------------------------
+;; -- Compatibility functions section --
+;; ------------------------------------------------------------
+
+(defun tramp-temporary-file-directory ()
+  "Return name of directory for temporary files (compat function).
+For Emacs, this is the variable `temporary-file-directory', for XEmacs
+this is the function `temp-directory'."
+  (cond ((boundp 'temporary-file-directory)
+         (symbol-value 'temporary-file-directory))
+        ((fboundp 'temp-directory)
+         (funcall (symbol-function 'temp-directory))) ;pacify byte-compiler
+        ((let ((d (getenv "TEMP"))) (and d (file-directory-p d)))
+         (file-name-as-directory (getenv "TEMP")))
+        ((let ((d (getenv "TMP"))) (and d (file-directory-p d)))
+         (file-name-as-directory (getenv "TMP")))
+        ((let ((d (getenv "TMPDIR"))) (and d (file-directory-p d)))
+         (file-name-as-directory (getenv "TMPDIR")))
+        ((file-exists-p "c:/temp") (file-name-as-directory "c:/temp"))
+        (t (message (concat "Neither `temporary-file-directory' nor "
+                            "`temp-directory' is defined -- using /tmp."))
+           (file-name-as-directory "/tmp"))))
+
+(defun tramp-read-passwd (prompt)
+  "Read a password from user (compat function).
+Invokes `read-passwd' if that is defined, else `ange-ftp-read-passwd'."
+  (apply
+   (if (fboundp 'read-passwd) #'read-passwd #'ange-ftp-read-passwd)
+   (list prompt)))
+
+(defun tramp-time-diff (t1 t2)
+  "Return the difference between the two times, in seconds.
+T1 and T2 are time values (as returned by `current-time' for example).
+
+NOTE: This function will fail if the time difference is too large to
+fit in an integer."
+  ;; Pacify byte-compiler with `symbol-function'.
+  (cond ((fboundp 'subtract-time)
+         (cadr (funcall (symbol-function 'subtract-time) t1 t2)))
+        ((fboundp 'itimer-time-difference)
+         (floor (funcall
+		 (symbol-function 'itimer-time-difference)
+		 (if (< (length t1) 3) (append t1 '(0)) t1)
+		 (if (< (length t2) 3) (append t2 '(0)) t2))))
+        (t
+         ;; snarfed from Emacs 21 time-date.el
+         (cadr (let ((borrow (< (cadr t1) (cadr t2))))
+                 (list (- (car t1) (car t2) (if borrow 1 0))
+                       (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))))))
+
+(defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
+  "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
+EOL-TYPE can be one of `dos', `unix', or `mac'."
+  (cond ((fboundp 'coding-system-change-eol-conversion)
+         (apply #'coding-system-change-eol-conversion
+                (list coding-system eol-type)))
+        ((fboundp 'subsidiary-coding-system)
+         (apply
+          #'subsidiary-coding-system
+          (list coding-system
+                (cond ((eq eol-type 'dos) 'crlf)
+                      ((eq eol-type 'unix) 'lf)
+                      ((eq eol-type 'mac) 'cr)
+                      (t
+                       (error "Unknown EOL-TYPE `%s', must be %s"
+                              eol-type
+                              "`dos', `unix', or `mac'"))))))
+        (t (error "Can't change EOL conversion -- is MULE missing?"))))
+
+(defun tramp-split-string (string pattern)
+  "Like `split-string' but omit empty strings.
+In Emacs, (split-string \"/foo/bar\" \"/\") returns (\"foo\" \"bar\").
+This is, the first, empty, element is omitted.  In XEmacs, the first
+element is not omitted.
+
+Note: this function has been written for `tramp-handle-file-truename'.
+If you want to use it for something else, you'll have to check whether
+it does the right thing."
+  (delete "" (split-string string pattern)))
+
+;; ------------------------------------------------------------ 
+;; -- Kludges section -- 
+;; ------------------------------------------------------------ 
+
+;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
+;; does not deal well with newline characters.  Newline is replaced by
+;; backslash newline.  But if, say, the string `a backslash newline b'
+;; is passed to a shell, the shell will expand this into "ab",
+;; completely omitting the newline.  This is not what was intended.
+;; It does not appear to be possible to make the function
+;; `shell-quote-argument' work with newlines without making it
+;; dependent on the shell used.  But within this package, we know that
+;; we will always use a Bourne-like shell, so we use an approach which
+;; groks newlines.
+;;
+;; The approach is simple: we call `shell-quote-argument', then
+;; massage the newline part of the result.
+;;
+;; This function should produce a string which is grokked by a Unix
+;; shell, even if the Emacs is running on Windows.  Since this is the
+;; kludges section, we bind `system-type' in such a way that
+;; `shell-quote-arguments'  behaves as if on Unix.
+;;
+;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
+;; function to work with Bourne-like shells.
+;;
+;; CCC: This function should be rewritten so that
+;; `shell-quote-argument' is not used.  This way, we are safe from
+;; changes in `shell-quote-argument'.
+(defun tramp-shell-quote-argument (s)
+  "Similar to `shell-quote-argument', but groks newlines.
+Only works for Bourne-like shells."
+  (let ((system-type 'not-windows))
+    (save-match-data
+      (let ((result (shell-quote-argument s))
+	    (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
+	(when (and (>= (length result) 2)
+		   (string= (substring result 0 2) "\\~"))
+	  (setq result (substring result 1)))
+	(while (string-match nl result)
+	  (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
+				      t t result)))
+	result))))
+
+;; ;; EFS hooks itself into the file name handling stuff in more places
+;; ;; than just `file-name-handler-alist'. The following tells EFS to stay
+;; ;; away from tramp.el paths.
+;; ;;
+;; ;; This is needed because EFS installs (efs-dired-before-readin) into
+;; ;; 'dired-before-readin-hook'. This prevents EFS from opening an FTP
+;; ;; connection to help it's dired process. Not that I have any real
+;; ;; idea *why* this is helpful to dired.
+;; ;;
+;; ;; Anyway, this advice fixes the problem (with a sledgehammer :)
+;; ;;
+;; ;; Daniel Pittman <daniel@danann.net>
+;; ;;
+;; ;; CCC: when the other defadvice calls have disappeared, make sure
+;; ;; not to call defadvice unless it's necessary.  How do we find out whether
+;; ;; it is necessary?  (featurep 'efs) is surely the wrong way --
+;; ;; EFS might nicht be loaded yet.
+;; (defadvice efs-ftp-path (around dont-match-tramp-path activate protect)
+;;   "Cause efs-ftp-path to fail when the path is a TRAMP path."
+;;   (if (tramp-tramp-file-p (ad-get-arg 0))
+;;       nil
+;;     ad-do-it))
+
+;; We currently use "[" and "]" in the filename format.  In Emacs
+;; 20.x, this means that Emacs wants to expand wildcards if
+;; `find-file-wildcards' is non-nil, and then barfs because no
+;; expansion could be found.  We detect this situation and do
+;; something really awful: we have `file-expand-wildcards' return the
+;; original filename if it can't expand anything.  Let's just hope
+;; that this doesn't break anything else.
+;;
+;; Another problem is that the check is done by Emacs version, which
+;; is really not what we want to do.  Oh, well.
+
+;;(when (and (not (featurep 'xemacs))
+;;	   (= emacs-major-version 20))
+;; It seems that this advice is needed in Emacs 21, too.
+(defadvice file-expand-wildcards (around tramp-fix activate)
+  (let ((name (ad-get-arg 0)))
+    (if (tramp-tramp-file-p name)
+	;; If it's a Tramp file, dissect it and look if wildcards
+	;; need to be expanded at all.
+	(let ((v (tramp-dissect-file-name name)))
+	  (if (string-match "[[*?]" (tramp-file-name-path v))
+	      (let ((res ad-do-it))
+		(setq ad-return-value (or res (list name))))
+	    (setq ad-return-value (list name))))
+      ;; If it is not a Tramp file, just run the original function.
+      (let ((res ad-do-it))
+	(setq ad-return-value (or res (list name)))))))
+;;  )
+
+;; Make the `reporter` functionality available for making bug reports about
+;; the package. A most useful piece of code.
+
+(unless (fboundp 'reporter-submit-bug-report)
+  (autoload 'reporter-submit-bug-report "reporter"))
+
+(defun tramp-bug ()
+  "Submit a bug report to the TRAMP developers."
+  (interactive)
+  (require 'reporter)
+  (let ((reporter-prompt-for-summary-p	t))
+    (reporter-submit-bug-report
+     tramp-bug-report-address		; to-address
+     (format "tramp (%s)" tramp-version) ; package name and version
+     `(;; Current state
+       tramp-ls-command
+       tramp-test-groks-nt
+       tramp-file-exists-command
+       tramp-current-multi-method
+       tramp-current-method
+       tramp-current-user
+       tramp-current-host
+
+       ;; System defaults
+       tramp-auto-save-directory        ; vars to dump
+       tramp-default-method
+       tramp-rsh-end-of-line
+       tramp-remote-path
+       tramp-login-prompt-regexp
+       tramp-password-prompt-regexp
+       tramp-wrong-passwd-regexp
+       tramp-temp-name-prefix
+       tramp-file-name-structure
+       tramp-file-name-regexp
+       tramp-multi-file-name-structure
+       tramp-multi-file-name-hop-structure
+       tramp-multi-methods
+       tramp-multi-connection-function-alist
+       tramp-make-tramp-file-format
+       tramp-end-of-output
+
+       ;; Non-tramp variables of interest
+       shell-prompt-pattern
+       backup-by-copying
+       backup-by-copying-when-linked
+       backup-by-copying-when-mismatch
+       ,(when (boundp 'backup-by-copying-when-privileged-mismatch)
+          'backup-by-copying-when-privileged-mismatch)
+       file-name-handler-alist)
+     nil				; pre-hook
+     nil				; post-hook
+     "\
+Enter your bug report in this message, including as much detail as you
+possibly can about the problem, what you did to cause it and what the
+local and remote machines are.
+
+If you can give a simple set of instructions to make this bug happen
+reliably, please include those.  Thank you for helping kill bugs in
+TRAMP.
+--bug report follows this line--")))
+
+(defalias 'tramp-submit-bug 'tramp-bug)
+
+(provide 'tramp)
+
+;; Make sure that we get integration with the VC package.
+;; When it is loaded, we need to pull in the integration module.
+;; This must come after (provide 'tramp) because tramp-vc.el
+;; requires tramp.
+(eval-after-load "vc"
+  '(require 'tramp-vc))
+
+;;; TODO:
+
+;; * Cooperate with PCL-CVS.  It uses start-process, which doesn't
+;;   work for remote files.
+;; * Allow /[method/user@host:port] syntax for the ssh "-p" argument.
+;; * Rewrite `tramp-shell-quote-argument' to abstain from using
+;; `shell-quote-argument'.
+;; * Completion gets confused when you leave out the method name.
+;; * Support `dired-compress-file' filename handler.
+;; * In Emacs 21, `insert-directory' shows total number of bytes used
+;;   by the files in that directory.  Add this here.
+;; * Avoid screen blanking when hitting `g' in dired.  (Eli Tziperman)
+;; * Make ffap.el grok Tramp filenames.  (Eli Tziperman)
+;; * When logging in, keep looking for questions according to an alist
+;;   and then invoke the right function.
+;; * Case-insensitive filename completion.  (Norbert Goevert.)
+;; * Running CVS remotely doesn't appear to work right.  It thinks
+;;   files are locked by somebody else even if I'm the locking user.
+;;   Sometimes, one gets `No CVSROOT specified' errors from CVS.
+;;   (Skip Montanaro)
+;; * Don't use globbing for directories with many files, as this is
+;;   likely to produce long command lines, and some shells choke on
+;;   long command lines.
+;; * Implement `load' operation.
+;; * Find out about the new auto-save mechanism in Emacs 21 and
+;;   do the right thing.
+;; * `vc-directory' does not work.  It never displays any files, even
+;;   if it does show files when run locally.
+;; * Allow correction of passwords, if the remote end allows this.
+;;   (Mark Hershberger)
+;; * Make sure permissions of tmp file are good.
+;;   (Nelson Minar <nelson@media.mit.edu>)
+;; * Grok passwd prompts with scp?  (David Winter
+;;   <winter@nevis1.nevis.columbia.edu>).  Maybe just do `ssh -l user
+;;   host', then wait a while for the passwd or passphrase prompt.  If
+;;   there is one, remember the passwd/phrase.
+;; * How to deal with MULE in `insert-file-contents' and `write-region'?
+;; * Do asynchronous `shell-command's.
+;; * Grok `append' parameter for `write-region'.
+;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
+;; * abbreviate-file-name
+;; * grok ~ in tramp-remote-path  (Henrik Holm <henrikh@tele.ntnu.no>)
+;; * `C' in dired gives error `not tramp file name'.
+;; * Also allow to omit user names when doing multi-hop.  Not sure yet
+;;   what the user names should default to, though.
+;; * better error checking.  At least whenever we see something
+;;   strange when doing zerop, we should kill the process and start
+;;   again.  (Greg Stark)
+;; * Add caching for filename completion.  (Greg Stark)
+;;   Of course, this has issues with usability (stale cache bites) 
+;;      -- <daniel@danann.net>
+;; * Provide a local cache of old versions of remote files for the rsync
+;;   transfer method to use.  (Greg Stark)
+;; * Remove unneeded parameters from methods.
+;; * Invoke rsync once for copying a whole directory hierarchy.
+;;   (Francesco Potortì)
+;; * Should we set PATH ourselves or should we rely on the remote end
+;;   to do it?
+;; * Do the autoconf thing.
+;; * Make it work for XEmacs 20, which is missing `with-timeout'.
+;; * Allow non-Unix remote systems.  (More a long-term thing.)
+;; * Make it work for different encodings, and for different file name
+;;   encodings, too.  (Daniel Pittman)
+;; * Change applicable functions to pass a struct tramp-file-name rather
+;;   than the individual items MULTI-METHOD, METHOD, USER, HOST, PATH.
+;; * Implement asynchronous shell commands.
+;; * Clean up unused *tramp/foo* buffers after a while.  (Pete Forman)
+;; * Progress reports while copying files.  (Michael Kifer)
+;; * `Smart' connection method that uses inline for small and out of
+;;   band for large files.  (Michael Kifer)
+;; * Don't search for perl5 and perl.  Instead, only search for perl and
+;;   then look if it's the right version (with `perl -v').
+;; * When editing a remote CVS controlled file as a different user, VC
+;;   gets confused about the file locking status.  Try to find out why
+;;   the workaround doesn't work.
+;; * When user is running ssh-agent, it would be useful to add the
+;;   passwords typed by the user to that agent.  This way, the next time
+;;   round, the users don't have to type all this in again.
+;;   This would be especially useful for start-process, I think.
+;;   An easy way to implement start-process is to open a second shell
+;;   connection which is inconvenient if the user has to reenter
+;;   passwords.
+;; * Change `copy-file' to grok the case where the filename handler
+;;   for the source and the target file are different.  Right now,
+;;   it looks at the source file and then calls that handler, if
+;;   there is one.  But since ange-ftp, for instance, does not know
+;;   about Tramp, it does not do the right thing if the target file
+;;   name is a Tramp name.
+
+;; Functions for file-name-handler-alist:
+;; diff-latest-backup-file -- in diff.el
+;; dired-compress-file
+;; dired-uncache -- this will be needed when we do insert-directory caching
+;; file-name-as-directory -- use primitive?
+;; file-name-directory -- use primitive?
+;; file-name-nondirectory -- use primitive?
+;; file-name-sans-versions -- use primitive?
+;; file-newer-than-file-p
+;; find-backup-file-name
+;; get-file-buffer -- use primitive
+;; load
+;; unhandled-file-name-directory
+;; vc-registered
+
+;;; tramp.el ends here
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/man/tramp.texi	Mon Jun 17 11:47:23 2002 +0000
@@ -0,0 +1,1626 @@
+\input texinfo   @c -*-texinfo-*-
+@c %**start of header
+@setfilename tramp.info
+@settitle TRAMP User Manual
+@setchapternewpage odd
+@c %**end of header
+
+@c This is *so* much nicer :)
+@footnotestyle end
+
+@c Version values, for easy modification
+@c NOTE: The 'UPDATED' value is updated by the 'time-stamp' function.
+@c       If you change it by hand, the modifications will not stay.
+@set VERSION $Revision: 2.20 $
+@set UPDATED Friday, 14 June, 2002
+
+
+@c Entries for @command{install-info} to use
+@direntry
+* TRAMP: (tramp).                Transparent Remote Access, Multiple Protocol
+                                 Emacs remote file access via rsh and rcp.
+@end direntry
+
+@c Macro to make formatting of the tramp program name consistent.
+@macro tramp
+@sc{tramp}
+@end macro
+
+@c Copying permissions, et al
+@ifinfo
+This file documents @tramp{}, a remote file editing package for Emacs and
+XEmacs.
+     
+Copyright @copyright{} 1999, 2000 Free Software Foundation, Inc.
+     
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+     
+@ignore 
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+   
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+     
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+@end ifinfo
+
+@tex
+
+@titlepage
+@title @tramp{} User Manual
+@subtitle Last updated @value{UPDATED}
+
+@author by Daniel Pittman
+@author based on documentation by Kai Gro@ss{}johann
+@page
+
+@vskip 0pt plus 1filll
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+     
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+     
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+
+@end titlepage
+@page
+
+@end tex
+
+@ifnottex
+@node Top, Copying, (dir), (dir)
+@top @tramp{} User Manual
+
+@tramp{} stands for `Transparent Remote (file) Access, Multiple
+Protocol'.  This package provides remote file editing, similar to
+@cite{ange-ftp} and @cite{EFS}.
+
+The difference is that ange-ftp uses FTP to transfer files between the
+local and the remote host, whereas @tramp{} uses a combination of
+@command{rsh} and @command{rcp} or other work-alike programs, such as
+@command{ssh}/@command{scp}.
+
+This is version @value{VERSION} of the @tramp{} manual, last updated on
+@value{UPDATED}.
+
+You can find the latest version of this document on the web at
+@uref{http://www.freesoftware.fsf.org/tramp/}.
+
+@ifhtml
+This manual is also available as a @uref{tramp_ja.html, Japanese
+translation}.
+
+The latest release of @tramp{} is available for
+@uref{http://savannah.gnu.org/download/tramp/,
+download}, or you may see @ref{Obtaining @tramp{}} for more details,
+including the CVS server details.
+
+@tramp{} also has a @uref{https://savannah.gnu.org/projects/tramp/,
+Savannah Project Page}.
+@end ifhtml
+
+There is a mailing list for @tramp{}, available at
+@email{tramp-devel@@mail.freesoftware.fsf.org}, and archived at
+@uref{http://www.mail-archive.com/emacs-rcp@@ls6.cs.uni-dortmund.de/} as
+well as the usual Savannah archives.
+
+@end ifnottex
+
+@menu
+* Copying::                     @tramp{} Copying conditions.
+* Overview::                    What @tramp{} can and cannot do.
+
+For the end user:
+* Obtaining @tramp{}::          How to obtain @tramp{}.
+* History::                     History of @tramp{}
+* Installation::                Installing @tramp{} with your (X)Emacs.
+* Configuration::               Configuring @tramp{} for use.
+* Usage::                       An overview of the operation of @tramp{}.
+* Bug Reports::                 Reporting Bugs and Problems
+* Frequently Asked Questions::  Questions and answers from the mailing list.
+
+For the developer:
+* Version Control::             The inner workings of remote version control.
+* Files directories and paths::  How file names, directories and paths are mangled and managed.
+* Issues::                      
+
+@detailmenu
+ --- The Detailed Node Listing ---
+
+Configuring @tramp{} for use
+
+* Connection types::            Types of connections made to remote machines.
+* Inline methods::              Inline methods.
+* External transfer methods::   External transfer methods.
+* Multi-hop Methods::           Connecting to a remote host using multiple hops.
+* Default Method::              Selecting a default method.
+* Customizing Methods::         Using Non-Standard Methods.
+* Remote Programs::             How @tramp{} finds and uses programs on the remote machine.
+* Remote shell setup::          
+
+Using @tramp
+
+* Filename Syntax::             @tramp{} filename conventions.
+* Multi-hop filename syntax::   Multi-hop filename conventions
+* Dired::                       Dired and filename completion.
+
+The inner workings of remote version control
+
+* Version Controlled Files::    Determining if a file is under version control.
+* Remote Commands::             Executing the version control commands on the remote machine.
+* Changed workfiles::           Detecting if the working file has changed.
+* Checking out files::          Bringing the workfile out of the repository.
+* Miscellaneous Version Control::  Things related to Version Control that don't fit elsewhere
+
+Things related to Version Control that don't fit elsewhere
+
+* Remote File Ownership::       How VC determines who owns a workfile.
+* Back-end Versions::           How VC determines what release your RCS is.
+
+How file names, directories and paths are mangled and managed.
+
+* Path deconstruction::         Breaking a path into its components.
+
+@end detailmenu
+@end menu
+
+@node Copying
+@chapter @tramp{} Copying conditions
+
+Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+tramp.el is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+tramp.el is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along
+with GNU Emacs; see the file COPYING. If not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
+
+
+@node Overview
+@chapter An overview of @tramp
+
+After the installation of @tramp{} into your Emacs, you will be able to
+access files on remote machines as though they were local. Access to the
+remote file system for editing files, version control, and
+@command{dired} are transparently enabled.
+
+Your access to the remote machine can be with the @command{rsh},
+@command{rlogin}, @command{telnet} programs or with any similar
+connection method. This connection must pass ASCII successfully to be
+usable but need not be 8-bit clean.
+
+The package provides support for @command{ssh} connections out of the
+box, one of the more common uses of the package. This allows relatively
+secure access to machines, especially if @command{ftp} access is
+disabled.
+
+The majority of activity carried out by @tramp{} requires only that the
+remote login is possible and is carried out at the terminal. In order to
+access remote files @tramp{} needs to transfer their content to the local
+machine temporarily.
+
+@tramp{} can transfer files between the machines in a variety of ways. The
+details are easy to select, depending on your needs and the machines in
+question.
+
+The fastest transfer methods rely on a remote file transfer package such
+as @command{rcp}, @command{scp} or @command{rsync}. The use of these
+methods is only possible if the file copy command does not ask for a
+password for the remote machine.
+
+If the remote copy methods are not suitable for you, @tramp{} also
+supports the use of encoded transfers directly through the shell. This
+requires that the @command{mimencode} or @command{uuencode} tools are
+available on the remote machine.
+
+Within these limitations, @tramp{} is quite powerful. It is worth noting
+that, as of the time of writing, it is far from a polished end-user
+product. For a while yet you should expect to run into rough edges and
+problems with the code now and then.
+
+It is finished enough that the developers use it for day to day work but
+the installation and setup can be a little difficult to master, as can
+the terminology.
+
+@tramp{} is still under active development and any problems you encounter,
+trivial or major, should be reported to the @tramp{} developers.
+@xref{Bug Reports}.
+
+
+@subsubheading Behind the scenes
+
+This section tries to explain what goes on behind the scenes when you
+access a remote file through @tramp{}.
+
+Suppose you type @kbd{C-x C-f} and enter part of an @tramp{} file name,
+then hit @kbd{@key{TAB}} for completion.  Suppose further that this is
+the first time that @tramp{} is invoked for the host in question.  Here's
+what happens:
+
+@itemize
+@item
+@tramp{} discovers that it needs a connection to the host. So it invokes
+@command{telnet HOST} or @command{rsh HOST -l USER} or a similar tool to
+connect to the remote host. Communication with this process happens
+through an Emacs buffer, that is, the output from the remote end goes
+into a buffer.
+
+@item
+The remote host may prompt for a login name (for @command{telnet}).  The
+login name is given in the file name, so @tramp{} sends the login name and
+a newline.
+
+@item
+The remote host may prompt for a password or pass phrase (for
+@command{rsh} or for @command{telnet} after sending the login name).
+@tramp{} displays the prompt in the minibuffer, asking you for the
+password or pass phrase.
+
+You enter the password or pass phrase.  @tramp{} sends it to the remote
+host, followed by a newline.
+
+@item
+@tramp{} now waits for the shell prompt or for a message that the login
+failed.
+
+If @tramp{} sees neither of them after a certain period of time (a minute,
+say), then it issues an error message saying that it couldn't find the
+remote shell prompt and shows you what the remote host has sent.
+
+If @tramp{} sees a `login failed' message, it tells you so, aborts the
+login attempt and allows you to try again.
+
+@item
+Suppose that the login was successful and @tramp{} sees the shell prompt
+from the remote host.  Now @tramp{} invokes @command{/bin/sh} because
+Bourne shells and C shells have different command
+syntaxes.@footnote{Invoking @command{/bin/sh} will fail if your login
+shell doesn't recognize @command{exec /bin/sh} as a valid command.
+Maybe you use the Scheme shell @command{scsh}@dots{}}
+
+After the Bourne shell has come up, @tramp{} sends a few commands to
+ensure a good working environment.  It turns off echoing, it sets the
+shell prompt, and a few other things.
+
+@item
+Now the remote shell is up and it good working order.  Remember, what
+was supposed to happen is that @tramp{} tries to find out what files exist
+on the remote host so that it can do filename completion.
+
+So, @tramp{} basically issues @command{cd} and @command{ls} commands and
+also sometimes @command{echo} with globbing.  Another command that is
+often used is @command{test} to find out whether a file is writable or a
+directory or the like.  The output of each command is parsed for the
+necessary operation.
+
+@item
+Suppose you are finished with filename completion, have entered @kbd{C-x
+C-f}, a full file name and hit @kbd{@key{RET}}.  Now comes the time to
+transfer the file contents from the remote host to the local host so
+that you can edit them.
+
+See above for an explanation of how @tramp{} transfers the file contents.
+
+For inline transfers, @tramp{} issues a command like @command{mimencode -b
+/path/to/remote/file}, waits until the output has accumulated in the
+buffer that's used for communication, then decodes that output to
+produce the file contents.
+
+For out-of-band transfers, @tramp{} issues a command like @command{rcp
+user@@host:/path/to/remote/file /tmp/tramp.4711} and then reads the local
+temporary file @file{/tmp/tramp.4711} into a buffer and deletes the
+temporary file.
+
+@item
+You now edit the buffer contents, blithely unaware of what has happened
+behind the scenes.  (Unless you have read this section, that is.)  When
+you are finished, you type @kbd{C-x C-s} to save the buffer.
+
+@item
+Again, @tramp{} transfers the file contents to the remote host either
+inline or out-of-band.  This is the reverse of what happens when reading
+the file.
+
+@end itemize
+
+I hope this has provided you with a basic overview of what happens
+behind the scenes when you open a file with @tramp{}.
+
+
+@c For the end user
+@node Obtaining @tramp{}
+@chapter Obtaining @tramp{}.
+
+@tramp{} is freely available on the Internet and the latest release may be
+downloaded from
+@uref{ftp://ls6-ftp.cs.uni-dortmund.de/pub/src/emacs/tramp.tar.gz}. This
+release includes the full documentation and code for @tramp{}, suitable
+for installation.
+
+For the especially brave, @tramp{} is available from CVS. The CVS version
+is the latest version of the code and may contain incomplete features or
+new issues. Use these versions at your own risk.
+
+Instructions for obtaining the latest development version of @tramp{}
+from CVS can be found by going to the Savannah project page at
+@uref{http://savannah.gnu.org/projects/tramp/} and then clicking on the
+CVS link in the navigation bar at the top.  Or follow the example
+session below:
+
+@example
+] @strong{cd ~/lisp}
+] @strong{cvs -d:pserver:anoncvs@@subversions.gnu.org:/cvsroot/tramp login}
+
+(Logging in to anoncvs@@subversions.gnu.org)
+CVS password: @strong{(just hit RET here)}
+@dots{}
+
+] @strong{cvs -z3 -d:pserver:anoncvs@@subversions.gnu.org:/cvsroot/tramp co tramp}
+@end example
+
+You should now have a directory @file{~/lisp/tramp} containing the latest
+version of @tramp{}. You can fetch the latest updates from the repository
+by issuing the command:
+
+@example
+] @strong{cd ~/lisp/tramp}
+] @strong{cvs update -d}
+@end example
+
+
+@node History
+@chapter History of @tramp{}
+
+Development was started end of November 1998.  The package was called
+`rssh.el', back then.  It only provided one method to access a file,
+using @command{ssh} to log in to a remote host and using @command{scp}
+to transfer the file contents.  After a while, the name was changed to
+`rcp.el', and now it's @tramp{}.  Along the way, many more methods for
+getting a remote shell and for transferring the file contents were
+added.  Support for VC was added.
+
+The most recent addition of a major feature was the multi-hop methods
+added in April 2000.
+
+
+@node Installation
+@chapter Installing @tramp{} into Emacs or XEmacs
+
+Installing @tramp{} into your Emacs or XEmacs is a relatively easy
+process, at least compared to rebuilding your machine from scratch. ;)
+
+Seriously though, the installation should be a fairly simple matter.
+
+The easiest way to proceed is as follows:
+
+@itemize
+@item
+Choose a directory, say @file{~/emacs/}.  Change into that directory and
+unpack the tarball.  This will give you a directory
+@file{~/emacs/tramp/} which contains subdirectories @file{lisp} for the
+Lisp code and @file{texi} for the documentation.
+
+@item
+Optionally byte-compile all files in the Lisp directory,
+@file{~/emacs/tramp/lisp/}, by issuing a command like the following from
+the top level directory @file{~/emacs/tramp/}:
+@example
+make EMACS=emacs all            # for Emacs users
+make EMACS=xemacs all           # for XEmacs users
+@end example
+
+@item
+NOTE:
+@example
+If you run into problems running the example @command{make}
+commands, don't dispare.  You can still byte compile the
+@file{*.el} files by opening emacs in @command{dired}
+(@command{C-x d}) mode, at @file{~/tramp/lisp}.  Mark the lisp
+files with @command{m}, then press @command{B} to byte compile
+your selections.
+
+Something similar can be done to create the info manual.  
+Just cd to @file{~/emacs/tramp/texi} and load the @file{tramp.texi}
+file in emacs.  Then press @command{M-x makeinfo-buffer <RET>}
+to generate @file{tramp.info}.
+@end example     
+
+@item
+Tell Emacs about the new Lisp directory and the @tramp{} package 
+with the following lines in @file{~/.emacs}:
+@lisp
+(add-to-list 'load-path "~/emacs/tramp/lisp/")
+(require 'tramp)
+@end lisp
+
+@item
+To be able to read the Info documentation, create a file
+@file{~/emacs/tramp/texi/dir} using for example the
+@command{install-info} command, and add the directory to the search 
+path for Info.
+
+@item
+NOTE:
+@example
+On systems using `gnu' @command{install-info}, the
+@command{install-info} syntax is very direct and simple.  One can 
+cd to @file{~/emacs/tramp/texi} and type:
+    @command{install-info tramp.info dir}
+and a @file{dir} file will be created with the @tramp{}
+entry.  The info reader will know how to interpret it, but must
+be told where to find it (see below).  If you want anything fancier
+you'll need to look through @command{man install-info}.
+
+Debian gnu/linux doesn't default to `gnu' @command{install-info} and
+uses its own version.  This version does not create a @file{dir} file
+for you from scratch.  You must provide a skeleton dir file it
+recognizes.  One can be found in a default install at
+@file{/usr/info/dir}.  Copy the top of this file down to the first
+occurrence of `* Menu' including that line plus one more blank line,
+to your working directory @file{texi/dir}, or use the sample provided
+in the @file{texi} directroy of this distribution.  See
+@file{texi/dir_sample}
+
+Once a @file{dir} file is in place, this command will make the entry.
+     install-info --infodir=. tramp.info
+If you want it in a specific category
+   (see @command{man install-info} for further details)
+@end example
+
+If the environment variable @env{INFOPATH} is set, add the directory
+@file{~/emacs/tramp/texi/} to it.  Else, add the directory to
+@code{Info-default-directory-list}, as follows:
+@lisp
+(add-to-list 'Info-default-directory-list "~/emacs/tramp/texi/")
+@end lisp
+XEmacs 21 users should use @code{Info-directory-list} rather than
+@code{Info-default-directory-list}.
+
+@end itemize
+
+
+For XEmacs users, the package @command{fsf-compat} must be installed.
+For details on package installation, see @ref{Packages, , ,xemacs}.
+@ifhtml
+(If the previous link doesn't work, try the XEmacs documentation at
+@uref{http://www.xemacs.org/Documentation/packageGuide.html,the XEmacs
+site}.)
+@end ifhtml
+
+@node Configuration
+@chapter Configuring @tramp{} for use
+
+@tramp{} is (normally) fully functional when it is initially
+installed. It is initially configured to use the @command{rsh} and
+@command{rcp} programs to connect to the remote host.
+
+On some hosts, there are problems with opening a connection.  These are
+related to the behavior of the remote shell.  See @xref{Remote shell
+setup}, for details on this.
+
+If you do not wish to use these commands to connect to the remote host,
+you should change the default connection and transfer method that @tramp
+uses. There are several different methods that @tramp{} can use to
+connect to remote machines and transfer files (@pxref{Connection types}).
+
+
+@menu
+* Connection types::            Types of connections made to remote machines.
+* Inline methods::              Inline methods.
+* External transfer methods::   External transfer methods.
+* Multi-hop Methods::           Connecting to a remote host using multiple hops.
+* Default Method::              Selecting a default method.
+* Customizing Methods::         Using Non-Standard Methods.
+* Remote Programs::             How @tramp{} finds and uses programs on the remote machine.
+* Remote shell setup::          Remote shell setup hints.
+* Windows setup hints::         Issues with Cygwin ssh.
+@end menu
+
+
+@node Connection types
+@section Types of connections made to remote machines.
+
+There are two basic types of transfer methods, each with its own
+advantages and limitations. Both types of connection make use of a
+remote shell access program such as @command{rsh}, @command{ssh} or
+@command{telnet} to connect to the remote machine.
+
+This connection is used to perform many of the operations that @tramp
+requires to make the remote file system transparently accessible from
+the local machine. It is only when visiting files that the methods
+differ.
+
+Loading or saving a remote file requires that the content of the file be
+transfered between the two machines. The content of the file can be
+transfered over the same connection used to log in to the remote machine
+or the file can be transfered through another connection using a remote
+copy program such as @command{rcp}, @command{scp} or @command{rsync}.
+The former are called @dfn{inline methods}, the latter are called
+@dfn{external transfer methods}.
+
+The performance of the external transfer methods is generally better
+than that of the inline methods.  This is caused by the need to encode
+and decode the data when transferring inline.
+
+The one exception to this rule are the @command{scp} based transfer
+methods.  While these methods do see better performance when actually
+transferring files, the overhead of the cryptographic negotiation at
+startup may drown out the improvement in file transfer times.
+
+External transfer methods do require that the remote copy command is not
+interactive --- that is, the command does not prompt you for a password.
+If you cannot perform remote copies without a password, you will need to
+use an inline transfer method to work with @tramp{}.
+
+A variant of the inline methods are the @dfn{multi-hop methods}.
+These methods allow you to connect a remote host using a number `hops',
+each of which connects to a different host.  This is useful if you are
+in a secured network where you need to go through a bastion host to
+connect to the outside world.
+
+
+@node Inline methods
+@section Inline methods
+
+The inline methods in @tramp{} are quite powerful and can work in
+situations where you cannot use an external transfer program to connect.
+Inline methods are the only methods that work when connecting to the
+remote machine via telnet.  (There are also strange inline methods which
+allow you to transfer files between @emph{user identities} rather than
+hosts, see below.)
+
+These methods depend on the existence of a suitable encoding and
+decoding command on remote machine. Locally, @tramp{} may be able to use
+features of Emacs to decode and encode the files or it may require
+access to external commands to perform that task.
+
+@tramp{} supports the use of @command{uuencode} to transfer files. This is
+@emph{not} recommended. The @command{uuencode} and @command{uudecode}
+commands are not well standardized and may not function correctly or at
+all on some machines, notably AIX and IRIX. These systems do not work
+with @command{uuencode} at all.  (But do see the note about AIX in the
+documentation for @var{tramp-methods}.)
+
+In summary, if possible use the @command{mimencode} methods to transfer
+the data base64 encoded. This has the advantage of using a built-in
+command in every modern Emacs, improving performance.
+
+@itemize
+@item @option{rm}  ---  @command{rsh} with @command{mimencode}
+
+Connect to the remote host with @command{rsh} and use base64 encoding to
+transfer files between the machines.
+
+This requires the @command{mimencode} command that is part of the
+@command{metamail} packages. This may not be installed on all remote
+machines.
+
+
+@item @option{sm}  ---  @command{ssh} with @command{mimencode}
+
+Connect to the remote host with @command{ssh} and use base64 encoding to
+transfer files between the machines.
+
+This is identical to the previous option except that the @command{ssh}
+package is used, making the connection more secure.
+
+There are also two variants, @option{sm1} and @option{sm2} that use the
+@command{ssh1} and @command{ssh2} commands explicitly. If you don't know
+what these are, you do not need these options.
+
+
+@item @option{tm}  ---  @command{telnet} with @command{mimencode}
+
+Connect to the remote host with @command{telnet} and use base64 encoding
+to transfer files between the machines.
+
+This requires the @command{mimencode} command that is part of the
+@command{metamail} packages.
+
+
+@item @option{ru}  ---  @command{rsh} with @command{uuencode}
+
+Connect to the remote host with @command{rsh} and use the
+@command{uuencode} and @command{uudecode} commands to transfer files
+between the machines.
+
+
+@item @option{su}  ---  @command{ssh} with @command{uuencode}
+
+Connect to the remote host with @command{ssh} and use the
+@command{uuencode} and @command{uudecode} commands to transfer files
+between the machines.
+
+As with the @command{ssh} and base64 option above, this provides the
+@option{su1} and @option{su2} methods to explicitly select an ssh
+version.
+
+Note that this method does not invoke the @command{su} program, see
+below for methods which use that.
+
+
+@item @option{tu}  ---  @command{telnet} with @command{uuencode}
+
+Connect to the remote host with @command{telnet} and use the
+@command{uuencode} and @command{uudecode} commands to transfer files
+between the machines.
+
+
+@item @option{sum} --- @command{su} with @command{mimencode}
+
+This method does not connect to a remote host at all, rather it uses the
+@command{su} program to allow you to edit files as another user.  Uses
+base64 encoding to transfer the file contents.
+
+
+@item @option{suu} --- @command{su} with @command{uuencode}
+
+Like @option{sum}, this uses the @command{su} program to allow you to
+edit files on the local host as another user.  Uses @command{uuencode}
+and @command{uudecode} to transfer the file contents.
+
+
+@item @option{sudm} --- @command{sudo} with @command{mimencode}
+
+This is similar to the @option{sum} method, but it uses @command{sudo}
+rather than @command{su} to become a different user.
+
+Note that @command{sudo} must be configured to allow you to start a
+shell as the user.  It would be nice if it was sufficient if
+@command{ls} and @command{mimencode} were allowed, but that is not easy
+to implement, so I haven't got around to it, yet.
+
+
+@item @option{sudu} --- @command{sudo} with @command{uuencode}
+
+This is similar to the @option{suu} method, but it uses @command{sudo}
+rather than @command{su} to become a different user.
+
+
+@item @option{smx} --- @command{ssh} with @command{mimencode}
+
+As you expect, this is similar to @option{sm}, only a little
+different.  Whereas @option{sm} opens a normal interactive shell on
+the remote host, this option uses @command{ssh -t -t HOST -l USER
+/bin/sh} tp open a connection.  This is useful for users where the
+normal login shell is set up to ask them a number of questions when
+logging in.  This procedure avoids these questions, and just gives
+@tramp{} a more-or-less `standard' login shell to work with.
+
+This is also useful for Windows users where @command{ssh}, when
+invoked from an Emacs buffer, tells them that it is not allocating a
+pseudo tty.  When this happens, the login shell is wont to not print
+any shell prompt, which confuses @tramp{} mightily.
+
+
+@item @option{km} --- @command{krlogin} with @command{mimencode}
+
+This method is also similar to @option{sm}.  It only uses the
+@command{krlogin -x} command to log in to the remote host.
+
+
+@item @option{plinku} --- @command{plink} with @command{uuencode}
+
+This method is mostly interesting for Windows users using the PuTTY
+implementation of SSH.  It uses @command{plink -ssh} to log in to the
+remote host.
+
+CCC: Do we have to connect to the remote host once from the command
+line to accept the SSH key?  Maybe this can be made automatic?
+
+@item @option{plinkm} --- @command{plink} with @command{mimencode}
+
+Like @option{plinku}, but uses base64 encoding instead of uu encoding.
+
+@end itemize
+
+
+
+@node External transfer methods
+@section External transfer methods
+
+The external transfer methods operate through multiple channels, using
+the remote shell connection for many actions while delegating file
+transfers to an external transfer utility.
+
+This saves the overhead of encoding and decoding that multiplexing the
+transfer through the one connection has with the inline methods.
+
+If you want to use an external transfer method you @emph{must} be able
+to execute the transfer utility to copy files to and from the remote
+machine without any interaction.
+
+This means that you will need to use @command{ssh-agent} if you use the
+@command{scp} program for transfers, or maybe your version of
+@command{scp} accepts a password on the command line.@footnote{PuTTY's
+@command{pscp} allows you to specify the password on the command line.}
+If you use @command{rsync} via @command{ssh} then the same rule must
+apply to that connection.
+
+If you cannot get @command{scp} to run without asking for a password but
+would still like to use @command{ssh} to secure your connection, have a
+look at the @command{ssh} based inline methods.
+
+
+@itemize
+@item @option{rcp}  ---  @command{rsh} and @command{rcp}
+
+This method uses the @command{rsh} and @command{rcp} commands to connect
+to the remote machine and transfer files. This is probably the fastest
+connection method available.
+
+
+@item @option{scp}  ---  @command{ssh} and @command{scp}
+
+Using @command{ssh} to connect to the remote host and @command{scp} to
+transfer files between the machines is the best method for securely
+connecting to a remote machine and accessing files.
+
+The performance of this option is also quite good. It may be slower than
+the inline methods when you often open and close small files however.
+The cost of the cryptographic handshake at the start of an @command{scp}
+session can begin to absorb the advantage that the lack of encoding and
+decoding presents.
+
+
+@item @option{rsync}  ---  @command{ssh} and @command{rsync}
+
+Using the @command{ssh} command to connect securely to the remote
+machine and the @command{rsync} command to transfer files is almost
+identical to the @option{scp} method.
+
+While @command{rsync} performs much better than @command{scp} when
+transferring files that exist on both hosts, this advantage is lost if
+the file exists only on one side of the connection.
+
+The @command{rsync} based method may be considerably faster than the
+@command{rcp} based methods when writing to the remote system. Reading
+files to the local machine is no faster than with a direct copy. 
+
+
+@item @option{scpx} --- @command{ssh} and @command{scp}
+
+As you expect, this is similar to @option{scp}, only a little
+different.  Whereas @option{scp} opens a normal interactive shell on the
+remote host, this option uses @command{ssh -t -t HOST -l USER /bin/sh} to
+open a connection.  This is useful for users where the normal login
+shell is set up to ask them a number of questions when logging in.  This
+procedure avoids these questions, and just gives @tramp{} a more-or-less
+`standard' login shell to work with. 
+
+This is also useful for Windows users where @command{ssh}, when
+invoked from an Emacs buffer, tells them that it is not allocating a
+pseudo tty.  When this happens, the login shell is wont to not print
+any shell prompt, which confuses @tramp{} mightily.
+
+
+@item @option{pscp} --- @command{plink} and @command{pscp}
+
+This method is similar to @option{scp}, but it uses the
+@command{plink} command to connect to the remote host, and it uses
+@command{pscp} for transferring the files.  These programs are part
+of PuTTY, an SSH implementation for Windows.
+
+
+@item @option{fcp} --- @command{fsh} and @command{fcp}
+
+This method is similar to @option{scp}, but it uses the @command{fsh}
+command to connect to the remote host, and it uses @command{fcp} for
+transferring the files.  @command{fsh/fcp} are a front-end for
+@command{ssh} which allow for reusing the same @command{ssh} session
+for submitting several commands.  This avoids the startup overhead of
+@command{scp} (which has to establish a secure connection whenever it
+is called).  Note, however, that you can also use one of the inline
+methods to achieve a similar effect.
+
+This method uses the command @command{fsh HOST -l USER /bin/sh -i} to
+establish the connection, it does not work to just say @command{fsh
+HOST -l USER}.
+
+@end itemize
+
+@node Multi-hop Methods
+@section Connecting to a remote host using multiple hops
+
+Sometimes, the methods described before are not sufficient.  Sometimes,
+it is not possible to connect to a remote host using a simple command.
+For example, if you are in a secured network, you might have to log in
+to a `bastion host' first before you can connect to the outside world.
+Of course, the target host may also require a bastion host.  The format
+of multi-hop filenames is slightly different than the format of normal
+@tramp{} methods.
+
+A multi-hop file name specifies a method, a number of hops, and a path
+name on the remote system.  The method specifies how the file is
+transferred through the inline connection.  The following two multi-hop
+methods are available:
+
+@itemize
+@item @option{multi} --- base64 encoding with @command{mimencode}
+
+The file is transferred through the connection in base64 encoding.  Uses
+the @command{mimencode} program for doing encoding and decoding, but
+uses an Emacs internal implementation on the local host if available.
+
+@item @option{multiu} --- use commands @command{uuencode} and @command{uudecode}
+
+The file is transferred through the connection in `uu' encoding.  Uses
+the @command{uuencode} and @command{uudecode} programs for encoding and
+decoding, but uses a Lisp implementation for decoding on the local host
+if available.
+
+@end itemize
+
+Each hop consists of a @dfn{hop method} specification, a user name and a
+host name.  The following hop methods are (currently) available:
+
+@itemize
+@item @option{telnet}
+
+Uses the well-known @command{telnet} program to connect to the host.
+Whereas user name and host name are supplied in the file name, the
+user is queried for the password.
+
+@item @option{rsh}
+
+This uses @command{rsh} to connect to the host.  You do not need to
+enter a password unless @command{rsh} explicitly asks for it.
+
+@item @option{ssh}
+
+This uses @command{ssh} to connect to the host.  You might have to enter
+a password or a pass phrase.
+
+@item @option{su}
+
+This method does not actually contact a different host, but it allows
+you to become a different user on the host you're currently on.  This
+might be useful if you want to edit files as root, but the remote host
+does not allow remote root logins.  In this case you can use
+@option{telnet}, @option{rsh} or @option{ssh} to connect to the
+remote host as a non-root user, then use an @option{su} hop to become
+root.  But @option{su} need not be the last hop in a sequence, you could
+also use it somewhere in the middle, if the need arises.
+
+Even though you @emph{must} specify both user and host with a
+@option{su} hop, the host name is ignored and only the user name is
+used.
+
+@item @option{sudo}
+
+This is similar to the @option{su} hop, except that it uses
+@command{sudo} rather than @command{su} to become a different user.
+
+@end itemize
+
+Some people might wish to use port forwarding with @code{ssh} or maybe
+they have to use a nonstandard port.  This can be accomplished by
+putting a stanza in @file{~/.ssh/config} for the account which specifies
+a different port number for a certain host name.  But it can also be
+accomplished within Tramp, by adding a multi-hop method.  For example:
+
+@lisp
+(add-to-list 'tramp-multi-connection-function-alist
+             '("sshf" tramp-multi-connect-rlogin "ssh %h -l %u -p 4400%n"))
+@end lisp
+
+Now you can use a @code{sshf} hop which connects to port 4400 instead of
+the standard port.
+
+
+@node Default Method
+@section Selecting a default method
+
+When you select an appropriate transfer method for your typical usage
+you should set the variable @var{tramp-default-method} to reflect that
+choice. This variable controls which method will be used when a method
+is not specified in the @tramp{} file path.  For example:
+
+@lisp
+(setq tramp-default-method "scp")
+@end lisp
+
+External transfer methods are normally preferable to inline transfer
+methods, giving better performance. They may not be useful if you use
+many remote machines where you cannot log in without a password.
+
+@xref{Inline methods}.
+@xref{External transfer methods}.
+@xref{Multi-hop Methods}.
+
+Another consideration with the selection of transfer methods is the
+environment you will use them in and, especially when used over the
+Internet, the security implications of your preferred method.
+
+The @command{rsh} and @command{telnet} methods send your password as
+plain text as you log in to the remote machine, as well as transferring
+the files in such a way that the content can easily be read from other
+machines.
+
+If you need to connect to remote systems that are accessible from the
+Internet, you should give serious thought to using @command{ssh} based
+methods to connect. These provide a much higher level of security,
+making it a non-trivial exercise for someone to obtain your password or
+read the content of the files you are editing.
+
+@node Customizing Methods
+@section Using Non-Standard Methods
+
+There is a variable @code{tramp-methods} which you can change if the
+predefined methods don't seem right.
+
+For the time being, I'll refer you to the Lisp documentation of that
+variable, accessible with @kbd{C-h v tramp-methods @key{RET}}.
+
+
+@node Remote Programs
+@section How @tramp{} finds and uses programs on the remote machine.
+
+@tramp{} depends on a number of programs on the remote host in order to
+function, including @command{ls}, @command{test}, @command{find} and
+@command{cat}.
+
+In addition to these required tools, there are various tools that may be
+required based on the connection method. See @ref{Inline methods} and
+@ref{External transfer methods} for details on these.
+
+Certain other tools, such as @command{perl} (or @command{perl5}) and
+@command{grep} will be used if they can be found. When they are
+available, they are used to improve the performance and accuracy of
+remote file access.
+
+When @tramp{} connects to the remote machine, it searches for the
+programs that it can use. The variable @var{tramp-remote-path} controls
+the directories searched on the remote machine.
+
+By default, this is set to a reasonable set of defaults for most
+machines. It is possible, however, that your local (or remote ;) system
+administrator has put the tools you want in some obscure local
+directory.
+
+In this case, you can still use them with @tramp{}. You simply need to
+add code to your @file{.emacs} to add the directory to the remote path.
+This will then be searched by @tramp{} when you connect and the software
+found.
+
+To add a directory to the remote search path, you could use code such
+as:
+
+@example
+(require 'tramp)                @i{; @tramp{} must be loaded before this}
+                                @i{; happens.}
+
+@i{; We have @command{perl} in "/usr/local/perl"}
+(add-to-list 'tramp-remote-path "/usr/local/perl")
+@end example
+
+@node Remote shell setup
+@comment  node-name,  next,  previous,  up
+@section Remote shell setup hints
+
+As explained in the @ref{Overview} section, @tramp{} connects to the
+remote host and talks to the shell it finds there.  Of course, when you
+log in, the shell executes its init files.  Suppose your init file
+requires you to enter the birthdate of your mother; clearly @tramp{}
+does not know this and hence fails to log you in to that host.
+
+There are different possible strategies for pursuing this problem.  One
+strategy is to enable @tramp{} to deal with all possible situations.
+This is a losing battle, since it is not possible to deal with
+@emph{all} situations.  The other strategy is to require you to set up
+the remote host such that it behaves like @tramp{} expect.  This might
+be inconvenient because you have to invest a lot of effort into shell
+setup before you can begin to use @tramp{}.
+
+The package, therefore, pursues a combined approach.  It tries to figure
+out some of the more common setups, and only requires you to avoid
+really exotic stuff.  For example, it looks through a list of
+directories to find some programs on the remote host.  And also, it
+knows that it is not obvious how to check whether a file exist, and
+therefore it tries different possibilities.  (On some hosts and shells,
+the command @code{test -e} does the trick, on some hosts the shell
+builtin doesn't work but the program @code{/usr/bin/test -e} or
+@code{/bin/test -e} works.  And on still other hosts, @code{ls -d} is
+the right way to do this.)
+
+Below you find a discussion of a few things that @tramp{} does not deal
+with, and that you therefore have to set up correctly.
+
+@itemize
+@item @code{shell-prompt-pattern}
+
+@vindex shell-prompt-pattern
+After logging in to the remote host, @tramp{} has to wait for the remote
+shell startup to finish before it can send commands to the remote
+shell.  The strategy here is to wait for the shell prompt.  In order to
+recognize the shell prompt, the variable @code{shell-prompt-pattern} has
+to be set correctly to recognize the shell prompt on the remote host.
+
+@item @code{tset} and other questions
+
+Some people invoke the @code{tset} program from their shell startup
+scripts which asks the user about the terminal type of the shell.  Maybe
+some shells ask other questions when they are started.  @tramp{} does
+not know how to answer these questions.  (A facility for enabling
+@tramp{} to answer these questions is planned for some future version,
+but don't hold your breath.)
+
+Therefore, you should take care that the shell does not ask any
+questions when invoked from @tramp{}.  You can do this by checking the
+@code{TERM} environment variable, it will be set to @code{dumb} when
+connecting.
+
+@vindex tramp-terminal-type
+The variable @code{tramp-terminal-type} can be used to change this value
+@code{dumb}.
+
+@end itemize
+
+
+@node Windows setup hints
+@section Issues with Cygwin ssh
+
+This section needs a lot of work!  Please help.
+
+If you use the Cygwin installation of ssh (you have to explicitly select
+it in the installer), then it should work out of the box to just select
+@code{smx} as the connection method.  You can find information about
+setting up Cygwin in their FAQ at @uref{http://cygwin.com/faq/}.
+
+
+@node Usage
+@chapter Using @tramp
+
+Once you have installed @tramp{} it will operate fairly transparently. You
+will be able to access files on any remote machine that you can log in
+to as though they were local.
+
+Files are specified to @tramp{} using a formalized syntax specifying the
+details of the system to connect to. This is similar to the syntax used
+by the @command{EFS} and @command{ange-ftp} packages.
+
+
+@menu
+* Filename Syntax::             @tramp{} filename conventions.
+* Multi-hop filename syntax::   Multi-hop filename conventions
+* Dired::                       Dired and filename completion.
+@end menu
+
+
+@node Filename Syntax
+@section @tramp{} filename conventions
+
+To access the file <path> on the remote machine <machine> you would
+specify the filename @file{/[<machine>]<path>}.  (The square brackets
+are part of the file name.)  This will connect to <machine> and transfer
+the file using the default method.  @xref{Default Method}.
+
+Some examples of @tramp{} filenames are:
+
+@table @file
+@item /[melancholia].emacs
+Edit the file @file{.emacs} in your home directory on the machine
+@code{melancholia}.
+
+@item /[melancholia.danann.net].emacs
+This edits the same file, using the fully qualified domain name of
+the machine.
+
+@item /[melancholia]~/.emacs
+This also edits the same file --- the @file{~} is expanded to your
+home directory on the remote machine, just like it is locally.
+
+@item /[melancholia]~daniel/.emacs
+This edits the file @file{.emacs} in the home directory of the user
+@code{daniel} on the machine @code{melancholia}. The @file{~<user>}
+construct is expanded to the home directory of that user on the remote
+machine.
+
+@item /[melancholia]/etc/squid.conf
+This edits the file @file{/etc/squid.conf} on the machine
+@code{melancholia}.
+
+@end table
+
+
+Unless you specify a different name to use, @tramp{} will use the current
+local user name as the remote user name to log in with. If you need to
+log in as a different user, you can specify the user name as part of the
+filename.
+
+To log in to the remote machine as a specific user, you use the syntax
+@file{/[<user>@@<machine>]/path/to.file}.  That means that connecting to
+@code{melancholia} as @code{daniel} and editing @file{.emacs} in your
+home directory you would specify @file{/[daniel@@melancholia].emacs}.
+
+
+It is also possible to specify other file transfer methods
+(@pxref{Default Method}) as part of the filename.  This is done by
+replacing the initial @file{/[} with @file{/[<method>/}.  (Note the
+trailing slash!)  The user, machine and file specification remain the
+same.
+
+So, to connect to the machine @code{melancholia} as @code{daniel}, using
+the @option{su} method to transfer files, and edit @file{.emacs} in my
+home directory I would specify the filename
+@file{/[su/daniel@@melancholia].emacs}.
+
+
+@node Multi-hop filename syntax
+@section Multi-hop filename conventions
+
+The syntax of multi-hop file names is necessarily slightly different
+than the syntax of other @tramp{} file names.  Here's an example multi-hop
+file name:
+
+@file{/[multi/rsh:out@@gate/telnet:kai@@real.host]/path/to.file}
+
+This is quite a mouthful.  So let's go through it step by step.  The
+file name consists of three parts, separated by slashes and square
+brackets.  The first part is @file{/[multi}, the method specification.
+The second part is @file{rsh:out@@gate/telnet:kai@@real.host} and
+specifies the hops.  (Yes, the second part may contain even more
+slashes, so that's why this file name has more than two colons in it.)
+The final part is @file{/path/to.file} and specifies the file name on
+the remote host.
+
+The first part and the final part should be clear.  @ref{Multi-hop
+Methods}, for a list of alternatives for the method specification.
+
+The second part can be subdivided again into components, so-called hops.
+In the above file name, there are two hops, @file{rsh:out@@gate} and
+@file{telnet:kai@@real.host}.
+
+Each hop can @emph{again} be subdivided into (three) components, the
+@dfn{hop method}, the @dfn{user name} and the @dfn{host name}.  The
+meaning of the second and third component should be clear, and the hop
+method says what program to use to perform that hop.
+
+The first hop, @file{rsh:out@@gate}, says to use @command{rsh} to log in
+as user @code{out} to the host @code{gate}.  Starting at that host, the
+second hop, @file{telnet:kai@@real.host}, says to use @command{telnet}
+to log in as user @code{kai} to host @code{real.host}.
+
+@xref{Multi-hop Methods}, for a list of possible hop method values.  The
+variable @var{tramp-multi-connection-function-alist} contains the list of
+possible hop methods and information on how to execute them, should you
+want to add your own.
+
+
+@node Dired
+@section Dired and filename completion
+
+@tramp{} works transparently with dired, enabling you to use this powerful
+file management tool to manage files on any machine you have access to
+over the Internet.
+
+Filename completion also works with @tramp{} for files on remote machines
+although there is no completion for user names or machine names at this
+stage.
+
+As filename completion needs to fetch the listing of files from the
+remote machine, this feature is sometimes fairly slow. As @tramp{} does not
+yet cache the results of directory listing, there is no gain in
+performance the second time you complete filenames.
+
+If you need to browse a directory tree, Dired is a better choice, at
+present, than filename completion. Dired has its own cache mechanism
+and will only fetch the directory listing once.
+
+
+@node Bug Reports
+@chapter Reporting Bugs and Problems
+
+Bugs and problems with @tramp{} are actively worked on by the development
+team. Feature requests and suggestions are also more than welcome.
+
+The @tramp{} mailing list is a great place to get information on working
+with @tramp{}, solving problems and general discussion and advice on topics
+relating to the package.
+
+The  mailing list is at @email{tramp-devel@@mail.freesoftware.fsf.org}.
+Messages sent to this address go to all the subscribers. This is
+@emph{not} the address to send subscription requests to.
+
+For help on subscribing to the list, send mail to the administrative
+address, @email{tramp-devel-request@@mail.freesoftware.fsf.org}, with the
+subject @samp{help}.
+
+To report a bug in @tramp{}, you should execute @kbd{M-x tramp-bug}. This
+will automatically generate a buffer with the details of your system and
+@tramp{} version.
+
+When submitting a bug report, please try to describe in excruciating
+detail the steps required to reproduce the problem, the setup of the
+remote machine and any special conditions that exist.
+
+If you can identify a minimal test case that reproduces the problem,
+include that with your bug report. This will make it much easier for the
+development team to analyze and correct the problem.
+
+@node Frequently Asked Questions
+@chapter Frequently Asked Questions
+
+@itemize @bullet
+@item Where can I get the latest @tramp{}?
+
+@tramp{} is available at
+@uref{ftp://ls6-ftp.cs.uni-dortmund.de/pub/src/emacs/tramp.tar.gz}.
+There is also a Savannah project page, at
+@uref{https://savannah.gnu.org/projects/tramp/}.
+
+
+@item Which systems does it work on?
+
+The package has been used successfully on Emacs 20 and Emacs 21, as well
+as XEmacs 21.  XEmacs 20 is more problematic, see the notes in
+@file{tramp.el}.  I don't think anybody has really tried it on Emacs 19.
+
+The package was intended to work on Unix, and it really expects a
+Unix-like system on the remote end, but some people seemed to have some
+success getting it to work on NT Emacs.
+
+There are some informations on Tramp on NT at the following URL; many
+thanks to Joe Stoy for providing the information:
+@uref{ftp://ftp.comlab.ox.ac.uk/tmp/Joe.Stoy/}
+
+The above mostly contains patches to old ssh versions; Tom Roche has a
+Web page with instructions:
+@uref{http://www4.ncsu.edu/~tlroche/plinkTramp.html}
+
+??? Is the XEmacs info correct?
+
+??? Can somebody provide some information for getting it to work on NT
+Emacs?  I think there was some issue with @command{ssh}?
+
+
+@item I can't stop EFS starting with XEmacs
+
+Not all the older versions of @tramp{} supported XEmacs correctly. The
+first thing to do is to make sure that you have the latest version of
+@tramp{} installed.
+
+If you do, please try and find out exactly the conditions required for
+the @code{EFS} handlers to fire. If you can, putting a breakpoint on
+@code{efs-ftp-path} and sending in the stack trace along with your bug
+report would make it easier for the developers to work out what is going
+wrong.
+
+
+@item File name completion does not work with @tramp{}
+
+When you log in to the remote machine, do you see the output of
+@command{ls} in color? If so, this may be the cause of your problems.
+
+@command{ls} outputs @acronym{ANSI} escape sequences that your terminal
+emulator interprets to set the colors. These escape sequences will
+confuse @tramp{} however.
+
+In your @file{.bashrc}, @file{.profile} or equivalent on the remote
+machine you probably have an alias configured that adds the option
+@option{--color=yes} or @option{--color=auto}.
+
+You should remove that alias and ensure that a new login @emph{does not}
+display the output of @command{ls} in color. If you still cannot use
+filename completion, report a bug to the @tramp{} developers.
+
+
+@item File name completion does not work in large directories
+
+@tramp{} uses globbing for some operations.  (Globbing means to use the
+shell to expand wildcards such as `*.c'.)  This might create long
+command lines, especially in directories with many files.  Some shell
+choke on long command lines, or don't cope well with the globbing
+itself.
+
+If you have a large directory on the remote end, you may wish to execute
+a command like @command{ls -d * ..?* > /dev/null} and see if it hangs.
+Note that you must first start the right shell, which might be
+@command{/bin/sh}, @command{ksh} or @command{bash}, depending on which
+of those supports tilde expansion.
+
+
+@item What kinds of systems does @tramp{} work on
+
+@tramp{} really expects the remote system to be a Unix-like system.  The
+local system should preferably be Unix-like, as well, but @tramp{} might
+work on NT with some tweaking.
+
+
+@item How can I get notified when @tramp{} file transfers are complete?
+
+The following snippet can be put in your @file{~/.emacs} file.  It makes
+Emacs beep after reading from or writing to the remote host.
+
+@lisp
+(defadvice tramp-handle-write-region
+  (after tramp-write-beep-advice activate)
+ " make tramp beep after writing a file."
+ (interactive)
+ (beep))
+(defadvice tramp-handle-do-copy-or-rename-file
+  (after tramp-copy-beep-advice activate)
+ " make tramp beep after copying a file."
+ (interactive)
+ (beep))
+(defadvice tramp-handle-insert-file-contents
+  (after tramp-copy-beep-advice activate)
+ " make tramp beep after copying a file."
+ (interactive)
+ (beep))
+@end lisp
+
+
+@item There's this @file{~/.sh_history} file on the remote host which
+  keeps growing and growing.  What's that?
+
+Sometimes, @tramp{} starts @code{ksh} on the remote host for tilde
+expansion.  Maybe @code{ksh} saves the history by default.  @tramp{}
+tries to turn off saving the history, but maybe you have to help.  For
+example, you could put this in your @file{.kshrc}:
+
+@example
+if [ -f $HOME/.sh_history ] ; then
+   /bin/rm $HOME/.sh_history
+fi
+if [ "$@{HISTFILE-unset@}" != "unset" ] ; then
+   unset HISTFILE
+fi
+if [ "$@{HISTSIZE-unset@}" != "unset" ] ; then
+   unset HISTSIZE
+fi
+@end example
+
+@end itemize
+
+
+@c For the developer
+@node Version Control
+@chapter The inner workings of remote version control
+
+Unlike EFS and ange-ftp, @tramp{} has full shell access to the remote
+machine. This makes it possible to provide version control for files
+accessed under @tramp{}.
+
+The actual version control binaries must be installed on the remote
+machine, accessible in the directories specified in
+@var{tramp-remote-path}.
+
+This transparent integration with the version control systems is one of
+the most valuable features provided by @tramp{}, but it is far from perfect.
+Work is ongoing to improve the transparency of the system.
+
+@menu
+* Version Controlled Files::    Determining if a file is under version control.
+* Remote Commands::             Executing the version control commands on the remote machine.
+* Changed workfiles::           Detecting if the working file has changed.
+* Checking out files::          Bringing the workfile out of the repository.
+* Miscellaneous Version Control::  Things related to Version Control that don't fit elsewhere
+@end menu
+
+
+@node Version Controlled Files
+@section Determining if a file is under version control
+
+The VC package uses the existence of on-disk revision control master
+files to determine if a given file is under revision control. These file
+tests happen on the remote machine through the standard @tramp{} mechanisms.
+
+
+@node Remote Commands
+@section Executing the version control commands on the remote machine
+
+There are no hooks provided by VC to allow intercepting of the version
+control command execution. The calls occur through the
+@code{call-process} mechanism, a function that is somewhat more
+efficient than the @code{shell-command} function but that does not
+provide hooks for remote execution of commands.
+
+To work around this, the functions @code{vc-do-command} and
+@code{vc-simple-command} have been advised to intercept requests for
+operations on files accessed via @tramp{}.
+
+In the case of a remote file, the @code{shell-command} interface is
+used, with some wrapper code, to provide the same functionality on the
+remote machine as would be seen on the local machine. 
+
+
+@node Changed workfiles
+@section Detecting if the working file has changed
+
+As there is currently no way to get access to the mtime of a file on a
+remote machine in a portable way, the @code{vc-workfile-unchanged-p}
+function is advised to call an @tramp{} specific function for remote files.
+
+The @code{tramp-vc-workfile-unchanged-p} function uses the functioning VC
+diff functionality to determine if any changes have occurred between the
+workfile and the version control master.
+
+This requires that a shell command be executed remotely, a process that
+is notably heavier-weight than the mtime comparison used for local
+files. Unfortunately, unless a portable solution to the issue is found,
+this will remain the cost of remote version control.
+
+
+@node Checking out files
+@section Bringing the workfile out of the repository
+
+VC will, by default, check for remote files and refuse to act on them
+when checking out files from the repository. To work around this
+problem, the function @code{vc-checkout} knows about @tramp{} files and
+allows version control to occur.
+
+
+@node Miscellaneous Version Control
+@section Things related to Version Control that don't fit elsewhere
+
+Minor implementation details, &c.
+
+@menu
+* Remote File Ownership::       How VC determines who owns a workfile.
+* Back-end Versions::           How VC determines what release your RCS is.
+@end menu
+
+
+@node Remote File Ownership
+@subsection How VC determines who owns a workfile
+
+Emacs provides the @code{user-full-name} function to return the login name
+of the current user as well as mapping from arbitrary user id values
+back to login names. The VC code uses this functionality to map from the
+uid of the owner of a workfile to the login name in some circumstances.
+
+This will not, for obvious reasons, work if the remote system has a
+different set of logins. As such, it is necessary to delegate to the
+remote machine the job of determining the login name associated with a
+uid.
+
+Unfortunately, with the profusion of distributed management systems such
+as @code{NIS}, @code{NIS+} and @code{NetInfo}, there is no simple,
+reliable and portable method for performing this mapping.
+
+Thankfully, the only place in the VC code that depends on the mapping of
+a uid to a login name is the @code{vc-file-owner} function. This returns
+the login of the owner of the file as a string.
+
+This function has been advised to use the output of @command{ls} on the
+remote machine to determine the login name, delegating the problem of
+mapping the uid to the login to the remote system which should know more
+about it than I do.
+
+
+@node Back-end Versions
+@subsection How VC determines what release your RCS is
+
+VC needs to know what release your revision control binaries you are
+running as not all features VC supports are available with older
+versions of @command{rcs(1)}, @command{cvs(1)} or @command{sccs(1)}.
+
+The default implementation of VC determines this value the first time it
+is needed and then stores the value globally to avoid the overhead of
+executing a process and parsing its output each time the information is
+needed.
+
+Unfortunately, life is not quite so easy when remote version control
+comes into the picture. Each remote machine may have a different version
+of the version control tools and, while this is painful, we need to
+ensure that unavailable features are not used remotely.
+
+To resolve this issue, @tramp{} currently takes the sledgehammer
+approach of making the release values of the revision control tools
+local to each @tramp{} buffer, forcing VC to determine these values
+again each time a new file is visited.
+
+This has, quite obviously, some performance implications. Thankfully,
+most of the common operations performed by VC do not actually require
+that the remote version be known. This makes the problem far less
+apparent.
+
+Eventually these values will be captured by @tramp{} on a system by
+system basis and the results cached to improve performance.
+
+
+@node Files directories and paths
+@chapter How file names, directories and paths are mangled and managed.
+
+@menu
+* Path deconstruction::         Breaking a path into its components.
+@end menu
+
+
+@node Path deconstruction
+@section Breaking a path into its components.
+
+@tramp{} filenames are somewhat different, obviously, to ordinary path
+names. As such, the lisp functions @code{file-name-directory} and
+@code{file-name-nondirectory} are overridden within the @tramp{} package.
+
+Their replacements are reasonably simplistic in their approach. They
+dissect the filename, call the original handler on the remote path and
+then rebuild the @tramp{} path with the result.
+
+This allows the platform specific hacks in the original handlers to take
+effect while preserving the @tramp{} path information.
+
+
+@node Issues
+@chapter Debatable Issues and What Was Decided
+
+@itemize @bullet
+@item The uuencode method does not always work.
+
+Due to the design of @tramp{}, the encoding and decoding programs need to
+read from stdin and write to stdout.  On some systems, @code{uudecode -o
+-} will read stdin and write the decoded file to stdout, on other
+systems @code{uudecode -p} does the same thing.  But some systems have
+uudecode implementations which cannot do this at all---it is not
+possible to call these uudecode implementations with suitable parameters
+so that they write to stdout.
+
+Of course, this could be circumvented: the @code{begin foo 644} line
+could be rewritten to put in some temporary file name, then
+@code{uudecode} could be called, then the temp file could be printed and
+deleted.
+
+But I have decided that this is too fragile to reliably work, so on some
+systems you'll have to do without the uuencode methods.
+
+@item @tramp{} does not work on XEmacs 20.
+
+This is because it requires the macro @code{with-timeout} which does not
+appear to exist in XEmacs 20.  I'm somewhat reluctant to add an
+emulation macro to @tramp{}, but if somebody who uses XEmacs 20 steps
+forward and wishes to implement and test it, please contact me or the
+mailing list.
+
+@end itemize
+
+
+@c End of tramp.texi - the TRAMP User Manual
+@bye
+
+@c TODO
+@c
+@c * Say something about the .login and .profile files of the remote
+@c   shells.
+@c * Explain how tramp.el works in principle: open a shell on a remote
+@c   host and then send commands to it.
+
+@c Local Variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c time-stamp-start: "@set UPDATED "
+@c time-stamp-format: "%:a, %:d %:b, %:y"
+@c time-stamp-end: "$"
+@c time-stamp-line-limit: 50
+@c End: