emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/lisp/net/tramp.el


From: Kai Großjohann
Subject: [Emacs-diffs] Changes to emacs/lisp/net/tramp.el
Date: Tue, 25 Jun 2002 14:15:06 -0400

Index: emacs/lisp/net/tramp.el
diff -c emacs/lisp/net/tramp.el:1.1 emacs/lisp/net/tramp.el:1.2
*** emacs/lisp/net/tramp.el:1.1 Mon Jun 17 07:47:23 2002
--- emacs/lisp/net/tramp.el     Tue Jun 25 14:15:03 2002
***************
*** 52,75 ****
  ;; the same directory.
  ;;
  ;; There's a mailing list for this, as well.  Its name is:
! ;;                address@hidden
  ;; Send a mail with `help' in the subject (!) to the administration
  ;; address for instructions on joining the list.  The administration
  ;; address is:
! ;;            address@hidden
  ;; 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 "address@hidden"
    "Email address to send bug reports to.")
--- 52,75 ----
  ;; the same directory.
  ;;
  ;; There's a mailing list for this, as well.  Its name is:
! ;;                address@hidden
  ;; Send a mail with `help' in the subject (!) to the administration
  ;; address for instructions on joining the list.  The administration
  ;; address is:
! ;;            address@hidden
  ;; You can also use the Web to subscribe, under the following URL:
! ;;            http://mail.freesoftware.fsf.org/mailman/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://savannah.gnu.org/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.1"
    "This version of tramp.")
  (defconst tramp-bug-report-address "address@hidden"
    "Email address to send bug reports to.")
***************
*** 776,782 ****
  
  (defcustom tramp-default-method "rcp"
    "*Default method to use for transferring files.
! See `tramp-methods' for possibilities."
    :group 'tramp
    :type 'string)
  
--- 776,805 ----
  
  (defcustom tramp-default-method "rcp"
    "*Default method to use for transferring files.
! See `tramp-methods' for possibilities.
! Also see `tramp-default-method-alist'."
!   :group 'tramp
!   :type 'string)
! 
! (defcustom tramp-default-method-alist nil
!   "*Default method to use for specific user/host pairs.
! This is an alist of items (HOST USER METHOD).  The first matching item
! specifies the method to use for a file name which does not specify a
! method.  HOST and USER are regular expressions or nil, which is
! interpreted as a regular expression which always matches.  If no entry
! matches, the variable `tramp-default-method' takes effect.
! 
! If the file name does not specify the user, lookup is done using the
! empty string for the user name.
! 
! See `tramp-methods' for a list of possibilities for METHOD."
!   :group 'tramp
!   :type '(repeat (list (regexp :tag "Host regexp")
!                      (regexp :tag "User regexp")
!                      (string :tag "Method"))))
! 
! (defcustom tramp-ftp-method "ftp"
!   "*When this method name is used, forward all calls to Ange-FTP."
    :group 'tramp
    :type 'string)
  
***************
*** 840,845 ****
--- 863,880 ----
    :group 'tramp
    :type 'boolean)
  
+ (defcustom tramp-sh-extra-args '(("/bash\\'" . "--norc"))
+   "*Alist specifying extra arguments to pass to the remote shell.
+ Entries are (REGEXP . ARGS) where REGEXP is a regular expression
+ matching the shell file name and ARGS is a string specifying the
+ arguments.
+ 
+ This variable is only used when Tramp needs to start up another shell
+ for tilde expansion.  The extra arguments should typically prevent the
+ shell from reading its init file."
+   :group 'tramp
+   :type '(alist :key-type string :value-type string))
+ 
  ;; File name format.
  
  (defcustom tramp-file-name-structure
***************
*** 1313,1318 ****
--- 1348,1384 ----
     ((fboundp 'point-at-eol)    (funcall 'point-at-eol))
     (t (save-excursion (end-of-line) (point)))))
  
+ (defmacro with-parsed-tramp-file-name (filename var &rest body)
+   "Parse a Tramp filename and make components available in the body.
+ 
+ First arg FILENAME is evaluated and dissected into its components.
+ Second arg VAR is a symbol.  It is used as a variable name to hold
+ the filename structure.  It is also used as a prefix for the variables
+ holding the components.  For example, if VAR is the symbol `foo', then
+ `foo' will be bound to the whole structure, `foo-multi-method' will
+ be bound to the multi-method component, and so on for `foo-method',
+ `foo-user', `foo-host', `foo-path'.
+ 
+ Remaining args are Lisp expressions to be evaluated (inside an implicit
+ `progn').
+ 
+ If VAR is nil, then we bind `v' to the structure and `multi-method',
+ `method', `user', `host', `path' to the components."
+   `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
+         (,(if var (intern (concat (symbol-name var) "-multi-method")) 
'multi-method)
+          (tramp-file-name-multi-method ,(or var 'v)))
+         (,(if var (intern (concat (symbol-name var) "-method")) 'method)
+          (tramp-file-name-method ,(or var 'v)))
+         (,(if var (intern (concat (symbol-name var) "-user")) 'user)
+          (tramp-file-name-user ,(or var 'v)))
+         (,(if var (intern (concat (symbol-name var) "-host")) 'host)
+          (tramp-file-name-host ,(or var 'v)))
+         (,(if var (intern (concat (symbol-name var) "-path")) 'path)
+          (tramp-file-name-path ,(or var 'v))))
+      ,@body))
+ 
+ (put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
+ 
  ;;; File Name Handler Functions:
  
  ;; The following file name handler ops are not implemented (yet?).
***************
*** 1320,1423 ****
  (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,
--- 1386,1472 ----
  (defun tramp-handle-make-symbolic-link
    (filename linkname &optional ok-if-already-exists)
    "Like `make-symbolic-link' for tramp files.
! The LINKNAME argument should look like \"/path/to/target\" or
! \"relative-name\",and not like a Tramp filename."
!   (error "Not implemented yet")
!   (with-parsed-tramp-file-name linkname l
!     (when (tramp-ange-ftp-file-name-p l-multi-method l-method)
!       (tramp-invoke-ange-ftp 'make-symbolic-link
!                            filename linkname ok-if-already-exists))
!     (let ((ln (tramp-get-remote-ln l-multi l-method l-user l-host))
!         (cwd (file-name-directory l-path)))
!       (unless ln
!       (signal 'file-error
!               (list "Making a symbolic link."
!                     "ln(1) does not exist on the remote host.")))
! 
!       ;; Do the 'confirm if exists' thing.
!       (when (file-exists-p (expand-file-name filename
!                                            CCC))
!       ;; 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? "
!                           l-path)))))
!           (signal 'file-already-exists (list "File already exists" l-path))))
      
!       ;; 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
!       fn-multi fn-method fn-user fn-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"))
!   (with-parsed-tramp-file-name file nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'load
!                            file noerror nomessage nosuffix must-suffix))
!     (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
!   (with-parsed-tramp-file-name file nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-name-directory file))
      (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,
***************
*** 1434,1531 ****
  
  (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.
--- 1483,1577 ----
  
  (defun tramp-handle-file-name-nondirectory (file)
    "Like `file-name-nondirectory' but aware of TRAMP files."
!   (with-parsed-tramp-file-name file nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-name-nondirectory file))
!     (file-name-nondirectory path)))
  
  (defun tramp-handle-file-truename (filename &optional counter prev-dirs)
    "Like `file-truename' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     ;; Ange-FTP does not support truename processing.  It returns the
!     ;; file name as-is.  So that's what we do, too.
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       filename)
!     (let* ((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."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-exists-p filename))
      (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.
***************
*** 1537,1551 ****
    (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
  
  
--- 1583,1596 ----
    (if (tramp-handle-file-exists-p filename)
        ;; file exists, find out stuff
        (save-excursion
!       (with-parsed-tramp-file-name filename nil
!         (when (tramp-ange-ftp-file-name-p multi-method method)
!           (tramp-invoke-ange-ftp 'file-attributes file))
          (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
  
  
***************
*** 1653,1708 ****
           (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
--- 1698,1719 ----
           (buffer-name)))
    (when time-list
      (tramp-run-real-handler 'set-visited-file-modtime (list time-list)))
!   (let ((f (buffer-file-name))
!       (coding-system-used nil))
!     (with-parsed-tramp-file-name f nil
!       ;; This operation is not handled by Ange-FTP!
!       (when (tramp-ange-ftp-file-name-p multi-method method)
!       (throw 'tramp-forward-to-ange-ftp
!              (tramp-run-real-handler 'set-visited-file-modtime
!                                      (list time-list))))
!       (let* ((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
***************
*** 1712,1721 ****
            (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,
--- 1723,1772 ----
            (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))))
  
+ ;; CCC continue here
+ 
+ ;; 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)))
+       (with-parsed-tramp-file-name f nil
+       (when (tramp-ange-ftp-file-name-p f)
+         ;; This one requires a hack since the file name is not passed
+         ;; on the arg list.
+         (let ((buffer-file-name (tramp-make-ange-ftp-file-name
+                                  user host path)))
+           (tramp-invoke-ange-ftp 'verify-visited-file-modtime buf)))
+       (let* ((attr (file-attributes f))
+              (modtime (nth 5 attr)))
+         (cond ((and attr (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)))
+               (attr
+                (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,
***************
*** 1724,1740 ****
  
  (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.
--- 1775,1789 ----
  
  (defun tramp-handle-set-file-modes (filename mode)
    "Like `set-file-modes' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'set-file-modes filename mode))
      (save-excursion
        (unless (zerop (tramp-send-command-and-check
!                     multi-method method user host
!                     (format "chmod %s %s"
!                             (tramp-decimal-to-octal mode)
!                             (tramp-shell-quote-argument path))))
        (signal 'file-error
                (list "Doing chmod"
                      ;; FIXME: extract the proper text from chmod's stderr.
***************
*** 1745,1761 ****
  
  (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
--- 1794,1819 ----
  
  (defun tramp-handle-file-executable-p (filename)
    "Like `file-executable-p' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-executable-p filename))
!     (zerop (tramp-run-test "-x" filename))))
  
  (defun tramp-handle-file-readable-p (filename)
    "Like `file-readable-p' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-readable-p filename))
!     (zerop (tramp-run-test "-r" filename))))
  
  (defun tramp-handle-file-accessible-directory-p (filename)
    "Like `file-accessible-directory-p' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-accessible-directory-p filename))
!     (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
***************
*** 1768,1809 ****
           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."
--- 1826,1869 ----
           nil)
          ((not (file-exists-p file2))
           t)
!         ;; We are sure both files exist at this point.  We assume that
!       ;; both files are Tramp files, otherwise we issue an error
!       ;; message.  Todo: make a better error message.
          (t
           (save-excursion
!          (with-parsed-tramp-file-name file1 v1
!            (with-parsed-tramp-file-name file2 v2
!              (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
!                         (tramp-ange-ftp-file-name-p v2-multi-method 
v2-method))
!                (tramp-invoke-ange-ftp 'file-newer-than-file-p
!                                       file1 file2))
!              (unless (and (equal v1-multi-method v2-multi-method)
!                           (equal v1-method v2-method)
!                           (equal v1-user v2-user)
!                           (equal v1-host v2-host))
!                (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
!                   v1-multi-method v1-method v1-user v1-host)
!                  (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."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-modes filename))
!     (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."
***************
*** 1815,1854 ****
    ;; 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.
  
--- 1875,1929 ----
    ;; we?
    ;;
    ;; Alternatives: `cd %s', `test -d %s'
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-directory-p filename))
!     (save-excursion
        (zerop
         (tramp-send-command-and-check
!       multi-method method user host
!       (format "test -d %s"
!               (tramp-shell-quote-argument path))
!       t)))))                          ;run command in subshell
  
  (defun tramp-handle-file-regular-p (filename)
    "Like `file-regular-p' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-regular-p filename))
!     (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."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-symlink-p filename))
!     (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."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-writable-p filename))
!     (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."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-ownership-preserved-p filename))
!     (or (not (tramp-handle-file-exists-p filename))
!       ;; Existing files must be writable.
!       (zerop (tramp-run-test "-O" filename)))))
  
  ;; Other file name ops.
  
***************
*** 1863,1964 ****
  ;; Philippe Troin <address@hidden>
  (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.  address@hidden
        (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?
--- 1938,2040 ----
  ;; Philippe Troin <address@hidden>
  (defun tramp-handle-directory-file-name (directory)
    "Like `directory-file-name' for tramp files."
!   (with-parsed-tramp-file-name directory nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'directory-file-name directory))
!     (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."
!   (with-parsed-tramp-file-name directory nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'directory-files
!                            directory full match nosort))
!     (let (result x)
        (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."
!   (with-parsed-tramp-file-name directory nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-name-all-completions
!                            filename directory))
!     (unless (save-match-data (string-match "/" filename))
!       (let* ((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.  address@hidden
!         (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?
***************
*** 1968,2021 ****
      (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)
--- 2044,2099 ----
      (error
       "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
       directory))
!   (with-parsed-tramp-file-name directory nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-name-completion
!                            filename 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."
!   (with-parsed-tramp-file-name filename v1
!     (with-parsed-tramp-file-name newname v2
!       (let ((ln (when v1 (tramp-get-remote-ln
!                         v1-multi-method v1-method v1-user v1-host))))
!       (unless (and v1-method v2-method v1-user v2-user v1-host v2-host
!                    (equal v1-multi-method v2-multi-method)
!                    (equal v1-method v2-method)
!                    (equal v1-user v2-user)
!                    (equal v1-host v2-host))
!         (error "add-name-to-file: %s"
!                "only implemented for same method, same user, same host"))
!       (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
!                  (tramp-ange-ftp-file-name-p v2-multi-method v2-method))
!         (tramp-invoke-ange-ftp 'add-name-to-file
!                                filename newname ok-if-already-exists))
!       (when (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
!         (tramp-invoke-ange-ftp 'add-name-to-file
!                                filename newname ok-if-already-exists))
!       (when (tramp-ange-ftp-file-name-p v2-multi-method v2-method)
!         (tramp-invoke-ange-ftp 'add-name-to-file
!                                filename newname ok-if-already-exists))
!       (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
!        v1-multi-method v1-method v1-user v1-host
!        (format "%s %s %s" ln (tramp-shell-quote-argument v1-path)
!                (tramp-shell-quote-argument v2-path))
!        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)
***************
*** 2067,2150 ****
      (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)
--- 2145,2224 ----
      (when (file-exists-p newname)
        (signal 'file-already-exists
                (list newname))))
!   (with-parsed-tramp-file-name filename v1
!     (with-parsed-tramp-file-name newname v2
!       (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method)
!                (tramp-ange-ftp-file-name-p v2-multi-method v2-method))
!       (tramp-invoke-ange-ftp
!                              (if (eq op 'copy) 'copy-file 'rename-file)
!                              filename newname ok-if-already-exists keep-date))
!       (let* ((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 v1-method v2-method
!                (equal v1-multi-method v2-multi-method)
!                (equal v1-method v2-method)
!                (equal v1-host v2-host)
!                (equal v1-user v2-user))
!           ;; 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
!            v1-multi-method v1-method v1-user v1-host v1-path v2-path
!            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
!                          v1-user v1-host
!                          (tramp-shell-quote-argument v1-path))))
!                   (f2 (if (not v2)
!                           newname
!                         (tramp-make-rcp-program-file-name
!                          v2-user v2-host
!                          (tramp-shell-quote-argument v2-path))))
!                   (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)
***************
*** 2174,2214 ****
  ;; 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.
  
--- 2248,2288 ----
  ;; mkdir
  (defun tramp-handle-make-directory (dir &optional parents)
    "Like `make-directory' for tramp files."
!   (with-parsed-tramp-file-name dir nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'make-directory dir parents))
      (tramp-barf-unless-okay
!      multi-method method user host
       (format " %s %s"
!            (if parents "mkdir -p" "mkdir")
!            (tramp-shell-quote-argument path))
       nil 'file-error
       "Couldn't make directory %s" dir)))
  
  ;; CCC error checking?
  (defun tramp-handle-delete-directory (directory)
    "Like `delete-directory' for tramp files."
!   (with-parsed-tramp-file-name directory nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'delete-directory directory))
      (save-excursion
        (tramp-send-command
!        multi-method method user host
         (format "rmdir %s ; echo ok"
!              (tramp-shell-quote-argument path)))
        (tramp-wait-for-output))))
  
  (defun tramp-handle-delete-file (filename)
    "Like `delete-file' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (with-tramp-calling-ange-ftp
!       nil 'delete-file (list filename)
!       (save-excursion
!       (unless (zerop (tramp-send-command-and-check
!                       multi-method method user host
!                       (format "rm -f %s"
!                               (tramp-shell-quote-argument path))))
!         (signal 'file-error "Couldn't delete Tramp file"))))))
  
  ;; Dired.
  
***************
*** 2217,2228 ****
  (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)
--- 2291,2300 ----
  (defun tramp-handle-dired-recursive-delete-directory (filename)
    "Recursively delete the directory given.
  This is like `dired-recursive-delete-directory' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'dired-recursive-delete-directory
!                            filename))
      ;; run a shell command 'rm -r <path>'
      ;; Code shamelessly stolen for the dired implementation and, um, hacked :)
      (or (tramp-handle-file-exists-p filename)
***************
*** 2231,2237 ****
         (list "Removing old file name" "no such directory" filename)))
      ;; Which is better, -r or -R? (-r works for me <address@hidden>)
      (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)
--- 2303,2309 ----
         (list "Removing old file name" "no such directory" filename)))
      ;; Which is better, -r or -R? (-r works for me <address@hidden>)
      (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)
***************
*** 2242,2255 ****
  
  (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
--- 2314,2325 ----
  
  (defun tramp-handle-dired-call-process (program discard &rest arguments)
    "Like `dired-call-process' for tramp files."
!   (with-parsed-tramp-file-name default-directory nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (let ((default-directory
!             (tramp-make-ange-ftp-file-name user host path)))
!       (tramp-invoke-ange-ftp 'dired-call-process
!                              program discard arguments)))
      (save-excursion
        (tramp-barf-unless-okay
         multi-method method user host
***************
*** 2285,2297 ****
  (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"
--- 2355,2364 ----
  (defun tramp-handle-insert-directory
    (filename switches &optional wildcard full-directory-p)
    "Like `insert-directory' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'insert-directory
!                            filename switches wildcard full-directory-p))
      (tramp-message-for-buffer
       multi-method method user host 10
       "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
***************
*** 2310,2342 ****
        ;; 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
--- 2377,2409 ----
        ;; 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
***************
*** 2351,2360 ****
      ;; 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
--- 2418,2427 ----
      ;; 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
***************
*** 2364,2370 ****
  ;; 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.
  
--- 2431,2441 ----
  ;; CCC is this the right thing to do?
  (defun tramp-handle-unhandled-file-name-directory (filename)
    "Like `unhandled-file-name-directory' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'unhandled-file-name-directory
!                            filename))
!     (expand-file-name "~/")))
  
  ;; Canonicalization of file names.
  
***************
*** 2396,2407 ****
        (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
--- 2467,2475 ----
        (tramp-run-real-handler 'expand-file-name
                                (list name nil))
      ;; Dissect NAME.
!     (with-parsed-tramp-file-name name nil
!       (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'expand-file-name name nil))
        (unless (file-name-absolute-p path)
        (setq path (concat "~/" path)))
        (save-excursion
***************
*** 2441,2499 ****
  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.
  
--- 2509,2567 ----
  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)
!       (with-parsed-tramp-file-name default-directory nil
!       (when (tramp-ange-ftp-file-name-p multi-method method)
!         (let ((default-directory (tramp-make-ange-ftp-file-name
!                                   user host path)))
!           (tramp-invoke-ange-ftp 'shell-command
!                                  command output-buffer error-buffer)))
!       (let (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
!            (concat "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.
  
***************
*** 2504,2607 ****
  
  (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
--- 2572,2677 ----
  
  (defun tramp-handle-file-local-copy (filename)
    "Like `file-local-copy' for tramp files."
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'file-local-copy filename))
!     (let ((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
***************
*** 2609,2620 ****
    "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
--- 2679,2688 ----
    "Like `insert-file-contents' for tramp files."
    (barf-if-buffer-read-only)
    (setq filename (expand-file-name filename))
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'insert-file-contents
!                            filename visit beg end replace))
      (if (not (tramp-handle-file-exists-p filename))
        (progn
          (when visit
***************
*** 2654,2842 ****
    (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
--- 2722,2915 ----
    (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")))
!   (with-parsed-tramp-file-name filename nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'write-region
!                            start end filename append visit lockname confirm))
!     (let ((curbuf (current-buffer))
!         (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
***************
*** 2871,2878 ****
  
  (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)
--- 2944,2951 ----
  
  (defun tramp-run-real-handler (operation args)
    "Invoke normal file name handler for OPERATION.
! First arg specifies the OPERATION, second arg is a list of arguments to
! pass to the OPERATION."
    (let ((inhibit-file-name-handlers
           (list 'tramp-file-name-handler
                 (and (eq inhibit-file-name-operation operation)
***************
*** 2880,2896 ****
          (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
--- 2953,2967 ----
          (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)))
      (if fn
!       (catch 'tramp-forward-to-ange-ftp
!         (save-match-data (apply (cdr fn) args)))
        (tramp-run-real-handler operation args))))
  
  ;; Register in file name handler alist
***************
*** 2906,2911 ****
--- 2977,2997 ----
      (setq file-name-handler-alist
          (cons jka (delete jka file-name-handler-alist)))))
  
+ (defun tramp-invoke-ange-ftp (operation &rest args)
+   "Invoke the Ange-FTP handler function and throw."
+   (let ((ange-ftp-name-format
+        (list (nth 0 tramp-file-name-structure)
+              (nth 3 tramp-file-name-structure)
+              (nth 2 tramp-file-name-structure)
+              (nth 4 tramp-file-name-structure))))
+     (throw 'tramp-forward-to-ange-ftp
+          (apply 'ange-ftp-hook-function operation args))))
+ 
+ (defun tramp-ange-ftp-file-name-p (multi-method method)
+   "Check if it's a filename that should be forwarded to Ange-FTP."
+   (and (null multi-method) (string= method tramp-ftp-method)))
+ 
+ 
  ;;; Interactions with other packages:
  
  ;; -- complete.el --
***************
*** 2913,2964 ****
  ;; 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
--- 2999,3050 ----
  ;; This function contributed by Ed Sabol
  (defun tramp-handle-expand-many-files (name)
    "Like `PC-expand-many-files' for tramp files."
!   (with-parsed-tramp-file-name name nil
!     (when (tramp-ange-ftp-file-name-p multi-method method)
!       (tramp-invoke-ange-ftp 'expand-many-files name))
!     (save-match-data
!       (if (or (string-match "\\*" name)
!             (string-match "\\?" name)
!             (string-match "\\[.*\\]" name))
!         (save-excursion
!           ;; Dissect NAME.
!           (let (bufstr)
!             ;; Perhaps invoke Ange-FTP.
!             (when (string= method tramp-ftp-method)
!               (signal 'tramp-run-ange-ftp (list 0)))
!             ;; 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
***************
*** 3202,3221 ****
       ((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))
--- 3288,3311 ----
       ((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"))
!       ;; Find arguments for this shell.
!       (let ((alist tramp-sh-extra-args)
!           item extra-args)
!       (while (and alist (null extra-args))
!         (setq item (pop alist))
!         (when (string-match (car item) shell)
!           (setq extra-args (cdr item))))
!       (when extra-args (setq shell (concat shell " " extra-args))))
        (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))
***************
*** 3236,3242 ****
                   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'.
--- 3326,3332 ----
                   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'.
***************
*** 4486,4506 ****
      (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)
--- 4576,4612 ----
      (save-match-data
        (unless (string-match (nth 0 tramp-file-name-structure) name)
          (error "Not a tramp file name: %s" name))
!       (setq method (match-string (nth 1 tramp-file-name-structure) name))
!       (if (and method (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.  First, find out default method.
!       (let ((user (match-string (nth 2 tramp-file-name-structure) name))
!             (host (match-string (nth 3 tramp-file-name-structure) name))
!             (path (match-string (nth 4 tramp-file-name-structure) name)))
!         (when (not method)
!           (setq method (tramp-find-default-method user host)))
!         (make-tramp-file-name
!          :multi-method nil
!          :method method
!          :user (or user nil)
!          :host host
!          :path path))))))
! 
! (defun tramp-find-default-method (user host)
!   "Look up the right method to use in `tramp-default-method-alist'."
!   (let ((choices tramp-default-method-alist)
!       (method tramp-default-method)
!       item)
!     (while choices
!       (setq item (pop choices))
!       (when (and (string-match (nth 0 item) host)
!                (string-match (nth 1 item) (or user "")))
!       (setq method (nth 2 item))
!       (setq choices nil)))
!     method))
!     
  ;; 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)
***************
*** 4581,4594 ****
          (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 "address@hidden:%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
--- 4687,4704 ----
          (incf i)))
      (concat prefix hops path)))
  
  (defun tramp-make-rcp-program-file-name (user host path)
    "Create a file name suitable to be passed to `rcp'."
    (if user
        (format "address@hidden:%s" user host path)
      (format "%s:%s" host path)))
  
+ (defun tramp-make-ange-ftp-file-name (user host path)
+   "Given user, host, and path, return an Ange-FTP filename."
+   (if user
+       (format "/address@hidden:%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
***************
*** 5047,5052 ****
--- 5157,5163 ----
  
  ;;; TODO:
  
+ ;; * Revise the comments near the beginning of the file.
  ;; * Cooperate with PCL-CVS.  It uses start-process, which doesn't
  ;;   work for remote files.
  ;; * Allow /[method/address@hidden:port] syntax for the ssh "-p" argument.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]