]> code.delx.au - gnu-emacs/blob - lisp/net/tramp.el
Version 2.0.25 released.
[gnu-emacs] / lisp / net / tramp.el
1 ;;; tramp.el --- Transparent Remote Access, Multiple Protocol -*- coding: iso-8859-1; -*-
2
3 ;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
4
5 ;; Author: Kai.Grossjohann@CS.Uni-Dortmund.DE
6 ;; Keywords: comm, processes
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;; This package provides remote file editing, similar to ange-ftp.
28 ;; The difference is that ange-ftp uses FTP to transfer files between
29 ;; the local and the remote host, whereas tramp.el uses a combination
30 ;; of rsh and rcp or other work-alike programs, such as ssh/scp.
31 ;;
32 ;; For more detailed instructions, please see the info file, which is
33 ;; included in the file `tramp.tar.gz' mentioned below.
34 ;;
35 ;; Notes:
36 ;; -----
37 ;;
38 ;; This package only works for Emacs 20 and higher, and for XEmacs 21
39 ;; and higher. (XEmacs 20 is missing the `with-timeout' macro. Emacs
40 ;; 19 is reported to have other problems. For XEmacs 21, you need the
41 ;; package `fsf-compat' for the `with-timeout' macro.)
42 ;;
43 ;; This version might not work with pre-Emacs 21 VC unless VC is
44 ;; loaded before tramp.el. Could you please test this and tell me about
45 ;; the result? Thanks.
46 ;;
47 ;; Also see the todo list at the bottom of this file.
48 ;;
49 ;; The current version of tramp.el can be retrieved from the following
50 ;; URL: ftp://ls6-ftp.cs.uni-dortmund.de/pub/src/emacs/tramp.tar.gz
51 ;; For your convenience, the *.el file is available separately from
52 ;; the same directory.
53 ;;
54 ;; There's a mailing list for this, as well. Its name is:
55 ;; tramp-devel@mail.freesoftware.fsf.org
56 ;; Send a mail with `help' in the subject (!) to the administration
57 ;; address for instructions on joining the list. The administration
58 ;; address is:
59 ;; tramp-devel-request@mail.freesoftware.fsf.org
60 ;; You can also use the Web to subscribe, under the following URL:
61 ;; http://mail.freesoftware.fsf.org/mailman/listinfo/tramp-devel
62 ;;
63 ;; For the adventurous, the current development sources are available
64 ;; via CVS. You can find instructions about this at the following URL:
65 ;; http://savannah.gnu.org/projects/tramp/
66 ;; Click on "CVS" in the navigation bar near the top.
67 ;;
68 ;; Don't forget to put on your asbestos longjohns, first!
69
70 ;;; Code:
71
72 ;; In the Tramp CVS repository, the version numer is auto-frobbed from
73 ;; the Makefile, so you should edit the top-level Makefile to change
74 ;; the version number.
75 (defconst tramp-version "2.0.25"
76 "This version of tramp.")
77
78 (defconst tramp-bug-report-address "tramp-devel@mail.freesoftware.fsf.org"
79 "Email address to send bug reports to.")
80
81 (require 'timer)
82 (require 'format-spec) ;from Gnus 5.8, also in tar ball
83 ;; The explicit check is not necessary in Emacs, which provides the
84 ;; feature even if implemented in C, but it appears to be necessary
85 ;; in XEmacs.
86 (unless (and (fboundp 'base64-encode-region)
87 (fboundp 'base64-decode-region))
88 (require 'base64)) ;for the mimencode methods
89 (require 'shell)
90 (require 'advice)
91
92 (autoload 'tramp-uuencode-region "tramp-uu"
93 "Implementation of `uuencode' in Lisp.")
94
95 (unless (fboundp 'uudecode-decode-region)
96 (autoload 'uudecode-decode-region "uudecode"))
97
98 ;; ;; It does not work to load EFS after loading TRAMP.
99 ;; (when (fboundp 'efs-file-handler-function)
100 ;; (require 'efs))
101
102 (eval-when-compile
103 (require 'cl)
104 (require 'custom)
105 ;; Emacs 19.34 compatibility hack -- is this needed?
106 (or (>= emacs-major-version 20)
107 (load "cl-seq")))
108
109 (unless (boundp 'custom-print-functions)
110 (defvar custom-print-functions nil)) ; not autoloaded before Emacs 20.4
111
112 ;; XEmacs is distributed with few Lisp packages. Further packages are
113 ;; installed using EFS. If we use a unified filename format, then
114 ;; Tramp is required in addition to EFS. (But why can't Tramp just
115 ;; disable EFS when Tramp is loaded? Then XEmacs can ship with EFS
116 ;; just like before.) Another reason for using a separate filename
117 ;; syntax on XEmacs is that EFS hooks into XEmacs in many places, but
118 ;; Tramp only knows how to deal with `file-name-handler-alist', not
119 ;; the other places.
120 ;;;###autoload
121 (defvar tramp-unified-filenames (not (featurep 'xemacs))
122 "Non-nil means to use unified Ange-FTP/Tramp filename syntax.
123 Nil means to use a separate filename syntax for Tramp.")
124
125 ;;; User Customizable Internal Variables:
126
127 (defgroup tramp nil
128 "Edit remote files with a combination of rsh and rcp or similar programs."
129 :group 'files)
130
131 (defcustom tramp-verbose 9
132 "*Verbosity level for tramp.el. 0 means be silent, 10 is most verbose."
133 :group 'tramp
134 :type 'integer)
135
136 (defcustom tramp-debug-buffer nil
137 "*Whether to send all commands and responses to a debug buffer."
138 :group 'tramp
139 :type 'boolean)
140
141 (defcustom tramp-auto-save-directory nil
142 "*Put auto-save files in this directory, if set.
143 The idea is to use a local directory so that auto-saving is faster."
144 :group 'tramp
145 :type '(choice (const nil)
146 string))
147
148 (defcustom tramp-encoding-shell
149 (if (memq system-type '(windows-nt))
150 (getenv "COMSPEC")
151 "/bin/sh")
152 "*Use this program for encoding and decoding commands on the local host.
153 This shell is used to execute the encoding and decoding command on the
154 local host, so if you want to use `~' in those commands, you should
155 choose a shell here which groks tilde expansion. `/bin/sh' normally
156 does not understand tilde expansion.
157
158 For encoding and deocding, commands like the following are executed:
159
160 /bin/sh -c COMMAND < INPUT > OUTPUT
161
162 This variable can be used to change the \"/bin/sh\" part. See the
163 variable `tramp-encoding-command-switch' for the \"-c\" part. Also, see the
164 variable `tramp-encoding-reads-stdin' to specify whether the commands read
165 standard input or a file.
166
167 Note that this variable is not used for remote commands. There are
168 mechanisms in tramp.el which automatically determine the right shell to
169 use for the remote host."
170 :group 'tramp
171 :type '(file :must-match t))
172
173 (defcustom tramp-encoding-command-switch
174 (if (string-match "cmd\\.exe" tramp-encoding-shell)
175 "/c"
176 "-c")
177 "*Use this switch together with `tramp-encoding-shell' for local commands.
178 See the variable `tramp-encoding-shell' for more information."
179 :group 'tramp
180 :type 'string)
181
182 (defcustom tramp-encoding-reads-stdin t
183 "*If non-nil, encoding commands read from standard input.
184 If nil, the filename is the last argument.
185
186 Note that the commands always must write to standard output."
187 :group 'tramp
188 :type 'boolean)
189
190 (defcustom tramp-multi-sh-program
191 tramp-encoding-shell
192 "*Use this program for bootstrapping multi-hop connections.
193 This variable is similar to `tramp-encoding-shell', but it is only used
194 when initializing a multi-hop connection. Therefore, the set of
195 commands sent to this shell is quite restricted, and if you are
196 careful it works to use CMD.EXE under Windows (instead of a Bourne-ish
197 shell which does not normally exist on Windows anyway).
198
199 To use multi-hop methods from Windows, you also need suitable entries
200 in `tramp-multi-connection-function-alist' for the first hop.
201
202 This variable defaults to the value of `tramp-encoding-shell'."
203 :group 'tramp
204 :type '(file :must-match t))
205
206 ;; CCC I have changed all occurrences of comint-quote-filename with
207 ;; tramp-shell-quote-argument, except in tramp-handle-expand-many-files.
208 ;; There, comint-quote-filename was removed altogether. If it turns
209 ;; out to be necessary there, something will need to be done.
210 ;;-(defcustom tramp-file-name-quote-list
211 ;;- '(?] ?[ ?\| ?& ?< ?> ?\( ?\) ?\; ?\ ?\* ?\? ?\! ?\" ?\' ?\` ?# ?\@ ?\+ )
212 ;;- "*Protect these characters from the remote shell.
213 ;;-Any character in this list is quoted (preceded with a backslash)
214 ;;-because it means something special to the shell. This takes effect
215 ;;-when sending file and directory names to the remote shell.
216 ;;-
217 ;;-See `comint-file-name-quote-list' for details."
218 ;;- :group 'tramp
219 ;;- :type '(repeat character))
220
221 (defcustom tramp-methods
222 '( ("rcp" (tramp-connection-function tramp-open-connection-rsh)
223 (tramp-rsh-program "rsh")
224 (tramp-rcp-program "rcp")
225 (tramp-remote-sh "/bin/sh")
226 (tramp-rsh-args nil)
227 (tramp-rcp-args nil)
228 (tramp-rcp-keep-date-arg "-p")
229 (tramp-su-program nil)
230 (tramp-su-args nil)
231 (tramp-telnet-program nil)
232 (tramp-telnet-args nil))
233 ("scp" (tramp-connection-function tramp-open-connection-rsh)
234 (tramp-rsh-program "ssh")
235 (tramp-rcp-program "scp")
236 (tramp-remote-sh "/bin/sh")
237 (tramp-rsh-args ("-e" "none"))
238 (tramp-rcp-args nil)
239 (tramp-rcp-keep-date-arg "-p")
240 (tramp-su-program nil)
241 (tramp-su-args nil)
242 (tramp-telnet-program nil)
243 (tramp-telnet-args nil))
244 ("scp1" (tramp-connection-function tramp-open-connection-rsh)
245 (tramp-rsh-program "ssh")
246 (tramp-rcp-program "scp")
247 (tramp-remote-sh "/bin/sh")
248 (tramp-rsh-args ("-1" "-e" "none"))
249 (tramp-rcp-args ("-1"))
250 (tramp-rcp-keep-date-arg "-p")
251 (tramp-su-program nil)
252 (tramp-su-args nil)
253 (tramp-telnet-program nil)
254 (tramp-telnet-args nil))
255 ("scp2" (tramp-connection-function tramp-open-connection-rsh)
256 (tramp-rsh-program "ssh")
257 (tramp-rcp-program "scp")
258 (tramp-remote-sh "/bin/sh")
259 (tramp-rsh-args ("-2" "-e" "none"))
260 (tramp-rcp-args ("-2"))
261 (tramp-rcp-keep-date-arg "-p")
262 (tramp-su-program nil)
263 (tramp-su-args nil)
264 (tramp-telnet-program nil)
265 (tramp-telnet-args nil))
266 ("scp1_old"
267 (tramp-connection-function tramp-open-connection-rsh)
268 (tramp-rsh-program "ssh1")
269 (tramp-rcp-program "scp1")
270 (tramp-remote-sh "/bin/sh")
271 (tramp-rsh-args ("-e" "none"))
272 (tramp-rcp-args nil)
273 (tramp-rcp-keep-date-arg "-p")
274 (tramp-su-program nil)
275 (tramp-su-args nil)
276 (tramp-telnet-program nil)
277 (tramp-telnet-args nil))
278 ("scp2_old"
279 (tramp-connection-function tramp-open-connection-rsh)
280 (tramp-rsh-program "ssh2")
281 (tramp-rcp-program "scp2")
282 (tramp-remote-sh "/bin/sh")
283 (tramp-rsh-args ("-e" "none"))
284 (tramp-rcp-args nil)
285 (tramp-rcp-keep-date-arg "-p")
286 (tramp-su-program nil)
287 (tramp-su-args nil)
288 (tramp-telnet-program nil)
289 (tramp-telnet-args nil))
290 ("rsync" (tramp-connection-function tramp-open-connection-rsh)
291 (tramp-rsh-program "ssh")
292 (tramp-rcp-program "rsync")
293 (tramp-remote-sh "/bin/sh")
294 (tramp-rsh-args ("-e" "none"))
295 (tramp-rcp-args ("-e" "ssh"))
296 (tramp-rcp-keep-date-arg "-t")
297 (tramp-su-program nil)
298 (tramp-su-args nil)
299 (tramp-telnet-program nil)
300 (tramp-telnet-args nil))
301 ("rsh" (tramp-connection-function tramp-open-connection-rsh)
302 (tramp-rsh-program "rsh")
303 (tramp-rcp-program nil)
304 (tramp-remote-sh "/bin/sh")
305 (tramp-rsh-args nil)
306 (tramp-rcp-args nil)
307 (tramp-rcp-keep-date-arg nil)
308 (tramp-su-program nil)
309 (tramp-su-args nil)
310 (tramp-telnet-program nil)
311 (tramp-telnet-args nil))
312 ("ssh" (tramp-connection-function tramp-open-connection-rsh)
313 (tramp-rsh-program "ssh")
314 (tramp-rcp-program nil)
315 (tramp-remote-sh "/bin/sh")
316 (tramp-rsh-args ("-e" "none"))
317 (tramp-rcp-args nil)
318 (tramp-rcp-keep-date-arg nil)
319 (tramp-su-program nil)
320 (tramp-su-args nil)
321 (tramp-telnet-program nil)
322 (tramp-telnet-args nil))
323 ("ssh1" (tramp-connection-function tramp-open-connection-rsh)
324 (tramp-rsh-program "ssh")
325 (tramp-rcp-program nil)
326 (tramp-remote-sh "/bin/sh")
327 (tramp-rsh-args ("-1" "-e" "none"))
328 (tramp-rcp-args ("-1"))
329 (tramp-rcp-keep-date-arg nil)
330 (tramp-su-program nil)
331 (tramp-su-args nil)
332 (tramp-telnet-program nil)
333 (tramp-telnet-args nil))
334 ("ssh2" (tramp-connection-function tramp-open-connection-rsh)
335 (tramp-rsh-program "ssh")
336 (tramp-rcp-program nil)
337 (tramp-remote-sh "/bin/sh")
338 (tramp-rsh-args ("-2" "-e" "none"))
339 (tramp-rcp-args ("-2"))
340 (tramp-rcp-keep-date-arg nil)
341 (tramp-su-program nil)
342 (tramp-su-args nil)
343 (tramp-telnet-program nil)
344 (tramp-telnet-args nil))
345 ("ssh1_old"
346 (tramp-connection-function tramp-open-connection-rsh)
347 (tramp-rsh-program "ssh1")
348 (tramp-rcp-program nil)
349 (tramp-remote-sh "/bin/sh")
350 (tramp-rsh-args ("-e" "none"))
351 (tramp-rcp-args nil)
352 (tramp-rcp-keep-date-arg nil)
353 (tramp-su-program nil)
354 (tramp-su-args nil)
355 (tramp-telnet-program nil)
356 (tramp-telnet-args nil))
357 ("ssh2_old"
358 (tramp-connection-function tramp-open-connection-rsh)
359 (tramp-rsh-program "ssh2")
360 (tramp-rcp-program nil)
361 (tramp-remote-sh "/bin/sh")
362 (tramp-rsh-args ("-e" "none"))
363 (tramp-rcp-args nil)
364 (tramp-rcp-keep-date-arg nil)
365 (tramp-su-program nil)
366 (tramp-su-args nil)
367 (tramp-telnet-program nil)
368 (tramp-telnet-args nil))
369 ("telnet"
370 (tramp-connection-function tramp-open-connection-telnet)
371 (tramp-rsh-program nil)
372 (tramp-rcp-program nil)
373 (tramp-remote-sh "/bin/sh")
374 (tramp-rsh-args nil)
375 (tramp-rcp-args nil)
376 (tramp-rcp-keep-date-arg nil)
377 (tramp-su-program nil)
378 (tramp-su-args nil)
379 (tramp-telnet-program "telnet")
380 (tramp-telnet-args nil))
381 ("su" (tramp-connection-function tramp-open-connection-su)
382 (tramp-rsh-program nil)
383 (tramp-rcp-program nil)
384 (tramp-remote-sh "/bin/sh")
385 (tramp-rsh-args nil)
386 (tramp-rcp-args nil)
387 (tramp-rcp-keep-date-arg nil)
388 (tramp-su-program "su")
389 (tramp-su-args ("-" "%u"))
390 (tramp-telnet-program nil)
391 (tramp-telnet-args nil))
392 ("sudo" (tramp-connection-function tramp-open-connection-su)
393 (tramp-rsh-program nil)
394 (tramp-rcp-program nil)
395 (tramp-remote-sh "/bin/sh")
396 (tramp-rsh-args nil)
397 (tramp-rcp-args nil)
398 (tramp-rcp-keep-date-arg nil)
399 (tramp-su-program "sudo")
400 (tramp-su-args ("-u" "%u" "-s"))
401 (tramp-telnet-program nil)
402 (tramp-telnet-args nil))
403 ("multi" (tramp-connection-function tramp-open-connection-multi)
404 (tramp-rsh-program nil)
405 (tramp-rcp-program nil)
406 (tramp-remote-sh "/bin/sh")
407 (tramp-rsh-args nil)
408 (tramp-rcp-args nil)
409 (tramp-rcp-keep-date-arg nil)
410 (tramp-su-program nil)
411 (tramp-su-args nil)
412 (tramp-telnet-program nil)
413 (tramp-telnet-args nil))
414 ("scpx" (tramp-connection-function tramp-open-connection-rsh)
415 (tramp-rsh-program "ssh")
416 (tramp-rcp-program "scp")
417 (tramp-remote-sh "/bin/sh")
418 (tramp-rsh-args ("-e" "none" "-t" "-t" "/bin/sh"))
419 (tramp-rcp-args nil)
420 (tramp-rcp-keep-date-arg "-p")
421 (tramp-telnet-program nil)
422 (tramp-telnet-args nil))
423 ("sshx" (tramp-connection-function tramp-open-connection-rsh)
424 (tramp-rsh-program "ssh")
425 (tramp-rcp-program nil)
426 (tramp-remote-sh "/bin/sh")
427 (tramp-rsh-args ("-e" "none" "-t" "-t" "/bin/sh"))
428 (tramp-rcp-args nil)
429 (tramp-rcp-keep-date-arg nil)
430 (tramp-su-program nil)
431 (tramp-su-args nil)
432 (tramp-telnet-program nil)
433 (tramp-telnet-args nil))
434 ("krlogin"
435 (tramp-connection-function tramp-open-connection-rsh)
436 (tramp-rsh-program "krlogin")
437 (tramp-rcp-program nil)
438 (tramp-remote-sh "/bin/sh")
439 (tramp-rsh-args ("-x"))
440 (tramp-rcp-args nil)
441 (tramp-rcp-keep-date-arg nil)
442 (tramp-su-program nil)
443 (tramp-su-args nil)
444 (tramp-telnet-program nil)
445 (tramp-telnet-args nil))
446 ("plink"
447 (tramp-connection-function tramp-open-connection-rsh)
448 (tramp-rsh-program "plink")
449 (tramp-rcp-program nil)
450 (tramp-remote-sh "/bin/sh")
451 (tramp-rsh-args ("-ssh")) ;optionally add "-v"
452 (tramp-rcp-args nil)
453 (tramp-rcp-keep-date-arg nil)
454 (tramp-su-program nil)
455 (tramp-su-args nil)
456 (tramp-telnet-program nil)
457 (tramp-telnet-args nil))
458 ("pscp"
459 (tramp-connection-function tramp-open-connection-rsh)
460 (tramp-rsh-program "plink")
461 (tramp-rcp-program "pscp")
462 (tramp-remote-sh "/bin/sh")
463 (tramp-rsh-args ("-ssh"))
464 (tramp-rcp-args nil)
465 (tramp-rcp-keep-date-arg "-p")
466 (tramp-su-program nil)
467 (tramp-su-args nil)
468 (tramp-telnet-program nil)
469 (tramp-telnet-args nil))
470 ("fcp"
471 (tramp-connection-function tramp-open-connection-rsh)
472 (tramp-rsh-program "fsh")
473 (tramp-rcp-program "fcp")
474 (tramp-remote-sh "/bin/sh -i")
475 (tramp-rsh-args ("sh" "-i"))
476 (tramp-rcp-args nil)
477 (tramp-rcp-keep-date-arg "-p")
478 (tramp-su-program nil)
479 (tramp-su-args nil)
480 (tramp-telnet-program nil)
481 (tramp-telnet-args nil))
482 )
483 "*Alist of methods for remote files.
484 This is a list of entries of the form (NAME PARAM1 PARAM2 ...).
485 Each NAME stands for a remote access method. Each PARAM is a
486 pair of the form (KEY VALUE). The following KEYs are defined:
487 * `tramp-connection-function'
488 This specifies the function to use to connect to the remote host.
489 Currently, `tramp-open-connection-rsh', `tramp-open-connection-telnet'
490 and `tramp-open-connection-su' are defined. See the documentation
491 of these functions for more details.
492 * `tramp-remote-sh'
493 This specifies the Bourne shell to use on the remote host. This
494 MUST be a Bourne-like shell. It is normally not necessary to set
495 this to any value other than \"/bin/sh\": tramp wants to use a shell
496 which groks tilde expansion, but it can search for it. Also note
497 that \"/bin/sh\" exists on all Unixen, this might not be true for
498 the value that you decide to use. You Have Been Warned.
499 * `tramp-rsh-program'
500 This specifies the name of the program to use for rsh; this might be
501 the full path to rsh or the name of a workalike program.
502 * `tramp-rsh-args'
503 This specifies the list of arguments to pass to the above
504 mentioned program. Please note that this is a list of arguments,
505 that is, normally you don't want to put \"-a -b\" or \"-f foo\"
506 here. Instead, you want two list elements, one for \"-a\" and one
507 for \"-b\", or one for \"-f\" and one for \"foo\".
508 * `tramp-rcp-program'
509 This specifies the name of the program to use for rcp; this might be
510 the full path to rcp or the name of a workalike program.
511 * `tramp-rcp-args'
512 This specifies the list of parameters to pass to the above mentioned
513 program, the hints for `tramp-rsh-args' also apply here.
514 * `tramp-rcp-keep-date-arg'
515 This specifies the parameter to use for `rcp' when the timestamp
516 of the original file should be kept. For `rcp', use `-p', for
517 `rsync', use `-t'.
518 * `tramp-su-program'
519 This specifies the name of the program to use for `su'.
520 * `tramp-su-args'
521 This specifies the list of arguments to pass to `su'.
522 \"%u\" is replaced by the user name, use \"%%\" for a literal
523 percent character.
524 * `tramp-telnet-program'
525 Specifies the telnet program to use when using
526 `tramp-open-connection-telnet' to log in.
527 * `tramp-telnet-args'
528 Specifies list of arguments to pass to `telnet'. The hints for
529 `tramp-rsh-args' also apply here.
530
531 What does all this mean? Well, you should specify `tramp-rsh-program',
532 `tramp-telnet-program' or `tramp-su-program' for all methods; this program
533 is used to log in to the remote site. Then, there are two ways to
534 actually transfer the files between the local and the remote side.
535 One way is using an additional rcp-like program. If you want to do
536 this, set `tramp-rcp-program' in the method.
537
538 Another possibility for file transfer is inline transfer, i.e. the
539 file is passed through the same buffer used by `tramp-rsh-program'. In
540 this case, the file contents need to be protected since the
541 `tramp-rsh-program' might use escape codes or the connection might not
542 be eight-bit clean. Therefore, file contents are encoded for transit.
543 See the variable `tramp-coding-commands' for details.
544
545 So, to summarize: if the method is an out-of-band method, then you
546 must specify `tramp-rcp-program' and `tramp-rcp-args'. If it is an
547 inline method, then these two parameters should be nil. Every method,
548 inline or out of band, must specify `tramp-connection-function' plus
549 the associated arguments (for example, the telnet program if you chose
550 `tramp-open-connection-telnet').
551
552 Notes:
553
554 When using `tramp-open-connection-su' the phrase `open connection to a
555 remote host' sounds strange, but it is used nevertheless, for
556 consistency. No connection is opened to a remote host, but `su' is
557 started on the local host. You are not allowed to specify a remote
558 host other than `localhost' or the name of the local host."
559 :group 'tramp
560 :type '(repeat
561 (cons string
562 (set (list (const tramp-connection-function) function)
563 (list (const tramp-rsh-program)
564 (choice (const nil) string))
565 (list (const tramp-rcp-program)
566 (choice (const nil) string))
567 (list (const tramp-remote-sh)
568 (choice (const nil) string))
569 (list (const tramp-rsh-args) (repeat string))
570 (list (const tramp-rcp-args) (repeat string))
571 (list (const tramp-rcp-keep-date-arg)
572 (choice (const nil) string))
573 (list (const tramp-su-program)
574 (choice (const nil) string))
575 (list (const tramp-su-args) (repeat string))
576 (list (const tramp-encoding-command)
577 (choice (const nil) string))
578 (list (const tramp-decoding-command)
579 (choice (const nil) string))
580 (list (const tramp-encoding-function)
581 (choice (const nil) function))
582 (list (const tramp-decoding-function)
583 (choice (const nil) function))
584 (list (const tramp-telnet-program)
585 (choice (const nil) string))
586 (list (const tramp-telnet-args) (repeat string))))))
587
588 (defcustom tramp-multi-methods '("multi" "multiu")
589 "*List of multi-hop methods.
590 Each entry in this list should be a method name as mentioned in the
591 variable `tramp-methods'."
592 :group 'tramp
593 :type '(repeat string))
594
595 (defcustom tramp-multi-connection-function-alist
596 '(("telnet" tramp-multi-connect-telnet "telnet %h%n")
597 ("rsh" tramp-multi-connect-rlogin "rsh %h -l %u%n")
598 ("ssh" tramp-multi-connect-rlogin "ssh %h -l %u%n")
599 ("su" tramp-multi-connect-su "su - %u%n")
600 ("sudo" tramp-multi-connect-su "sudo -u %u -s%n"))
601 "*List of connection functions for multi-hop methods.
602 Each list item is a list of three items (METHOD FUNCTION COMMAND),
603 where METHOD is the name as used in the file name, FUNCTION is the
604 function to be executed, and COMMAND is the shell command used for
605 connecting.
606
607 COMMAND may contain percent escapes. `%u' will be replaced with the
608 user name, `%h' will be replaced with the host name, and `%n' will be
609 replaced with an end-of-line character, as specified in the variable
610 `tramp-rsh-end-of-line'. Use `%%' for a literal percent character.
611 Note that the interpretation of the percent escapes also depends on
612 the FUNCTION. For example, the `%u' escape is forbidden with the
613 function `tramp-multi-connect-telnet'. See the documentation of the
614 various functions for details."
615 :group 'tramp
616 :type '(repeat (list string function string)))
617
618 (defcustom tramp-default-method "ssh"
619 "*Default method to use for transferring files.
620 See `tramp-methods' for possibilities.
621 Also see `tramp-default-method-alist'.
622
623 Emacs uses a unified filename syntax for Tramp and Ange-FTP.
624 For backward compatibility, the default value of this variable
625 is \"ftp\" on Emacs. But XEmacs uses a separate filename syntax
626 for Tramp and EFS, so there the default method is \"sm\"."
627 :group 'tramp
628 :type 'string)
629
630 (defcustom tramp-default-method-alist
631 (when tramp-unified-filenames
632 '(("\\`ftp\\." "" "ftp")
633 ("" "\\`\\(anonymous\\|ftp\\)\\'" "ftp")
634 ("\\`localhost\\'" "\\`root\\'" "su")))
635 "*Default method to use for specific user/host pairs.
636 This is an alist of items (HOST USER METHOD). The first matching item
637 specifies the method to use for a file name which does not specify a
638 method. HOST and USER are regular expressions or nil, which is
639 interpreted as a regular expression which always matches. If no entry
640 matches, the variable `tramp-default-method' takes effect.
641
642 If the file name does not specify the user, lookup is done using the
643 empty string for the user name.
644
645 See `tramp-methods' for a list of possibilities for METHOD."
646 :group 'tramp
647 :type '(repeat (list (regexp :tag "Host regexp")
648 (regexp :tag "User regexp")
649 (string :tag "Method"))))
650
651 (defcustom tramp-ftp-method "ftp"
652 "*When this method name is used, forward all calls to Ange-FTP."
653 :group 'tramp
654 :type 'string)
655
656 ;; Default values for non-Unices seeked
657 (defconst tramp-completion-function-alist-rsh
658 (unless (memq system-type '(windows-nt))
659 '((tramp-parse-rhosts "/etc/hosts.equiv")
660 (tramp-parse-rhosts "~/.rhosts")))
661 "Default list of (FUNCTION FILE) pairs to be examined for rsh methods."
662 )
663
664 ;; Default values for non-Unices seeked
665 (defconst tramp-completion-function-alist-ssh
666 (unless (memq system-type '(windows-nt))
667 '((tramp-parse-rhosts "/etc/hosts.equiv")
668 (tramp-parse-rhosts "/etc/shosts.equiv")
669 (tramp-parse-shosts "/etc/ssh_known_hosts")
670 (tramp-parse-rhosts "~/.rhosts")
671 (tramp-parse-rhosts "~/.shosts")
672 (tramp-parse-shosts "~/.ssh/known_hosts")))
673 "Default list of (FUNCTION FILE) pairs to be examined for ssh methods."
674 )
675
676 ;; Default values for non-Unices seeked
677 (defconst tramp-completion-function-alist-telnet
678 (unless (memq system-type '(windows-nt))
679 '((tramp-parse-hosts "/etc/hosts")))
680 "Default list of (FUNCTION FILE) pairs to be examined for telnet methods."
681 )
682
683 ;; Default values for non-Unices seeked
684 (defconst tramp-completion-function-alist-su
685 (unless (memq system-type '(windows-nt))
686 '((tramp-parse-passwd "/etc/passwd")))
687 "Default list of (FUNCTION FILE) pairs to be examined for su methods."
688 )
689
690 ;; Default values for non-Unices seeked
691 (defconst tramp-completion-function-alist-ftp
692 (unless (memq system-type '(windows-nt))
693 '((tramp-parse-netrc "~/.netrc")))
694 "Default list of (FUNCTION FILE) pairs to be examined for ftp methods."
695 )
696
697 (defcustom tramp-completion-function-alist
698 (list (cons "rcp" tramp-completion-function-alist-rsh)
699 (cons "scp" tramp-completion-function-alist-ssh)
700 (cons "scp1" tramp-completion-function-alist-ssh)
701 (cons "scp2" tramp-completion-function-alist-ssh)
702 (cons "scp1_old" tramp-completion-function-alist-ssh)
703 (cons "scp2_old" tramp-completion-function-alist-ssh)
704 (cons "rsync" tramp-completion-function-alist-rsh)
705 (cons "rsh" tramp-completion-function-alist-rsh)
706 (cons "ssh" tramp-completion-function-alist-ssh)
707 (cons "ssh1" tramp-completion-function-alist-ssh)
708 (cons "ssh2" tramp-completion-function-alist-ssh)
709 (cons "ssh1_old" tramp-completion-function-alist-ssh)
710 (cons "ssh2_old" tramp-completion-function-alist-ssh)
711 (cons "telnet" tramp-completion-function-alist-telnet)
712 (cons "su" tramp-completion-function-alist-su)
713 (cons "sudo" tramp-completion-function-alist-su)
714 (cons "multi" nil)
715 (cons "scpx" tramp-completion-function-alist-ssh)
716 (cons "sshx" tramp-completion-function-alist-ssh)
717 (cons "krlogin" tramp-completion-function-alist-rsh)
718 (cons "plink" tramp-completion-function-alist-ssh)
719 (cons "pscp" tramp-completion-function-alist-ssh)
720 (cons "fcp" tramp-completion-function-alist-ssh)
721 (cons "ftp" tramp-completion-function-alist-ftp)
722 )
723 "*Alist of methods for remote files.
724 This is a list of entries of the form (NAME PAIR1 PAIR2 ...).
725 Each NAME stands for a remote access method. Each PAIR is of the form
726 \(FUNCTION FILE). FUNCTION is responsible to extract user names and host
727 names from FILE for completion. The following predefined FUNCTIONs exists:
728
729 * `tramp-parse-rhosts' for \".rhosts\" like files,
730 * `tramp-parse-shosts' for \"ssh_known_hosts\" like files,
731 * `tramp-parse-hosts' for \"/etc/hosts\" like files, and
732 * `tramp-parse-passwd' for \"/etc/passwd\" like files.
733 * `tramp-parse-netrc ' for \".netrc\" like files.
734
735 FUNCTION can also see a customer defined function. For more details see
736 the info pages."
737 :group 'tramp
738 :type '(repeat
739 (cons string
740 (choice (const nil) (repeat (list function file))))))
741
742 (defcustom tramp-rsh-end-of-line "\n"
743 "*String used for end of line in rsh connections.
744 I don't think this ever needs to be changed, so please tell me about it
745 if you need to change this.
746 Also see `tramp-password-end-of-line'."
747 :group 'tramp
748 :type 'string)
749
750 (defcustom tramp-password-end-of-line tramp-rsh-end-of-line
751 "*String used for end of line after sending a password.
752 It seems that people using plink under Windows need to send
753 \"\\r\\n\" (carriage-return, then newline) after a password, but just
754 \"\\n\" after all other lines. This variable can be used for the
755 password, see `tramp-rsh-end-of-line' for the other cases.
756
757 The default value is to use the same value as `tramp-rsh-end-of-line'."
758 :group 'tramp
759 :type 'string)
760
761 (defcustom tramp-remote-path
762 '("/bin" "/usr/bin" "/usr/sbin" "/usr/local/bin" "/usr/ccs/bin"
763 "/local/bin" "/local/freeware/bin" "/local/gnu/bin"
764 "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin")
765 "*List of directories to search for executables on remote host.
766 Please notify me about other semi-standard directories to include here.
767
768 You can use `~' in this list, but when searching for a shell which groks
769 tilde expansion, all directory names starting with `~' will be ignored."
770 :group 'tramp
771 :type '(repeat string))
772
773 (defcustom tramp-login-prompt-regexp
774 ".*ogin: *"
775 "*Regexp matching login-like prompts.
776 The regexp should match at end of buffer."
777 :group 'tramp
778 :type 'regexp)
779
780 (defcustom tramp-shell-prompt-pattern
781 "^[^#$%>\n]*[#$%>] *"
782 "Regexp to match prompts from remote shell.
783 Normally, Tramp expects you to configure `shell-prompt-pattern'
784 correctly, but sometimes it happens that you are connecting to a
785 remote host which sends a different kind of shell prompt. Therefore,
786 Tramp recognizes things matched by `shell-prompt-pattern' as prompt,
787 and also things matched by this variable. The default value of this
788 variable is the same as the default value of `shell-prompt-pattern',
789 which should work well in many cases."
790 :group 'tramp
791 :type 'regexp)
792
793 (defcustom tramp-password-prompt-regexp
794 "^.*\\([pP]assword\\|passphrase.*\\):\^@? *"
795 "*Regexp matching password-like prompts.
796 The regexp should match at end of buffer.
797
798 The `sudo' program appears to insert a `^@' character into the prompt."
799 :group 'tramp
800 :type 'regexp)
801
802 (defcustom tramp-wrong-passwd-regexp
803 (concat "^.*"
804 ;; These strings should be on the last line
805 (regexp-opt '("Permission denied."
806 "Login incorrect"
807 "Login Incorrect"
808 "Connection refused"
809 "Connection closed"
810 "Sorry, try again."
811 "Name or service not known"
812 "Host key verification failed.") t)
813 ".*"
814 "\\|"
815 "^.*\\("
816 ;; Here comes a list of regexes, separated by \\|
817 "Received signal [0-9]+"
818 "\\).*")
819 "*Regexp matching a `login failed' message.
820 The regexp should match at end of buffer."
821 :group 'tramp
822 :type 'regexp)
823
824 (defcustom tramp-yesno-prompt-regexp
825 (concat
826 (regexp-opt '("Are you sure you want to continue connecting (yes/no)?") t)
827 "\\s-*")
828 "Regular expression matching all yes/no queries which need to be confirmed.
829 The confirmation should be done with yes or no.
830 The regexp should match at end of buffer.
831 See also `tramp-yn-prompt-regexp'."
832 :group 'tramp
833 :type 'regexp)
834
835 (defcustom tramp-yn-prompt-regexp
836 (concat (regexp-opt '("Store key in cache? (y/n)") t)
837 "\\s-*")
838 "Regular expression matching all y/n queries which need to be confirmed.
839 The confirmation should be done with y or n.
840 The regexp should match at end of buffer.
841 See also `tramp-yesno-prompt-regexp'."
842 :group 'tramp
843 :type 'regexp)
844
845 (defcustom tramp-terminal-prompt-regexp
846 (concat "\\("
847 "TERM = (.*)"
848 "\\|"
849 "Terminal type\\? \\[.*\\]"
850 "\\)\\s-*")
851 "Regular expression matching all terminal setting prompts.
852 The regexp should match at end of buffer.
853 The answer will be provided by `tramp-action-terminal', which see."
854 :group 'tramp
855 :type 'regexp)
856
857 (defcustom tramp-temp-name-prefix "tramp."
858 "*Prefix to use for temporary files.
859 If this is a relative file name (such as \"tramp.\"), it is considered
860 relative to the directory name returned by the function
861 `tramp-temporary-file-directory' (which see). It may also be an
862 absolute file name; don't forget to include a prefix for the filename
863 part, though."
864 :group 'tramp
865 :type 'string)
866
867 (defcustom tramp-discard-garbage nil
868 "*If non-nil, try to discard garbage sent by remote shell.
869 Some shells send such garbage upon connection setup."
870 :group 'tramp
871 :type 'boolean)
872
873 (defcustom tramp-sh-extra-args '(("/bash\\'" . "--norc"))
874 "*Alist specifying extra arguments to pass to the remote shell.
875 Entries are (REGEXP . ARGS) where REGEXP is a regular expression
876 matching the shell file name and ARGS is a string specifying the
877 arguments.
878
879 This variable is only used when Tramp needs to start up another shell
880 for tilde expansion. The extra arguments should typically prevent the
881 shell from reading its init file."
882 :group 'tramp
883 :type '(alist :key-type string :value-type string))
884
885 (defcustom tramp-prefix-format
886 (if tramp-unified-filenames "/" "/[")
887 "*String matching the very beginning of tramp file names.
888 Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'."
889 :group 'tramp
890 :type 'string)
891
892 (defcustom tramp-prefix-regexp
893 (concat "^" (regexp-quote tramp-prefix-format))
894 "*Regexp matching the very beginning of tramp file names.
895 Should always start with \"^\". Derived from `tramp-prefix-format'."
896 :group 'tramp
897 :type 'regexp)
898
899 (defcustom tramp-method-regexp
900 "[a-zA-Z_0-9-]+"
901 "*Regexp matching methods identifiers."
902 :group 'tramp
903 :type 'regexp)
904
905 ;; It is a little bit annoying that in XEmacs case this delimeter is different
906 ;; for single-hop and multi-hop cases.
907 (defcustom tramp-postfix-single-method-format
908 (if tramp-unified-filenames ":" "/")
909 "*String matching delimeter between method and user or host names.
910 Applicable for single-hop methods.
911 Used in `tramp-make-tramp-file-name'."
912 :group 'tramp
913 :type 'string)
914
915 (defcustom tramp-postfix-single-method-regexp
916 (regexp-quote tramp-postfix-single-method-format)
917 "*Regexp matching delimeter between method and user or host names.
918 Applicable for single-hop methods.
919 Derived from `tramp-postfix-single-method-format'."
920 :group 'tramp
921 :type 'regexp)
922
923 (defcustom tramp-postfix-multi-method-format
924 ":"
925 "*String matching delimeter between method and user or host names.
926 Applicable for multi-hop methods.
927 Used in `tramp-make-tramp-multi-file-name'."
928 :group 'tramp
929 :type 'string)
930
931 (defcustom tramp-postfix-multi-method-regexp
932 (regexp-quote tramp-postfix-multi-method-format)
933 "*Regexp matching delimeter between method and user or host names.
934 Applicable for multi-hop methods.
935 Derived from `tramp-postfix-multi-method-format'."
936 :group 'tramp
937 :type 'regexp)
938
939 (defcustom tramp-postfix-multi-hop-format
940 (if tramp-unified-filenames ":" "/")
941 "*String matching delimeter between path and next method.
942 Applicable for multi-hop methods.
943 Used in `tramp-make-tramp-multi-file-name'."
944 :group 'tramp
945 :type 'string)
946
947 (defcustom tramp-postfix-multi-hop-regexp
948 (regexp-quote tramp-postfix-multi-hop-format)
949 "*Regexp matching delimeter between path and next method.
950 Applicable for multi-hop methods.
951 Derived from `tramp-postfix-multi-hop-format'."
952 :group 'tramp
953 :type 'regexp)
954
955 (defcustom tramp-user-regexp
956 "[^:@/ \t]*"
957 "*Regexp matching user names."
958 :group 'tramp
959 :type 'regexp)
960
961 (defcustom tramp-postfix-user-format
962 "@"
963 "*String matching delimeter between user and host names.
964 Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'."
965 :group 'tramp
966 :type 'string)
967
968 (defcustom tramp-postfix-user-regexp
969 (regexp-quote tramp-postfix-user-format)
970 "*Regexp matching delimeter between user and host names.
971 Derived from `tramp-postfix-user-format'."
972 :group 'tramp
973 :type 'regexp)
974
975 (defcustom tramp-host-regexp
976 "[a-zA-Z0-9_.-]*"
977 "*Regexp matching host names."
978 :group 'tramp
979 :type 'regexp)
980
981 (defcustom tramp-host-with-port-regexp
982 "[a-zA-Z0-9_.#-]*"
983 "*Regexp matching host names."
984 :group 'tramp
985 :type 'regexp)
986
987 (defcustom tramp-postfix-host-format
988 (if tramp-unified-filenames ":" "]")
989 "*String matching delimeter between host names and paths.
990 Used in `tramp-make-tramp-file-name' and `tramp-make-tramp-multi-file-name'."
991 :group 'tramp
992 :type 'string)
993
994 (defcustom tramp-postfix-host-regexp
995 (regexp-quote tramp-postfix-host-format)
996 "*Regexp matching delimeter between host names and paths.
997 Derived from `tramp-postfix-host-format'."
998 :group 'tramp
999 :type 'regexp)
1000
1001 (defcustom tramp-path-regexp
1002 ".*$"
1003 "*Regexp matching paths."
1004 :group 'tramp
1005 :type 'regexp)
1006
1007 ;; File name format.
1008
1009 (defcustom tramp-file-name-structure
1010 (list
1011 (concat
1012 tramp-prefix-regexp
1013 "\\(" "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp "\\)?"
1014 "\\(" "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp "\\)?"
1015 "\\(" tramp-host-with-port-regexp "\\)" tramp-postfix-host-regexp
1016 "\\(" tramp-path-regexp "\\)")
1017 2 4 5 6)
1018
1019 "*List of five elements (REGEXP METHOD USER HOST FILE), detailing \
1020 the tramp file name structure.
1021
1022 The first element REGEXP is a regular expression matching a tramp file
1023 name. The regex should contain parentheses around the method name,
1024 the user name, the host name, and the file name parts.
1025
1026 The second element METHOD is a number, saying which pair of
1027 parentheses matches the method name. The third element USER is
1028 similar, but for the user name. The fourth element HOST is similar,
1029 but for the host name. The fifth element FILE is for the file name.
1030 These numbers are passed directly to `match-string', which see. That
1031 means the opening parentheses are counted to identify the pair.
1032
1033 See also `tramp-file-name-regexp'."
1034 :group 'tramp
1035 :type '(list (regexp :tag "File name regexp")
1036 (integer :tag "Paren pair for method name")
1037 (integer :tag "Paren pair for user name ")
1038 (integer :tag "Paren pair for host name ")
1039 (integer :tag "Paren pair for file name ")))
1040
1041 ;;;###autoload
1042 (defconst tramp-file-name-regexp-unified
1043 "\\`/[^/:]+:"
1044 "Value for `tramp-file-name-regexp' for unified remoting.
1045 Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
1046 Tramp. See `tramp-file-name-structure-unified' for more explanations.")
1047
1048 ;;;###autoload
1049 (defconst tramp-file-name-regexp-separate
1050 "\\`/\\[.*\\]"
1051 "Value for `tramp-file-name-regexp' for separate remoting.
1052 XEmacs uses a separate filename syntax for Tramp and EFS.
1053 See `tramp-file-name-structure-separate' for more explanations.")
1054
1055 ;;;###autoload
1056 (defcustom tramp-file-name-regexp
1057 (if tramp-unified-filenames
1058 tramp-file-name-regexp-unified
1059 tramp-file-name-regexp-separate)
1060 "*Regular expression matching file names handled by tramp.
1061 This regexp should match tramp file names but no other file names.
1062 \(When tramp.el is loaded, this regular expression is prepended to
1063 `file-name-handler-alist', and that is searched sequentially. Thus,
1064 if the tramp entry appears rather early in the `file-name-handler-alist'
1065 and is a bit too general, then some files might be considered tramp
1066 files which are not really tramp files.
1067
1068 Please note that the entry in `file-name-handler-alist' is made when
1069 this file (tramp.el) is loaded. This means that this variable must be set
1070 before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1071 updated after changing this variable.
1072
1073 Also see `tramp-file-name-structure'."
1074 :group 'tramp
1075 :type 'regexp)
1076
1077 ;;;###autoload
1078 (defconst tramp-completion-file-name-regexp-unified
1079 "^/[^/]*$"
1080 "Value for `tramp-completion-file-name-regexp' for unified remoting.
1081 Emacs (not XEmacs) uses a unified filename syntax for Ange-FTP and
1082 Tramp. See `tramp-file-name-structure-unified' for more explanations.")
1083
1084 ;;;###autoload
1085 (defconst tramp-completion-file-name-regexp-separate
1086 "^/\\([[][^]]*\\)?$"
1087 "Value for `tramp-completion-file-name-regexp' for separate remoting.
1088 XEmacs uses a separate filename syntax for Tramp and EFS.
1089 See `tramp-file-name-structure-separate' for more explanations.")
1090
1091 ;;;###autoload
1092 (defcustom tramp-completion-file-name-regexp
1093 (if tramp-unified-filenames
1094 tramp-completion-file-name-regexp-unified
1095 tramp-completion-file-name-regexp-separate)
1096 "*Regular expression matching file names handled by tramp completion.
1097 This regexp should match partial tramp file names only.
1098
1099 Please note that the entry in `file-name-handler-alist' is made when
1100 this file (tramp.el) is loaded. This means that this variable must be set
1101 before loading tramp.el. Alternatively, `file-name-handler-alist' can be
1102 updated after changing this variable.
1103
1104 Also see `tramp-file-name-structure'."
1105 :group 'tramp
1106 :type 'regexp)
1107
1108 (defcustom tramp-multi-file-name-structure
1109 (list
1110 (concat
1111 tramp-prefix-regexp
1112 "\\(" "\\(" tramp-method-regexp "\\)" "\\)?"
1113 "\\(" "\\(" tramp-postfix-multi-hop-regexp "%s" "\\)+" "\\)?"
1114 tramp-postfix-host-regexp "\\(" tramp-path-regexp "\\)")
1115 2 3 -1)
1116 "*Describes the file name structure of `multi' files.
1117 Multi files allow you to contact a remote host in several hops.
1118 This is a list of four elements (REGEXP METHOD HOP PATH).
1119
1120 The first element, REGEXP, gives a regular expression to match against
1121 the file name. In this regular expression, `%s' is replaced with the
1122 value of `tramp-multi-file-name-hop-structure'. (Note: in order to
1123 allow multiple hops, you normally want to use something like
1124 \"\\\\(\\\\(%s\\\\)+\\\\)\" in the regular expression. The outer pair
1125 of parentheses is used for the HOP element, see below.)
1126
1127 All remaining elements are numbers. METHOD gives the number of the
1128 paren pair which matches the method name. HOP gives the number of the
1129 paren pair which matches the hop sequence. PATH gives the number of
1130 the paren pair which matches the path name on the remote host.
1131
1132 PATH can also be negative, which means to count from the end. Ie, a
1133 value of -1 means the last paren pair.
1134
1135 I think it would be good if the regexp matches the whole of the
1136 string, but I haven't actually tried what happens if it doesn't..."
1137 :group 'tramp
1138 :type '(list (regexp :tag "File name regexp")
1139 (integer :tag "Paren pair for method name")
1140 (integer :tag "Paren pair for hops")
1141 (integer :tag "Paren pair to match path")))
1142
1143 (defcustom tramp-multi-file-name-hop-structure
1144 (list
1145 (concat
1146 "\\(" tramp-method-regexp "\\)" tramp-postfix-multi-method-regexp
1147 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
1148 "\\(" tramp-host-with-port-regexp "\\)")
1149 1 2 3)
1150 "*Describes the structure of a hop in multi files.
1151 This is a list of four elements (REGEXP METHOD USER HOST). First
1152 element REGEXP is used to match against the hop. Pair number METHOD
1153 matches the method of one hop, pair number USER matches the user of
1154 one hop, pair number HOST matches the host of one hop.
1155
1156 This regular expression should match exactly all of one hop."
1157 :group 'tramp
1158 :type '(list (regexp :tag "Hop regexp")
1159 (integer :tag "Paren pair for method name")
1160 (integer :tag "Paren pair for user name")
1161 (integer :tag "Paren pair for host name")))
1162
1163 (defcustom tramp-make-multi-tramp-file-format
1164 (list
1165 (concat tramp-prefix-format "%m")
1166 (concat tramp-postfix-multi-hop-format
1167 "%m" tramp-postfix-multi-method-format
1168 "%u" tramp-postfix-user-format
1169 "%h")
1170 (concat tramp-postfix-host-format "%p"))
1171 "*Describes how to construct a `multi' file name.
1172 This is a list of three elements PREFIX, HOP and PATH.
1173
1174 The first element PREFIX says how to construct the prefix, the second
1175 element HOP specifies what each hop looks like, and the final element
1176 PATH says how to construct the path name.
1177
1178 In PREFIX, `%%' means `%' and `%m' means the method name.
1179
1180 In HOP, `%%' means `%' and `%m', `%u', `%h' mean the hop method, hop
1181 user and hop host, respectively.
1182
1183 In PATH, `%%' means `%' and `%p' means the path name.
1184
1185 The resulting file name always contains one copy of PREFIX and one
1186 copy of PATH, but there is one copy of HOP for each hop in the file
1187 name.
1188
1189 Note: the current implementation requires the prefix to contain the
1190 method name, followed by all the hops, and the path name must come
1191 last."
1192 :group 'tramp
1193 :type '(list string string string))
1194
1195 (defcustom tramp-terminal-type "dumb"
1196 "*Value of TERM environment variable for logging in to remote host.
1197 Because Tramp wants to parse the output of the remote shell, it is easily
1198 confused by ANSI color escape sequences and suchlike. Often, shell init
1199 files conditionalize this setup based on the TERM environment variable."
1200 :group 'tramp
1201 :type 'string)
1202
1203 (defcustom tramp-completion-without-shell-p nil
1204 "*If nil, use shell wildcards for completion, else rely on Lisp only.
1205 Using shell wildcards for completions has the advantage that it can be
1206 fast even in large directories, but completion is always
1207 case-sensitive. Relying on Lisp only means that case-insensitive
1208 completion is possible (subject to the variable `completion-ignore-case'),
1209 but it might be slow on large directories."
1210 :group 'tramp
1211 :type 'boolean)
1212
1213 (defcustom tramp-actions-before-shell
1214 '((tramp-password-prompt-regexp tramp-action-password)
1215 (tramp-login-prompt-regexp tramp-action-login)
1216 (shell-prompt-pattern tramp-action-succeed)
1217 (tramp-shell-prompt-pattern tramp-action-succeed)
1218 (tramp-wrong-passwd-regexp tramp-action-permission-denied)
1219 (tramp-yesno-prompt-regexp tramp-action-yesno)
1220 (tramp-yn-prompt-regexp tramp-action-yn)
1221 (tramp-terminal-prompt-regexp tramp-action-terminal))
1222 "List of pattern/action pairs.
1223 Whenever a pattern matches, the corresponding action is performed.
1224 Each item looks like (PATTERN ACTION).
1225
1226 The PATTERN should be a symbol, a variable. The value of this
1227 variable gives the regular expression to search for. Note that the
1228 regexp must match at the end of the buffer, \"\\'\" is implicitly
1229 appended to it.
1230
1231 The ACTION should also be a symbol, but a function. When the
1232 corresponding PATTERN matches, the ACTION function is called."
1233 :group 'tramp
1234 :type '(repeat (list variable function)))
1235
1236 (defcustom tramp-multi-actions
1237 '((tramp-password-prompt-regexp tramp-multi-action-password)
1238 (tramp-login-prompt-regexp tramp-multi-action-login)
1239 (shell-prompt-pattern tramp-multi-action-succeed)
1240 (tramp-shell-prompt-pattern tramp-multi-action-succeed)
1241 (tramp-wrong-passwd-regexp tramp-multi-action-permission-denied))
1242 "List of pattern/action pairs.
1243 This list is used for each hop in multi-hop connections.
1244 See `tramp-actions-before-shell' for more info."
1245 :group 'tramp
1246 :type '(repeat (list variable function)))
1247
1248 ;;; Internal Variables:
1249
1250 (defvar tramp-buffer-file-attributes nil
1251 "Holds the `ls -ild' output for the current buffer.
1252 This variable is local to each buffer. It is not used if the remote
1253 machine groks Perl. If it is used, it's used as an emulation for
1254 the visited file modtime.")
1255 (make-variable-buffer-local 'tramp-buffer-file-attributes)
1256
1257 (defvar tramp-end-of-output "/////"
1258 "String used to recognize end of output.")
1259
1260 (defvar tramp-connection-function nil
1261 "This internal variable holds a parameter for `tramp-methods'.
1262 In the connection buffer, this variable has the value of the like-named
1263 method parameter, as specified in `tramp-methods' (which see).")
1264
1265 (defvar tramp-remote-sh nil
1266 "This internal variable holds a parameter for `tramp-methods'.
1267 In the connection buffer, this variable has the value of the like-named
1268 method parameter, as specified in `tramp-methods' (which see).")
1269
1270 (defvar tramp-rsh-program nil
1271 "This internal variable holds a parameter for `tramp-methods'.
1272 In the connection buffer, this variable has the value of the like-named
1273 method parameter, as specified in `tramp-methods' (which see).")
1274
1275 (defvar tramp-rsh-args nil
1276 "This internal variable holds a parameter for `tramp-methods'.
1277 In the connection buffer, this variable has the value of the like-named
1278 method parameter, as specified in `tramp-methods' (which see).")
1279
1280 (defvar tramp-rcp-program nil
1281 "This internal variable holds a parameter for `tramp-methods'.
1282 In the connection buffer, this variable has the value of the like-named
1283 method parameter, as specified in `tramp-methods' (which see).")
1284
1285 (defvar tramp-rcp-args nil
1286 "This internal variable holds a parameter for `tramp-methods'.
1287 In the connection buffer, this variable has the value of the like-named
1288 method parameter, as specified in `tramp-methods' (which see).")
1289
1290 (defvar tramp-rcp-keep-date-arg nil
1291 "This internal variable holds a parameter for `tramp-methods'.
1292 In the connection buffer, this variable has the value of the like-named
1293 method parameter, as specified in `tramp-methods' (which see).")
1294
1295 (defvar tramp-encoding-command nil
1296 "This internal variable holds a parameter for `tramp-methods'.
1297 In the connection buffer, this variable has the value of the like-named
1298 method parameter, as specified in `tramp-methods' (which see).")
1299
1300 (defvar tramp-decoding-command nil
1301 "This internal variable holds a parameter for `tramp-methods'.
1302 In the connection buffer, this variable has the value of the like-named
1303 method parameter, as specified in `tramp-methods' (which see).")
1304
1305 (defvar tramp-encoding-function nil
1306 "This internal variable holds a parameter for `tramp-methods'.
1307 In the connection buffer, this variable has the value of the like-named
1308 method parameter, as specified in `tramp-methods' (which see).")
1309
1310 (defvar tramp-decoding-function nil
1311 "This internal variable holds a parameter for `tramp-methods'.
1312 In the connection buffer, this variable has the value of the like-named
1313 method parameter, as specified in `tramp-methods' (which see).")
1314
1315 (defvar tramp-telnet-program nil
1316 "This internal variable holds a parameter for `tramp-methods'.
1317 In the connection buffer, this variable has the value of the like-named
1318 method parameter, as specified in `tramp-methods' (which see).")
1319
1320 (defvar tramp-telnet-args nil
1321 "This internal variable holds a parameter for `tramp-methods'.
1322 In the connection buffer, this variable has the value of the like-named
1323 method parameter, as specified in `tramp-methods' (which see).")
1324
1325 (defvar tramp-su-program nil
1326 "This internal variable holds a parameter for `tramp-methods'.
1327 In the connection buffer, this variable has the value of the like-named
1328 method parameter, as specified in `tramp-methods' (which see).")
1329
1330 ;; CCC `local in each buffer'?
1331 (defvar tramp-ls-command nil
1332 "This command is used to get a long listing with numeric user and group ids.
1333 This variable is automatically made buffer-local to each rsh process buffer
1334 upon opening the connection.")
1335
1336 (defvar tramp-current-multi-method nil
1337 "Name of `multi' connection method for this *tramp* buffer, or nil if not multi.
1338 This variable is automatically made buffer-local to each rsh process buffer
1339 upon opening the connection.")
1340
1341 (defvar tramp-current-method nil
1342 "Connection method for this *tramp* buffer.
1343 This variable is automatically made buffer-local to each rsh process buffer
1344 upon opening the connection.")
1345
1346 (defvar tramp-current-user nil
1347 "Remote login name for this *tramp* buffer.
1348 This variable is automatically made buffer-local to each rsh process buffer
1349 upon opening the connection.")
1350
1351 (defvar tramp-current-host nil
1352 "Remote host for this *tramp* buffer.
1353 This variable is automatically made buffer-local to each rsh process buffer
1354 upon opening the connection.")
1355
1356 (defvar tramp-test-groks-nt nil
1357 "Whether the `test' command groks the `-nt' switch.
1358 \(`test A -nt B' tests if file A is newer than file B.)
1359 This variable is automatically made buffer-local to each rsh process buffer
1360 upon opening the connection.")
1361
1362 (defvar tramp-file-exists-command nil
1363 "Command to use for checking if a file exists.
1364 This variable is automatically made buffer-local to each rsh process buffer
1365 upon opening the connection.")
1366
1367 (defconst tramp-uudecode "\
1368 tramp_uudecode () {
1369 \(echo begin 600 /tmp/tramp.$$; tail +2) | uudecode
1370 cat /tmp/tramp.$$
1371 rm -f /tmp/tramp.$$
1372 }"
1373 "Shell function to implement `uudecode' to standard output.
1374 Many systems support `uudecode -o -' for this or `uudecode -p', but
1375 some systems don't, and for them we have this shell function.")
1376
1377 ;; Perl script to implement `file-attributes' in a Lisp `read'able
1378 ;; output. If you are hacking on this, note that you get *no* output
1379 ;; unless this spits out a complete line, including the '\n' at the
1380 ;; end.
1381 (defconst tramp-perl-file-attributes "\
1382 $f = $ARGV[0];
1383 @s = lstat($f);
1384 if (($s[2] & 0170000) == 0120000) { $l = readlink($f); $l = \"\\\"$l\\\"\"; }
1385 elsif (($s[2] & 0170000) == 040000) { $l = \"t\"; }
1386 else { $l = \"nil\" };
1387 printf(\"(%s %u %d %d (%u %u) (%u %u) (%u %u) %u %u t (%u . %u) (%u %u))\\n\",
1388 $l, $s[3], $s[4], $s[5], $s[8] >> 16 & 0xffff, $s[8] & 0xffff,
1389 $s[9] >> 16 & 0xffff, $s[9] & 0xffff, $s[10] >> 16 & 0xffff, $s[10] & 0xffff,
1390 $s[7], $s[2], $s[1] >> 16 & 0xffff, $s[1] & 0xffff, $s[0] >> 16 & 0xffff, $s[0] & 0xffff);"
1391 "Perl script to produce output suitable for use with `file-attributes'
1392 on the remote file system.")
1393
1394 ;; ;; These two use uu encoding.
1395 ;; (defvar tramp-perl-encode "%s -e'\
1396 ;; print qq(begin 644 xxx\n);
1397 ;; my $s = q();
1398 ;; my $res = q();
1399 ;; while (read(STDIN, $s, 45)) {
1400 ;; print pack(q(u), $s);
1401 ;; }
1402 ;; print qq(`\n);
1403 ;; print qq(end\n);
1404 ;; '"
1405 ;; "Perl program to use for encoding a file.
1406 ;; Escape sequence %s is replaced with name of Perl binary.")
1407
1408 ;; (defvar tramp-perl-decode "%s -ne '
1409 ;; print unpack q(u), $_;
1410 ;; '"
1411 ;; "Perl program to use for decoding a file.
1412 ;; Escape sequence %s is replaced with name of Perl binary.")
1413
1414 ;; These two use base64 encoding.
1415 (defvar tramp-perl-encode-with-module
1416 "perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)'"
1417 "Perl program to use for encoding a file.
1418 Escape sequence %s is replaced with name of Perl binary.
1419 This string is passed to `format', so percent characters need to be doubled.
1420 This implementation requires the MIME::Base64 Perl module to be installed
1421 on the remote host.")
1422
1423 (defvar tramp-perl-decode-with-module
1424 "perl -MMIME::Base64 -0777 -ne 'print decode_base64($_)'"
1425 "Perl program to use for decoding a file.
1426 Escape sequence %s is replaced with name of Perl binary.
1427 This string is passed to `format', so percent characters need to be doubled.
1428 This implementation requires the MIME::Base64 Perl module to be installed
1429 on the remote host.")
1430
1431 (defvar tramp-perl-encode
1432 "%s -e '
1433 # This script contributed by Juanma Barranquero <lektu@terra.es>.
1434 # Copyright (C) 2002 Free Software Foundation, Inc.
1435 use strict;
1436
1437 my %%trans = do {
1438 my $i = 0;
1439 map {(substr(unpack(q(B8), chr $i++), 2, 6), $_)}
1440 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/);
1441 };
1442
1443 binmode(\\*STDIN);
1444
1445 # We read in chunks of 54 bytes, to generate output lines
1446 # of 72 chars (plus end of line)
1447 $/ = \\54;
1448
1449 while (my $data = <STDIN>) {
1450 my $pad = q();
1451
1452 # Only for the last chunk, and only if did not fill the last three-byte packet
1453 if (eof) {
1454 my $mod = length($data) %% 3;
1455 $pad = q(=) x (3 - $mod) if $mod;
1456 }
1457
1458 # Not the fastest method, but it is simple: unpack to binary string, split
1459 # by groups of 6 bits and convert back from binary to byte; then map into
1460 # the translation table
1461 print
1462 join q(),
1463 map($trans{$_},
1464 (substr(unpack(q(B*), $data) . q(00000), 0, 432) =~ /....../g)),
1465 $pad,
1466 qq(\\n);
1467 }
1468 '"
1469 "Perl program to use for encoding a file.
1470 Escape sequence %s is replaced with name of Perl binary.
1471 This string is passed to `format', so percent characters need to be doubled.")
1472
1473 (defvar tramp-perl-decode
1474 "%s -e '
1475 # This script contributed by Juanma Barranquero <lektu@terra.es>.
1476 # Copyright (C) 2002 Free Software Foundation, Inc.
1477 use strict;
1478
1479 my %%trans = do {
1480 my $i = 0;
1481 map {($_, substr(unpack(q(B8), chr $i++), 2, 6))}
1482 split //, q(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
1483 };
1484
1485 my %%bytes = map {(unpack(q(B8), chr $_), chr $_)} 0 .. 255;
1486
1487 binmode(\\*STDOUT);
1488
1489 # We are going to accumulate into $pending to accept any line length
1490 # (we do not check they are <= 76 chars as the RFC says)
1491 my $pending = q();
1492
1493 while (my $data = <STDIN>) {
1494 chomp $data;
1495
1496 # If we find one or two =, we have reached the end and
1497 # any following data is to be discarded
1498 my $finished = $data =~ s/(==?).*/$1/;
1499 $pending .= $data;
1500
1501 my $len = length($pending);
1502 my $chunk = substr($pending, 0, $len & ~3);
1503
1504 # Easy method: translate from chars to (pregenerated) six-bit packets, join,
1505 # split in 8-bit chunks and convert back to char.
1506 print join q(),
1507 map $bytes{$_},
1508 ((join q(), map {$trans{$_} || q()} split //, $chunk) =~ /......../g);
1509
1510 last if $finished;
1511 }
1512 '"
1513 "Perl program to use for decoding a file.
1514 Escape sequence %s is replaced with name of Perl binary.
1515 This string is passed to `format', so percent characters need to be doubled.")
1516
1517 ; These values conform to `file-attributes' from XEmacs 21.2.
1518 ; GNU Emacs and other tools not checked.
1519 (defconst tramp-file-mode-type-map '((0 . "-") ; Normal file (SVID-v2 and XPG2)
1520 (1 . "p") ; fifo
1521 (2 . "c") ; character device
1522 (3 . "m") ; multiplexed character device (v7)
1523 (4 . "d") ; directory
1524 (5 . "?") ; Named special file (XENIX)
1525 (6 . "b") ; block device
1526 (7 . "?") ; multiplexed block device (v7)
1527 (8 . "-") ; regular file
1528 (9 . "n") ; network special file (HP-UX)
1529 (10 . "l") ; symlink
1530 (11 . "?") ; ACL shadow inode (Solaris, not userspace)
1531 (12 . "s") ; socket
1532 (13 . "D") ; door special (Solaris)
1533 (14 . "w")) ; whiteout (BSD)
1534 "A list of file types returned from the `stat' system call.
1535 This is used to map a mode number to a permission string.")
1536
1537 (defvar tramp-dos-coding-system
1538 (if (and (fboundp 'coding-system-p)
1539 (funcall 'coding-system-p '(dos)))
1540 'dos
1541 'undecided-dos)
1542 "Some Emacsen know the `dos' coding system, others need `undecided-dos'.")
1543
1544 (defvar tramp-last-cmd-time nil
1545 "Internal Tramp variable recording the time when the last cmd was sent.
1546 This variable is buffer-local in every buffer.")
1547 (make-variable-buffer-local 'tramp-last-cmd-time)
1548
1549 ;; This variable does not have the right value in XEmacs. What should
1550 ;; I use instead of find-operation-coding-system in XEmacs?
1551 (defvar tramp-feature-write-region-fix
1552 (when (fboundp 'find-operation-coding-system)
1553 (let ((file-coding-system-alist '(("test" emacs-mule))))
1554 (find-operation-coding-system 'write-region 0 0 "" nil "test")))
1555 "Internal variable to say if `write-region' chooses the right coding.
1556 Older versions of Emacs chose the coding system for `write-region' based
1557 on the FILENAME argument, even if VISIT was a string.")
1558
1559 ;; New handlers should be added here. The following operations can be
1560 ;; handled using the normal primitives: file-name-as-directory,
1561 ;; file-name-directory, file-name-nondirectory,
1562 ;; file-name-sans-versions, get-file-buffer.
1563 (defconst tramp-file-name-handler-alist
1564 '(
1565 (load . tramp-handle-load)
1566 (make-symbolic-link . tramp-handle-make-symbolic-link)
1567 (file-name-directory . tramp-handle-file-name-directory)
1568 (file-name-nondirectory . tramp-handle-file-name-nondirectory)
1569 (file-truename . tramp-handle-file-truename)
1570 (file-exists-p . tramp-handle-file-exists-p)
1571 (file-directory-p . tramp-handle-file-directory-p)
1572 (file-executable-p . tramp-handle-file-executable-p)
1573 (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
1574 (file-readable-p . tramp-handle-file-readable-p)
1575 (file-regular-p . tramp-handle-file-regular-p)
1576 (file-symlink-p . tramp-handle-file-symlink-p)
1577 (file-writable-p . tramp-handle-file-writable-p)
1578 (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p)
1579 (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
1580 (file-attributes . tramp-handle-file-attributes)
1581 (file-modes . tramp-handle-file-modes)
1582 (file-directory-files . tramp-handle-file-directory-files)
1583 (directory-files . tramp-handle-directory-files)
1584 (file-name-all-completions . tramp-handle-file-name-all-completions)
1585 (file-name-completion . tramp-handle-file-name-completion)
1586 (add-name-to-file . tramp-handle-add-name-to-file)
1587 (copy-file . tramp-handle-copy-file)
1588 (rename-file . tramp-handle-rename-file)
1589 (set-file-modes . tramp-handle-set-file-modes)
1590 (make-directory . tramp-handle-make-directory)
1591 (delete-directory . tramp-handle-delete-directory)
1592 (delete-file . tramp-handle-delete-file)
1593 (directory-file-name . tramp-handle-directory-file-name)
1594 (shell-command . tramp-handle-shell-command)
1595 (insert-directory . tramp-handle-insert-directory)
1596 (expand-file-name . tramp-handle-expand-file-name)
1597 (file-local-copy . tramp-handle-file-local-copy)
1598 (insert-file-contents . tramp-handle-insert-file-contents)
1599 (write-region . tramp-handle-write-region)
1600 (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory)
1601 (dired-call-process . tramp-handle-dired-call-process)
1602 (dired-recursive-delete-directory
1603 . tramp-handle-dired-recursive-delete-directory)
1604 (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
1605 (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime))
1606 "Alist of handler functions.
1607 Operations not mentioned here will be handled by the normal Emacs functions.")
1608
1609 ;; Handlers for partial tramp file names. For GNU Emacs just
1610 ;; `file-name-all-completions' is needed. The other ones are necessary
1611 ;; for XEmacs.
1612 (defconst tramp-completion-file-name-handler-alist
1613 '(
1614 (file-name-directory . tramp-completion-handle-file-name-directory)
1615 (file-name-nondirectory . tramp-completion-handle-file-name-nondirectory)
1616 (file-exists-p . tramp-completion-handle-file-exists-p)
1617 (file-name-all-completions . tramp-completion-handle-file-name-all-completions)
1618 (file-name-completion . tramp-completion-handle-file-name-completion)
1619 (expand-file-name . tramp-completion-handle-expand-file-name))
1620 "Alist of completion handler functions.
1621 Used for file names matching `tramp-file-name-regexp'. Operations not
1622 mentioned here will be handled by `tramp-file-name-handler-alist' or the
1623 normal Emacs functions.")
1624
1625 ;;; Internal functions which must come first.
1626
1627 (defsubst tramp-message (level fmt-string &rest args)
1628 "Emit a message depending on verbosity level.
1629 First arg LEVEL says to be quiet if `tramp-verbose' is less than LEVEL. The
1630 message is emitted only if `tramp-verbose' is greater than or equal to LEVEL.
1631 Calls function `message' with FMT-STRING as control string and the remaining
1632 ARGS to actually emit the message (if applicable).
1633
1634 This function expects to be called from the tramp buffer only!"
1635 (when (<= level tramp-verbose)
1636 (apply #'message (concat "tramp: " fmt-string) args)
1637 (when tramp-debug-buffer
1638 (save-excursion
1639 (set-buffer
1640 (tramp-get-debug-buffer
1641 tramp-current-multi-method tramp-current-method
1642 tramp-current-user tramp-current-host))
1643 (goto-char (point-max))
1644 (tramp-insert-with-face
1645 'italic
1646 (concat "# " (apply #'format fmt-string args) "\n"))))))
1647
1648 (defun tramp-message-for-buffer
1649 (multi-method method user host level fmt-string &rest args)
1650 "Like `tramp-message' but temporarily switches to the tramp buffer.
1651 First three args METHOD, USER, and HOST identify the tramp buffer to use,
1652 remaining args passed to `tramp-message'."
1653 (save-excursion
1654 (set-buffer (tramp-get-buffer multi-method method user host))
1655 (apply 'tramp-message level fmt-string args)))
1656
1657 (defsubst tramp-line-end-position nil
1658 "Return point at end of line.
1659 Calls `line-end-position' or `point-at-eol' if defined, else
1660 own implementation."
1661 (cond
1662 ((fboundp 'line-end-position) (funcall 'line-end-position))
1663 ((fboundp 'point-at-eol) (funcall 'point-at-eol))
1664 (t (save-excursion (end-of-line) (point)))))
1665
1666 (defmacro with-parsed-tramp-file-name (filename var &rest body)
1667 "Parse a Tramp filename and make components available in the body.
1668
1669 First arg FILENAME is evaluated and dissected into its components.
1670 Second arg VAR is a symbol. It is used as a variable name to hold
1671 the filename structure. It is also used as a prefix for the variables
1672 holding the components. For example, if VAR is the symbol `foo', then
1673 `foo' will be bound to the whole structure, `foo-multi-method' will
1674 be bound to the multi-method component, and so on for `foo-method',
1675 `foo-user', `foo-host', `foo-path'.
1676
1677 Remaining args are Lisp expressions to be evaluated (inside an implicit
1678 `progn').
1679
1680 If VAR is nil, then we bind `v' to the structure and `multi-method',
1681 `method', `user', `host', `path' to the components."
1682 `(let* ((,(or var 'v) (tramp-dissect-file-name ,filename))
1683 (,(if var (intern (concat (symbol-name var) "-multi-method")) 'multi-method)
1684 (tramp-file-name-multi-method ,(or var 'v)))
1685 (,(if var (intern (concat (symbol-name var) "-method")) 'method)
1686 (tramp-file-name-method ,(or var 'v)))
1687 (,(if var (intern (concat (symbol-name var) "-user")) 'user)
1688 (tramp-file-name-user ,(or var 'v)))
1689 (,(if var (intern (concat (symbol-name var) "-host")) 'host)
1690 (tramp-file-name-host ,(or var 'v)))
1691 (,(if var (intern (concat (symbol-name var) "-path")) 'path)
1692 (tramp-file-name-path ,(or var 'v))))
1693 ,@body))
1694
1695 (put 'with-parsed-tramp-file-name 'lisp-indent-function 2)
1696
1697 ;;; Config Manipulation Functions:
1698
1699 (defun tramp-set-completion-function (method function-list)
1700 "Sets the list of completion functions for METHOD.
1701 FUNCTION-LIST is a list of entries of the form (FUNCTION FILE).
1702 The FUNCTION is intended to parse FILE according its syntax.
1703 It might be a predefined FUNCTION, or a user defined FUNCTION.
1704 Predefined FUNCTIONs are `tramp-parse-rhosts', `tramp-parse-shosts',
1705 `tramp-parse-hosts', and `tramp-parse-passwd'.
1706 Example:
1707
1708 (tramp-set-completion-function
1709 \"ssh\"
1710 '((tramp-parse-shosts \"/etc/ssh_known_hosts\")
1711 (tramp-parse-shosts \"~/.ssh/known_hosts\")))"
1712
1713 (let ((v (cdr (assoc method tramp-completion-function-alist))))
1714 (when v (setcdr v function-list))))
1715
1716 (defun tramp-get-completion-function (method)
1717 "Returns list of completion functions for METHOD.
1718 For definition of that list see `tramp-set-completion-function'."
1719 (cdr (assoc method tramp-completion-function-alist)))
1720
1721 ;;; File Name Handler Functions:
1722
1723 (defun tramp-handle-make-symbolic-link
1724 (filename linkname &optional ok-if-already-exists)
1725 "Like `make-symbolic-link' for tramp files.
1726 If LINKNAME is a non-Tramp file, it is used verbatim as the target of
1727 the symlink. If LINKNAME is a Tramp file, only the path component is
1728 used as the target of the symlink.
1729
1730 If LINKNAME is a Tramp file and the path component is relative, then
1731 it is expanded first, before the path component is taken. Note that
1732 this can give surprising results if the user/host for the source and
1733 target of the symlink differ."
1734 (with-parsed-tramp-file-name linkname l
1735 (when (tramp-ange-ftp-file-name-p l-multi-method l-method l-user l-host)
1736 (tramp-invoke-ange-ftp 'make-symbolic-link
1737 filename linkname ok-if-already-exists))
1738 (let ((ln (tramp-get-remote-ln l-multi-method l-method l-user l-host))
1739 (cwd (file-name-directory l-path)))
1740 (unless ln
1741 (signal 'file-error
1742 (list "Making a symbolic link."
1743 "ln(1) does not exist on the remote host.")))
1744
1745 ;; Do the 'confirm if exists' thing.
1746 (when (file-exists-p linkname)
1747 ;; What to do?
1748 (if (or (null ok-if-already-exists) ; not allowed to exist
1749 (and (numberp ok-if-already-exists)
1750 (not (yes-or-no-p
1751 (format
1752 "File %s already exists; make it a link anyway? "
1753 l-path)))))
1754 (signal 'file-already-exists (list "File already exists" l-path))
1755 (delete-file linkname)))
1756
1757 ;; If FILENAME is a Tramp name, use just the path component.
1758 (when (tramp-tramp-file-p filename)
1759 (setq filename (tramp-file-name-path
1760 (tramp-dissect-file-name
1761 (expand-file-name filename)))))
1762
1763 ;; Right, they are on the same host, regardless of user, method, etc.
1764 ;; We now make the link on the remote machine. This will occur as the user
1765 ;; that FILENAME belongs to.
1766 (zerop
1767 (tramp-send-command-and-check
1768 l-multi-method l-method l-user l-host
1769 (format "cd %s && %s -sf %s %s"
1770 cwd ln
1771 filename
1772 l-path)
1773 t)))))
1774
1775
1776 (defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
1777 "Like `load' for tramp files. Not implemented!"
1778 (unless (file-name-absolute-p file)
1779 (error "Tramp cannot `load' files without absolute path name"))
1780 (with-parsed-tramp-file-name file nil
1781 (when (tramp-ange-ftp-file-name-p multi-method method user host)
1782 (tramp-invoke-ange-ftp 'load
1783 file noerror nomessage nosuffix must-suffix))
1784 (unless nosuffix
1785 (cond ((file-exists-p (concat file ".elc"))
1786 (setq file (concat file ".elc")))
1787 ((file-exists-p (concat file ".el"))
1788 (setq file (concat file ".el")))))
1789 (when must-suffix
1790 ;; The first condition is always true for absolute file names.
1791 ;; Included for safety's sake.
1792 (unless (or (file-name-directory file)
1793 (string-match "\\.elc?\\'" file))
1794 (error "File `%s' does not include a `.el' or `.elc' suffix"
1795 file)))
1796 (unless noerror
1797 (when (not (file-exists-p file))
1798 (error "Cannot load nonexistant file `%s'" file)))
1799 (if (not (file-exists-p file))
1800 nil
1801 (unless nomessage
1802 (message "Loading %s..." file))
1803 (let ((local-copy (file-local-copy file)))
1804 ;; MUST-SUFFIX doesn't exist on XEmacs, so let it default to nil.
1805 (load local-copy noerror t t)
1806 (delete-file local-copy))
1807 (unless nomessage
1808 (message "Loading %s...done" file))
1809 t)))
1810
1811 ;; Path manipulation functions that grok TRAMP paths...
1812 (defun tramp-handle-file-name-directory (file)
1813 "Like `file-name-directory' but aware of TRAMP files."
1814 ;; everything except the last filename thing is the directory
1815 (with-parsed-tramp-file-name file nil
1816 (when (tramp-ange-ftp-file-name-p multi-method method user host)
1817 (tramp-invoke-ange-ftp 'file-name-directory file))
1818 ;; For the following condition, two possibilities should be tried:
1819 ;; (1) (string= path "")
1820 ;; (2) (or (string= path "") (string= path "/"))
1821 ;; The second variant fails when completing a "/" directory on
1822 ;; the remote host, that is a filename which looks like
1823 ;; "/user@host:/". But maybe wildcards fail with the first variant.
1824 ;; We should do some investigation.
1825 (if (string= path "")
1826 ;; For a filename like "/[foo]", we return "/". The `else'
1827 ;; case would return "/[foo]" unchanged. But if we do that,
1828 ;; then `file-expand-wildcards' ceases to work. It's not
1829 ;; quite clear to me what's the intuition that tells that this
1830 ;; behavior is the right behavior, but oh, well.
1831 "/"
1832 ;; run the command on the path portion only
1833 ;; CCC: This should take into account the remote machine type, no?
1834 ;; --daniel <daniel@danann.net>
1835 (tramp-make-tramp-file-name multi-method method user host
1836 ;; This will not recurse...
1837 (or (file-name-directory path) "")))))
1838
1839 (defun tramp-handle-file-name-nondirectory (file)
1840 "Like `file-name-nondirectory' but aware of TRAMP files."
1841 (with-parsed-tramp-file-name file nil
1842 (when (tramp-ange-ftp-file-name-p multi-method method user host)
1843 (tramp-invoke-ange-ftp 'file-name-nondirectory file))
1844 (file-name-nondirectory path)))
1845
1846 (defun tramp-handle-file-truename (filename &optional counter prev-dirs)
1847 "Like `file-truename' for tramp files."
1848 (with-parsed-tramp-file-name filename nil
1849 ;; Ange-FTP does not support truename processing, but for
1850 ;; convenience we pretend it did and forward the call to Ange-FTP
1851 ;; anyway. Ange-FTP then just invokes `identity'.
1852 (when (tramp-ange-ftp-file-name-p multi-method method user host)
1853 (tramp-invoke-ange-ftp 'file-truename filename))
1854 (let* ((steps (tramp-split-string path "/"))
1855 (pathdir (let ((directory-sep-char ?/))
1856 (file-name-as-directory path)))
1857 (is-dir (string= path pathdir))
1858 (thisstep nil)
1859 (numchase 0)
1860 ;; Don't make the following value larger than necessary.
1861 ;; People expect an error message in a timely fashion when
1862 ;; something is wrong; otherwise they might think that Emacs
1863 ;; is hung. Of course, correctness has to come first.
1864 (numchase-limit 20)
1865 (result nil) ;result steps in reverse order
1866 symlink-target)
1867 (tramp-message-for-buffer
1868 multi-method method user host
1869 10 "Finding true name for `%s'" filename)
1870 (while (and steps (< numchase numchase-limit))
1871 (setq thisstep (pop steps))
1872 (tramp-message-for-buffer
1873 multi-method method user host
1874 10 "Check %s"
1875 (mapconcat 'identity
1876 (append '("") (reverse result) (list thisstep))
1877 "/"))
1878 (setq symlink-target
1879 (nth 0 (tramp-handle-file-attributes
1880 (tramp-make-tramp-file-name
1881 multi-method method user host
1882 (mapconcat 'identity
1883 (append '("")
1884 (reverse result)
1885 (list thisstep))
1886 "/")))))
1887 (cond ((string= "." thisstep)
1888 (tramp-message-for-buffer multi-method method user host
1889 10 "Ignoring step `.'"))
1890 ((string= ".." thisstep)
1891 (tramp-message-for-buffer multi-method method user host
1892 10 "Processing step `..'")
1893 (pop result))
1894 ((stringp symlink-target)
1895 ;; It's a symlink, follow it.
1896 (tramp-message-for-buffer
1897 multi-method method user host
1898 10 "Follow symlink to %s" symlink-target)
1899 (setq numchase (1+ numchase))
1900 (when (file-name-absolute-p symlink-target)
1901 (setq result nil))
1902 (setq steps
1903 (append (tramp-split-string symlink-target "/") steps)))
1904 (t
1905 ;; It's a file.
1906 (setq result (cons thisstep result)))))
1907 (when (>= numchase numchase-limit)
1908 (error "Maximum number (%d) of symlinks exceeded" numchase-limit))
1909 (setq result (reverse result))
1910 ;; Combine list to form string.
1911 (setq result
1912 (if result
1913 (mapconcat 'identity (cons "" result) "/")
1914 "/"))
1915 (when (and is-dir (or (string= "" result)
1916 (not (string= (substring result -1) "/"))))
1917 (setq result (concat result "/")))
1918 (tramp-message-for-buffer
1919 multi-method method user host
1920 10 "True name of `%s' is `%s'" filename result)
1921 (tramp-make-tramp-file-name
1922 multi-method method user host result))))
1923
1924 ;; Basic functions.
1925
1926 (defun tramp-handle-file-exists-p (filename)
1927 "Like `file-exists-p' for tramp files."
1928 (with-parsed-tramp-file-name filename nil
1929 (when (tramp-ange-ftp-file-name-p multi-method method user host)
1930 (tramp-invoke-ange-ftp 'file-exists-p filename))
1931 (save-excursion
1932 (zerop (tramp-send-command-and-check
1933 multi-method method user host
1934 (format
1935 (tramp-get-file-exists-command multi-method method user host)
1936 (tramp-shell-quote-argument path)))))))
1937
1938 ;; CCC: This should check for an error condition and signal failure
1939 ;; when something goes wrong.
1940 ;; Daniel Pittman <daniel@danann.net>
1941 (defun tramp-handle-file-attributes (filename &optional nonnumeric)
1942 "Like `file-attributes' for tramp files.
1943 Optional argument NONNUMERIC means return user and group name
1944 rather than as numbers."
1945 (let (result)
1946 (with-parsed-tramp-file-name filename nil
1947 (when (tramp-ange-ftp-file-name-p multi-method method user host)
1948 (tramp-invoke-ange-ftp 'file-attributes filename))
1949 (when (tramp-handle-file-exists-p filename)
1950 ;; file exists, find out stuff
1951 (save-excursion
1952 (if (tramp-get-remote-perl multi-method method user host)
1953 (setq result
1954 (tramp-handle-file-attributes-with-perl
1955 multi-method method user host path nonnumeric))
1956 (setq result
1957 (tramp-handle-file-attributes-with-ls
1958 multi-method method user host path nonnumeric))))))
1959 result))
1960
1961
1962 (defun tramp-handle-file-attributes-with-ls
1963 (multi-method method user host path &optional nonnumeric)
1964 "Implement `file-attributes' for tramp files using the ls(1) command."
1965 (let (symlinkp dirp
1966 res-inode res-filemodes res-numlinks
1967 res-uid res-gid res-size res-symlink-target)
1968 (tramp-message-for-buffer multi-method method user host 10
1969 "file attributes with ls: %s"
1970 (tramp-make-tramp-file-name
1971 multi-method method user host path))
1972 (tramp-send-command
1973 multi-method method user host
1974 (format "%s %s %s"
1975 (tramp-get-ls-command multi-method method user host)
1976 (if nonnumeric "-ild" "-ildn")
1977 (tramp-shell-quote-argument path)))
1978 (tramp-wait-for-output)
1979 ;; parse `ls -l' output ...
1980 ;; ... inode
1981 (setq res-inode
1982 (condition-case err
1983 (read (current-buffer))
1984 (invalid-read-syntax
1985 (when (and (equal (cadr err)
1986 "Integer constant overflow in reader")
1987 (string-match
1988 "^[0-9]+\\([0-9][0-9][0-9][0-9][0-9]\\)\\'"
1989 (caddr err)))
1990 (let* ((big (read (substring (caddr err) 0
1991 (match-beginning 1))))
1992 (small (read (match-string 1 (caddr err))))
1993 (twiddle (/ small 65536)))
1994 (cons (+ big twiddle)
1995 (- small (* twiddle 65536))))))))
1996 ;; ... file mode flags
1997 (setq res-filemodes (symbol-name (read (current-buffer))))
1998 ;; ... number links
1999 (setq res-numlinks (read (current-buffer)))
2000 ;; ... uid and gid
2001 (setq res-uid (read (current-buffer)))
2002 (setq res-gid (read (current-buffer)))
2003 (unless nonnumeric
2004 (unless (numberp res-uid) (setq res-uid -1))
2005 (unless (numberp res-gid) (setq res-gid -1)))
2006 ;; ... size
2007 (setq res-size (read (current-buffer)))
2008 ;; From the file modes, figure out other stuff.
2009 (setq symlinkp (eq ?l (aref res-filemodes 0)))
2010 (setq dirp (eq ?d (aref res-filemodes 0)))
2011 ;; if symlink, find out file name pointed to
2012 (when symlinkp
2013 (search-forward "-> ")
2014 (setq res-symlink-target
2015 (buffer-substring (point)
2016 (tramp-line-end-position))))
2017 ;; return data gathered
2018 (list
2019 ;; 0. t for directory, string (name linked to) for symbolic
2020 ;; link, or nil.
2021 (or dirp res-symlink-target nil)
2022 ;; 1. Number of links to file.
2023 res-numlinks
2024 ;; 2. File uid.
2025 res-uid
2026 ;; 3. File gid.
2027 res-gid
2028 ;; 4. Last access time, as a list of two integers. First
2029 ;; integer has high-order 16 bits of time, second has low 16
2030 ;; bits.
2031 ;; 5. Last modification time, likewise.
2032 ;; 6. Last status change time, likewise.
2033 '(0 0) '(0 0) '(0 0) ;CCC how to find out?
2034 ;; 7. Size in bytes (-1, if number is out of range).
2035 res-size
2036 ;; 8. File modes, as a string of ten letters or dashes as in ls -l.
2037 res-filemodes
2038 ;; 9. t iff file's gid would change if file were deleted and
2039 ;; recreated.
2040 nil ;hm?
2041 ;; 10. inode number.
2042 res-inode
2043 ;; 11. Device number.
2044 -1 ;hm?
2045 )))
2046
2047 (defun tramp-handle-file-attributes-with-perl
2048 (multi-method method user host path &optional nonnumeric)
2049 "Implement `file-attributes' for tramp files using a Perl script.
2050
2051 The Perl command is sent to the remote machine when the connection
2052 is initially created and is kept cached by the remote shell."
2053 (tramp-message-for-buffer multi-method method user host 10
2054 "file attributes with perl: %s"
2055 (tramp-make-tramp-file-name
2056 multi-method method user host path))
2057 (tramp-send-command
2058 multi-method method user host
2059 (format "tramp_file_attributes %s"
2060 (tramp-shell-quote-argument path)))
2061 (tramp-wait-for-output)
2062 (let ((result (read (current-buffer))))
2063 (setcar (nthcdr 8 result)
2064 (tramp-file-mode-from-int (nth 8 result)))
2065 result))
2066
2067 (defun tramp-handle-set-visited-file-modtime (&optional time-list)
2068 "Like `set-visited-file-modtime' for tramp files."
2069 (unless (buffer-file-name)
2070 (error "Can't set-visited-file-modtime: buffer `%s' not visiting a file"
2071 (buffer-name)))
2072 (when time-list
2073 (tramp-run-real-handler 'set-visited-file-modtime (list time-list)))
2074 (let ((f (buffer-file-name))
2075 (coding-system-used nil))
2076 (with-parsed-tramp-file-name f nil
2077 ;; This operation is not handled by Ange-FTP! Compare this
2078 ;; behavior with `file-truename' which Ange-FTP does not really
2079 ;; handle, either, but at least it pretends to. I wonder if
2080 ;; Ange-FTP should also pretend to grok
2081 ;; `set-visited-file-modtime', for consistency?
2082 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2083 (throw 'tramp-forward-to-ange-ftp
2084 (tramp-run-real-handler 'set-visited-file-modtime
2085 (list time-list))))
2086 (let* ((attr (file-attributes f))
2087 (modtime (nth 5 attr)))
2088 ;; We use '(0 0) as a don't-know value. See also
2089 ;; `tramp-handle-file-attributes-with-ls'.
2090 (when (boundp 'last-coding-system-used)
2091 (setq coding-system-used last-coding-system-used))
2092 (if (not (equal modtime '(0 0)))
2093 (tramp-run-real-handler 'set-visited-file-modtime (list modtime))
2094 (save-excursion
2095 (tramp-send-command
2096 multi-method method user host
2097 (format "%s -ild %s"
2098 (tramp-get-ls-command multi-method method user host)
2099 (tramp-shell-quote-argument path)))
2100 (tramp-wait-for-output)
2101 (setq attr (buffer-substring (point)
2102 (progn (end-of-line) (point)))))
2103 (setq tramp-buffer-file-attributes attr))
2104 (when (boundp 'last-coding-system-used)
2105 (setq last-coding-system-used coding-system-used))
2106 nil))))
2107
2108 ;; CCC continue here
2109
2110 ;; This function makes the same assumption as
2111 ;; `tramp-handle-set-visited-file-modtime'.
2112 (defun tramp-handle-verify-visited-file-modtime (buf)
2113 "Like `verify-visited-file-modtime' for tramp files."
2114 (with-current-buffer buf
2115 (let ((f (buffer-file-name)))
2116 (with-parsed-tramp-file-name f nil
2117 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2118 ;; This one requires a hack since the file name is not passed
2119 ;; on the arg list.
2120 (let ((buffer-file-name (tramp-make-ange-ftp-file-name
2121 user host path)))
2122 (tramp-invoke-ange-ftp 'verify-visited-file-modtime buf)))
2123 (let* ((attr (file-attributes f))
2124 (modtime (nth 5 attr)))
2125 (cond ((and attr (not (equal modtime '(0 0))))
2126 ;; Why does `file-attributes' return a list (HIGH
2127 ;; LOW), but `visited-file-modtime' returns a cons
2128 ;; (HIGH . LOW)?
2129 (let ((mt (visited-file-modtime)))
2130 (< (abs (tramp-time-diff
2131 modtime (list (car mt) (cdr mt)))) 2)))
2132 (attr
2133 (save-excursion
2134 (tramp-send-command
2135 multi-method method user host
2136 (format "%s -ild %s"
2137 (tramp-get-ls-command multi-method method
2138 user host)
2139 (tramp-shell-quote-argument path)))
2140 (tramp-wait-for-output)
2141 (setq attr (buffer-substring
2142 (point) (progn (end-of-line) (point)))))
2143 (equal tramp-buffer-file-attributes attr))
2144 ;; If file does not exist, say it is not modified.
2145 (t nil)))))))
2146
2147 (defadvice clear-visited-file-modtime (after tramp activate)
2148 "Set `tramp-buffer-file-attributes' back to nil.
2149 Tramp uses this variable as an emulation for the actual modtime of the file,
2150 if the remote host can't provide the modtime."
2151 (setq tramp-buffer-file-attributes nil))
2152
2153 (defun tramp-handle-set-file-modes (filename mode)
2154 "Like `set-file-modes' for tramp files."
2155 (with-parsed-tramp-file-name filename nil
2156 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2157 (tramp-invoke-ange-ftp 'set-file-modes mode filename))
2158 (save-excursion
2159 (unless (zerop (tramp-send-command-and-check
2160 multi-method method user host
2161 (format "chmod %s %s"
2162 (tramp-decimal-to-octal mode)
2163 (tramp-shell-quote-argument path))))
2164 (signal 'file-error
2165 (list "Doing chmod"
2166 ;; FIXME: extract the proper text from chmod's stderr.
2167 "error while changing file's mode"
2168 filename))))))
2169
2170 ;; Simple functions using the `test' command.
2171
2172 (defun tramp-handle-file-executable-p (filename)
2173 "Like `file-executable-p' for tramp files."
2174 (with-parsed-tramp-file-name filename nil
2175 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2176 (tramp-invoke-ange-ftp 'file-executable-p filename))
2177 (zerop (tramp-run-test "-x" filename))))
2178
2179 (defun tramp-handle-file-readable-p (filename)
2180 "Like `file-readable-p' for tramp files."
2181 (with-parsed-tramp-file-name filename nil
2182 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2183 (tramp-invoke-ange-ftp 'file-readable-p filename))
2184 (zerop (tramp-run-test "-r" filename))))
2185
2186 (defun tramp-handle-file-accessible-directory-p (filename)
2187 "Like `file-accessible-directory-p' for tramp files."
2188 (with-parsed-tramp-file-name filename nil
2189 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2190 (tramp-invoke-ange-ftp 'file-accessible-directory-p filename))
2191 (and (zerop (tramp-run-test "-d" filename))
2192 (zerop (tramp-run-test "-r" filename))
2193 (zerop (tramp-run-test "-x" filename)))))
2194
2195 ;; When the remote shell is started, it looks for a shell which groks
2196 ;; tilde expansion. Here, we assume that all shells which grok tilde
2197 ;; expansion will also provide a `test' command which groks `-nt' (for
2198 ;; newer than). If this breaks, tell me about it and I'll try to do
2199 ;; something smarter about it.
2200 (defun tramp-handle-file-newer-than-file-p (file1 file2)
2201 "Like `file-newer-than-file-p' for tramp files."
2202 (cond ((not (file-exists-p file1))
2203 nil)
2204 ((not (file-exists-p file2))
2205 t)
2206 ;; We are sure both files exist at this point.
2207 (t
2208 (save-excursion
2209 ;; We try to get the mtime of both files. If they are not
2210 ;; equal to the "dont-know" value, then we subtract the times
2211 ;; and obtain the result.
2212 (let ((fa1 (file-attributes file1))
2213 (fa2 (file-attributes file2)))
2214 (if (and (not (equal (nth 5 fa1) '(0 0)))
2215 (not (equal (nth 5 fa2) '(0 0))))
2216 (> 0 (car (subtract-time (nth 5 fa1) (nth 5 fa2))))
2217 ;; If one of them is the dont-know value, then we can
2218 ;; still try to run a shell command on the remote host.
2219 ;; However, this only works if both files are Tramp
2220 ;; files and both have the same method, same user, same
2221 ;; host.
2222 (unless (and (tramp-tramp-file-p file1)
2223 (tramp-tramp-file-p file2))
2224 (signal
2225 'file-error
2226 (list
2227 "Cannot check if Tramp file is newer than non-Tramp file"
2228 file1 file2)))
2229 (with-parsed-tramp-file-name file1 v1
2230 (with-parsed-tramp-file-name file2 v2
2231 (when (and (tramp-ange-ftp-file-name-p
2232 v1-multi-method v1-method v1-user v1-host)
2233 (tramp-ange-ftp-file-name-p
2234 v2-multi-method v2-method v2-user v2-host))
2235 (tramp-invoke-ange-ftp 'file-newer-than-file-p
2236 file1 file2))
2237 (unless (and (equal v1-multi-method v2-multi-method)
2238 (equal v1-method v2-method)
2239 (equal v1-user v2-user)
2240 (equal v1-host v2-host))
2241 (signal 'file-error
2242 (list "Files must have same method, user, host"
2243 file1 file2)))
2244 (unless (and (tramp-tramp-file-p file1)
2245 (tramp-tramp-file-p file2))
2246 (signal 'file-error
2247 (list "Files must be tramp files on same host"
2248 file1 file2)))
2249 (if (tramp-get-test-groks-nt
2250 v1-multi-method v1-method v1-user v1-host)
2251 (zerop (tramp-run-test2 "test" file1 file2 "-nt"))
2252 (zerop (tramp-run-test2
2253 "tramp_test_nt" file1 file2)))))))))))
2254
2255 ;; Functions implemented using the basic functions above.
2256
2257 (defun tramp-handle-file-modes (filename)
2258 "Like `file-modes' for tramp files."
2259 (with-parsed-tramp-file-name filename nil
2260 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2261 (tramp-invoke-ange-ftp 'file-modes filename))
2262 (when (file-exists-p filename)
2263 (tramp-mode-string-to-int
2264 (nth 8 (tramp-handle-file-attributes filename))))))
2265
2266 (defun tramp-handle-file-directory-p (filename)
2267 "Like `file-directory-p' for tramp files."
2268 ;; Care must be taken that this function returns `t' for symlinks
2269 ;; pointing to directories. Surely the most obvious implementation
2270 ;; would be `test -d', but that returns false for such symlinks.
2271 ;; CCC: Stefan Monnier says that `test -d' follows symlinks. And
2272 ;; I now think he's right. So we could be using `test -d', couldn't
2273 ;; we?
2274 ;;
2275 ;; Alternatives: `cd %s', `test -d %s'
2276 (with-parsed-tramp-file-name filename nil
2277 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2278 (tramp-invoke-ange-ftp 'file-directory-p filename))
2279 (save-excursion
2280 (zerop
2281 (tramp-send-command-and-check
2282 multi-method method user host
2283 (format "test -d %s"
2284 (tramp-shell-quote-argument path))
2285 t))))) ;run command in subshell
2286
2287 (defun tramp-handle-file-regular-p (filename)
2288 "Like `file-regular-p' for tramp files."
2289 (with-parsed-tramp-file-name filename nil
2290 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2291 (tramp-invoke-ange-ftp 'file-regular-p filename))
2292 (and (tramp-handle-file-exists-p filename)
2293 (eq ?- (aref (nth 8 (tramp-handle-file-attributes filename)) 0)))))
2294
2295 (defun tramp-handle-file-symlink-p (filename)
2296 "Like `file-symlink-p' for tramp files."
2297 (with-parsed-tramp-file-name filename nil
2298 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2299 (tramp-invoke-ange-ftp 'file-symlink-p filename))
2300 (let ((x (car (tramp-handle-file-attributes filename))))
2301 (when (stringp x) x))))
2302
2303 (defun tramp-handle-file-writable-p (filename)
2304 "Like `file-writable-p' for tramp files."
2305 (with-parsed-tramp-file-name filename nil
2306 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2307 (tramp-invoke-ange-ftp 'file-writable-p filename))
2308 (if (tramp-handle-file-exists-p filename)
2309 ;; Existing files must be writable.
2310 (zerop (tramp-run-test "-w" filename))
2311 ;; If file doesn't exist, check if directory is writable.
2312 (and (zerop (tramp-run-test
2313 "-d" (tramp-handle-file-name-directory filename)))
2314 (zerop (tramp-run-test
2315 "-w" (tramp-handle-file-name-directory filename)))))))
2316
2317 (defun tramp-handle-file-ownership-preserved-p (filename)
2318 "Like `file-ownership-preserved-p' for tramp files."
2319 (with-parsed-tramp-file-name filename nil
2320 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2321 (tramp-invoke-ange-ftp 'file-ownership-preserved-p filename))
2322 (or (not (tramp-handle-file-exists-p filename))
2323 ;; Existing files must be writable.
2324 (zerop (tramp-run-test "-O" filename)))))
2325
2326 ;; Other file name ops.
2327
2328 ;; ;; Matthias Köppe <mkoeppe@mail.math.uni-magdeburg.de>
2329 ;; (defun tramp-handle-directory-file-name (directory)
2330 ;; "Like `directory-file-name' for tramp files."
2331 ;; (if (and (eq (aref directory (- (length directory) 1)) ?/)
2332 ;; (not (eq (aref directory (- (length directory) 2)) ?:)))
2333 ;; (substring directory 0 (- (length directory) 1))
2334 ;; directory))
2335
2336 ;; Philippe Troin <phil@fifi.org>
2337 (defun tramp-handle-directory-file-name (directory)
2338 "Like `directory-file-name' for tramp files."
2339 (with-parsed-tramp-file-name directory nil
2340 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2341 (tramp-invoke-ange-ftp 'directory-file-name directory))
2342 (let ((directory-length-1 (1- (length directory))))
2343 (save-match-data
2344 (if (and (eq (aref directory directory-length-1) ?/)
2345 (eq (string-match tramp-file-name-regexp directory) 0)
2346 (/= (match-end 0) directory-length-1))
2347 (substring directory 0 directory-length-1)
2348 directory)))))
2349
2350 ;; Directory listings.
2351
2352 (defun tramp-handle-directory-files (directory
2353 &optional full match nosort files-only)
2354 "Like `directory-files' for tramp files."
2355 (with-parsed-tramp-file-name directory nil
2356 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2357 (tramp-invoke-ange-ftp 'directory-files
2358 directory full match nosort files-only))
2359 (let (result x)
2360 (save-excursion
2361 (tramp-barf-unless-okay
2362 multi-method method user host
2363 (concat "cd " (tramp-shell-quote-argument path))
2364 nil
2365 'file-error
2366 "tramp-handle-directory-files: couldn't `cd %s'"
2367 (tramp-shell-quote-argument path))
2368 (tramp-send-command
2369 multi-method method user host
2370 (concat (tramp-get-ls-command multi-method method user host)
2371 " -a | cat"))
2372 (tramp-wait-for-output)
2373 (goto-char (point-max))
2374 (while (zerop (forward-line -1))
2375 (setq x (buffer-substring (point)
2376 (tramp-line-end-position)))
2377 (when (or (not match) (string-match match x))
2378 (if full
2379 (push (concat (file-name-as-directory directory)
2380 x)
2381 result)
2382 (push x result))))
2383 (tramp-send-command multi-method method user host "cd")
2384 (tramp-wait-for-output)
2385 ;; Remove non-files or non-directories if necessary. Using
2386 ;; the remote shell for this would probably be way faster.
2387 ;; Maybe something could be adapted from
2388 ;; tramp-handle-file-name-all-completions.
2389 (when files-only
2390 (let ((temp (nreverse result))
2391 item)
2392 (setq result nil)
2393 (if (equal files-only t)
2394 ;; files only
2395 (while temp
2396 (setq item (pop temp))
2397 (when (file-regular-p item)
2398 (push item result)))
2399 ;; directories only
2400 (while temp
2401 (setq item (pop temp))
2402 (when (file-directory-p item)
2403 (push item result)))))))
2404 result)))
2405
2406 ;; This function should return "foo/" for directories and "bar" for
2407 ;; files. We use `ls -ad' to get a list of files (including
2408 ;; directories), and `find . -type d \! -name . -prune' to get a list
2409 ;; of directories.
2410 (defun tramp-handle-file-name-all-completions (filename directory)
2411 "Like `file-name-all-completions' for tramp files."
2412 (with-parsed-tramp-file-name directory nil
2413 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2414 (tramp-invoke-ange-ftp 'file-name-all-completions
2415 filename directory))
2416 (unless (save-match-data (string-match "/" filename))
2417 (let* ((nowild tramp-completion-without-shell-p)
2418 result)
2419 (save-excursion
2420 (tramp-barf-unless-okay
2421 multi-method method user host
2422 (format "cd %s" (tramp-shell-quote-argument path))
2423 nil 'file-error
2424 "tramp-handle-file-name-all-completions: Couldn't `cd %s'"
2425 (tramp-shell-quote-argument path))
2426
2427 ;; Get a list of directories and files, including reliably
2428 ;; tagging the directories with a trailing '/'. Because I
2429 ;; rock. --daniel@danann.net
2430 (tramp-send-command
2431 multi-method method user host
2432 (format (concat "%s -a %s 2>/dev/null | while read f; do "
2433 "if test -d \"$f\" 2>/dev/null; "
2434 "then echo \"$f/\"; else echo \"$f\"; fi; done")
2435 (tramp-get-ls-command multi-method method user host)
2436 (if (or nowild (zerop (length filename)))
2437 ""
2438 (format "-d %s*"
2439 (tramp-shell-quote-argument filename)))))
2440
2441 ;; Now grab the output.
2442 (tramp-wait-for-output)
2443 (goto-char (point-max))
2444 (while (zerop (forward-line -1))
2445 (push (buffer-substring (point)
2446 (tramp-line-end-position))
2447 result))
2448
2449 (tramp-send-command multi-method method user host "cd")
2450 (tramp-wait-for-output)
2451
2452 ;; Return the list.
2453 (if nowild
2454 (all-completions filename (mapcar 'list result))
2455 result))))))
2456
2457
2458 ;; The following isn't needed for Emacs 20 but for 19.34?
2459 (defun tramp-handle-file-name-completion (filename directory)
2460 "Like `file-name-completion' for tramp files."
2461 (unless (tramp-tramp-file-p directory)
2462 (error
2463 "tramp-handle-file-name-completion invoked on non-tramp directory `%s'"
2464 directory))
2465 (with-parsed-tramp-file-name directory nil
2466 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2467 (tramp-invoke-ange-ftp 'file-name-completion
2468 filename directory))
2469 (try-completion
2470 filename
2471 (mapcar (lambda (x) (cons x nil))
2472 (tramp-handle-file-name-all-completions filename directory)))))
2473
2474 ;; cp, mv and ln
2475
2476 (defun tramp-handle-add-name-to-file
2477 (filename newname &optional ok-if-already-exists)
2478 "Like `add-name-to-file' for tramp files."
2479 (with-parsed-tramp-file-name filename v1
2480 (with-parsed-tramp-file-name newname v2
2481 (let ((ln (when v1 (tramp-get-remote-ln
2482 v1-multi-method v1-method v1-user v1-host))))
2483 (unless (and v1-method v2-method v1-user v2-user v1-host v2-host
2484 (equal v1-multi-method v2-multi-method)
2485 (equal v1-method v2-method)
2486 (equal v1-user v2-user)
2487 (equal v1-host v2-host))
2488 (error "add-name-to-file: %s"
2489 "only implemented for same method, same user, same host"))
2490 (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method v1-user v1-host)
2491 (tramp-ange-ftp-file-name-p v2-multi-method v2-method v2-user v2-host))
2492 (tramp-invoke-ange-ftp 'add-name-to-file
2493 filename newname ok-if-already-exists))
2494 (when (tramp-ange-ftp-file-name-p v1-multi-method v1-method v1-user v1-host)
2495 (tramp-invoke-ange-ftp 'add-name-to-file
2496 filename newname ok-if-already-exists))
2497 (when (tramp-ange-ftp-file-name-p v2-multi-method v2-method v2-user v2-host)
2498 (tramp-invoke-ange-ftp 'add-name-to-file
2499 filename newname ok-if-already-exists))
2500 (when (and (not ok-if-already-exists)
2501 (file-exists-p newname)
2502 (not (numberp ok-if-already-exists))
2503 (y-or-n-p
2504 (format
2505 "File %s already exists; make it a new name anyway? "
2506 newname)))
2507 (error "add-name-to-file: file %s already exists" newname))
2508 (tramp-barf-unless-okay
2509 v1-multi-method v1-method v1-user v1-host
2510 (format "%s %s %s" ln (tramp-shell-quote-argument v1-path)
2511 (tramp-shell-quote-argument v2-path))
2512 nil 'file-error
2513 "error with add-name-to-file, see buffer `%s' for details"
2514 (buffer-name))))))
2515
2516 (defun tramp-handle-copy-file
2517 (filename newname &optional ok-if-already-exists keep-date)
2518 "Like `copy-file' for tramp files."
2519 ;; Check if both files are local -- invoke normal copy-file.
2520 ;; Otherwise, use tramp from local system.
2521 (setq filename (expand-file-name filename))
2522 (setq newname (expand-file-name newname))
2523 ;; At least one file a tramp file?
2524 (if (or (tramp-tramp-file-p filename)
2525 (tramp-tramp-file-p newname))
2526 (tramp-do-copy-or-rename-file
2527 'copy filename newname ok-if-already-exists keep-date)
2528 (tramp-run-real-handler
2529 'copy-file
2530 (list filename newname ok-if-already-exists keep-date))))
2531
2532 (defun tramp-handle-rename-file
2533 (filename newname &optional ok-if-already-exists)
2534 "Like `rename-file' for tramp files."
2535 ;; Check if both files are local -- invoke normal rename-file.
2536 ;; Otherwise, use tramp from local system.
2537 (setq filename (expand-file-name filename))
2538 (setq newname (expand-file-name newname))
2539 ;; At least one file a tramp file?
2540 (if (or (tramp-tramp-file-p filename)
2541 (tramp-tramp-file-p newname))
2542 (tramp-do-copy-or-rename-file
2543 'rename filename newname ok-if-already-exists)
2544 (tramp-run-real-handler 'rename-file
2545 (list filename newname ok-if-already-exists))))
2546
2547 (defun tramp-do-copy-or-rename-file
2548 (op filename newname &optional ok-if-already-exists keep-date)
2549 "Copy or rename a remote file.
2550 OP must be `copy' or `rename' and indicates the operation to perform.
2551 FILENAME specifies the file to copy or rename, NEWNAME is the name of
2552 the new file (for copy) or the new name of the file (for rename).
2553 OK-IF-ALREADY-EXISTS means don't barf if NEWNAME exists already.
2554 KEEP-DATE means to make sure that NEWNAME has the same timestamp
2555 as FILENAME.
2556
2557 This function is invoked by `tramp-handle-copy-file' and
2558 `tramp-handle-rename-file'. It is an error if OP is neither of `copy'
2559 and `rename'. FILENAME and NEWNAME must be absolute file names."
2560 (unless (memq op '(copy rename))
2561 (error "Unknown operation `%s', must be `copy' or `rename'" op))
2562 (unless ok-if-already-exists
2563 (when (file-exists-p newname)
2564 (signal 'file-already-exists
2565 (list newname))))
2566 (let ((t1 (tramp-tramp-file-p filename))
2567 (t2 (tramp-tramp-file-p newname)))
2568 ;; Check which ones of source and target are Tramp files.
2569 (cond
2570 ((and t1 t2)
2571 ;; Both are Tramp files.
2572 (with-parsed-tramp-file-name filename v1
2573 (with-parsed-tramp-file-name newname v2
2574 ;; Possibly invoke Ange-FTP.
2575 (when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method v1-user v1-host)
2576 (tramp-ange-ftp-file-name-p v2-multi-method v2-method v2-user v2-host))
2577 (if (eq op 'copy)
2578 (tramp-invoke-ange-ftp
2579 'copy-file filename newname ok-if-already-exists keep-date)
2580 (tramp-invoke-ange-ftp
2581 'rename-file filename newname ok-if-already-exists)))
2582 ;; Check if we can use a shortcut.
2583 (if (and (equal v1-multi-method v2-multi-method)
2584 (equal v1-method v2-method)
2585 (equal v1-host v2-host)
2586 (equal v1-user v2-user))
2587 ;; Shortcut: if method, host, user are the same for both
2588 ;; files, we invoke `cp' or `mv' on the remote host
2589 ;; directly.
2590 (tramp-do-copy-or-rename-file-directly
2591 op v1-multi-method v1-method v1-user v1-host
2592 v1-path v2-path keep-date)
2593 ;; The shortcut was not possible. So we copy the
2594 ;; file first. If the operation was `rename', we go
2595 ;; back and delete the original file (if the copy was
2596 ;; successful). The approach is simple-minded: we
2597 ;; create a new buffer, insert the contents of the
2598 ;; source file into it, then write out the buffer to
2599 ;; the target file. The advantage is that it doesn't
2600 ;; matter which filename handlers are used for the
2601 ;; source and target file.
2602
2603 ;; CCC: If both source and target are Tramp files,
2604 ;; and both are using the same rcp-program, then we
2605 ;; can invoke rcp directly. Note that
2606 ;; default-directory should point to a local
2607 ;; directory if we want to invoke rcp.
2608 (tramp-do-copy-or-rename-via-buffer
2609 op filename newname keep-date)))))
2610 ((or t1 t2)
2611 ;; Use the generic method via a Tramp buffer.
2612 (tramp-do-copy-or-rename-via-buffer op filename newname keep-date))
2613 (t
2614 ;; One of them must be a Tramp file.
2615 (error "Tramp implementation says this cannot happen")))))
2616
2617 (defun tramp-do-copy-or-rename-via-buffer (op filename newname keep-date)
2618 "Use an Emacs buffer to copy or rename a file.
2619 First arg OP is either `copy' or `rename' and indicates the operation.
2620 FILENAME is the source file, NEWNAME the target file.
2621 KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME."
2622 (let ((trampbuf (get-buffer-create "*tramp output*")))
2623 (when keep-date
2624 (tramp-message
2625 1 (concat "Warning: cannot preserve file time stamp"
2626 " with inline copying across machines")))
2627 (save-excursion
2628 (set-buffer trampbuf) (erase-buffer)
2629 (insert-file-contents-literally filename)
2630 (let ((coding-system-for-write 'no-conversion))
2631 (write-region (point-min) (point-max) newname)))
2632 ;; If the operation was `rename', delete the original file.
2633 (unless (eq op 'copy)
2634 (delete-file filename))))
2635
2636 (defun tramp-do-copy-or-rename-file-directly
2637 (op multi-method method user host path1 path2 keep-date)
2638 "Invokes `cp' or `mv' on the remote system.
2639 OP must be one of `copy' or `rename', indicating `cp' or `mv',
2640 respectively. METHOD, USER, and HOST specify the connection.
2641 PATH1 and PATH2 specify the two arguments of `cp' or `mv'.
2642 If KEEP-DATE is non-nil, preserve the time stamp when copying."
2643 ;; CCC: What happens to the timestamp when renaming?
2644 (let ((cmd (cond ((and (eq op 'copy) keep-date) "cp -f -p")
2645 ((eq op 'copy) "cp -f")
2646 ((eq op 'rename) "mv -f")
2647 (t (error
2648 "Unknown operation `%s', must be `copy' or `rename'"
2649 op)))))
2650 (save-excursion
2651 (tramp-barf-unless-okay
2652 multi-method method user host
2653 (format "%s %s %s"
2654 cmd
2655 (tramp-shell-quote-argument path1)
2656 (tramp-shell-quote-argument path2))
2657 nil 'file-error
2658 "Copying directly failed, see buffer `%s' for details."
2659 (buffer-name)))))
2660
2661 ;; mkdir
2662 (defun tramp-handle-make-directory (dir &optional parents)
2663 "Like `make-directory' for tramp files."
2664 (setq dir (expand-file-name dir))
2665 (with-parsed-tramp-file-name dir nil
2666 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2667 (tramp-invoke-ange-ftp 'make-directory dir parents))
2668 (save-excursion
2669 (tramp-barf-unless-okay
2670 multi-method method user host
2671 (format " %s %s"
2672 (if parents "mkdir -p" "mkdir")
2673 (tramp-shell-quote-argument path))
2674 nil 'file-error
2675 "Couldn't make directory %s" dir))))
2676
2677 ;; CCC error checking?
2678 (defun tramp-handle-delete-directory (directory)
2679 "Like `delete-directory' for tramp files."
2680 (setq directory (expand-file-name directory))
2681 (with-parsed-tramp-file-name directory nil
2682 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2683 (tramp-invoke-ange-ftp 'delete-directory directory))
2684 (save-excursion
2685 (tramp-send-command
2686 multi-method method user host
2687 (format "rmdir %s ; echo ok"
2688 (tramp-shell-quote-argument path)))
2689 (tramp-wait-for-output))))
2690
2691 (defun tramp-handle-delete-file (filename)
2692 "Like `delete-file' for tramp files."
2693 (setq filename (expand-file-name filename))
2694 (with-parsed-tramp-file-name filename nil
2695 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2696 (tramp-invoke-ange-ftp 'delete-file filename))
2697 (save-excursion
2698 (unless (zerop (tramp-send-command-and-check
2699 multi-method method user host
2700 (format "rm -f %s"
2701 (tramp-shell-quote-argument path))))
2702 (signal 'file-error "Couldn't delete Tramp file")))))
2703
2704 ;; Dired.
2705
2706 ;; CCC: This does not seem to be enough. Something dies when
2707 ;; we try and delete two directories under TRAMP :/
2708 (defun tramp-handle-dired-recursive-delete-directory (filename)
2709 "Recursively delete the directory given.
2710 This is like `dired-recursive-delete-directory' for tramp files."
2711 (with-parsed-tramp-file-name filename nil
2712 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2713 (tramp-invoke-ange-ftp 'dired-recursive-delete-directory
2714 filename))
2715 ;; run a shell command 'rm -r <path>'
2716 ;; Code shamelessly stolen for the dired implementation and, um, hacked :)
2717 (or (tramp-handle-file-exists-p filename)
2718 (signal
2719 'file-error
2720 (list "Removing old file name" "no such directory" filename)))
2721 ;; Which is better, -r or -R? (-r works for me <daniel@danann.net>)
2722 (tramp-send-command multi-method method user host
2723 (format "rm -r %s" (tramp-shell-quote-argument path)))
2724 ;; Wait for the remote system to return to us...
2725 ;; This might take a while, allow it plenty of time.
2726 (tramp-wait-for-output 120)
2727 ;; Make sure that it worked...
2728 (and (tramp-handle-file-exists-p filename)
2729 (error "Failed to recusively delete %s" filename))))
2730
2731
2732 (defun tramp-handle-dired-call-process (program discard &rest arguments)
2733 "Like `dired-call-process' for tramp files."
2734 (with-parsed-tramp-file-name default-directory nil
2735 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2736 (let ((default-directory
2737 (tramp-make-ange-ftp-file-name user host path)))
2738 (tramp-invoke-ange-ftp 'dired-call-process
2739 program discard arguments)))
2740 (save-excursion
2741 (tramp-barf-unless-okay
2742 multi-method method user host
2743 (format "cd %s" (tramp-shell-quote-argument path))
2744 nil 'file-error
2745 "tramp-handle-dired-call-process: Couldn't `cd %s'"
2746 (tramp-shell-quote-argument path))
2747 (tramp-send-command
2748 multi-method method user host
2749 (mapconcat #'tramp-shell-quote-argument (cons program arguments) " "))
2750 (tramp-wait-for-output))
2751 (unless discard
2752 (insert-buffer (tramp-get-buffer multi-method method user host)))
2753 (save-excursion
2754 (prog1
2755 (tramp-send-command-and-check multi-method method user host nil)
2756 (tramp-send-command multi-method method user host "cd")
2757 (tramp-wait-for-output)))))
2758
2759 ;; Pacify byte-compiler. The function is needed on XEmacs only. I'm
2760 ;; not sure at all that this is the right way to do it, but let's hope
2761 ;; it works for now, and wait for a guru to point out the Right Way to
2762 ;; achieve this.
2763 ;;(eval-when-compile
2764 ;; (unless (fboundp 'dired-insert-set-properties)
2765 ;; (fset 'dired-insert-set-properties 'ignore)))
2766 ;; Gerd suggests this:
2767 (eval-when-compile (require 'dired))
2768 ;; Note that dired is required at run-time, too, when it is needed.
2769 ;; It is only needed on XEmacs for the function
2770 ;; `dired-insert-set-properties'.
2771
2772 (defun tramp-handle-insert-directory
2773 (filename switches &optional wildcard full-directory-p)
2774 "Like `insert-directory' for tramp files."
2775 ;; For the moment, we assume that the remote "ls" program does not
2776 ;; grok "--dired". In the future, we should detect this on
2777 ;; connection setup.
2778 (when (string-match "^--dired\\s-+" switches)
2779 (setq switches (replace-match "" nil t switches)))
2780 (setq filename (expand-file-name filename))
2781 (with-parsed-tramp-file-name filename nil
2782 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2783 (tramp-invoke-ange-ftp 'insert-directory
2784 filename switches wildcard full-directory-p))
2785 (tramp-message-for-buffer
2786 multi-method method user host 10
2787 "Inserting directory `ls %s %s', wildcard %s, fulldir %s"
2788 switches filename (if wildcard "yes" "no")
2789 (if full-directory-p "yes" "no"))
2790 (when wildcard
2791 (setq wildcard (file-name-nondirectory path))
2792 (setq path (file-name-directory path)))
2793 (when (listp switches)
2794 (setq switches (mapconcat 'identity switches " ")))
2795 (unless full-directory-p
2796 (setq switches (concat "-d " switches)))
2797 (when wildcard
2798 (setq switches (concat switches " " wildcard)))
2799 (save-excursion
2800 ;; If `full-directory-p', we just say `ls -l FILENAME'.
2801 ;; Else we chdir to the parent directory, then say `ls -ld BASENAME'.
2802 (if full-directory-p
2803 (tramp-send-command
2804 multi-method method user host
2805 (format "%s %s %s"
2806 (tramp-get-ls-command multi-method method user host)
2807 switches
2808 (if wildcard
2809 path
2810 (tramp-shell-quote-argument (concat path ".")))))
2811 (tramp-barf-unless-okay
2812 multi-method method user host
2813 (format "cd %s" (tramp-shell-quote-argument
2814 (file-name-directory path)))
2815 nil 'file-error
2816 "Couldn't `cd %s'"
2817 (tramp-shell-quote-argument (file-name-directory path)))
2818 (tramp-send-command
2819 multi-method method user host
2820 (format "%s %s %s"
2821 (tramp-get-ls-command multi-method method user host)
2822 switches
2823 (if full-directory-p
2824 ;; Add "/." to make sure we got complete dir
2825 ;; listing for symlinks, too.
2826 (concat (file-name-as-directory
2827 (file-name-nondirectory path)) ".")
2828 (file-name-nondirectory path)))))
2829 (sit-for 1) ;needed for rsh but not ssh?
2830 (tramp-wait-for-output))
2831 (let ((old-pos (point)))
2832 (insert-buffer-substring
2833 (tramp-get-buffer multi-method method user host))
2834 ;; On XEmacs, we want to call (exchange-point-and-mark t), but
2835 ;; that doesn't exist on Emacs, so we use this workaround instead.
2836 ;; Since zmacs-region-stays doesn't exist in Emacs, this ought to
2837 ;; be safe. Thanks to Daniel Pittman <daniel@danann.net>.
2838 ;; (let ((zmacs-region-stays t))
2839 ;; (exchange-point-and-mark))
2840 (save-excursion
2841 (tramp-send-command multi-method method user host "cd")
2842 (tramp-wait-for-output))
2843 ;; Another XEmacs specialty follows. What's the right way to do
2844 ;; it?
2845 (when (and (featurep 'xemacs)
2846 (eq major-mode 'dired-mode))
2847 (save-excursion
2848 (require 'dired)
2849 (dired-insert-set-properties old-pos (point)))))))
2850
2851 ;; Continuation of kluge to pacify byte-compiler.
2852 ;;(eval-when-compile
2853 ;; (when (eq (symbol-function 'dired-insert-set-properties) 'ignore)
2854 ;; (fmakunbound 'dired-insert-set-properties)))
2855
2856 ;; CCC is this the right thing to do?
2857 (defun tramp-handle-unhandled-file-name-directory (filename)
2858 "Like `unhandled-file-name-directory' for tramp files."
2859 (with-parsed-tramp-file-name filename nil
2860 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2861 (tramp-invoke-ange-ftp 'unhandled-file-name-directory
2862 filename))
2863 (expand-file-name "~/")))
2864
2865 ;; Canonicalization of file names.
2866
2867 (defun tramp-drop-volume-letter (name)
2868 "Cut off unnecessary drive letter from file NAME.
2869 The function `tramp-handle-expand-file-name' calls `expand-file-name'
2870 locally on a remote file name. When the local system is a W32 system
2871 but the remote system is Unix, this introduces a superfluous drive
2872 letter into the file name. This function removes it.
2873
2874 Doesn't do anything if the NAME does not start with a drive letter."
2875 (if (and (> (length name) 1)
2876 (char-equal (aref name 1) ?:)
2877 (let ((c1 (aref name 0)))
2878 (or (and (>= c1 ?A) (<= c1 ?Z))
2879 (and (>= c1 ?a) (<= c1 ?z)))))
2880 (substring name 2)
2881 name))
2882
2883 (defun tramp-handle-expand-file-name (name &optional dir)
2884 "Like `expand-file-name' for tramp files."
2885 ;; If DIR is not given, use DEFAULT-DIRECTORY or "/".
2886 (setq dir (or dir default-directory "/"))
2887 ;; Unless NAME is absolute, concat DIR and NAME.
2888 (unless (file-name-absolute-p name)
2889 (setq name (concat (file-name-as-directory dir) name)))
2890 ;; If NAME is not a tramp file, run the real handler
2891 (if (not (tramp-tramp-file-p name))
2892 (tramp-run-real-handler 'expand-file-name
2893 (list name nil))
2894 ;; Dissect NAME.
2895 (with-parsed-tramp-file-name name nil
2896 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2897 (tramp-invoke-ange-ftp 'expand-file-name name nil))
2898 (unless (file-name-absolute-p path)
2899 (setq path (concat "~/" path)))
2900 (save-excursion
2901 ;; Tilde expansion if necessary. This needs a shell which
2902 ;; groks tilde expansion! The function `tramp-find-shell' is
2903 ;; supposed to find such a shell on the remote host. Please
2904 ;; tell me about it when this doesn't work on your system.
2905 (when (string-match "\\`\\(~[^/]*\\)\\(.*\\)\\'" path)
2906 (let ((uname (match-string 1 path))
2907 (fname (match-string 2 path)))
2908 ;; CCC fanatic error checking?
2909 (set-buffer (tramp-get-buffer multi-method method user host))
2910 (erase-buffer)
2911 (tramp-send-command
2912 multi-method method user host
2913 (format "cd %s; pwd" uname)
2914 t)
2915 (tramp-wait-for-output)
2916 (goto-char (point-min))
2917 (setq uname (buffer-substring (point) (tramp-line-end-position)))
2918 (setq path (concat uname fname))
2919 (erase-buffer)))
2920 ;; No tilde characters in file name, do normal
2921 ;; expand-file-name (this does "/./" and "/../"). We bind
2922 ;; directory-sep-char here for XEmacs on Windows, which would
2923 ;; otherwise use backslash.
2924 (let ((directory-sep-char ?/))
2925 (tramp-make-tramp-file-name
2926 multi-method method user host
2927 (tramp-drop-volume-letter
2928 (tramp-run-real-handler 'expand-file-name (list path)))))))))
2929
2930 ;; Remote commands.
2931
2932 (defun tramp-handle-shell-command (command &optional output-buffer error-buffer)
2933 "Like `shell-command' for tramp files.
2934 This will break if COMMAND prints a newline, followed by the value of
2935 `tramp-end-of-output', followed by another newline."
2936 (if (tramp-tramp-file-p default-directory)
2937 (with-parsed-tramp-file-name default-directory nil
2938 (when (tramp-ange-ftp-file-name-p multi-method method user host)
2939 (let ((default-directory (tramp-make-ange-ftp-file-name
2940 user host path)))
2941 (tramp-invoke-ange-ftp 'shell-command
2942 command output-buffer error-buffer)))
2943 (let (status)
2944 (when (string-match "&[ \t]*\\'" command)
2945 (error "Tramp doesn't grok asynchronous shell commands, yet"))
2946 (when error-buffer
2947 (error "Tramp doesn't grok optional third arg ERROR-BUFFER, yet"))
2948 (save-excursion
2949 (tramp-barf-unless-okay
2950 multi-method method user host
2951 (format "cd %s" (tramp-shell-quote-argument path))
2952 nil 'file-error
2953 "tramp-handle-shell-command: Couldn't `cd %s'"
2954 (tramp-shell-quote-argument path))
2955 (tramp-send-command multi-method method user host
2956 (concat command "; tramp_old_status=$?"))
2957 ;; This will break if the shell command prints "/////"
2958 ;; somewhere. Let's just hope for the best...
2959 (tramp-wait-for-output))
2960 (unless output-buffer
2961 (setq output-buffer (get-buffer-create "*Shell Command Output*"))
2962 (set-buffer output-buffer)
2963 (erase-buffer))
2964 (unless (bufferp output-buffer)
2965 (setq output-buffer (current-buffer)))
2966 (set-buffer output-buffer)
2967 (insert-buffer (tramp-get-buffer multi-method method user host))
2968 (save-excursion
2969 (tramp-send-command multi-method method user host "cd")
2970 (tramp-wait-for-output)
2971 (tramp-send-command
2972 multi-method method user host
2973 (concat "tramp_set_exit_status $tramp_old_status;"
2974 " echo tramp_exit_status $?"))
2975 (tramp-wait-for-output)
2976 (goto-char (point-max))
2977 (unless (search-backward "tramp_exit_status " nil t)
2978 (error "Couldn't find exit status of `%s'" command))
2979 (skip-chars-forward "^ ")
2980 (setq status (read (current-buffer))))
2981 (unless (zerop (buffer-size))
2982 (pop-to-buffer output-buffer))
2983 status))
2984 ;; The following is only executed if something strange was
2985 ;; happening. Emit a helpful message and do it anyway.
2986 (message "tramp-handle-shell-command called with non-tramp directory: `%s'"
2987 default-directory)
2988 (tramp-run-real-handler 'shell-command
2989 (list command output-buffer error-buffer))))
2990
2991 ;; File Editing.
2992
2993 (defsubst tramp-make-temp-file ()
2994 (funcall (if (fboundp 'make-temp-file) 'make-temp-file 'make-temp-name)
2995 (expand-file-name tramp-temp-name-prefix
2996 (tramp-temporary-file-directory))))
2997
2998 (defun tramp-handle-file-local-copy (filename)
2999 "Like `file-local-copy' for tramp files."
3000 (with-parsed-tramp-file-name filename nil
3001 (when (tramp-ange-ftp-file-name-p multi-method method user host)
3002 (tramp-invoke-ange-ftp 'file-local-copy filename))
3003 (let ((output-buf (get-buffer-create "*tramp output*"))
3004 (tramp-buf (tramp-get-buffer multi-method method user host))
3005 (rcp-program (tramp-get-rcp-program
3006 multi-method
3007 (tramp-find-method multi-method method user host)
3008 user host))
3009 (rcp-args (tramp-get-rcp-args
3010 multi-method
3011 (tramp-find-method multi-method method user host)
3012 user host))
3013 ;; We used to bind the following as late as possible.
3014 ;; loc-enc and loc-dec were bound directly before the if
3015 ;; statement that checks them. But the functions
3016 ;; tramp-get-* might invoke the "are you awake" check in
3017 ;; tramp-maybe-open-connection, which is an unfortunate time
3018 ;; since we rely on the buffer contents at that spot.
3019 (rem-enc (tramp-get-remote-encoding multi-method method user host))
3020 (rem-dec (tramp-get-remote-decoding multi-method method user host))
3021 (loc-enc (tramp-get-local-encoding multi-method method user host))
3022 (loc-dec (tramp-get-local-decoding multi-method method user host))
3023 tmpfil)
3024 (unless (file-exists-p filename)
3025 (error "Cannot make local copy of non-existing file `%s'"
3026 filename))
3027 (setq tmpfil (tramp-make-temp-file))
3028 (cond (rcp-program
3029 ;; Use rcp-like program for file transfer.
3030 (tramp-message-for-buffer
3031 multi-method method user host
3032 5 "Fetching %s to tmp file %s..." filename tmpfil)
3033 (save-excursion (set-buffer output-buf) (erase-buffer))
3034 (unless (equal
3035 0
3036 (apply #'call-process
3037 rcp-program
3038 nil output-buf nil
3039 (append rcp-args
3040 (list
3041 (tramp-make-rcp-program-file-name
3042 user host
3043 (tramp-shell-quote-argument path))
3044 tmpfil))))
3045 (pop-to-buffer output-buf)
3046 (error
3047 (concat "tramp-handle-file-local-copy: `%s' didn't work, "
3048 "see buffer `%s' for details")
3049 rcp-program output-buf))
3050 (tramp-message-for-buffer
3051 multi-method method user host
3052 5 "Fetching %s to tmp file %s...done" filename tmpfil))
3053 ((and rem-enc rem-dec)
3054 ;; Use inline encoding for file transfer.
3055 (save-excursion
3056 ;; Following line for setting tramp-current-method,
3057 ;; tramp-current-user, tramp-current-host.
3058 (set-buffer tramp-buf)
3059 (tramp-message 5 "Encoding remote file %s..." filename)
3060 (tramp-barf-unless-okay
3061 multi-method method user host
3062 (concat rem-enc " < " (tramp-shell-quote-argument path))
3063 nil 'file-error
3064 "Encoding remote file failed, see buffer `%s' for details"
3065 tramp-buf)
3066 ;; Remove trailing status code
3067 (goto-char (point-max))
3068 (delete-region (point) (progn (forward-line -1) (point)))
3069
3070 (tramp-message 5 "Decoding remote file %s..." filename)
3071
3072 ;; Here is where loc-enc and loc-dec used to be let-bound.
3073 (if (and (symbolp loc-dec) (fboundp loc-dec))
3074 ;; If local decoding is a function, we call it.
3075 (let ((tmpbuf (get-buffer-create " *tramp tmp*")))
3076 (set-buffer tmpbuf)
3077 (erase-buffer)
3078 (insert-buffer tramp-buf)
3079 (tramp-message-for-buffer
3080 multi-method method user host
3081 6 "Decoding remote file %s with function %s..."
3082 filename loc-dec)
3083 (set-buffer tmpbuf)
3084 ;; Douglas Gray Stephens <DGrayStephens@slb.com>
3085 ;; says that we need to strip tramp_exit_status
3086 ;; line from the output here. Go to point-max,
3087 ;; search backward for tramp_exit_status, delete
3088 ;; between point and point-max if found.
3089 (let ((coding-system-for-write 'no-conversion))
3090 (funcall loc-dec (point-min) (point-max))
3091 (write-region (point-min) (point-max) tmpfil))
3092 (kill-buffer tmpbuf))
3093 ;; If tramp-decoding-function is not defined for this
3094 ;; method, we invoke tramp-decoding-command instead.
3095 (let ((tmpfil2 (tramp-make-temp-file)))
3096 (write-region (point-min) (point-max) tmpfil2)
3097 (tramp-message
3098 6 "Decoding remote file %s with command %s..."
3099 filename loc-dec)
3100 (tramp-call-local-coding-command
3101 loc-dec tmpfil2 tmpfil)
3102 (delete-file tmpfil2)))
3103 (tramp-message-for-buffer
3104 multi-method method user host
3105 5 "Decoding remote file %s...done" filename)))
3106
3107 (t (error "Wrong method specification for `%s'" method)))
3108 tmpfil)))
3109
3110
3111 (defun tramp-handle-insert-file-contents
3112 (filename &optional visit beg end replace)
3113 "Like `insert-file-contents' for tramp files."
3114 (barf-if-buffer-read-only)
3115 (setq filename (expand-file-name filename))
3116 (with-parsed-tramp-file-name filename nil
3117 (when (tramp-ange-ftp-file-name-p multi-method method user host)
3118 (tramp-invoke-ange-ftp 'insert-file-contents
3119 filename visit beg end replace))
3120 (if (not (tramp-handle-file-exists-p filename))
3121 (progn
3122 (when visit
3123 (setq buffer-file-name filename)
3124 (set-visited-file-modtime)
3125 (set-buffer-modified-p nil))
3126 (signal 'file-error
3127 (format "File `%s' not found on remote host" filename))
3128 (list (tramp-handle-expand-file-name filename) 0))
3129 (let ((local-copy (tramp-handle-file-local-copy filename))
3130 (coding-system-used nil)
3131 (result nil))
3132 (when visit
3133 (setq buffer-file-name filename)
3134 (set-visited-file-modtime)
3135 (set-buffer-modified-p nil))
3136 (tramp-message-for-buffer
3137 multi-method method user host
3138 9 "Inserting local temp file `%s'..." local-copy)
3139 (setq result
3140 (tramp-run-real-handler 'insert-file-contents
3141 (list local-copy nil beg end replace)))
3142 ;; Now `last-coding-system-used' has right value. Remember it.
3143 (when (boundp 'last-coding-system-used)
3144 (setq coding-system-used last-coding-system-used))
3145 (tramp-message-for-buffer
3146 multi-method method user host
3147 9 "Inserting local temp file `%s'...done" local-copy)
3148 (delete-file local-copy)
3149 (when (boundp 'last-coding-system-used)
3150 (setq last-coding-system-used coding-system-used))
3151 (list (expand-file-name filename)
3152 (second result))))))
3153
3154 ;; CCC grok APPEND, LOCKNAME, CONFIRM
3155 (defun tramp-handle-write-region
3156 (start end filename &optional append visit lockname confirm)
3157 "Like `write-region' for tramp files."
3158 (unless (eq append nil)
3159 (error "Cannot append to file using tramp (`%s')" filename))
3160 (setq filename (expand-file-name filename))
3161 ;; Following part commented out because we don't know what to do about
3162 ;; file locking, and it does not appear to be a problem to ignore it.
3163 ;; Ange-ftp ignores it, too.
3164 ;; (when (and lockname (stringp lockname))
3165 ;; (setq lockname (expand-file-name lockname)))
3166 ;; (unless (or (eq lockname nil)
3167 ;; (string= lockname filename))
3168 ;; (error
3169 ;; "tramp-handle-write-region: LOCKNAME must be nil or equal FILENAME"))
3170 ;; XEmacs takes a coding system as the sevent argument, not `confirm'
3171 (when (and (not (featurep 'xemacs))
3172 confirm (file-exists-p filename))
3173 (unless (y-or-n-p (format "File %s exists; overwrite anyway? "
3174 filename))
3175 (error "File not overwritten")))
3176 (with-parsed-tramp-file-name filename nil
3177 (when (tramp-ange-ftp-file-name-p multi-method method user host)
3178 (tramp-invoke-ange-ftp 'write-region
3179 start end filename append visit))
3180 (let ((curbuf (current-buffer))
3181 (rcp-program (tramp-get-rcp-program
3182 multi-method (tramp-find-method multi-method method user host)
3183 user host))
3184 (rcp-args (tramp-get-rcp-args
3185 multi-method
3186 (tramp-find-method multi-method method user host)
3187 user host))
3188 (rem-enc (tramp-get-remote-encoding multi-method method user host))
3189 (rem-dec (tramp-get-remote-decoding multi-method method user host))
3190 (loc-enc (tramp-get-local-encoding multi-method method user host))
3191 (loc-dec (tramp-get-local-decoding multi-method method user host))
3192 (trampbuf (get-buffer-create "*tramp output*"))
3193 ;; We use this to save the value of `last-coding-system-used'
3194 ;; after writing the tmp file. At the end of the function,
3195 ;; we set `last-coding-system-used' to this saved value.
3196 ;; This way, any intermediary coding systems used while
3197 ;; talking to the remote shell or suchlike won't hose this
3198 ;; variable. This approach was snarfed from ange-ftp.el.
3199 coding-system-used
3200 tmpfil)
3201 ;; Write region into a tmp file. This isn't really needed if we
3202 ;; use an encoding function, but currently we use it always
3203 ;; because this makes the logic simpler.
3204 (setq tmpfil (tramp-make-temp-file))
3205 ;; We say `no-message' here because we don't want the visited file
3206 ;; modtime data to be clobbered from the temp file. We call
3207 ;; `set-visited-file-modtime' ourselves later on.
3208 (tramp-run-real-handler
3209 'write-region
3210 (if confirm ; don't pass this arg unless defined for backward compat.
3211 (list start end tmpfil append 'no-message lockname confirm)
3212 (list start end tmpfil append 'no-message lockname)))
3213 ;; Now, `last-coding-system-used' has the right value. Remember it.
3214 (when (boundp 'last-coding-system-used)
3215 (setq coding-system-used last-coding-system-used))
3216 ;; This is a bit lengthy due to the different methods possible for
3217 ;; file transfer. First, we check whether the method uses an rcp
3218 ;; program. If so, we call it. Otherwise, both encoding and
3219 ;; decoding command must be specified. However, if the method
3220 ;; _also_ specifies an encoding function, then that is used for
3221 ;; encoding the contents of the tmp file.
3222 (cond (rcp-program
3223 ;; use rcp-like program for file transfer
3224 (let ((argl (append rcp-args
3225 (list
3226 tmpfil
3227 (tramp-make-rcp-program-file-name
3228 user host
3229 (tramp-shell-quote-argument path))))))
3230 (tramp-message-for-buffer
3231 multi-method method user host
3232 6 "Writing tmp file using `%s'..." rcp-program)
3233 (save-excursion (set-buffer trampbuf) (erase-buffer))
3234 (when tramp-debug-buffer
3235 (save-excursion
3236 (set-buffer (tramp-get-debug-buffer multi-method
3237 method user host))
3238 (goto-char (point-max))
3239 (tramp-insert-with-face
3240 'bold (format "$ %s %s\n" rcp-program
3241 (mapconcat 'identity argl " ")))))
3242 (unless (equal 0
3243 (apply #'call-process
3244 rcp-program nil trampbuf nil argl))
3245 (pop-to-buffer trampbuf)
3246 (error
3247 "Cannot write region to file `%s', command `%s' failed"
3248 filename rcp-program))
3249 (tramp-message-for-buffer
3250 multi-method method user host
3251 6 "Transferring file using `%s'...done"
3252 rcp-program)))
3253 ((and rem-enc rem-dec)
3254 ;; Use inline file transfer
3255 (let ((tmpbuf (get-buffer-create " *tramp file transfer*")))
3256 (save-excursion
3257 ;; Encode tmpfil into tmpbuf
3258 (tramp-message-for-buffer multi-method method user host
3259 5 "Encoding region...")
3260 (set-buffer tmpbuf)
3261 (erase-buffer)
3262 ;; Use encoding function or command.
3263 (if (and (symbolp loc-enc) (fboundp loc-enc))
3264 (progn
3265 (tramp-message-for-buffer
3266 multi-method method user host
3267 6 "Encoding region using function...")
3268 (insert-file-contents-literally tmpfil)
3269 ;; CCC. The following `let' is a workaround for
3270 ;; the base64.el that comes with pgnus-0.84. If
3271 ;; both of the following conditions are
3272 ;; satisfied, it tries to write to a local file
3273 ;; in default-directory, but at this point,
3274 ;; default-directory is remote.
3275 ;; (CALL-PROCESS-REGION can't write to remote
3276 ;; files, it seems.) The file in question is a
3277 ;; tmp file anyway.
3278 (let ((default-directory
3279 (tramp-temporary-file-directory)))
3280 (funcall loc-enc (point-min) (point-max)))
3281 (goto-char (point-max))
3282 (unless (bolp)
3283 (newline)))
3284 (tramp-message-for-buffer
3285 multi-method method user host
3286 6 "Encoding region using command `%s'..." loc-enc)
3287 (unless (equal 0 (tramp-call-local-coding-command
3288 loc-enc tmpfil t))
3289 (pop-to-buffer trampbuf)
3290 (error (concat "Cannot write to `%s', local encoding"
3291 " command `%s' failed")
3292 filename loc-enc)))
3293 ;; Send tmpbuf into remote decoding command which
3294 ;; writes to remote file. Because this happens on the
3295 ;; remote host, we cannot use the function.
3296 (tramp-message-for-buffer
3297 multi-method method user host
3298 5 "Decoding region into remote file %s..." filename)
3299 (tramp-send-command
3300 multi-method method user host
3301 (format "%s >%s <<'EOF'"
3302 rem-dec
3303 (tramp-shell-quote-argument path)))
3304 (set-buffer tmpbuf)
3305 (tramp-message-for-buffer
3306 multi-method method user host
3307 6 "Sending data to remote host...")
3308 (tramp-send-region multi-method method user host
3309 (point-min) (point-max))
3310 ;; wait for remote decoding to complete
3311 (tramp-message-for-buffer
3312 multi-method method user host
3313 6 "Sending end of data token...")
3314 (tramp-send-command
3315 multi-method method user host "EOF" nil t)
3316 (tramp-message-for-buffer
3317 multi-method method user host 6
3318 "Waiting for remote host to process data...")
3319 (set-buffer (tramp-get-buffer multi-method method user host))
3320 (tramp-wait-for-output)
3321 (tramp-barf-unless-okay
3322 multi-method method user host nil nil 'file-error
3323 (concat "Couldn't write region to `%s',"
3324 " decode using `%s' failed")
3325 filename rem-dec)
3326 (tramp-message 5 "Decoding region into remote file %s...done"
3327 filename)
3328 (kill-buffer tmpbuf))))
3329 (t
3330 (error
3331 (concat "Method `%s' should specify both encoding and "
3332 "decoding command or an rcp program")
3333 method)))
3334 (delete-file tmpfil)
3335 (unless (equal curbuf (current-buffer))
3336 (error "Buffer has changed from `%s' to `%s'"
3337 curbuf (current-buffer)))
3338 (when (eq visit t)
3339 (set-visited-file-modtime))
3340 ;; Make `last-coding-system-used' have the right value.
3341 (when (boundp 'last-coding-system-used)
3342 (setq last-coding-system-used coding-system-used))
3343 (when (or (eq visit t)
3344 (eq visit nil)
3345 (stringp visit))
3346 (message "Wrote %s" filename)))))
3347
3348 ;; Call down to the real handler.
3349 ;; Because EFS does not play nicely with TRAMP (both systems match an
3350 ;; TRAMP path) it is needed to disable efs as well as tramp for the
3351 ;; operation.
3352 ;;
3353 ;; Other than that, this is the canon file-handler code that the doco
3354 ;; says should be used here. Which is nice.
3355 ;;
3356 ;; Under XEmacs current, EFS also hooks in as
3357 ;; efs-sifn-handler-function to handle any path with environment
3358 ;; variables. This has two implications:
3359 ;; 1) That EFS may not be completely dead (yet) for TRAMP paths
3360 ;; 2) That TRAMP might want to do the same thing.
3361 ;; Details as they come in.
3362 ;;
3363 ;; Daniel Pittman <daniel@danann.net>
3364
3365 ;; (defun tramp-run-real-handler (operation args)
3366 ;; "Invoke normal file name handler for OPERATION.
3367 ;; This inhibits EFS and Ange-FTP, too, because they conflict with tramp.
3368 ;; First arg specifies the OPERATION, remaining ARGS are passed to the
3369 ;; OPERATION."
3370 ;; (let ((inhibit-file-name-handlers
3371 ;; (list 'tramp-file-name-handler
3372 ;; 'efs-file-handler-function
3373 ;; 'ange-ftp-hook-function
3374 ;; (and (eq inhibit-file-name-operation operation)
3375 ;; inhibit-file-name-handlers)))
3376 ;; (inhibit-file-name-operation operation))
3377 ;; (apply operation args)))
3378
3379 (defun tramp-run-real-handler (operation args)
3380 "Invoke normal file name handler for OPERATION.
3381 First arg specifies the OPERATION, second arg is a list of arguments to
3382 pass to the OPERATION."
3383 (let* ((op (if (eq operation 'ange-ftp-hook-function)
3384 (car args)
3385 operation))
3386 (inhibit-file-name-handlers
3387 (list 'tramp-file-name-handler
3388 'tramp-completion-file-name-handler
3389 (and (eq inhibit-file-name-operation op)
3390 inhibit-file-name-handlers)))
3391 (inhibit-file-name-operation op))
3392 (apply operation args)))
3393
3394 ;; This function is used from `tramp-completion-file-name-handler' functions
3395 ;; only, if `tramp-completion-mode' is true. But this cannot be checked here
3396 ;; because the check is based on a full filename, not available for all
3397 ;; basic I/O operations.
3398 (defun tramp-completion-run-real-handler (operation args)
3399 "Invoke `tramp-file-name-handler' for OPERATION.
3400 First arg specifies the OPERATION, second arg is a list of arguments to
3401 pass to the OPERATION."
3402 (let* ((op (if (eq operation 'ange-ftp-hook-function)
3403 (car args)
3404 operation))
3405 (inhibit-file-name-handlers
3406 (list 'tramp-completion-file-name-handler
3407 (and (eq inhibit-file-name-operation op)
3408 inhibit-file-name-handlers)))
3409 (inhibit-file-name-operation op))
3410 (apply operation args)))
3411
3412 ;; Main function.
3413 ;;;###autoload
3414 (defun tramp-file-name-handler (operation &rest args)
3415 "Invoke tramp file name handler.
3416 Falls back to normal file name handler if no tramp file name handler exists."
3417 (let ((fn (assoc operation tramp-file-name-handler-alist)))
3418 (if fn
3419 (catch 'tramp-forward-to-ange-ftp
3420 (save-match-data (apply (cdr fn) args)))
3421 (tramp-run-real-handler operation args))))
3422
3423 (put 'tramp-file-name-handler 'file-remote-p t) ;for file-remote-p
3424
3425 ;;;###autoload
3426 (defun tramp-completion-file-name-handler (operation &rest args)
3427 "Invoke tramp file name completion handler.
3428 Falls back to normal file name handler if no tramp file name handler exists."
3429 ;; (setq tramp-debug-buffer t)
3430 ;; (tramp-message 1 "%s %s" operation args)
3431 ;; (tramp-message 1 "%s %s\n%s"
3432 ;; operation args (with-output-to-string (backtrace)))
3433 (let ((fn (assoc operation tramp-completion-file-name-handler-alist)))
3434 (if fn
3435 (catch 'tramp-forward-to-ange-ftp
3436 (save-match-data (apply (cdr fn) args)))
3437 (tramp-completion-run-real-handler operation args))))
3438
3439 ;; Register in file name handler alist
3440 ;;;###autoload
3441 (add-to-list 'file-name-handler-alist
3442 (cons tramp-file-name-regexp 'tramp-file-name-handler))
3443 (add-to-list 'file-name-handler-alist
3444 (cons tramp-completion-file-name-regexp
3445 'tramp-completion-file-name-handler))
3446
3447 ;; To handle EFS, the following functions need to be dealt with:
3448 ;;
3449 ;; * dired-before-readin-hook contains efs-dired-before-readin
3450 ;; * file-name-handler-alist contains efs-file-handler-function
3451 ;; and efs-root-handler-function and efs-sifn-handler-function
3452 ;; * find-file-hooks contains efs-set-buffer-mode
3453 ;;
3454 ;; But it won't happen for EFS since the XEmacs maintainers
3455 ;; don't want to use a unified filename syntax.
3456 (defun tramp-disable-ange-ftp ()
3457 "Turn Ange-FTP off.
3458 This is useful for unified remoting. See
3459 `tramp-file-name-structure-unified' and
3460 `tramp-file-name-structure-separate' for details. Requests suitable
3461 for Ange-FTP will be forwarded to Ange-FTP. Also see the variables
3462 `tramp-ftp-method', `tramp-default-method', and
3463 `tramp-default-method-alist'.
3464
3465 This function is not needed in Emacsen which include Tramp, but is
3466 present for backward compatibility."
3467 (let ((a1 (rassq 'ange-ftp-hook-function file-name-handler-alist))
3468 (a2 (rassq 'ange-ftp-completion-hook-function file-name-handler-alist)))
3469 (setq file-name-handler-alist
3470 (delete a1 (delete a2 file-name-handler-alist)))))
3471 (tramp-disable-ange-ftp)
3472
3473 (defun tramp-repair-jka-compr ()
3474 "If jka-compr is already loaded, move it to the front of
3475 `file-name-handler-alist'. On Emacs 21.4 or so this will not be
3476 necessary anymore."
3477 (let ((jka (rassoc 'jka-compr-handler file-name-handler-alist)))
3478 (when jka
3479 (setq file-name-handler-alist
3480 (cons jka (delete jka file-name-handler-alist))))))
3481 (tramp-repair-jka-compr)
3482
3483 (defun tramp-flatten-list (arg)
3484 "Expands all lists inside ARG to a sequential list.
3485 Return (nil) if arg is nil."
3486 (let ((car (car arg))
3487 (cdr (cdr arg)))
3488 (cond
3489 ((eq arg nil) '(nil))
3490 ((listp car)
3491 (if (null cdr)
3492 (tramp-flatten-list car)
3493 (append (tramp-flatten-list car) (tramp-flatten-list cdr))))
3494 ((null cdr) (list car))
3495 (t (cons car (tramp-flatten-list cdr))))))
3496
3497 (defun tramp-invoke-ange-ftp (operation &rest args)
3498 "Invoke the Ange-FTP handler function and throw."
3499 (or (boundp 'ange-ftp-name-format)
3500 (and (require 'ange-ftp)
3501 (tramp-disable-ange-ftp)))
3502 (let ((ange-ftp-name-format
3503 (list (nth 0 tramp-file-name-structure)
3504 (nth 3 tramp-file-name-structure)
3505 (nth 2 tramp-file-name-structure)
3506 (nth 4 tramp-file-name-structure))))
3507 (throw 'tramp-forward-to-ange-ftp
3508 (tramp-run-real-handler 'ange-ftp-hook-function
3509 (cons operation args)))))
3510
3511 (defun tramp-ange-ftp-file-name-p (multi-method method user host)
3512 "Check if it's a filename that should be forwarded to Ange-FTP."
3513 (and tramp-unified-filenames
3514 (null multi-method)
3515 (string= (tramp-find-method multi-method method user host) tramp-ftp-method)))
3516
3517
3518 ;;; Interactions with other packages:
3519
3520 ;; -- complete.el --
3521
3522 ;; This function contributed by Ed Sabol
3523 (defun tramp-handle-expand-many-files (name)
3524 "Like `PC-expand-many-files' for tramp files."
3525 (with-parsed-tramp-file-name name nil
3526 (when (tramp-ange-ftp-file-name-p multi-method method user host)
3527 (tramp-invoke-ange-ftp 'expand-many-files name))
3528 (save-match-data
3529 (if (or (string-match "\\*" name)
3530 (string-match "\\?" name)
3531 (string-match "\\[.*\\]" name))
3532 (save-excursion
3533 (let (bufstr)
3534 ;; CCC: To do it right, we should quote certain characters
3535 ;; in the file name, but since the echo command is going to
3536 ;; break anyway when there are spaces in the file names, we
3537 ;; don't bother.
3538 ;;-(let ((comint-file-name-quote-list
3539 ;;- (set-difference tramp-file-name-quote-list
3540 ;;- '(?\* ?\? ?[ ?]))))
3541 ;;- (tramp-send-command
3542 ;;- multi-method method user host
3543 ;;- (format "echo %s" (comint-quote-filename path)))
3544 ;;- (tramp-wait-for-output))
3545 (tramp-send-command multi-method method user host
3546 (format "echo %s" path))
3547 (tramp-wait-for-output)
3548 (setq bufstr (buffer-substring (point-min)
3549 (tramp-line-end-position)))
3550 (goto-char (point-min))
3551 (if (string-equal path bufstr)
3552 nil
3553 (insert "(\"")
3554 (while (search-forward " " nil t)
3555 (delete-backward-char 1)
3556 (insert "\" \""))
3557 (goto-char (point-max))
3558 (delete-backward-char 1)
3559 (insert "\")")
3560 (goto-char (point-min))
3561 (mapcar
3562 (function (lambda (x)
3563 (tramp-make-tramp-file-name multi-method method
3564 user host x)))
3565 (read (current-buffer))))))
3566 (list (tramp-handle-expand-file-name name))))))
3567
3568 ;; Check for complete.el and override PC-expand-many-files if appropriate.
3569 (eval-when-compile
3570 (defun tramp-save-PC-expand-many-files (name))); avoid compiler warning
3571
3572 (defun tramp-setup-complete ()
3573 (fset 'tramp-save-PC-expand-many-files
3574 (symbol-function 'PC-expand-many-files))
3575 (defun PC-expand-many-files (name)
3576 (if (tramp-tramp-file-p name)
3577 (tramp-handle-expand-many-files name)
3578 (tramp-save-PC-expand-many-files name))))
3579
3580 ;; Why isn't eval-after-load sufficient?
3581 (if (fboundp 'PC-expand-many-files)
3582 (tramp-setup-complete)
3583 (eval-after-load "complete" '(tramp-setup-complete)))
3584
3585 ;;; File name handler functions for completion mode
3586
3587 ;; Necessary because `tramp-file-name-regexp-unified' and
3588 ;; `tramp-completion-file-name-regexp-unified' aren't different.
3589 ;; If nil, `tramp-completion-run-real-handler' is called (i.e. forwarding to
3590 ;; `tramp-file-name-handler'). Otherwise, it takes `tramp-run-real-handler'.
3591 ;; Using `last-input-event' is a little bit risky, because completing a file
3592 ;; might require loading other files, like "~/.netrc", and for them it
3593 ;; shouldn't be decided based on that variable. On the other hand, those files
3594 ;; shouldn't have partial tramp file name syntax. Maybe another variable should
3595 ;; be introduced overwriting this check in such cases. Or we change tramp
3596 ;; file name syntax in order to avoid ambiguities, like in XEmacs ...
3597 ;; In case of XEmacs it can be always true (and wouldn't be necessary).
3598 (defun tramp-completion-mode (file)
3599 "Checks whether method / user name / host name completion is active."
3600 (cond
3601 ((featurep 'xemacs) t)
3602 ((string-match "^/.*:.*:$" file) nil)
3603 ((string-match
3604 (concat tramp-prefix-regexp
3605 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp "$")
3606 file)
3607 (member (match-string 1 file)
3608 (cons tramp-ftp-method (mapcar 'car tramp-methods))))
3609 ((or (equal last-input-event 'tab)
3610 (and (not (event-modifiers last-input-event))
3611 (integerp last-input-event)
3612 (or (char-equal last-input-event ?\?)
3613 (char-equal last-input-event ?\t) ; handled by 'tab already?
3614 (char-equal last-input-event ?\ ))))
3615 t)))
3616
3617 (defun tramp-completion-handle-file-exists-p (filename)
3618 "Like `file-exists-p' for tramp files."
3619 (if (tramp-completion-mode filename)
3620 (tramp-run-real-handler
3621 'file-exists-p (list filename))
3622 (tramp-completion-run-real-handler
3623 'file-exists-p (list filename))))
3624
3625 ;; Path manipulation in case of partial TRAMP file names.
3626 (defun tramp-completion-handle-file-name-directory (file)
3627 "Like `file-name-directory' but aware of TRAMP files."
3628 (if (tramp-completion-mode file)
3629 "/"
3630 (tramp-completion-run-real-handler
3631 'file-name-directory (list file))))
3632
3633 ;; Path manipulation in case of partial TRAMP file names.
3634 (defun tramp-completion-handle-file-name-nondirectory (file)
3635 "Like `file-name-nondirectory' but aware of TRAMP files."
3636 (substring
3637 file (length (tramp-completion-handle-file-name-directory file))))
3638
3639 ;; Method, host name and user name completion.
3640 ;; `tramp-completion-dissect-file-name' returns a list of
3641 ;; tramp-file-name structures. For all of them we return possible completions.
3642 (defun tramp-completion-handle-file-name-all-completions (filename directory)
3643 "Like `file-name-all-completions' for partial tramp files."
3644
3645 (let*
3646 ((fullname (concat directory filename))
3647 ;; local files
3648 (result
3649 (if (tramp-completion-mode fullname)
3650 (tramp-run-real-handler
3651 'file-name-all-completions (list filename directory))
3652 (tramp-completion-run-real-handler
3653 'file-name-all-completions (list filename directory))))
3654 ;; possible completion structures
3655 (v (tramp-completion-dissect-file-name fullname)))
3656
3657 (while v
3658 (let* ((car (car v))
3659 (multi-method (tramp-file-name-multi-method car))
3660 (method (tramp-file-name-method car))
3661 (user (tramp-file-name-user car))
3662 (host (tramp-file-name-host car))
3663 (path (tramp-file-name-path car))
3664 (m (tramp-find-method multi-method method user host))
3665 all-user-hosts)
3666
3667 (unless (or multi-method ;; Not handled (yet).
3668 path) ;; Nothing to complete
3669
3670 (if (or user host)
3671
3672 ;; Method dependent user / host combinations
3673 (progn
3674 (mapcar
3675 '(lambda (x)
3676 (setq all-user-hosts
3677 (append all-user-hosts
3678 (funcall (nth 0 x) (nth 1 x)))))
3679 (tramp-get-completion-function m))
3680
3681 (setq result (append result
3682 (mapcar
3683 '(lambda (x)
3684 (tramp-get-completion-user-host
3685 method user host (nth 0 x) (nth 1 x)))
3686 (delq nil all-user-hosts)))))
3687
3688 ;; Possible methods
3689 (setq result
3690 (append result (tramp-get-completion-methods m)))))
3691
3692 (setq v (delq car v))))
3693
3694 ;;; unify list, remove nil elements
3695 (let (result1)
3696 (while result
3697 (let ((car (car result)))
3698 (when car (add-to-list 'result1 car))
3699 (setq result (delq car result))))
3700
3701 result1)))
3702
3703 ;; Method, host name and user name completion for a file.
3704 (defun tramp-completion-handle-file-name-completion (filename directory)
3705 "Like `file-name-completion' for tramp files."
3706 (try-completion filename
3707 (mapcar 'list (file-name-all-completions filename directory))))
3708
3709 ;; I misuse a little bit the tramp-file-name structure in order to handle
3710 ;; completion possibilities for partial methods / user names / host names.
3711 ;; Return value is a list of tramp-file-name structures according to possible
3712 ;; completions. If "multi-method" or "path" is non-nil it means there
3713 ;; shouldn't be a completion anymore.
3714
3715 ;; Expected results:
3716
3717 ;; "/x" "/[x" "/x@" "/[x@" "/x@y" "/[x@y"
3718 ;; [nil nil nil "x" nil] [nil nil "x" nil nil] [nil nil "x" "y" nil]
3719 ;; [nil nil "x" nil nil]
3720 ;; [nil "x" nil nil nil]
3721
3722 ;; "/x:" "/x:y" "/x:y:"
3723 ;; [nil nil nil "x" ""] [nil nil nil "x" "y"] [nil "x" nil "y" ""]
3724 ;; "/[x/" "/[x/y"
3725 ;; [nil "x" nil "" nil] [nil "x" nil "y" nil]
3726 ;; [nil "x" "" nil nil] [nil "x" "y" nil nil]
3727
3728 ;; "/x:y@" "/x:y@z" "/x:y@z:"
3729 ;; [nil nil nil "x" "y@"] [nil nil nil "x" "y@z"] [nil "x" "y" "z" ""]
3730 ;; "/[x/y@" "/[x/y@z"
3731 ;; [nil "x" nil "y" nil] [nil "x" "y" "z" nil]
3732 (defun tramp-completion-dissect-file-name (name)
3733 "Returns a list of `tramp-file-name' structures.
3734 They are collected by `tramp-completion-dissect-file-name1'."
3735
3736 (let* ((result)
3737 (x-nil "\\|\\(\\)"))
3738
3739 ;; "/method" "/[method"
3740 (defconst tramp-completion-file-name-structure1
3741 (list (concat tramp-prefix-regexp "\\(" tramp-method-regexp x-nil "\\)$")
3742 1 9 9 9))
3743 ;; "/user" "/[user"
3744 (defconst tramp-completion-file-name-structure2
3745 (list (concat tramp-prefix-regexp "\\(" tramp-user-regexp x-nil "\\)$")
3746 9 1 9 9))
3747 ;; "/host" "/[host"
3748 (defconst tramp-completion-file-name-structure3
3749 (list (concat tramp-prefix-regexp "\\(" tramp-host-regexp x-nil "\\)$")
3750 9 9 1 9))
3751 ;; "/user@host" "/[user@host"
3752 (defconst tramp-completion-file-name-structure4
3753 (list (concat tramp-prefix-regexp
3754 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
3755 "\\(" tramp-host-regexp x-nil "\\)$")
3756 9 1 2 9))
3757 ;; "/method:user" "/[method/user"
3758 (defconst tramp-completion-file-name-structure5
3759 (list (concat tramp-prefix-regexp
3760 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp
3761 "\\(" tramp-user-regexp x-nil "\\)$")
3762 1 2 9 9))
3763 ;; "/method:host" "/[method/host"
3764 (defconst tramp-completion-file-name-structure6
3765 (list (concat tramp-prefix-regexp
3766 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp
3767 "\\(" tramp-host-regexp x-nil "\\)$")
3768 1 9 2 9))
3769 ;; "/method:user@host" "/[method/user@host"
3770 (defconst tramp-completion-file-name-structure7
3771 (list (concat tramp-prefix-regexp
3772 "\\(" tramp-method-regexp "\\)" tramp-postfix-single-method-regexp
3773 "\\(" tramp-user-regexp "\\)" tramp-postfix-user-regexp
3774 "\\(" tramp-host-regexp x-nil "\\)$")
3775 1 2 3 9))
3776
3777 (mapcar '(lambda (regexp)
3778 (add-to-list 'result
3779 (tramp-completion-dissect-file-name1 regexp name)))
3780 (list
3781 tramp-completion-file-name-structure1
3782 tramp-completion-file-name-structure2
3783 tramp-completion-file-name-structure3
3784 tramp-completion-file-name-structure4
3785 tramp-completion-file-name-structure5
3786 tramp-completion-file-name-structure6
3787 tramp-completion-file-name-structure7
3788 tramp-file-name-structure))
3789
3790 (delq nil result)))
3791
3792 (defun tramp-completion-dissect-file-name1 (structure name)
3793 "Returns a `tramp-file-name' structure matching STRUCTURE.
3794 The structure consists of multi-method, remote method, remote user,
3795 remote host and remote path name."
3796
3797 (let (method)
3798 (save-match-data
3799 (when (string-match (nth 0 structure) name)
3800 (setq method (match-string (nth 1 structure) name))
3801 (if (and method (member method tramp-multi-methods))
3802 ;; Not handled (yet).
3803 (make-tramp-file-name
3804 :multi-method method
3805 :method nil
3806 :user nil
3807 :host nil
3808 :path nil)
3809 (let ((user (match-string (nth 2 structure) name))
3810 (host (match-string (nth 3 structure) name))
3811 (path (match-string (nth 4 structure) name)))
3812 (make-tramp-file-name
3813 :multi-method nil
3814 :method method
3815 :user user
3816 :host host
3817 :path path)))))))
3818
3819 ;; This function returns all possible method completions, adding the
3820 ;; trailing method delimeter.
3821 ;; In case of Emacs, `tramp-ftp-method' is handled as well because it doesn't
3822 ;; belong to `tramp-methods'.
3823 (defun tramp-get-completion-methods (partial-method)
3824 "Returns all method completions for PARTIAL-METHOD."
3825 (let ((all-methods (delete "multi" (mapcar 'car tramp-methods))))
3826
3827 (mapcar
3828 '(lambda (method)
3829 (and method
3830 (string-match (concat "^" (regexp-quote partial-method)) method)
3831 ;; we must remove leading "/".
3832 (substring (tramp-make-tramp-file-name nil method nil nil nil) 1)))
3833
3834 (add-to-list 'all-methods
3835 (when tramp-unified-filenames tramp-ftp-method)))))
3836
3837 ;; Compares partial user and host names with possible completions.
3838 (defun tramp-get-completion-user-host (method partial-user partial-host user host)
3839 "Returns the most expanded string for user and host name completion.
3840 PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
3841 (cond
3842
3843 ((and partial-user partial-host)
3844 (if (and host
3845 (string-match (concat "^" (regexp-quote partial-host)) host)
3846 (string-equal partial-user (or user partial-user)))
3847 (setq user partial-user)
3848 (setq user nil
3849 host nil)))
3850
3851 (partial-user
3852 (setq host nil)
3853 (unless
3854 (and user (string-match (concat "^" (regexp-quote partial-user)) user))
3855 (setq user nil)))
3856
3857 (partial-host
3858 (setq user nil)
3859 (unless
3860 (and host (string-match (concat "^" (regexp-quote partial-host)) host))
3861 (setq host nil)))
3862
3863 (t (setq user nil
3864 host nil)))
3865
3866 (unless (zerop (+ (length user) (length host)))
3867 ;; we must remove leading "/".
3868 (substring (tramp-make-tramp-file-name nil method user host nil) 1)))
3869
3870 (defun tramp-parse-rhosts (filename)
3871 "Return a list of (user host) tuples allowed to access.
3872 Either user or host may be nil."
3873
3874 (let (res)
3875 (when (file-exists-p filename)
3876 (with-temp-buffer
3877 (insert-file-contents filename)
3878 (goto-char (point-min))
3879 (while (not (eobp))
3880 (push (tramp-parse-rhosts-group) res))))
3881 res))
3882
3883 ;; Taken from gnus/netrc.el
3884 (eval-and-compile
3885 (defalias 'tramp-point-at-eol
3886 (if (fboundp 'point-at-eol)
3887 'point-at-eol
3888 'line-end-position)))
3889
3890 (defun tramp-parse-rhosts-group ()
3891 "Return a (user host) tuple allowed to access.
3892 Either user or host may be nil."
3893
3894 (let ((result)
3895 (regexp
3896 (concat
3897 "^\\(" tramp-host-regexp "\\)"
3898 "\\([ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
3899
3900 (narrow-to-region (point) (tramp-point-at-eol))
3901 (when (re-search-forward regexp nil t)
3902 (setq result (append (list (match-string 3) (match-string 1)))))
3903 (widen)
3904 (forward-line 1)
3905 result))
3906
3907 (defun tramp-parse-shosts (filename)
3908 "Return a list of (user host) tuples allowed to access.
3909 User is always nil."
3910
3911 (let (res)
3912 (when (file-exists-p filename)
3913 (with-temp-buffer
3914 (insert-file-contents filename)
3915 (goto-char (point-min))
3916 (while (not (eobp))
3917 (push (tramp-parse-shosts-group) res))))
3918 res))
3919
3920 (defun tramp-parse-shosts-group ()
3921 "Return a (user host) tuple allowed to access.
3922 User is always nil."
3923
3924 (let ((result)
3925 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
3926
3927 (narrow-to-region (point) (tramp-point-at-eol))
3928 (when (re-search-forward regexp nil t)
3929 (setq result (list nil (match-string 1))))
3930 (widen)
3931 (or
3932 (> (skip-chars-forward ",") 0)
3933 (forward-line 1))
3934 result))
3935
3936 (defun tramp-parse-hosts (filename)
3937 "Return a list of (user host) tuples allowed to access.
3938 User is always nil."
3939
3940 (let (res)
3941 (when (file-exists-p filename)
3942 (with-temp-buffer
3943 (insert-file-contents filename)
3944 (goto-char (point-min))
3945 (while (not (eobp))
3946 (push (tramp-parse-hosts-group) res))))
3947 res))
3948
3949 (defun tramp-parse-hosts-group ()
3950 "Return a (user host) tuple allowed to access.
3951 User is always nil."
3952
3953 (let ((result)
3954 (regexp (concat "^\\(" tramp-host-regexp "\\)")))
3955
3956 (narrow-to-region (point) (tramp-point-at-eol))
3957 (when (re-search-forward regexp nil t)
3958 (unless (char-equal (or (char-after) ?\n) ?:) ; no IPv6
3959 (setq result (list nil (match-string 1)))))
3960 (widen)
3961 (or
3962 (> (skip-chars-forward " \t") 0)
3963 (forward-line 1))
3964 result))
3965
3966 (defun tramp-parse-passwd (filename)
3967 "Return a list of (user host) tuples allowed to access.
3968 Host is always \"localhost\"."
3969
3970 (let (res)
3971 (if (and (symbolp 'user) (zerop (length user)))
3972 '(("root" nil))
3973 (when (file-exists-p filename)
3974 (with-temp-buffer
3975 (insert-file-contents filename)
3976 (goto-char (point-min))
3977 (while (not (eobp))
3978 (push (tramp-parse-passwd-group) res))))
3979 res)))
3980
3981 (defun tramp-parse-passwd-group ()
3982 "Return a (user host) tuple allowed to access.
3983 Host is always \"localhost\"."
3984
3985 (let ((result)
3986 (regexp (concat "^\\(" tramp-user-regexp "\\):")))
3987
3988 (narrow-to-region (point) (tramp-point-at-eol))
3989 (when (re-search-forward regexp nil t)
3990 (setq result (list (match-string 1) "localhost")))
3991 (widen)
3992 (forward-line 1)
3993 result))
3994
3995 (defun tramp-parse-netrc (filename)
3996 "Return a list of (user host) tuples allowed to access.
3997 User may be nil."
3998
3999 (let (res)
4000 (when (file-exists-p filename)
4001 (with-temp-buffer
4002 (insert-file-contents filename)
4003 (goto-char (point-min))
4004 (while (not (eobp))
4005 (push (tramp-parse-netrc-group) res))))
4006 res))
4007
4008 (defun tramp-parse-netrc-group ()
4009 "Return a (user host) tuple allowed to access.
4010 User may be nil."
4011
4012 (let ((result)
4013 (regexp
4014 (concat
4015 "^[ \t]*machine[ \t]+" "\\(" tramp-host-regexp "\\)"
4016 "\\([ \t]+login[ \t]+" "\\(" tramp-user-regexp "\\)" "\\)?")))
4017
4018 (narrow-to-region (point) (tramp-point-at-eol))
4019 (when (re-search-forward regexp nil t)
4020 (setq result (list (match-string 3) (match-string 1))))
4021 (widen)
4022 (forward-line 1)
4023 result))
4024
4025 (defun tramp-completion-handle-expand-file-name (name &optional dir)
4026 "Like `expand-file-name' for tramp files."
4027 (let ((fullname (concat (or dir default-directory) name)))
4028 (if (tramp-completion-mode fullname)
4029 (tramp-run-real-handler
4030 'expand-file-name (list name dir))
4031 (tramp-completion-run-real-handler
4032 'expand-file-name (list name dir)))))
4033
4034 ;;; Internal Functions:
4035
4036 (defun tramp-set-auto-save ()
4037 (when (and (buffer-file-name)
4038 (tramp-tramp-file-p (buffer-file-name))
4039 auto-save-default)
4040 (auto-save-mode 1)))
4041 (add-hook 'find-file-hooks 'tramp-set-auto-save t)
4042
4043 (defun tramp-run-test (switch filename)
4044 "Run `test' on the remote system, given a SWITCH and a FILENAME.
4045 Returns the exit code of the `test' program."
4046 (let ((v (tramp-dissect-file-name filename)))
4047 (save-excursion
4048 (tramp-send-command-and-check
4049 (tramp-file-name-multi-method v) (tramp-file-name-method v)
4050 (tramp-file-name-user v) (tramp-file-name-host v)
4051 (format "test %s %s" switch
4052 (tramp-shell-quote-argument (tramp-file-name-path v)))))))
4053
4054 (defun tramp-run-test2 (program file1 file2 &optional switch)
4055 "Run `test'-like PROGRAM on the remote system, given FILE1, FILE2.
4056 The optional SWITCH is inserted between the two files.
4057 Returns the exit code of the `test' PROGRAM. Barfs if the methods,
4058 hosts, or files, disagree."
4059 (let* ((v1 (tramp-dissect-file-name file1))
4060 (v2 (tramp-dissect-file-name file2))
4061 (mmethod1 (tramp-file-name-multi-method v1))
4062 (mmethod2 (tramp-file-name-multi-method v2))
4063 (method1 (tramp-file-name-method v1))
4064 (method2 (tramp-file-name-method v2))
4065 (user1 (tramp-file-name-user v1))
4066 (user2 (tramp-file-name-user v2))
4067 (host1 (tramp-file-name-host v1))
4068 (host2 (tramp-file-name-host v2))
4069 (path1 (tramp-file-name-path v1))
4070 (path2 (tramp-file-name-path v2)))
4071 (unless (and method1 method2 host1 host2
4072 (equal mmethod1 mmethod2)
4073 (equal method1 method2)
4074 (equal user1 user2)
4075 (equal host1 host2))
4076 (error "tramp-run-test2: %s"
4077 "only implemented for same method, same user, same host"))
4078 (save-excursion
4079 (tramp-send-command-and-check
4080 mmethod1 method1 user1 host1
4081 (format "%s %s %s %s"
4082 program
4083 (tramp-shell-quote-argument path1)
4084 (or switch "")
4085 (tramp-shell-quote-argument path2))))))
4086
4087 (defun tramp-buffer-name (multi-method method user host)
4088 "A name for the connection buffer for USER at HOST using METHOD."
4089 (cond (multi-method
4090 (tramp-buffer-name-multi-method "tramp" multi-method method user host))
4091 (user
4092 (format "*tramp/%s %s@%s*" method user host))
4093 (t
4094 (format "*tramp/%s %s*" method host))))
4095
4096 (defun tramp-buffer-name-multi-method (prefix multi-method method user host)
4097 "A name for the multi method connection buffer.
4098 MULTI-METHOD gives the multi method, METHOD the array of methods,
4099 USER the array of user names, HOST the array of host names."
4100 (unless (and (= (length method) (length user))
4101 (= (length method) (length host)))
4102 (error "Syntax error in multi method (implementation error)"))
4103 (let ((len (length method))
4104 (i 0)
4105 string-list)
4106 (while (< i len)
4107 (setq string-list
4108 (cons (if (aref user i)
4109 (format "%s#%s@%s:" (aref method i)
4110 (aref user i) (aref host i))
4111 (format "%s@%s:" (aref method i) (aref host i)))
4112 string-list))
4113 (incf i))
4114 (format "*%s/%s %s*"
4115 prefix multi-method
4116 (apply 'concat (reverse string-list)))))
4117
4118 (defun tramp-get-buffer (multi-method method user host)
4119 "Get the connection buffer to be used for USER at HOST using METHOD."
4120 (get-buffer-create (tramp-buffer-name multi-method method user host)))
4121
4122 (defun tramp-debug-buffer-name (multi-method method user host)
4123 "A name for the debug buffer for USER at HOST using METHOD."
4124 (cond (multi-method
4125 (tramp-buffer-name-multi-method "debug tramp"
4126 multi-method method user host))
4127 (user
4128 (format "*debug tramp/%s %s@%s*" method user host))
4129 (t
4130 (format "*debug tramp/%s %s*" method host))))
4131
4132 (defun tramp-get-debug-buffer (multi-method method user host)
4133 "Get the debug buffer for USER at HOST using METHOD."
4134 (get-buffer-create (tramp-debug-buffer-name multi-method method user host)))
4135
4136 (defun tramp-find-executable (multi-method method user host
4137 progname dirlist ignore-tilde)
4138 "Searches for PROGNAME in all directories mentioned in DIRLIST.
4139 First args METHOD, USER and HOST specify the connection, PROGNAME
4140 is the program to search for, and DIRLIST gives the list of directories
4141 to search. If IGNORE-TILDE is non-nil, directory names starting
4142 with `~' will be ignored.
4143
4144 Returns the full path name of PROGNAME, if found, and nil otherwise.
4145
4146 This function expects to be in the right *tramp* buffer."
4147 (let (result)
4148 (when ignore-tilde
4149 ;; Remove all ~/foo directories from dirlist. In Emacs 20,
4150 ;; `remove' is in CL, and we want to avoid CL dependencies.
4151 (let (newdl d)
4152 (while dirlist
4153 (setq d (car dirlist))
4154 (setq dirlist (cdr dirlist))
4155 (unless (char-equal ?~ (aref d 0))
4156 (setq newdl (cons d newdl))))
4157 (setq dirlist (nreverse newdl))))
4158 (tramp-send-command
4159 multi-method method user host
4160 (format (concat "while read d; "
4161 "do if test -x $d/%s -a -f $d/%s; "
4162 "then echo tramp_executable $d/%s; "
4163 "break; fi; done <<'EOF'")
4164 progname progname progname))
4165 (mapcar (lambda (d)
4166 (tramp-send-command multi-method method user host d))
4167 dirlist)
4168 (tramp-send-command multi-method method user host "EOF")
4169 (tramp-wait-for-output)
4170 (goto-char (point-max))
4171 (when (search-backward "tramp_executable " nil t)
4172 (skip-chars-forward "^ ")
4173 (skip-chars-forward " ")
4174 (buffer-substring (point) (tramp-line-end-position)))))
4175
4176 (defun tramp-set-remote-path (multi-method method user host var dirlist)
4177 "Sets the remote environment VAR to existing directories from DIRLIST.
4178 I.e., for each directory in DIRLIST, it is tested whether it exists and if
4179 so, it is added to the environment variable VAR."
4180 (let ((existing-dirs
4181 (mapcar
4182 (lambda (x)
4183 (when (and
4184 (file-exists-p
4185 (tramp-make-tramp-file-name multi-method method user host x))
4186 (file-directory-p
4187 (tramp-make-tramp-file-name multi-method method user host x)))
4188 x))
4189 dirlist)))
4190 (tramp-send-command
4191 multi-method method user host
4192 (concat var "="
4193 (mapconcat 'identity (delq nil existing-dirs) ":")
4194 "; export " var))
4195 (tramp-wait-for-output)))
4196
4197 ;; -- communication with external shell --
4198
4199 (defun tramp-find-file-exists-command (multi-method method user host)
4200 "Find a command on the remote host for checking if a file exists.
4201 Here, we are looking for a command which has zero exit status if the
4202 file exists and nonzero exit status otherwise."
4203 (make-local-variable 'tramp-file-exists-command)
4204 (tramp-message 9 "Finding command to check if file exists")
4205 (let ((existing
4206 (tramp-make-tramp-file-name
4207 multi-method method user host
4208 "/")) ;assume this file always exists
4209 (nonexisting
4210 (tramp-make-tramp-file-name
4211 multi-method method user host
4212 "/ this file does not exist "))) ;assume this never exists
4213 ;; The algorithm is as follows: we try a list of several commands.
4214 ;; For each command, we first run `$cmd /' -- this should return
4215 ;; true, as the root directory always exists. And then we run
4216 ;; `$cmd /this\ file\ does\ not\ exist', hoping that the file indeed
4217 ;; does not exist. This should return false. We use the first
4218 ;; command we find that seems to work.
4219 ;; The list of commands to try is as follows:
4220 ;; `ls -d' This works on most systems, but NetBSD 1.4
4221 ;; has a bug: `ls' always returns zero exit
4222 ;; status, even for files which don't exist.
4223 ;; `test -e' Some Bourne shells have a `test' builtin
4224 ;; which does not know the `-e' option.
4225 ;; `/bin/test -e' For those, the `test' binary on disk normally
4226 ;; provides the option. Alas, the binary
4227 ;; is sometimes `/bin/test' and sometimes it's
4228 ;; `/usr/bin/test'.
4229 ;; `/usr/bin/test -e' In case `/bin/test' does not exist.
4230 (unless (or
4231 (and (setq tramp-file-exists-command "test -e %s")
4232 (tramp-handle-file-exists-p existing)
4233 (not (tramp-handle-file-exists-p nonexisting)))
4234 (and (setq tramp-file-exists-command "/bin/test -e %s")
4235 (tramp-handle-file-exists-p existing)
4236 (not (tramp-handle-file-exists-p nonexisting)))
4237 (and (setq tramp-file-exists-command "/usr/bin/test -e %s")
4238 (tramp-handle-file-exists-p existing)
4239 (not (tramp-handle-file-exists-p nonexisting)))
4240 (and (setq tramp-file-exists-command "ls -d %s")
4241 (tramp-handle-file-exists-p existing)
4242 (not (tramp-handle-file-exists-p nonexisting))))
4243 (error "Couldn't find command to check if file exists."))))
4244
4245
4246 ;; CCC test ksh or bash found for tilde expansion?
4247 (defun tramp-find-shell (multi-method method user host)
4248 "Find a shell on the remote host which groks tilde expansion."
4249 (let ((shell nil))
4250 (tramp-send-command multi-method method user host "echo ~root")
4251 (tramp-wait-for-output)
4252 (cond
4253 ((string-match "^~root$" (buffer-string))
4254 (setq shell
4255 (or (tramp-find-executable multi-method method user host
4256 "bash" tramp-remote-path t)
4257 (tramp-find-executable multi-method method user host
4258 "ksh" tramp-remote-path t)))
4259 (unless shell
4260 (error "Couldn't find a shell which groks tilde expansion"))
4261 ;; Find arguments for this shell.
4262 (let ((alist tramp-sh-extra-args)
4263 item extra-args)
4264 (while (and alist (null extra-args))
4265 (setq item (pop alist))
4266 (when (string-match (car item) shell)
4267 (setq extra-args (cdr item))))
4268 (when extra-args (setq shell (concat shell " " extra-args))))
4269 (tramp-message
4270 5 "Starting remote shell `%s' for tilde expansion..." shell)
4271 (tramp-send-command
4272 multi-method method user host
4273 (concat "PS1='$ ' exec " shell)) ;
4274 (unless (tramp-wait-for-regexp
4275 (get-buffer-process (current-buffer))
4276 60 (format "\\(\\(%s\\)\\|\\(%s\\)\\)\\'"
4277 tramp-shell-prompt-pattern shell-prompt-pattern))
4278 (pop-to-buffer (buffer-name))
4279 (error "Couldn't find remote `%s' prompt." shell))
4280 (tramp-message
4281 9 "Setting remote shell prompt...")
4282 ;; Douglas Gray Stephens <DGrayStephens@slb.com> says that we
4283 ;; must use "\n" here, not tramp-rsh-end-of-line. Kai left the
4284 ;; last tramp-rsh-end-of-line, Douglas wanted to replace that,
4285 ;; as well.
4286 (process-send-string nil (format "PS1='%s%s%s'; PS2=''; PS3=''%s"
4287 tramp-rsh-end-of-line
4288 tramp-end-of-output
4289 tramp-rsh-end-of-line
4290 tramp-rsh-end-of-line))
4291 (tramp-wait-for-output)
4292 (tramp-message
4293 9 "Setting remote shell prompt...done")
4294 )
4295 (t (tramp-message 5 "Remote `%s' groks tilde expansion, good"
4296 (tramp-get-remote-sh multi-method method user host))))))
4297
4298 (defun tramp-check-ls-command (multi-method method user host cmd)
4299 "Checks whether the given `ls' executable groks `-n'.
4300 METHOD, USER and HOST specify the connection, CMD (the full path name of)
4301 the `ls' executable. Returns t if CMD supports the `-n' option, nil
4302 otherwise."
4303 (tramp-message 9 "Checking remote `%s' command for `-n' option"
4304 cmd)
4305 (when (tramp-handle-file-executable-p
4306 (tramp-make-tramp-file-name multi-method method user host cmd))
4307 (let ((result nil))
4308 (tramp-message 7 "Testing remote command `%s' for -n..." cmd)
4309 (setq result
4310 (tramp-send-command-and-check
4311 multi-method method user host
4312 (format "%s -lnd / >/dev/null"
4313 cmd)))
4314 (tramp-message 7 "Testing remote command `%s' for -n...%s"
4315 cmd
4316 (if (zerop result) "okay" "failed"))
4317 (zerop result))))
4318
4319 (defun tramp-check-ls-commands (multi-method method user host cmd dirlist)
4320 "Checks whether the given `ls' executable in one of the dirs groks `-n'.
4321 Returns nil if none was found, else the command is returned."
4322 (let ((dl dirlist)
4323 (result nil)
4324 (directory-sep-char ?/)) ;for XEmacs
4325 ;; It would be better to use the CL function `find', but
4326 ;; we don't want run-time dependencies on CL.
4327 (while (and dl (not result))
4328 (let ((x (concat (file-name-as-directory (car dl)) cmd)))
4329 (when (tramp-check-ls-command multi-method method user host x)
4330 (setq result x)))
4331 (setq dl (cdr dl)))
4332 result))
4333
4334 (defun tramp-find-ls-command (multi-method method user host)
4335 "Finds an `ls' command which groks the `-n' option, returning nil if failed.
4336 \(This option prints numeric user and group ids in a long listing.)"
4337 (tramp-message 9 "Finding a suitable `ls' command")
4338 (or
4339 (tramp-check-ls-commands multi-method method user host "ls" tramp-remote-path)
4340 (tramp-check-ls-commands multi-method method user host "gnuls" tramp-remote-path)
4341 (tramp-check-ls-commands multi-method method user host "gls" tramp-remote-path)))
4342
4343 ;; ------------------------------------------------------------
4344 ;; -- Functions for establishing connection --
4345 ;; ------------------------------------------------------------
4346
4347 ;; The following functions are actions to be taken when seeing certain
4348 ;; prompts from the remote host. See the variable
4349 ;; `tramp-actions-before-shell' for usage of these functions.
4350
4351 (defun tramp-action-login (p multi-method method user host)
4352 "Send the login name."
4353 (tramp-message 9 "Sending login name `%s'"
4354 (or user (user-login-name)))
4355 (erase-buffer)
4356 (process-send-string nil (concat (or user (user-login-name))
4357 tramp-rsh-end-of-line)))
4358
4359 (defun tramp-action-password (p multi-method method user host)
4360 "Query the user for a password."
4361 (let ((pw-prompt (match-string 0)))
4362 (when (tramp-method-out-of-band-p multi-method method user host)
4363 (kill-process (get-buffer-process (current-buffer)))
4364 (error (concat "Out of band method `%s' not applicable "
4365 "for remote shell asking for a password")
4366 method))
4367 (tramp-message 9 "Sending password")
4368 (tramp-enter-password p pw-prompt)))
4369
4370 (defun tramp-action-succeed (p multi-method method user host)
4371 "Signal success in finding shell prompt."
4372 (tramp-message 9 "Found remote shell prompt.")
4373 (erase-buffer)
4374 (throw 'tramp-action 'ok))
4375
4376 (defun tramp-action-permission-denied (p multi-method method user host)
4377 "Signal permission denied."
4378 (pop-to-buffer (tramp-get-buffer multi-method method user host))
4379 (tramp-message 9 "Permission denied by remote host.")
4380 (kill-process p)
4381 (throw 'tramp-action 'permission-denied))
4382
4383 (defun tramp-action-yesno (p multi-method method user host)
4384 "Ask the user for confirmation using `yes-or-no-p'.
4385 Send \"yes\" to remote process on confirmation, abort otherwise.
4386 See also `tramp-action-yn'."
4387 (save-window-excursion
4388 (pop-to-buffer (tramp-get-buffer multi-method method user host))
4389 (unless (yes-or-no-p (match-string 0))
4390 (kill-process p)
4391 (erase-buffer)
4392 (throw 'tramp-action 'permission-denied))
4393 (process-send-string p (concat "yes" tramp-rsh-end-of-line))
4394 (erase-buffer)))
4395
4396 (defun tramp-action-yn (p multi-method method user host)
4397 "Ask the user for confirmation using `y-or-n-p'.
4398 Send \"y\" to remote process on confirmation, abort otherwise.
4399 See also `tramp-action-yesno'."
4400 (save-window-excursion
4401 (pop-to-buffer (tramp-get-buffer multi-method method user host))
4402 (unless (y-or-n-p (match-string 0))
4403 (kill-process p)
4404 (erase-buffer)
4405 (throw 'tramp-action 'permission-denied))
4406 (process-send-string p (concat "y" tramp-rsh-end-of-line))))
4407
4408 (defun tramp-action-terminal (p multi-method method user host)
4409 "Tell the remote host which terminal type to use.
4410 The terminal type can be configured with `tramp-terminal-type'."
4411 (tramp-message 9 "Setting `%s' as terminal type."
4412 tramp-terminal-type)
4413 (erase-buffer)
4414 (process-send-string nil (concat tramp-terminal-type
4415 tramp-rsh-end-of-line)))
4416
4417 ;; The following functions are specifically for multi connections.
4418
4419 (defun tramp-multi-action-login (p method user host)
4420 "Send the login name."
4421 (tramp-message 9 "Sending login name `%s'" user)
4422 (erase-buffer)
4423 (process-send-string p (concat user tramp-rsh-end-of-line)))
4424
4425 (defun tramp-multi-action-password (p method user host)
4426 "Query the user for a password."
4427 (tramp-message 9 "Sending password")
4428 (tramp-enter-password p (match-string 0)))
4429
4430 (defun tramp-multi-action-succeed (p method user host)
4431 "Signal success in finding shell prompt."
4432 (tramp-message 9 "Found shell prompt on `%s'" host)
4433 (erase-buffer)
4434 (throw 'tramp-action 'ok))
4435
4436 (defun tramp-multi-action-permission-denied (p method user host)
4437 "Signal permission denied."
4438 (tramp-message 9 "Permission denied by remote host `%s'" host)
4439 (kill-process p)
4440 (erase-buffer)
4441 (throw 'tramp-action 'permission-denied))
4442
4443 ;; Functions for processing the actions.
4444
4445 (defun tramp-process-one-action (p multi-method method user host actions)
4446 "Wait for output from the shell and perform one action."
4447 (let (found item pattern action todo)
4448 (erase-buffer)
4449 (tramp-message 9 "Waiting 60s for prompt from remote shell")
4450 (with-timeout (60 (throw 'tramp-action 'timeout))
4451 (while (not found)
4452 (accept-process-output p 1)
4453 (goto-char (point-min))
4454 (setq todo actions)
4455 (while todo
4456 (goto-char (point-min))
4457 (setq item (pop todo))
4458 (setq pattern (symbol-value (nth 0 item)))
4459 (setq action (nth 1 item))
4460 (tramp-message 10 "Looking for regexp \"%s\" from remote shell"
4461 pattern)
4462 (when (re-search-forward (concat pattern "\\'") nil t)
4463 (setq found (funcall action p multi-method method user host)))))
4464 found)))
4465
4466 (defun tramp-process-actions (p multi-method method user host actions)
4467 "Perform actions until success."
4468 (let (exit)
4469 (while (not exit)
4470 (tramp-message 9 "Waiting for prompts from remote shell")
4471 (setq exit
4472 (catch 'tramp-action
4473 (tramp-process-one-action
4474 p multi-method method user host actions)
4475 nil)))
4476 (unless (eq exit 'ok)
4477 (error "Login failed"))))
4478
4479 ;; For multi-actions.
4480
4481 (defun tramp-process-one-multi-action (p method user host actions)
4482 "Wait for output from the shell and perform one action."
4483 (let (found item pattern action todo)
4484 (erase-buffer)
4485 (tramp-message 9 "Waiting 60s for prompt from remote shell")
4486 (with-timeout (60 (throw 'tramp-action 'timeout))
4487 (while (not found)
4488 (accept-process-output p 1)
4489 (setq todo actions)
4490 (goto-char (point-min))
4491 (while todo
4492 (goto-char (point-min))
4493 (setq item (pop todo))
4494 (setq pattern (symbol-value (nth 0 item)))
4495 (setq action (nth 1 item))
4496 (tramp-message 10 "Looking for regexp \"%s\" from remote shell"
4497 pattern)
4498 (when (re-search-forward (concat pattern "\\'") nil t)
4499 (setq found (funcall action p method user host)))))
4500 found)))
4501
4502 (defun tramp-process-multi-actions (p method user host actions)
4503 "Perform actions until success."
4504 (let (exit)
4505 (while (not exit)
4506 (tramp-message 9 "Waiting for prompts from remote shell")
4507 (setq exit
4508 (catch 'tramp-action
4509 (tramp-process-one-multi-action p method user host actions)
4510 nil)))
4511 (unless (eq exit 'ok)
4512 (error "Login failed"))))
4513
4514 ;; The actual functions for opening connections.
4515
4516 (defun tramp-open-connection-telnet (multi-method method user host)
4517 "Open a connection using a telnet METHOD.
4518 This starts the command `telnet HOST ARGS'[*], then waits for a remote
4519 login prompt, then sends the user name USER, then waits for a remote
4520 password prompt. It queries the user for the password, then sends the
4521 password to the remote host.
4522
4523 If USER is nil, uses value returned by `(user-login-name)' instead.
4524
4525 Recognition of the remote shell prompt is based on the variables
4526 `shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be
4527 set up correctly.
4528
4529 Please note that it is NOT possible to use this connection method
4530 together with an out-of-band transfer method! You must use an inline
4531 transfer method.
4532
4533 Maybe the different regular expressions need to be tuned.
4534
4535 * Actually, the telnet program as well as the args to be used can be
4536 specified in the method parameters, see the variable `tramp-methods'."
4537 (save-match-data
4538 (when (tramp-method-out-of-band-p multi-method method user host)
4539 (error "Cannot use out-of-band method `%s' with telnet connection method"
4540 method))
4541 (when multi-method
4542 (error "Cannot multi-connect using telnet connection method"))
4543 (tramp-pre-connection multi-method method user host)
4544 (tramp-message 7 "Opening connection for %s@%s using %s..."
4545 (or user (user-login-name)) host method)
4546 (let ((process-environment (copy-sequence process-environment)))
4547 (setenv "TERM" tramp-terminal-type)
4548 (let* ((default-directory (tramp-temporary-file-directory))
4549 ;; If we omit the conditional here, then we would use
4550 ;; `undecided-dos' in some cases. With the conditional,
4551 ;; we use nil in these cases. Which one is right?
4552 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4553 (> emacs-major-version 20))
4554 tramp-dos-coding-system))
4555 (p (apply 'start-process
4556 (tramp-buffer-name multi-method method user host)
4557 (tramp-get-buffer multi-method method user host)
4558 (tramp-get-telnet-program
4559 multi-method
4560 (tramp-find-method multi-method method user host)
4561 user host)
4562 host
4563 (tramp-get-telnet-args
4564 multi-method
4565 (tramp-find-method multi-method method user host)
4566 user host)))
4567 (found nil)
4568 (pw nil))
4569 (process-kill-without-query p)
4570 (set-buffer (tramp-get-buffer multi-method method user host))
4571 (erase-buffer)
4572 (tramp-process-actions p multi-method method user host
4573 tramp-actions-before-shell)
4574 (tramp-open-connection-setup-interactive-shell
4575 p multi-method method user host)
4576 (tramp-post-connection multi-method method user host)))))
4577
4578
4579 (defun tramp-open-connection-rsh (multi-method method user host)
4580 "Open a connection using an rsh METHOD.
4581 This starts the command `rsh HOST -l USER'[*], then waits for a remote
4582 password or shell prompt. If a password prompt is seen, the user is
4583 queried for a password, this function sends the password to the remote
4584 host and waits for a shell prompt.
4585
4586 If USER is nil, start the command `rsh HOST'[*] instead
4587
4588 Recognition of the remote shell prompt is based on the variables
4589 `shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be
4590 set up correctly.
4591
4592 Please note that it is NOT possible to use this connection method with
4593 an out-of-band transfer method if this function asks the user for a
4594 password! You must use an inline transfer method in this case.
4595 Sadly, the transfer method cannot be switched on the fly, instead you
4596 must specify the right method in the file name.
4597
4598 Kludgy feature: if HOST has the form \"xx#yy\", then yy is assumed to
4599 be a port number for ssh, and \"-p yy\" will be added to the list of
4600 arguments, and xx will be used as the host name to connect to.
4601
4602 * Actually, the rsh program to be used can be specified in the
4603 method parameters, see the variable `tramp-methods'."
4604 (save-match-data
4605 (when multi-method
4606 (error "Cannot multi-connect using rsh connection method"))
4607 (tramp-pre-connection multi-method method user host)
4608 (if (and user (not (string= user "")))
4609 (tramp-message 7 "Opening connection for %s@%s using %s..."
4610 user host method)
4611 (tramp-message 7 "Opening connection at %s using %s..." host method))
4612 (let ((process-environment (copy-sequence process-environment))
4613 (bufnam (tramp-buffer-name multi-method method user host))
4614 (buf (tramp-get-buffer multi-method method user host))
4615 (rsh-program (tramp-get-rsh-program
4616 multi-method
4617 (tramp-find-method multi-method method user host)
4618 user host))
4619 (rsh-args (tramp-get-rsh-args
4620 multi-method
4621 (tramp-find-method multi-method method user host)
4622 user host)))
4623 ;; The following should be changed. We need a more general
4624 ;; mechanism to parse extra host args.
4625 (when (string-match "\\([^#]*\\)#\\(.*\\)" host)
4626 (setq rsh-args (cons "-p" (cons (match-string 2 host) rsh-args)))
4627 (setq host (match-string 1 host)))
4628 (setenv "TERM" tramp-terminal-type)
4629 (let* ((default-directory (tramp-temporary-file-directory))
4630 ;; If we omit the conditional, we would use
4631 ;; `undecided-dos' in some cases. With the conditional,
4632 ;; we use nil in these cases. Which one is right?
4633 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4634 (> emacs-major-version 20))
4635 tramp-dos-coding-system))
4636 (p (if (and user (not (string= user "")))
4637 (apply #'start-process bufnam buf rsh-program
4638 host "-l" user rsh-args)
4639 (apply #'start-process bufnam buf rsh-program
4640 host rsh-args)))
4641 (found nil))
4642 (process-kill-without-query p)
4643
4644 (set-buffer buf)
4645 (tramp-process-actions p multi-method method user host
4646 tramp-actions-before-shell)
4647 (tramp-message 7 "Initializing remote shell")
4648 (tramp-open-connection-setup-interactive-shell
4649 p multi-method method user host)
4650 (tramp-post-connection multi-method method user host)))))
4651
4652 (defun tramp-open-connection-su (multi-method method user host)
4653 "Open a connection using the `su' program with METHOD.
4654 This starts `su - USER', then waits for a password prompt. The HOST
4655 name must be equal to the local host name or to `localhost'.
4656
4657 If USER is nil, uses value returned by user-login-name instead.
4658
4659 Recognition of the remote shell prompt is based on the variables
4660 `shell-prompt-pattern' and `tramp-shell-prompt-pattern' which must be
4661 set up correctly. Note that the other user may have a different shell
4662 prompt than you do, so it is not at all unlikely that the variable
4663 `shell-prompt-pattern' is set up wrongly!"
4664 (save-match-data
4665 (when (tramp-method-out-of-band-p multi-method method user host)
4666 (error "Cannot use out-of-band method `%s' with `su' connection method"
4667 method))
4668 (unless (or (string-match (concat "^" (regexp-quote host))
4669 (system-name))
4670 (string= "localhost" host)
4671 (string= "" host))
4672 (error
4673 "Cannot connect to different host `%s' with `su' connection method"
4674 host))
4675 (tramp-pre-connection multi-method method user host)
4676 (tramp-message 7 "Opening connection for `%s' using `%s'..."
4677 (or user "<root>") method)
4678 (let ((process-environment (copy-sequence process-environment)))
4679 (setenv "TERM" tramp-terminal-type)
4680 (let* ((default-directory (tramp-temporary-file-directory))
4681 ;; If we omit the conditional, we use `undecided-dos' in
4682 ;; some cases. With the conditional, we use nil in these
4683 ;; cases. What's the difference? Which one is right?
4684 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4685 (> emacs-major-version 20))
4686 tramp-dos-coding-system))
4687 (p (apply 'start-process
4688 (tramp-buffer-name multi-method method user host)
4689 (tramp-get-buffer multi-method method user host)
4690 (tramp-get-su-program
4691 multi-method
4692 (tramp-find-method multi-method method user host)
4693 user host)
4694 (mapcar
4695 '(lambda (x)
4696 (format-spec x `((?u . ,(or user "root")))))
4697 (tramp-get-su-args
4698 multi-method
4699 (tramp-find-method multi-method method user host)
4700 user host))))
4701 (found nil)
4702 (pw nil))
4703 (process-kill-without-query p)
4704 (set-buffer (tramp-get-buffer multi-method method user host))
4705 (tramp-process-actions p multi-method method user host
4706 tramp-actions-before-shell)
4707 (tramp-open-connection-setup-interactive-shell
4708 p multi-method method user host)
4709 (tramp-post-connection multi-method method
4710 user host)))))
4711
4712 ;; HHH: Not Changed. Multi method. It is not clear to me how this can
4713 ;; handle not giving a user name in the "file name".
4714 ;;
4715 ;; This is more difficult than for the single-hop method. In the
4716 ;; multi-hop-method, the desired behaviour should be that the
4717 ;; user must specify names for the telnet hops of which the user
4718 ;; name is different than the "original" name (or different from
4719 ;; the previous hop.
4720 (defun tramp-open-connection-multi (multi-method method user host)
4721 "Open a multi-hop connection using METHOD.
4722 This uses a slightly changed file name syntax. The idea is to say
4723 [multi/telnet:u1@h1/rsh:u2@h2]/path/to/file
4724 This will use telnet to log in as u1 to h1, then use rsh from there to
4725 log in as u2 to h2."
4726 (save-match-data
4727 (unless multi-method
4728 (error "Multi-hop open connection function called on non-multi method"))
4729 (when (tramp-method-out-of-band-p multi-method method user host)
4730 (error "No out of band multi-hop connections"))
4731 (unless (and (arrayp method) (not (stringp method)))
4732 (error "METHOD must be an array of strings for multi methods"))
4733 (unless (and (arrayp user) (not (stringp user)))
4734 (error "USER must be an array of strings for multi methods"))
4735 (unless (and (arrayp host) (not (stringp host)))
4736 (error "HOST must be an array of strings for multi methods"))
4737 (unless (and (= (length method) (length user))
4738 (= (length method) (length host)))
4739 (error "Arrays METHOD, USER, HOST must have equal length"))
4740 (tramp-pre-connection multi-method method user host)
4741 (tramp-message 7 "Opening `%s' connection..." multi-method)
4742 (let ((process-environment (copy-sequence process-environment)))
4743 (setenv "TERM" tramp-terminal-type)
4744 (let* ((default-directory (tramp-temporary-file-directory))
4745 ;; If we omit the conditional, we use `undecided-dos' in
4746 ;; some cases. With the conditional, we use nil in these
4747 ;; cases. What's the difference? Which one is right?
4748 (coding-system-for-read (unless (and (not (featurep 'xemacs))
4749 (> emacs-major-version 20))
4750 tramp-dos-coding-system))
4751 (p (start-process (tramp-buffer-name multi-method method user host)
4752 (tramp-get-buffer multi-method method user host)
4753 tramp-multi-sh-program))
4754 (num-hops (length method))
4755 (i 0))
4756 (process-kill-without-query p)
4757 (tramp-message 9 "Waiting 60s for local shell to come up...")
4758 (unless (tramp-wait-for-regexp
4759 p 60 (format "\\(%s\\)\\'\\|\\(%s\\)\\'"
4760 shell-prompt-pattern tramp-shell-prompt-pattern))
4761 (pop-to-buffer (buffer-name))
4762 (kill-process p)
4763 (error "Couldn't find local shell prompt"))
4764 ;; Now do all the connections as specified.
4765 (while (< i num-hops)
4766 (let* ((m (aref method i))
4767 (u (aref user i))
4768 (h (aref host i))
4769 (entry (assoc m tramp-multi-connection-function-alist))
4770 (multi-func (nth 1 entry))
4771 (command (nth 2 entry)))
4772 ;; The multi-funcs don't need to do save-match-data, as that
4773 ;; is done here.
4774 (funcall multi-func p m u h command)
4775 (erase-buffer)
4776 (incf i)))
4777 (tramp-open-connection-setup-interactive-shell
4778 p multi-method method user host)
4779 (tramp-post-connection multi-method method user host)))))
4780
4781 ;; HHH: Changed. Multi method. Don't know how to handle this in the case
4782 ;; of no user name provided. Hack to make it work as it did before:
4783 ;; changed `user' to `(or user (user-login-name))' in the places where
4784 ;; the value is actually used.
4785 (defun tramp-multi-connect-telnet (p method user host command)
4786 "Issue `telnet' command.
4787 Uses shell COMMAND to issue a `telnet' command to log in as USER to
4788 HOST. You can use percent escapes in COMMAND: `%h' is replaced with
4789 the host name, and `%n' is replaced with an end of line character, as
4790 set in `tramp-rsh-end-of-line'. Use `%%' if you want a literal percent
4791 character.
4792
4793 If USER is nil, uses the return value of (user-login-name) instead."
4794 (let ((cmd (format-spec command
4795 `((?h . ,host) (?n . ,tramp-rsh-end-of-line))))
4796 (cmd1 (format-spec command `((?h . ,host) (?n . ""))))
4797 found pw)
4798 (erase-buffer)
4799 (tramp-message 9 "Sending telnet command `%s'" cmd1)
4800 (process-send-string p cmd)
4801 (tramp-process-multi-actions p method user host
4802 tramp-multi-actions)))
4803
4804 ;; HHH: Changed. Multi method. Don't know how to handle this in the case
4805 ;; of no user name provided. Hack to make it work as it did before:
4806 ;; changed `user' to `(or user (user-login-name))' in the places where
4807 ;; the value is actually used.
4808 (defun tramp-multi-connect-rlogin (p method user host command)
4809 "Issue `rlogin' command.
4810 Uses shell COMMAND to issue an `rlogin' command to log in as USER to
4811 HOST. You can use percent escapes in COMMAND. `%u' will be replaced
4812 with the user name, `%h' will be replaced with the host name, and `%n'
4813 will be replaced with the value of `tramp-rsh-end-of-line'. You can use
4814 `%%' if you want to use a literal percent character.
4815
4816 If USER is nil, uses the return value of (user-login-name) instead."
4817 (let ((cmd (format-spec command `((?h . ,host)
4818 (?u . ,(or user (user-login-name)))
4819 (?n . ,tramp-rsh-end-of-line))))
4820 (cmd1 (format-spec command `((?h . ,host)
4821 (?u . ,(or user (user-login-name)))
4822 (?n . ""))))
4823 found)
4824 (erase-buffer)
4825 (tramp-message 9 "Sending rlogin command `%s'" cmd1)
4826 (process-send-string p cmd)
4827 (tramp-process-multi-actions p method user host
4828 tramp-multi-actions)))
4829
4830 ;; HHH: Changed. Multi method. Don't know how to handle this in the case
4831 ;; of no user name provided. Hack to make it work as it did before:
4832 ;; changed `user' to `(or user (user-login-name))' in the places where
4833 ;; the value is actually used.
4834 (defun tramp-multi-connect-su (p method user host command)
4835 "Issue `su' command.
4836 Uses shell COMMAND to issue a `su' command to log in as USER on
4837 HOST. The HOST name is ignored, this just changes the user id on the
4838 host currently logged in to.
4839
4840 If USER is nil, uses the return value of (user-login-name) instead.
4841
4842 You can use percent escapes in the COMMAND. `%u' is replaced with the
4843 user name, and `%n' is replaced with the value of
4844 `tramp-rsh-end-of-line'. Use `%%' if you want a literal percent
4845 character."
4846 (let ((cmd (format-spec command `((?u . ,(or user (user-login-name)))
4847 (?n . ,tramp-rsh-end-of-line))))
4848 (cmd1 (format-spec command `((?u . ,(or user (user-login-name)))
4849 (?n . ""))))
4850 found)
4851 (erase-buffer)
4852 (tramp-message 9 "Sending su command `%s'" cmd1)
4853 (process-send-string p cmd)
4854 (tramp-process-multi-actions p method user host
4855 tramp-multi-actions)))
4856
4857 ;; Utility functions.
4858
4859 (defun tramp-wait-for-regexp (proc timeout regexp)
4860 "Wait for a REGEXP to appear from process PROC within TIMEOUT seconds.
4861 Expects the output of PROC to be sent to the current buffer. Returns
4862 the string that matched, or nil. Waits indefinitely if TIMEOUT is
4863 nil."
4864 (let ((found nil)
4865 (start-time (current-time)))
4866 (cond (timeout
4867 ;; Work around a bug in XEmacs 21, where the timeout
4868 ;; expires faster than it should. This degenerates
4869 ;; to polling for buggy XEmacsen, but oh, well.
4870 (while (and (not found)
4871 (< (tramp-time-diff (current-time) start-time)
4872 timeout))
4873 (with-timeout (timeout)
4874 (while (not found)
4875 (accept-process-output proc 1)
4876 (goto-char (point-min))
4877 (setq found (when (re-search-forward regexp nil t)
4878 (tramp-match-string-list)))))))
4879 (t
4880 (while (not found)
4881 (accept-process-output proc 1)
4882 (goto-char (point-min))
4883 (setq found (when (re-search-forward regexp nil t)
4884 (tramp-match-string-list))))))
4885 (when tramp-debug-buffer
4886 (append-to-buffer
4887 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
4888 tramp-current-user tramp-current-host)
4889 (point-min) (point-max))
4890 (when (not found)
4891 (save-excursion
4892 (set-buffer
4893 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
4894 tramp-current-user tramp-current-host))
4895 (goto-char (point-max))
4896 (insert "[[Regexp `" regexp "' not found"
4897 (if timeout (format " in %d secs" timeout) "")
4898 "]]"))))
4899 found))
4900
4901 (defun tramp-enter-password (p prompt)
4902 "Prompt for a password and send it to the remote end.
4903 Uses PROMPT as a prompt and sends the password to process P."
4904 (let ((pw (tramp-read-passwd prompt)))
4905 (erase-buffer)
4906 (process-send-string p (concat pw tramp-password-end-of-line))))
4907
4908 ;; HHH: Not Changed. This might handle the case where USER is not
4909 ;; given in the "File name" very poorly. Then, the local
4910 ;; variable tramp-current user will be set to nil.
4911 (defun tramp-pre-connection (multi-method method user host)
4912 "Do some setup before actually logging in.
4913 METHOD, USER and HOST specify the connection."
4914 (set-buffer (tramp-get-buffer multi-method method user host))
4915 (set (make-local-variable 'tramp-current-multi-method) multi-method)
4916 (set (make-local-variable 'tramp-current-method) method)
4917 (set (make-local-variable 'tramp-current-user) user)
4918 (set (make-local-variable 'tramp-current-host) host)
4919 (set (make-local-variable 'inhibit-eol-conversion) nil)
4920 (erase-buffer))
4921
4922 (defun tramp-open-connection-setup-interactive-shell
4923 (p multi-method method user host)
4924 "Set up an interactive shell.
4925 Mainly sets the prompt and the echo correctly. P is the shell process
4926 to set up. METHOD, USER and HOST specify the connection."
4927 ;; Wait a bit in case the remote end feels like sending a little
4928 ;; junk first. It seems that fencepost.gnu.org does this when doing
4929 ;; a Kerberos login.
4930 (sit-for 1)
4931 (tramp-discard-garbage-erase-buffer p multi-method method user host)
4932 ;; It is useful to set the prompt in the following command because
4933 ;; some people have a setting for $PS1 which /bin/sh doesn't know
4934 ;; about and thus /bin/sh will display a strange prompt. For
4935 ;; example, if $PS1 has "${CWD}" in the value, then ksh will display
4936 ;; the current working directory but /bin/sh will display a dollar
4937 ;; sign. The following command line sets $PS1 to a sane value, and
4938 ;; works under Bourne-ish shells as well as csh-like shells. Daniel
4939 ;; Pittman reports that the unusual positioning of the single quotes
4940 ;; makes it work under `rc', too.
4941 (process-send-string nil (format "exec env 'PS1=$ ' %s%s"
4942 (tramp-get-remote-sh
4943 multi-method method user host)
4944 tramp-rsh-end-of-line))
4945 (when tramp-debug-buffer
4946 (save-excursion
4947 (set-buffer (tramp-get-debug-buffer multi-method method user host))
4948 (goto-char (point-max))
4949 (tramp-insert-with-face
4950 'bold (format "$ exec env PS1='$ ' %s\n"
4951 (tramp-get-remote-sh multi-method method user host)))))
4952 (tramp-message 9 "Waiting 30s for remote `%s' to come up..."
4953 (tramp-get-remote-sh multi-method method user host))
4954 (unless (tramp-wait-for-regexp
4955 p 30 (format "\\(%s\\|%s\\)\\'"
4956 shell-prompt-pattern tramp-shell-prompt-pattern))
4957 (pop-to-buffer (buffer-name))
4958 (error "Remote `%s' didn't come up. See buffer `%s' for details"
4959 (tramp-get-remote-sh multi-method method user host)
4960 (buffer-name)))
4961 (tramp-message 9 "Setting up remote shell environment")
4962 (tramp-discard-garbage-erase-buffer p multi-method method user host)
4963 (process-send-string
4964 nil (format "stty -inlcr -echo kill '^U'%s" tramp-rsh-end-of-line))
4965 (unless (tramp-wait-for-regexp
4966 p 30 (format "\\(%s\\|%s\\)\\'"
4967 shell-prompt-pattern tramp-shell-prompt-pattern))
4968 (pop-to-buffer (buffer-name))
4969 (error "Couldn't `stty -echo', see buffer `%s'" (buffer-name)))
4970 (erase-buffer)
4971 (process-send-string nil (format "TERM=dumb; export TERM%s"
4972 tramp-rsh-end-of-line))
4973 (unless (tramp-wait-for-regexp
4974 p 30 (format "\\(%s\\|%s\\)\\'"
4975 shell-prompt-pattern tramp-shell-prompt-pattern))
4976 (pop-to-buffer (buffer-name))
4977 (error "Couldn't `TERM=dumb; export TERM', see buffer `%s'" (buffer-name)))
4978 ;; Try to set up the coding system correctly.
4979 ;; CCC this can't be the right way to do it. Hm.
4980 (save-excursion
4981 (erase-buffer)
4982 (tramp-message 9 "Determining coding system")
4983 (process-send-string nil (format "echo foo ; echo bar %s"
4984 tramp-rsh-end-of-line))
4985 (unless (tramp-wait-for-regexp
4986 p 30 (format "\\(%s\\|%s\\)\\'"
4987 shell-prompt-pattern tramp-shell-prompt-pattern))
4988 (pop-to-buffer (buffer-name))
4989 (error "Couldn't `echo foo; echo bar' to determine line endings'"))
4990 (goto-char (point-min))
4991 (if (featurep 'mule)
4992 ;; Use MULE to select the right EOL convention for communicating
4993 ;; with the process.
4994 (let* ((cs (or (process-coding-system p) (cons 'undecided 'undecided)))
4995 cs-decode cs-encode)
4996 (when (symbolp cs) (setq cs (cons cs cs)))
4997 (setq cs-decode (car cs))
4998 (setq cs-encode (cdr cs))
4999 (unless cs-decode (setq cs-decode 'undecided))
5000 (unless cs-encode (setq cs-encode 'undecided))
5001 (setq cs-encode (tramp-coding-system-change-eol-conversion
5002 cs-encode 'unix))
5003 (when (search-forward "\r" nil t)
5004 (setq cs-decode (tramp-coding-system-change-eol-conversion
5005 cs-decode 'dos)))
5006 (set-buffer-process-coding-system cs-decode cs-encode))
5007 ;; Look for ^M and do something useful if found.
5008 (when (search-forward "\r" nil t)
5009 ;; We have found a ^M but cannot frob the process coding system
5010 ;; because we're running on a non-MULE Emacs. Let's try
5011 ;; stty, instead.
5012 (tramp-message 9 "Trying `stty -onlcr'")
5013 (process-send-string nil (format "stty -onlcr%s" tramp-rsh-end-of-line))
5014 (unless (tramp-wait-for-regexp
5015 p 30 (format "\\(%s\\|%s\\)\\'"
5016 shell-prompt-pattern tramp-shell-prompt-pattern))
5017 (pop-to-buffer (buffer-name))
5018 (error "Couldn't `stty -onlcr', see buffer `%s'" (buffer-name))))))
5019 (erase-buffer)
5020 (tramp-message
5021 9 "Waiting 30s for `HISTFILE=$HOME/.tramp_history; HISTSIZE=1'")
5022 (process-send-string
5023 nil (format "HISTFILE=$HOME/.tramp_history; HISTSIZE=1%s"
5024 tramp-rsh-end-of-line))
5025 (unless (tramp-wait-for-regexp
5026 p 30 (format "\\(%s\\|%s\\)\\'"
5027 shell-prompt-pattern tramp-shell-prompt-pattern))
5028 (pop-to-buffer (buffer-name))
5029 (error (concat "Couldn't `HISTFILE=$HOME/.tramp_history; "
5030 "HISTSIZE=1', see buffer `%s'")
5031 (buffer-name)))
5032 (erase-buffer)
5033 (tramp-message 9 "Waiting 30s for `set +o vi +o emacs'")
5034 (process-send-string
5035 nil (format "set +o vi +o emacs%s" ;mustn't `>/dev/null' with AIX?
5036 tramp-rsh-end-of-line))
5037 (unless (tramp-wait-for-regexp
5038 p 30 (format "\\(%s\\|%s\\)\\'"
5039 shell-prompt-pattern tramp-shell-prompt-pattern))
5040 (pop-to-buffer (buffer-name))
5041 (error "Couldn't `set +o vi +o emacs', see buffer `%s'"
5042 (buffer-name)))
5043 (erase-buffer)
5044 (tramp-message 9 "Waiting 30s for `unset MAIL MAILCHECK MAILPATH'")
5045 (process-send-string
5046 nil (format "unset MAIL MAILCHECK MAILPATH 1>/dev/null 2>/dev/null%s"
5047 tramp-rsh-end-of-line))
5048 (unless (tramp-wait-for-regexp
5049 p 30 (format "\\(%s\\|%s\\)\\'"
5050 shell-prompt-pattern tramp-shell-prompt-pattern))
5051 (pop-to-buffer (buffer-name))
5052 (error "Couldn't `unset MAIL MAILCHECK MAILPATH', see buffer `%s'"
5053 (buffer-name)))
5054 (erase-buffer)
5055 (tramp-message 9 "Waiting 30s for `unset CDPATH'")
5056 (process-send-string
5057 nil (format "unset CDPATH%s" tramp-rsh-end-of-line))
5058 (unless (tramp-wait-for-regexp
5059 p 30 (format "\\(%s\\|%s\\)\\'"
5060 shell-prompt-pattern tramp-shell-prompt-pattern))
5061 (pop-to-buffer (buffer-name))
5062 (error "Couldn't `unset CDPATH', see buffer `%s'"
5063 (buffer-name)))
5064 (erase-buffer)
5065 (tramp-message 9 "Setting shell prompt")
5066 ;; Douglas Gray Stephens <DGrayStephens@slb.com> says that we must
5067 ;; use "\n" here, not tramp-rsh-end-of-line. We also manually frob
5068 ;; the last time we sent a command, to avoid tramp-send-command to send
5069 ;; "echo are you awake".
5070 (setq tramp-last-cmd-time (current-time))
5071 (tramp-send-command
5072 multi-method method user host
5073 (format "PS1='%s%s%s'; PS2=''; PS3=''"
5074 tramp-rsh-end-of-line
5075 tramp-end-of-output
5076 tramp-rsh-end-of-line))
5077 (tramp-wait-for-output))
5078
5079 (defun tramp-post-connection (multi-method method user host)
5080 "Prepare a remote shell before being able to work on it.
5081 METHOD, USER and HOST specify the connection.
5082 Among other things, this finds a shell which groks tilde expansion,
5083 tries to find an `ls' command which groks the `-n' option, sets the
5084 locale to C and sets up the remote shell search path."
5085 ;; Search for a good shell before searching for a command which
5086 ;; checks if a file exists. This is done because Tramp wants to use
5087 ;; "test foo; echo $?" to check if various conditions hold, and
5088 ;; there are buggy /bin/sh implementations which don't execute the
5089 ;; "echo $?" part if the "test" part has an error. In particular,
5090 ;; the Solaris /bin/sh is a problem. I'm betting that all systems
5091 ;; with buggy /bin/sh implementations will have a working bash or
5092 ;; ksh. Whee...
5093 (tramp-find-shell multi-method method user host)
5094 ;; Without (sit-for 0.1) at least, my machine will almost always blow
5095 ;; up on 'not numberp /root' - a race that causes the 'echo ~root'
5096 ;; output of (tramp-find-shell) to show up along with the output of
5097 ;; (tramp-find-ls-command) testing.
5098 ;;
5099 ;; I can't work out why this is a problem though. The (tramp-wait-for-output)
5100 ;; call in (tramp-find-shell) *should* make this not happen, I thought.
5101 ;;
5102 ;; After much debugging I couldn't find any problem with the implementation
5103 ;; of that function though. The workaround stays for me at least. :/
5104 ;;
5105 ;; Daniel Pittman <daniel@danann.net>
5106 (sleep-for 1)
5107 (erase-buffer)
5108 (tramp-find-file-exists-command multi-method method user host)
5109 (make-local-variable 'tramp-ls-command)
5110 (setq tramp-ls-command (tramp-find-ls-command multi-method method user host))
5111 (unless tramp-ls-command
5112 (tramp-message
5113 1
5114 "Danger! Couldn't find ls which groks -n. Muddling through anyway")
5115 (setq tramp-ls-command
5116 (tramp-find-executable multi-method method user host
5117 "ls" tramp-remote-path nil)))
5118 (unless tramp-ls-command
5119 (error "Fatal error: Couldn't find remote executable `ls'"))
5120 (tramp-message 5 "Using remote command `%s' for getting directory listings"
5121 tramp-ls-command)
5122 (tramp-send-command multi-method method user host
5123 (concat "tramp_set_exit_status () {" tramp-rsh-end-of-line
5124 "return $1" tramp-rsh-end-of-line
5125 "}"))
5126 (tramp-wait-for-output)
5127 ;; Set remote PATH variable.
5128 (tramp-set-remote-path multi-method method user host "PATH" tramp-remote-path)
5129 ;; Tell remote shell to use standard time format, needed for
5130 ;; parsing `ls -l' output.
5131 (tramp-send-command multi-method method user host
5132 "LC_TIME=C; export LC_TIME; echo huhu")
5133 (tramp-wait-for-output)
5134 (tramp-send-command multi-method method user host
5135 "mesg n; echo huhu")
5136 (tramp-wait-for-output)
5137 (tramp-send-command multi-method method user host
5138 "biff n ; echo huhu")
5139 (tramp-wait-for-output)
5140 ;; Unalias ls(1) to work around issues with those silly people who make it
5141 ;; spit out ANSI escapes or whatever.
5142 (tramp-send-command multi-method method user host
5143 "unalias ls; echo huhu")
5144 (tramp-wait-for-output)
5145 ;; Does `test A -nt B' work? Use abominable `find' construct if it
5146 ;; doesn't. BSD/OS 4.0 wants the parentheses around the command,
5147 ;; for otherwise the shell crashes.
5148 (erase-buffer)
5149 (make-local-variable 'tramp-test-groks-nt)
5150 (tramp-send-command multi-method method user host
5151 "( test / -nt / )")
5152 (tramp-wait-for-output)
5153 (goto-char (point-min))
5154 (setq tramp-test-groks-nt
5155 (looking-at (format "\n%s\r?\n" (regexp-quote tramp-end-of-output))))
5156 (unless tramp-test-groks-nt
5157 (tramp-send-command
5158 multi-method method user host
5159 (concat "tramp_test_nt () {" tramp-rsh-end-of-line
5160 "test -n \"`find $1 -prune -newer $2 -print`\"" tramp-rsh-end-of-line
5161 "}")))
5162 (tramp-wait-for-output)
5163 ;; Send the fallback `uudecode' script.
5164 (erase-buffer)
5165 (tramp-send-linewise multi-method method user host tramp-uudecode)
5166 (tramp-wait-for-output)
5167 ;; Find a `perl'.
5168 (erase-buffer)
5169 (let ((tramp-remote-perl
5170 (or (tramp-find-executable multi-method method user host
5171 "perl5" tramp-remote-path nil)
5172 (tramp-find-executable multi-method method user host
5173 "perl" tramp-remote-path nil))))
5174 (when tramp-remote-perl
5175 (tramp-set-connection-property "perl" tramp-remote-perl
5176 multi-method method user host)
5177 ;; Set up stat in Perl if we can.
5178 (when tramp-remote-perl
5179 (tramp-message 5 "Sending the Perl `file-attributes' implementation.")
5180 (tramp-send-linewise
5181 multi-method method user host
5182 (concat "tramp_file_attributes () {\n"
5183 tramp-remote-perl
5184 " -e '" tramp-perl-file-attributes "' $1 2>/dev/null\n"
5185 "}"))
5186 (tramp-wait-for-output)
5187 (unless (tramp-get-rcp-program
5188 multi-method
5189 (tramp-find-method multi-method method user host)
5190 user host)
5191 (tramp-message 5 "Sending the Perl `mime-encode' implementations.")
5192 (tramp-send-linewise
5193 multi-method method user host
5194 (concat "tramp_encode () {\n"
5195 (format tramp-perl-encode tramp-remote-perl)
5196 " 2>/dev/null"
5197 "\n}"))
5198 (tramp-wait-for-output)
5199 (tramp-send-linewise
5200 multi-method method user host
5201 (concat "tramp_encode_with_module () {\n"
5202 (format tramp-perl-encode-with-module tramp-remote-perl)
5203 " 2>/dev/null"
5204 "\n}"))
5205 (tramp-wait-for-output)
5206 (tramp-message 5 "Sending the Perl `mime-decode' implementations.")
5207 (tramp-send-linewise
5208 multi-method method user host
5209 (concat "tramp_decode () {\n"
5210 (format tramp-perl-decode tramp-remote-perl)
5211 " 2>/dev/null"
5212 "\n}"))
5213 (tramp-wait-for-output)
5214 (tramp-send-linewise
5215 multi-method method user host
5216 (concat "tramp_decode_with_module () {\n"
5217 (format tramp-perl-decode-with-module tramp-remote-perl)
5218 " 2>/dev/null"
5219 "\n}"))
5220 (tramp-wait-for-output)))))
5221 ;; Find ln(1)
5222 (erase-buffer)
5223 (let ((ln (tramp-find-executable multi-method method user host
5224 "ln" tramp-remote-path nil)))
5225 (when ln
5226 (tramp-set-connection-property "ln" ln multi-method method user host)))
5227 (erase-buffer)
5228 ;; Find the right encoding/decoding commands to use.
5229 (unless (tramp-get-rcp-program
5230 multi-method
5231 (tramp-find-method multi-method method user host)
5232 user host)
5233 (tramp-find-inline-encoding multi-method method user host))
5234 ;; If encoding/decoding command are given, test to see if they work.
5235 ;; CCC: Maybe it would be useful to run the encoder both locally and
5236 ;; remotely to see if they produce the same result.
5237 (let ((rem-enc (tramp-get-remote-encoding multi-method method user host))
5238 (rem-dec (tramp-get-remote-decoding multi-method method user host))
5239 (magic-string "xyzzy"))
5240 (when (and (or rem-dec rem-enc) (not (and rem-dec rem-enc)))
5241 (tramp-kill-process multi-method method user host)
5242 ;; Improve error message and/or error check.
5243 (error
5244 "Must give both decoding and encoding command in method definition"))
5245 (when (and rem-enc rem-dec)
5246 (tramp-message
5247 5
5248 "Checking to see if encoding/decoding commands work on remote host...")
5249 (tramp-send-command
5250 multi-method method user host
5251 (format "echo %s | %s | %s"
5252 (tramp-shell-quote-argument magic-string) rem-enc rem-dec))
5253 (tramp-wait-for-output)
5254 (unless (looking-at (regexp-quote magic-string))
5255 (tramp-kill-process multi-method method user host)
5256 (error "Remote host cannot execute de/encoding commands. See buffer `%s' for details"
5257 (buffer-name)))
5258 (erase-buffer)
5259 (tramp-message
5260 5 "Checking to see if encoding/decoding commands work on remote host...done"))))
5261
5262 ;; CCC: We should either implement a Perl version of base64 encoding
5263 ;; and decoding. Then we just use that in the last item. The other
5264 ;; alternative is to use the Perl version of UU encoding. But then
5265 ;; we need a Lisp version of uuencode.
5266 ;;
5267 ;; Old text from documentation of tramp-methods:
5268 ;; Using a uuencode/uudecode inline method is discouraged, please use one
5269 ;; of the base64 methods instead since base64 encoding is much more
5270 ;; reliable and the commands are more standardized between the different
5271 ;; Unix versions. But if you can't use base64 for some reason, please
5272 ;; note that the default uudecode command does not work well for some
5273 ;; Unices, in particular AIX and Irix. For AIX, you might want to use
5274 ;; the following command for uudecode:
5275 ;;
5276 ;; sed '/^begin/d;/^[` ]$/d;/^end/d' | iconv -f uucode -t ISO8859-1
5277 ;;
5278 ;; For Irix, no solution is known yet.
5279
5280 (defvar tramp-coding-commands
5281 '(("mimencode -b" "mimencode -u -b"
5282 base64-encode-region base64-decode-region)
5283 ("mmencode -b" "mmencode -u -b"
5284 base64-encode-region base64-decode-region)
5285 ("recode data..base64" "recode base64..data"
5286 base64-encode-region base64-decode-region)
5287 ("uuencode xxx" "uudecode -o -"
5288 tramp-uuencode-region uudecode-decode-region)
5289 ("uuencode xxx" "uudecode -p"
5290 tramp-uuencode-region uudecode-decode-region)
5291 ("uuencode xxx" "tramp_uudecode"
5292 tramp-uuencode-region uudecode-decode-region)
5293 ("tramp_encode_with_module" "tramp_decode_with_module"
5294 base64-encode-region base64-decode-region)
5295 ("tramp_encode" "tramp_decode"
5296 base64-encode-region base64-decode-region))
5297 "List of coding commands for inline transfer.
5298 Each item is a list that looks like this:
5299
5300 \(REMOTE-ENCODING REMOTE-DECODING LOCAL-ENCODING LOCAL-DECODING)
5301
5302 The REMOTE-ENCODING should be a string, giving a command accepting a
5303 plain file on standard input and writing the encoded file to standard
5304 output. The REMOTE-DECODING should also be a string, giving a command
5305 accepting an encoded file on standard input and writing the decoded
5306 file to standard output.
5307
5308 LOCAL-ENCODING and LOCAL-DECODING can be strings, giving commands, or
5309 symbols, giving functions. If they are strings, then they can contain
5310 the \"%s\" format specifier. If that specifier is present, the input
5311 filename will be put into the command line at that spot. If the
5312 specifier is not present, the input should be read from standard
5313 input.
5314
5315 If they are functions, they will be called with two arguments, start
5316 and end of region, and are expected to replace the region contents
5317 with the encoded or decoded results, respectively.")
5318
5319 (defun tramp-find-inline-encoding (multi-method method user host)
5320 "Find an inline transfer encoding that works.
5321 Goes through the list `tramp-coding-commands'."
5322 (let ((commands tramp-coding-commands)
5323 (magic "xyzzy")
5324 item found)
5325 (while (and commands (null found))
5326 (setq item (pop commands))
5327 (catch 'wont-work
5328 (let ((rem-enc (nth 0 item))
5329 (rem-dec (nth 1 item))
5330 (loc-enc (nth 2 item))
5331 (loc-dec (nth 3 item)))
5332 ;; Check if remote encoding and decoding commands can be
5333 ;; called remotely with null input and output. This makes
5334 ;; sure there are no syntax errors and the command is really
5335 ;; found. Note that we do not redirect stdout to /dev/null,
5336 ;; for two reaons: when checking the decoding command, we
5337 ;; actually check the output it gives. And also, when
5338 ;; redirecting "mimencode" output to /dev/null, then as root
5339 ;; it might change the permissions of /dev/null!
5340 (tramp-message-for-buffer
5341 multi-method method user host 9
5342 "Checking remote encoding command `%s' for sanity" rem-enc)
5343 (unless (zerop (tramp-send-command-and-check
5344 multi-method method user host
5345 (format "%s </dev/null" rem-enc) t))
5346 (throw 'wont-work nil))
5347 (tramp-message-for-buffer
5348 multi-method method user host 9
5349 "Checking remote decoding command `%s' for sanity" rem-dec)
5350 (unless (zerop (tramp-send-command-and-check
5351 multi-method method user host
5352 (format "echo %s | %s | %s"
5353 magic rem-enc rem-dec) t))
5354 (throw 'wont-work nil))
5355 (save-excursion
5356 (goto-char (point-min))
5357 (unless (looking-at (regexp-quote magic))
5358 (throw 'wont-work nil)))
5359 ;; If the local encoder or decoder is a string, the
5360 ;; corresponding command has to work locally.
5361 (when (stringp loc-enc)
5362 (tramp-message-for-buffer
5363 multi-method method user host 9
5364 "Checking local encoding command `%s' for sanity" loc-enc)
5365 (unless (zerop (tramp-call-local-coding-command
5366 loc-enc nil nil))
5367 (throw 'wont-work nil)))
5368 (when (stringp loc-dec)
5369 (tramp-message-for-buffer
5370 multi-method method user host 9
5371 "Checking local decoding command `%s' for sanity" loc-dec)
5372 (unless (zerop (tramp-call-local-coding-command
5373 loc-dec nil nil))
5374 (throw 'wont-work nil)))
5375 ;; CCC: At this point, maybe we should check that the output
5376 ;; of the commands is correct. But for the moment we will
5377 ;; assume that commands working on empty input will also
5378 ;; work in practice.
5379 (setq found item))))
5380 ;; Did we find something? If not, issue error. If so,
5381 ;; set connection properties.
5382 (unless found
5383 (error "Couldn't find an inline transfer encoding"))
5384 (let ((rem-enc (nth 0 found))
5385 (rem-dec (nth 1 found))
5386 (loc-enc (nth 2 found))
5387 (loc-dec (nth 3 found)))
5388 (tramp-message 10 "Using remote encoding %s" rem-enc)
5389 (tramp-set-remote-encoding multi-method method user host rem-enc)
5390 (tramp-message 10 "Using remote decoding %s" rem-dec)
5391 (tramp-set-remote-decoding multi-method method user host rem-dec)
5392 (tramp-message 10 "Using local encoding %s" loc-enc)
5393 (tramp-set-local-encoding multi-method method user host loc-enc)
5394 (tramp-message 10 "Using local decoding %s" loc-dec)
5395 (tramp-set-local-decoding multi-method method user host loc-dec))))
5396
5397 (defun tramp-call-local-coding-command (cmd input output)
5398 "Call the local encoding or decoding command.
5399 If CMD contains \"%s\", provide input file INPUT there in command.
5400 Otherwise, INPUT is passed via standard input.
5401 INPUT can also be nil which means `/dev/null'.
5402 OUTPUT can be a string (which specifies a filename), or t (which
5403 means standard output and thus the current buffer), or nil (which
5404 means discard it)."
5405 (call-process
5406 tramp-encoding-shell ;program
5407 (when (and input (not (string-match "%s" cmd)))
5408 input) ;input
5409 (if (eq output t) t nil) ;output
5410 nil ;redisplay
5411 tramp-encoding-command-switch
5412 ;; actual shell command
5413 (concat
5414 (if (string-match "%s" cmd) (format cmd input) cmd)
5415 (if (stringp output) (concat "> " output) ""))))
5416
5417 (defun tramp-maybe-open-connection (multi-method method user host)
5418 "Maybe open a connection to HOST, logging in as USER, using METHOD.
5419 Does not do anything if a connection is already open, but re-opens the
5420 connection if a previous connection has died for some reason."
5421 (let ((p (get-buffer-process
5422 (tramp-get-buffer multi-method method user host)))
5423 last-cmd-time)
5424 ;; If too much time has passed since last command was sent, look
5425 ;; whether process is still alive. If it isn't, kill it. When
5426 ;; using ssh, it can sometimes happen that the remote end has hung
5427 ;; up but the local ssh client doesn't recognize this until it
5428 ;; tries to send some data to the remote end. So that's why we
5429 ;; try to send a command from time to time, then look again
5430 ;; whether the process is really alive.
5431 (save-excursion
5432 (set-buffer (tramp-get-buffer multi-method method user host))
5433 (when (and tramp-last-cmd-time
5434 (> (tramp-time-diff (current-time) tramp-last-cmd-time) 60)
5435 p (processp p) (memq (process-status p) '(run open)))
5436 (tramp-send-command
5437 multi-method method user host "echo are you awake" nil t)
5438 (unless (tramp-wait-for-output 10)
5439 (delete-process p)
5440 (setq p nil))
5441 (erase-buffer)))
5442 (unless (and p (processp p) (memq (process-status p) '(run open)))
5443 (when (and p (processp p))
5444 (delete-process p))
5445 (funcall (tramp-get-connection-function
5446 multi-method
5447 (tramp-find-method multi-method method user host)
5448 user host)
5449 multi-method method user host))))
5450
5451 (defun tramp-send-command
5452 (multi-method method user host command &optional noerase neveropen)
5453 "Send the COMMAND to USER at HOST (logged in using METHOD).
5454 Erases temporary buffer before sending the command (unless NOERASE
5455 is true).
5456 If optional seventh arg NEVEROPEN is non-nil, never try to open the
5457 connection. This is meant to be used from
5458 `tramp-maybe-open-connection' only."
5459 (or neveropen
5460 (tramp-maybe-open-connection multi-method method user host))
5461 (setq tramp-last-cmd-time (current-time))
5462 (when tramp-debug-buffer
5463 (save-excursion
5464 (set-buffer (tramp-get-debug-buffer multi-method method user host))
5465 (goto-char (point-max))
5466 (tramp-insert-with-face 'bold (format "$ %s\n" command))))
5467 (let ((proc nil))
5468 (set-buffer (tramp-get-buffer multi-method method user host))
5469 (unless noerase (erase-buffer))
5470 (setq proc (get-buffer-process (current-buffer)))
5471 (process-send-string proc
5472 (concat command tramp-rsh-end-of-line))))
5473
5474 ;; It seems that Tru64 Unix does not like it if long strings are sent
5475 ;; to it in one go. (This happens when sending the Perl
5476 ;; `file-attributes' implementation, for instance.) Therefore, we
5477 ;; have this function which waits a bit at each line.
5478 (defun tramp-send-linewise
5479 (multi-method method user host string &optional noerase)
5480 "Send the STRING to USER at HOST linewise.
5481 Erases temporary buffer before sending the STRING (unless NOERASE
5482 is true).
5483
5484 The STRING is expected to use Unix line-endings, but the lines sent to
5485 the remote host use line-endings as defined in the variable
5486 `tramp-rsh-end-of-line'."
5487 (tramp-maybe-open-connection multi-method method user host)
5488 (when tramp-debug-buffer
5489 (save-excursion
5490 (set-buffer (tramp-get-debug-buffer multi-method method user host))
5491 (goto-char (point-max))
5492 (tramp-insert-with-face 'bold (format "$ %s\n" string))))
5493 (let ((proc nil)
5494 (lines (split-string string "\n")))
5495 (set-buffer (tramp-get-buffer multi-method method user host))
5496 (unless noerase (erase-buffer))
5497 (setq proc (get-buffer-process (current-buffer)))
5498 (mapcar (lambda (x)
5499 (sleep-for 0.1)
5500 (process-send-string proc
5501 (concat x tramp-rsh-end-of-line)))
5502 lines)))
5503
5504 (defun tramp-wait-for-output (&optional timeout)
5505 "Wait for output from remote rsh command."
5506 (let ((proc (get-buffer-process (current-buffer)))
5507 (found nil)
5508 (start-time (current-time))
5509 (end-of-output (concat "^"
5510 (regexp-quote tramp-end-of-output)
5511 "\r?$")))
5512 ;; Algorithm: get waiting output. See if last line contains
5513 ;; end-of-output sentinel. If not, wait a bit and again get
5514 ;; waiting output. Repeat until timeout expires or end-of-output
5515 ;; sentinel is seen. Will hang if timeout is nil and
5516 ;; end-of-output sentinel never appears.
5517 (save-match-data
5518 (cond (timeout
5519 ;; Work around an XEmacs bug, where the timeout expires
5520 ;; faster than it should. This degenerates into polling
5521 ;; for buggy XEmacsen, but oh, well.
5522 (while (and (not found)
5523 (< (tramp-time-diff (current-time) start-time)
5524 timeout))
5525 (with-timeout (timeout)
5526 (while (not found)
5527 (accept-process-output proc 1)
5528 (goto-char (point-max))
5529 (forward-line -1)
5530 (setq found (looking-at end-of-output))))))
5531 (t
5532 (while (not found)
5533 (accept-process-output proc 1)
5534 (goto-char (point-max))
5535 (forward-line -1)
5536 (setq found (looking-at end-of-output))))))
5537 ;; At this point, either the timeout has expired or we have found
5538 ;; the end-of-output sentinel.
5539 (when found
5540 (goto-char (point-max))
5541 (forward-line -2)
5542 (delete-region (point) (point-max)))
5543 ;; Add output to debug buffer if appropriate.
5544 (when tramp-debug-buffer
5545 (append-to-buffer
5546 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
5547 tramp-current-user tramp-current-host)
5548 (point-min) (point-max))
5549 (when (not found)
5550 (save-excursion
5551 (set-buffer
5552 (tramp-get-debug-buffer tramp-current-multi-method tramp-current-method
5553 tramp-current-user tramp-current-host))
5554 (goto-char (point-max))
5555 (insert "[[Remote prompt `" end-of-output "' not found"
5556 (if timeout (format " in %d secs" timeout) "")
5557 "]]"))))
5558 (goto-char (point-min))
5559 ;; Return value is whether end-of-output sentinel was found.
5560 found))
5561
5562 (defun tramp-match-string-list (&optional string)
5563 "Returns list of all match strings.
5564 That is, (list (match-string 0) (match-string 1) ...), according to the
5565 number of matches."
5566 (let* ((nmatches (/ (length (match-data)) 2))
5567 (i (- nmatches 1))
5568 (res nil))
5569 (while (>= i 0)
5570 (setq res (cons (match-string i string) res))
5571 (setq i (- i 1)))
5572 res))
5573
5574 (defun tramp-send-command-and-check (multi-method method user host command
5575 &optional subshell)
5576 "Run COMMAND and check its exit status.
5577 MULTI-METHOD and METHOD specify how to log in (as USER) to the remote HOST.
5578 Sends `echo $?' along with the COMMAND for checking the exit status. If
5579 COMMAND is nil, just sends `echo $?'. Returns the exit status found.
5580
5581 If the optional argument SUBSHELL is non-nil, the command is executed in
5582 a subshell, ie surrounded by parentheses."
5583 (tramp-send-command multi-method method user host
5584 (concat (if subshell "( " "")
5585 command
5586 (if command " 2>/dev/null; " "")
5587 "echo tramp_exit_status $?"
5588 (if subshell " )" " ")))
5589 (tramp-wait-for-output)
5590 (goto-char (point-max))
5591 (unless (search-backward "tramp_exit_status " nil t)
5592 (error "Couldn't find exit status of `%s'" command))
5593 (skip-chars-forward "^ ")
5594 (read (current-buffer)))
5595
5596 (defun tramp-barf-unless-okay (multi-method method user host command subshell
5597 signal fmt &rest args)
5598 "Run COMMAND, check exit status, throw error if exit status not okay.
5599 Similar to `tramp-send-command-and-check' but accepts two more arguments
5600 FMT and ARGS which are passed to `error'."
5601 (unless (zerop (tramp-send-command-and-check
5602 multi-method method user host command subshell))
5603 ;; CCC: really pop-to-buffer? Maybe it's appropriate to be more
5604 ;; silent.
5605 (pop-to-buffer (current-buffer))
5606 (funcall 'signal signal (apply 'format fmt args))))
5607
5608 ;; Chunked sending kluge.
5609 (defvar tramp-chunksize nil
5610 "If non-nil, chunksize for sending things to remote host.")
5611
5612 (defun tramp-send-region (multi-method method user host start end)
5613 "Send the region from START to END to remote command
5614 running as USER on HOST using METHOD."
5615 (let ((proc (get-buffer-process
5616 (tramp-get-buffer multi-method method user host))))
5617 (unless proc
5618 (error "Can't send region to remote host -- not logged in"))
5619 (if tramp-chunksize
5620 (let ((pos start))
5621 (while (< pos end)
5622 (tramp-message-for-buffer
5623 multi-method method user host 10
5624 "Sending chunk from %s to %s" pos end)
5625 (process-send-region proc
5626 pos
5627 (min (+ pos tramp-chunksize)
5628 end))
5629 (setq pos (+ pos tramp-chunksize))
5630 (sleep-for 0.1)))
5631 (process-send-region proc start end))
5632 (when tramp-debug-buffer
5633 (append-to-buffer
5634 (tramp-get-debug-buffer multi-method method user host)
5635 start end))))
5636
5637 (defun tramp-send-eof (multi-method method user host)
5638 "Send EOF to the remote end.
5639 METHOD, HOST and USER specify the connection."
5640 (let ((proc (get-buffer-process
5641 (tramp-get-buffer multi-method method user host))))
5642 (unless proc
5643 (error "Can't send EOF to remote host -- not logged in"))
5644 (process-send-eof proc)))
5645 ; (process-send-string proc "\^D")))
5646
5647 (defun tramp-kill-process (multi-method method user host)
5648 "Kill the connection process used by Tramp.
5649 MULTI-METHOD, METHOD, USER, and HOST specify the connection."
5650 (let ((proc (get-buffer-process
5651 (tramp-get-buffer multi-method method user host))))
5652 (kill-process proc)))
5653
5654 (defun tramp-discard-garbage-erase-buffer (p multi-method method user host)
5655 "Erase buffer, then discard subsequent garbage.
5656 If `tramp-discard-garbage' is nil, just erase buffer."
5657 (if (not tramp-discard-garbage)
5658 (erase-buffer)
5659 (while (prog1 (erase-buffer) (accept-process-output p 0.25))
5660 (when tramp-debug-buffer
5661 (save-excursion
5662 (set-buffer (tramp-get-debug-buffer multi-method method user host))
5663 (goto-char (point-max))
5664 (tramp-insert-with-face
5665 'bold (format "Additional characters detected\n")))))))
5666
5667 (defun tramp-mode-string-to-int (mode-string)
5668 "Converts a ten-letter `drwxrwxrwx'-style mode string into mode bits."
5669 (let* ((mode-chars (string-to-vector mode-string))
5670 (owner-read (aref mode-chars 1))
5671 (owner-write (aref mode-chars 2))
5672 (owner-execute-or-setid (aref mode-chars 3))
5673 (group-read (aref mode-chars 4))
5674 (group-write (aref mode-chars 5))
5675 (group-execute-or-setid (aref mode-chars 6))
5676 (other-read (aref mode-chars 7))
5677 (other-write (aref mode-chars 8))
5678 (other-execute-or-sticky (aref mode-chars 9)))
5679 (save-match-data
5680 (logior
5681 (case owner-read
5682 (?r (tramp-octal-to-decimal "00400")) (?- 0)
5683 (t (error "Second char `%c' must be one of `r-'" owner-read)))
5684 (case owner-write
5685 (?w (tramp-octal-to-decimal "00200")) (?- 0)
5686 (t (error "Third char `%c' must be one of `w-'" owner-write)))
5687 (case owner-execute-or-setid
5688 (?x (tramp-octal-to-decimal "00100"))
5689 (?S (tramp-octal-to-decimal "04000"))
5690 (?s (tramp-octal-to-decimal "04100"))
5691 (?- 0)
5692 (t (error "Fourth char `%c' must be one of `xsS-'"
5693 owner-execute-or-setid)))
5694 (case group-read
5695 (?r (tramp-octal-to-decimal "00040")) (?- 0)
5696 (t (error "Fifth char `%c' must be one of `r-'" group-read)))
5697 (case group-write
5698 (?w (tramp-octal-to-decimal "00020")) (?- 0)
5699 (t (error "Sixth char `%c' must be one of `w-'" group-write)))
5700 (case group-execute-or-setid
5701 (?x (tramp-octal-to-decimal "00010"))
5702 (?S (tramp-octal-to-decimal "02000"))
5703 (?s (tramp-octal-to-decimal "02010"))
5704 (?- 0)
5705 (t (error "Seventh char `%c' must be one of `xsS-'"
5706 group-execute-or-setid)))
5707 (case other-read
5708 (?r (tramp-octal-to-decimal "00004")) (?- 0)
5709 (t (error "Eighth char `%c' must be one of `r-'" other-read)))
5710 (case other-write
5711 (?w (tramp-octal-to-decimal "00002")) (?- 0)
5712 (t (error "Nineth char `%c' must be one of `w-'" other-write)))
5713 (case other-execute-or-sticky
5714 (?x (tramp-octal-to-decimal "00001"))
5715 (?T (tramp-octal-to-decimal "01000"))
5716 (?t (tramp-octal-to-decimal "01001"))
5717 (?- 0)
5718 (t (error "Tenth char `%c' must be one of `xtT-'"
5719 other-execute-or-sticky)))))))
5720
5721
5722 (defun tramp-file-mode-from-int (mode)
5723 "Turn an integer representing a file mode into an ls(1)-like string."
5724 (let ((type (cdr (assoc (logand (lsh mode -12) 15) tramp-file-mode-type-map)))
5725 (user (logand (lsh mode -6) 7))
5726 (group (logand (lsh mode -3) 7))
5727 (other (logand (lsh mode -0) 7))
5728 (suid (> (logand (lsh mode -9) 4) 0))
5729 (sgid (> (logand (lsh mode -9) 2) 0))
5730 (sticky (> (logand (lsh mode -9) 1) 0)))
5731 (setq user (tramp-file-mode-permissions user suid "s"))
5732 (setq group (tramp-file-mode-permissions group sgid "s"))
5733 (setq other (tramp-file-mode-permissions other sticky "t"))
5734 (concat type user group other)))
5735
5736
5737 (defun tramp-file-mode-permissions (perm suid suid-text)
5738 "Convert a permission bitset into a string.
5739 This is used internally by `tramp-file-mode-from-int'."
5740 (let ((r (> (logand perm 4) 0))
5741 (w (> (logand perm 2) 0))
5742 (x (> (logand perm 1) 0)))
5743 (concat (or (and r "r") "-")
5744 (or (and w "w") "-")
5745 (or (and suid x suid-text) ; suid, execute
5746 (and suid (upcase suid-text)) ; suid, !execute
5747 (and x "x") "-")))) ; !suid
5748
5749
5750 (defun tramp-decimal-to-octal (i)
5751 "Return a string consisting of the octal digits of I.
5752 Not actually used. Use `(format \"%o\" i)' instead?"
5753 (cond ((< i 0) (error "Cannot convert negative number to octal"))
5754 ((not (integerp i)) (error "Cannot convert non-integer to octal"))
5755 ((zerop i) "0")
5756 (t (concat (tramp-decimal-to-octal (/ i 8))
5757 (number-to-string (% i 8))))))
5758
5759
5760 ;;(defun tramp-octal-to-decimal (ostr)
5761 ;; "Given a string of octal digits, return a decimal number."
5762 ;; (cond ((null ostr) 0)
5763 ;; ((string= "" ostr) 0)
5764 ;; (t (let ((last (aref ostr (1- (length ostr))))
5765 ;; (rest (substring ostr 0 (1- (length ostr)))))
5766 ;; (unless (and (>= last ?0)
5767 ;; (<= last ?7))
5768 ;; (error "Not an octal digit: %c" last))
5769 ;; (+ (- last ?0) (* 8 (tramp-octal-to-decimal rest)))))))
5770 ;; Kudos to Gerd Moellmann for this suggestion.
5771 (defun tramp-octal-to-decimal (ostr)
5772 "Given a string of octal digits, return a decimal number."
5773 (let ((x (or ostr "")))
5774 ;; `save-match' is in `tramp-mode-string-to-int' which calls this.
5775 (unless (string-match "\\`[0-7]*\\'" x)
5776 (error "Non-octal junk in string `%s'" x))
5777 (string-to-number ostr 8)))
5778
5779 (defun tramp-shell-case-fold (string)
5780 "Converts STRING to shell glob pattern which ignores case."
5781 (mapconcat
5782 (lambda (c)
5783 (if (equal (downcase c) (upcase c))
5784 (vector c)
5785 (format "[%c%c]" (downcase c) (upcase c))))
5786 string
5787 ""))
5788
5789
5790 ;; ------------------------------------------------------------
5791 ;; -- TRAMP file names --
5792 ;; ------------------------------------------------------------
5793 ;; Conversion functions between external representation and
5794 ;; internal data structure. Convenience functions for internal
5795 ;; data structure.
5796
5797 (defstruct tramp-file-name multi-method method user host path)
5798
5799 (defun tramp-tramp-file-p (name)
5800 "Return t iff NAME is a tramp file."
5801 (save-match-data
5802 (string-match tramp-file-name-regexp name)))
5803
5804 ;; HHH: Changed. Used to assign the return value of (user-login-name)
5805 ;; to the `user' part of the structure if a user name was not
5806 ;; provided, now it assigns nil.
5807 (defun tramp-dissect-file-name (name)
5808 "Return an `tramp-file-name' structure.
5809 The structure consists of remote method, remote user, remote host and
5810 remote path name."
5811 (let (method)
5812 (save-match-data
5813 (unless (string-match (nth 0 tramp-file-name-structure) name)
5814 (error "Not a tramp file name: %s" name))
5815 (setq method (match-string (nth 1 tramp-file-name-structure) name))
5816 (if (and method (member method tramp-multi-methods))
5817 ;; If it's a multi method, the file name structure contains
5818 ;; arrays of method, user and host.
5819 (tramp-dissect-multi-file-name name)
5820 ;; Normal method. First, find out default method.
5821 (let ((user (match-string (nth 2 tramp-file-name-structure) name))
5822 (host (match-string (nth 3 tramp-file-name-structure) name))
5823 (path (match-string (nth 4 tramp-file-name-structure) name)))
5824 (make-tramp-file-name
5825 :multi-method nil
5826 :method method
5827 :user (or user nil)
5828 :host host
5829 :path path))))))
5830
5831 (defun tramp-find-default-method (user host)
5832 "Look up the right method to use in `tramp-default-method-alist'."
5833 (let ((choices tramp-default-method-alist)
5834 (method tramp-default-method)
5835 item)
5836 (while choices
5837 (setq item (pop choices))
5838 (when (and (string-match (nth 0 item) (or host ""))
5839 (string-match (nth 1 item) (or user "")))
5840 (setq method (nth 2 item))
5841 (setq choices nil)))
5842 method))
5843
5844 (defun tramp-find-method (multi-method method user host)
5845 "Return the right method string to use.
5846 This is MULTI-METHOD, if non-nil. Otherwise, it is METHOD, if non-nil.
5847 If both MULTI-METHOD and METHOD are nil, do a lookup in
5848 `tramp-default-method-alist'."
5849 (or multi-method method (tramp-find-default-method user host)))
5850
5851 ;; HHH: Not Changed. Multi method. Will probably not handle the case where
5852 ;; a user name is not provided in the "file name" very well.
5853 (defun tramp-dissect-multi-file-name (name)
5854 "Not implemented yet."
5855 (let ((regexp (nth 0 tramp-multi-file-name-structure))
5856 (method-index (nth 1 tramp-multi-file-name-structure))
5857 (hops-index (nth 2 tramp-multi-file-name-structure))
5858 (path-index (nth 3 tramp-multi-file-name-structure))
5859 (hop-regexp (nth 0 tramp-multi-file-name-hop-structure))
5860 (hop-method-index (nth 1 tramp-multi-file-name-hop-structure))
5861 (hop-user-index (nth 2 tramp-multi-file-name-hop-structure))
5862 (hop-host-index (nth 3 tramp-multi-file-name-hop-structure))
5863 method hops len hop-methods hop-users hop-hosts path)
5864 (unless (string-match (format regexp hop-regexp) name)
5865 (error "Not a multi tramp file name: %s" name))
5866 (setq method (match-string method-index name))
5867 (setq hops (match-string hops-index name))
5868 (setq len (/ (length (match-data t)) 2))
5869 (when (< path-index 0) (incf path-index len))
5870 (setq path (match-string path-index name))
5871 (let ((index 0))
5872 (while (string-match hop-regexp hops index)
5873 (setq index (match-end 0))
5874 (setq hop-methods
5875 (cons (match-string hop-method-index hops) hop-methods))
5876 (setq hop-users
5877 (cons (match-string hop-user-index hops) hop-users))
5878 (setq hop-hosts
5879 (cons (match-string hop-host-index hops) hop-hosts))))
5880 (make-tramp-file-name
5881 :multi-method method
5882 :method (apply 'vector (reverse hop-methods))
5883 :user (apply 'vector (reverse hop-users))
5884 :host (apply 'vector (reverse hop-hosts))
5885 :path path)))
5886
5887 (defun tramp-make-tramp-file-name (multi-method method user host path)
5888 "Constructs a tramp file name from METHOD, USER, HOST and PATH."
5889 (if multi-method
5890 (tramp-make-tramp-multi-file-name multi-method method user host path)
5891 (format-spec
5892 (concat tramp-prefix-format
5893 (when method (concat "%m" tramp-postfix-single-method-format))
5894 (when user (concat "%u" tramp-postfix-user-format))
5895 (when host (concat "%h" tramp-postfix-host-format))
5896 (when path (concat "%p")))
5897 `((?m . ,method) (?u . ,user) (?h . ,host) (?p . ,path)))))
5898
5899 ;; CCC: Henrik Holm: Not Changed. Multi Method. What should be done
5900 ;; with this when USER is nil?
5901 (defun tramp-make-tramp-multi-file-name (multi-method method user host path)
5902 "Constructs a tramp file name for a multi-hop method."
5903 (unless tramp-make-multi-tramp-file-format
5904 (error "`tramp-make-multi-tramp-file-format' is nil"))
5905 (let* ((prefix-format (nth 0 tramp-make-multi-tramp-file-format))
5906 (hop-format (nth 1 tramp-make-multi-tramp-file-format))
5907 (path-format (nth 2 tramp-make-multi-tramp-file-format))
5908 (prefix (format-spec prefix-format `((?m . ,multi-method))))
5909 (hops "")
5910 (path (format-spec path-format `((?p . ,path))))
5911 (i 0)
5912 (len (length method)))
5913 (while (< i len)
5914 (let ((m (aref method i)) (u (aref user i)) (h (aref host i)))
5915 (setq hops (concat hops (format-spec hop-format
5916 `((?m . ,m) (?u . ,u) (?h . ,h)))))
5917 (incf i)))
5918 (concat prefix hops path)))
5919
5920 (defun tramp-make-rcp-program-file-name (user host path)
5921 "Create a file name suitable to be passed to `rcp'."
5922 (if user
5923 (format "%s@%s:%s" user host path)
5924 (format "%s:%s" host path)))
5925
5926 (defun tramp-make-ange-ftp-file-name (user host path)
5927 "Given user, host, and path, return an Ange-FTP filename."
5928 (if user
5929 (format "/%s@%s:%s" user host path)
5930 (format "/%s:%s" host path)))
5931
5932 (defun tramp-method-out-of-band-p (multi-method method user host)
5933 "Return t if this is an out-of-band method, nil otherwise.
5934 It is important to check for this condition, since it is not possible
5935 to enter a password for the `tramp-rcp-program'."
5936 (tramp-get-rcp-program
5937 multi-method
5938 (tramp-find-method multi-method method user host)
5939 user host))
5940
5941 ;; Variables local to connection.
5942
5943 (defun tramp-get-ls-command (multi-method method user host)
5944 (save-excursion
5945 (tramp-maybe-open-connection multi-method method user host)
5946 (set-buffer (tramp-get-buffer multi-method method user host))
5947 tramp-ls-command))
5948
5949 (defun tramp-get-test-groks-nt (multi-method method user host)
5950 (save-excursion
5951 (tramp-maybe-open-connection multi-method method user host)
5952 (set-buffer (tramp-get-buffer multi-method method user host))
5953 tramp-test-groks-nt))
5954
5955 (defun tramp-get-file-exists-command (multi-method method user host)
5956 (save-excursion
5957 (tramp-maybe-open-connection multi-method method user host)
5958 (set-buffer (tramp-get-buffer multi-method method user host))
5959 tramp-file-exists-command))
5960
5961 (defun tramp-get-remote-perl (multi-method method user host)
5962 (tramp-get-connection-property "perl" nil multi-method method user host))
5963
5964 (defun tramp-get-remote-ln (multi-method method user host)
5965 (tramp-get-connection-property "ln" nil multi-method method user host))
5966
5967 ;; Get a property of a TRAMP connection.
5968 (defun tramp-get-connection-property
5969 (property default multi-method method user host)
5970 "Get the named property for the connection.
5971 If the value is not set for the connection, return `default'"
5972 (tramp-maybe-open-connection multi-method method user host)
5973 (with-current-buffer (tramp-get-buffer multi-method method user host)
5974 (let (error)
5975 (condition-case nil
5976 (symbol-value (intern (concat "tramp-connection-property-" property)))
5977 (error default)))))
5978
5979 ;; Set a property of a TRAMP connection.
5980 (defun tramp-set-connection-property
5981 (property value multi-method method user host)
5982 "Set the named property of a TRAMP connection."
5983 (tramp-maybe-open-connection multi-method method user host)
5984 (with-current-buffer (tramp-get-buffer multi-method method user host)
5985 (set (make-local-variable
5986 (intern (concat "tramp-connection-property-" property)))
5987 value)))
5988
5989 ;; Some predefined connection properties.
5990 (defun tramp-set-remote-encoding (multi-method method user host rem-enc)
5991 (tramp-set-connection-property "remote-encoding" rem-enc
5992 multi-method method user host))
5993 (defun tramp-get-remote-encoding (multi-method method user host)
5994 (tramp-get-connection-property "remote-encoding" nil
5995 multi-method method user host))
5996
5997 (defun tramp-set-remote-decoding (multi-method method user host rem-dec)
5998 (tramp-set-connection-property "remote-decoding" rem-dec
5999 multi-method method user host))
6000 (defun tramp-get-remote-decoding (multi-method method user host)
6001 (tramp-get-connection-property "remote-decoding" nil
6002 multi-method method user host))
6003
6004 (defun tramp-set-local-encoding (multi-method method user host loc-enc)
6005 (tramp-set-connection-property "local-encoding" loc-enc
6006 multi-method method user host))
6007 (defun tramp-get-local-encoding (multi-method method user host)
6008 (tramp-get-connection-property "local-encoding" nil
6009 multi-method method user host))
6010
6011 (defun tramp-set-local-decoding (multi-method method user host loc-dec)
6012 (tramp-set-connection-property "local-decoding" loc-dec
6013 multi-method method user host))
6014 (defun tramp-get-local-decoding (multi-method method user host)
6015 (tramp-get-connection-property "local-decoding" nil
6016 multi-method method user host))
6017
6018
6019
6020 (defun tramp-get-connection-function (multi-method method user host)
6021 (second (or (assoc 'tramp-connection-function
6022 (assoc (tramp-find-method multi-method method user host)
6023 tramp-methods))
6024 (error "Method `%s' didn't specify a connection function"
6025 (or multi-method method)))))
6026
6027 (defun tramp-get-remote-sh (multi-method method user host)
6028 (second (or (assoc 'tramp-remote-sh
6029 (assoc (tramp-find-method multi-method method user host)
6030 tramp-methods))
6031 (error "Method `%s' didn't specify a remote shell"
6032 (or multi-method method)))))
6033
6034 (defun tramp-get-rsh-program (multi-method method user host)
6035 (second (or (assoc 'tramp-rsh-program
6036 (assoc (tramp-find-method multi-method method user host)
6037 tramp-methods))
6038 (error "Method `%s' didn't specify an rsh program"
6039 (or multi-method method)))))
6040
6041 (defun tramp-get-rsh-args (multi-method method user host)
6042 (second (or (assoc 'tramp-rsh-args
6043 (assoc (tramp-find-method multi-method method user host)
6044 tramp-methods))
6045 (error "Method `%s' didn't specify rsh args"
6046 (or multi-method method)))))
6047
6048 (defun tramp-get-rcp-program (multi-method method user host)
6049 (second (or (assoc 'tramp-rcp-program
6050 (assoc (tramp-find-method multi-method method user host)
6051 tramp-methods))
6052 (error "Method `%s' didn't specify an rcp program"
6053 (or multi-method method)))))
6054
6055 (defun tramp-get-rcp-args (multi-method method user host)
6056 (second (or (assoc 'tramp-rcp-args
6057 (assoc (tramp-find-method multi-method method user host)
6058 tramp-methods))
6059 (error "Method `%s' didn't specify rcp args"
6060 (or multi-method method)))))
6061
6062 (defun tramp-get-rcp-keep-date-arg (multi-method method user host)
6063 (second (or (assoc 'tramp-rcp-keep-date-arg
6064 (assoc (tramp-find-method multi-method method user host)
6065 tramp-methods))
6066 (error "Method `%s' didn't specify `keep-date' arg for tramp"
6067 (or multi-method method)))))
6068
6069 (defun tramp-get-su-program (multi-method method user host)
6070 (second (or (assoc 'tramp-su-program
6071 (assoc (tramp-find-method multi-method method user host)
6072 tramp-methods))
6073 (error "Method `%s' didn't specify a su program"
6074 (or multi-method method)))))
6075
6076 (defun tramp-get-su-args (multi-method method user host)
6077 (second (or (assoc 'tramp-su-args
6078 (assoc (tramp-find-method multi-method method user host)
6079 tramp-methods))
6080 (error "Method `%s' didn't specify su args"
6081 (or multi-method method)))))
6082
6083 (defun tramp-get-telnet-program (multi-method method user host)
6084 (second (or (assoc 'tramp-telnet-program
6085 (assoc (tramp-find-method multi-method method user host)
6086 tramp-methods))
6087 (error "Method `%s' didn't specify a telnet program"
6088 (or multi-method method)))))
6089
6090 (defun tramp-get-telnet-args (multi-method method user host)
6091 (second (or (assoc 'tramp-telnet-args
6092 (assoc (tramp-find-method multi-method method user host)
6093 tramp-methods))
6094 (error "Method `%s' didn't specify telnet args"
6095 (or multi-method method)))))
6096
6097
6098 ;; Auto saving to a special directory.
6099
6100 (defun tramp-make-auto-save-file-name (fn)
6101 "Returns a file name in `tramp-auto-save-directory' for autosaving this file."
6102 (when tramp-auto-save-directory
6103 (unless (file-exists-p tramp-auto-save-directory)
6104 (make-directory tramp-auto-save-directory t)))
6105 ;; jka-compr doesn't like auto-saving, so by appending "~" to the
6106 ;; file name we make sure that jka-compr isn't used for the
6107 ;; auto-save file.
6108 (let ((buffer-file-name (expand-file-name
6109 (tramp-subst-strs-in-string '(("_" . "|")
6110 ("/" . "_a")
6111 (":" . "_b")
6112 ("|" . "__")
6113 ("[" . "_l")
6114 ("]" . "_r"))
6115 fn)
6116 tramp-auto-save-directory)))
6117 (make-auto-save-file-name)))
6118
6119 (defadvice make-auto-save-file-name
6120 (around tramp-advice-make-auto-save-file-name () activate)
6121 "Invoke `tramp-make-auto-save-file-name' for tramp files."
6122 (if (and (buffer-file-name) (tramp-tramp-file-p (buffer-file-name))
6123 tramp-auto-save-directory)
6124 (setq ad-return-value
6125 (tramp-make-auto-save-file-name (buffer-file-name)))
6126 ad-do-it))
6127
6128 (defun tramp-subst-strs-in-string (alist string)
6129 "Replace all occurrences of the string FROM with TO in STRING.
6130 ALIST is of the form ((FROM . TO) ...)."
6131 (save-match-data
6132 (while alist
6133 (let* ((pr (car alist))
6134 (from (car pr))
6135 (to (cdr pr)))
6136 (while (string-match (regexp-quote from) string)
6137 (setq string (replace-match to t t string)))
6138 (setq alist (cdr alist))))
6139 string))
6140
6141 (defun tramp-insert-with-face (face string)
6142 "Insert text with a specific face."
6143 (let ((start (point)))
6144 (insert string)
6145 (add-text-properties start (point) (list 'face face))))
6146
6147 ;; ------------------------------------------------------------
6148 ;; -- Compatibility functions section --
6149 ;; ------------------------------------------------------------
6150
6151 (defun tramp-temporary-file-directory ()
6152 "Return name of directory for temporary files (compat function).
6153 For Emacs, this is the variable `temporary-file-directory', for XEmacs
6154 this is the function `temp-directory'."
6155 (cond ((boundp 'temporary-file-directory)
6156 (symbol-value 'temporary-file-directory))
6157 ((fboundp 'temp-directory)
6158 (funcall (symbol-function 'temp-directory))) ;pacify byte-compiler
6159 ((let ((d (getenv "TEMP"))) (and d (file-directory-p d)))
6160 (file-name-as-directory (getenv "TEMP")))
6161 ((let ((d (getenv "TMP"))) (and d (file-directory-p d)))
6162 (file-name-as-directory (getenv "TMP")))
6163 ((let ((d (getenv "TMPDIR"))) (and d (file-directory-p d)))
6164 (file-name-as-directory (getenv "TMPDIR")))
6165 ((file-exists-p "c:/temp") (file-name-as-directory "c:/temp"))
6166 (t (message (concat "Neither `temporary-file-directory' nor "
6167 "`temp-directory' is defined -- using /tmp."))
6168 (file-name-as-directory "/tmp"))))
6169
6170 (defun tramp-read-passwd (prompt)
6171 "Read a password from user (compat function).
6172 Invokes `read-passwd' if that is defined, else `ange-ftp-read-passwd'."
6173 (apply
6174 (if (fboundp 'read-passwd) #'read-passwd #'ange-ftp-read-passwd)
6175 (list prompt)))
6176
6177 (defun tramp-time-diff (t1 t2)
6178 "Return the difference between the two times, in seconds.
6179 T1 and T2 are time values (as returned by `current-time' for example).
6180
6181 NOTE: This function will fail if the time difference is too large to
6182 fit in an integer."
6183 ;; Pacify byte-compiler with `symbol-function'.
6184 (cond ((fboundp 'subtract-time)
6185 (cadr (funcall (symbol-function 'subtract-time) t1 t2)))
6186 ((fboundp 'itimer-time-difference)
6187 (floor (funcall
6188 (symbol-function 'itimer-time-difference)
6189 (if (< (length t1) 3) (append t1 '(0)) t1)
6190 (if (< (length t2) 3) (append t2 '(0)) t2))))
6191 (t
6192 ;; snarfed from Emacs 21 time-date.el
6193 (cadr (let ((borrow (< (cadr t1) (cadr t2))))
6194 (list (- (car t1) (car t2) (if borrow 1 0))
6195 (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2))))))))
6196
6197 (defun tramp-coding-system-change-eol-conversion (coding-system eol-type)
6198 "Return a coding system like CODING-SYSTEM but with given EOL-TYPE.
6199 EOL-TYPE can be one of `dos', `unix', or `mac'."
6200 (cond ((fboundp 'coding-system-change-eol-conversion)
6201 (apply #'coding-system-change-eol-conversion
6202 (list coding-system eol-type)))
6203 ((fboundp 'subsidiary-coding-system)
6204 (apply
6205 #'subsidiary-coding-system
6206 (list coding-system
6207 (cond ((eq eol-type 'dos) 'crlf)
6208 ((eq eol-type 'unix) 'lf)
6209 ((eq eol-type 'mac) 'cr)
6210 (t
6211 (error "Unknown EOL-TYPE `%s', must be %s"
6212 eol-type
6213 "`dos', `unix', or `mac'"))))))
6214 (t (error "Can't change EOL conversion -- is MULE missing?"))))
6215
6216 (defun tramp-split-string (string pattern)
6217 "Like `split-string' but omit empty strings.
6218 In Emacs, (split-string \"/foo/bar\" \"/\") returns (\"foo\" \"bar\").
6219 This is, the first, empty, element is omitted. In XEmacs, the first
6220 element is not omitted.
6221
6222 Note: this function has been written for `tramp-handle-file-truename'.
6223 If you want to use it for something else, you'll have to check whether
6224 it does the right thing."
6225 (delete "" (split-string string pattern)))
6226
6227 ;; ------------------------------------------------------------
6228 ;; -- Kludges section --
6229 ;; ------------------------------------------------------------
6230
6231 ;; Currently (as of Emacs 20.5), the function `shell-quote-argument'
6232 ;; does not deal well with newline characters. Newline is replaced by
6233 ;; backslash newline. But if, say, the string `a backslash newline b'
6234 ;; is passed to a shell, the shell will expand this into "ab",
6235 ;; completely omitting the newline. This is not what was intended.
6236 ;; It does not appear to be possible to make the function
6237 ;; `shell-quote-argument' work with newlines without making it
6238 ;; dependent on the shell used. But within this package, we know that
6239 ;; we will always use a Bourne-like shell, so we use an approach which
6240 ;; groks newlines.
6241 ;;
6242 ;; The approach is simple: we call `shell-quote-argument', then
6243 ;; massage the newline part of the result.
6244 ;;
6245 ;; This function should produce a string which is grokked by a Unix
6246 ;; shell, even if the Emacs is running on Windows. Since this is the
6247 ;; kludges section, we bind `system-type' in such a way that
6248 ;; `shell-quote-arguments' behaves as if on Unix.
6249 ;;
6250 ;; Thanks to Mario DeWeerd for the hint that it is sufficient for this
6251 ;; function to work with Bourne-like shells.
6252 ;;
6253 ;; CCC: This function should be rewritten so that
6254 ;; `shell-quote-argument' is not used. This way, we are safe from
6255 ;; changes in `shell-quote-argument'.
6256 (defun tramp-shell-quote-argument (s)
6257 "Similar to `shell-quote-argument', but groks newlines.
6258 Only works for Bourne-like shells."
6259 (let ((system-type 'not-windows))
6260 (save-match-data
6261 (let ((result (shell-quote-argument s))
6262 (nl (regexp-quote (format "\\%s" tramp-rsh-end-of-line))))
6263 (when (and (>= (length result) 2)
6264 (string= (substring result 0 2) "\\~"))
6265 (setq result (substring result 1)))
6266 (while (string-match nl result)
6267 (setq result (replace-match (format "'%s'" tramp-rsh-end-of-line)
6268 t t result)))
6269 result))))
6270
6271 ;; ;; EFS hooks itself into the file name handling stuff in more places
6272 ;; ;; than just `file-name-handler-alist'. The following tells EFS to stay
6273 ;; ;; away from tramp.el paths.
6274 ;; ;;
6275 ;; ;; This is needed because EFS installs (efs-dired-before-readin) into
6276 ;; ;; 'dired-before-readin-hook'. This prevents EFS from opening an FTP
6277 ;; ;; connection to help it's dired process. Not that I have any real
6278 ;; ;; idea *why* this is helpful to dired.
6279 ;; ;;
6280 ;; ;; Anyway, this advice fixes the problem (with a sledgehammer :)
6281 ;; ;;
6282 ;; ;; Daniel Pittman <daniel@danann.net>
6283 ;; ;;
6284 ;; ;; CCC: when the other defadvice calls have disappeared, make sure
6285 ;; ;; not to call defadvice unless it's necessary. How do we find out whether
6286 ;; ;; it is necessary? (featurep 'efs) is surely the wrong way --
6287 ;; ;; EFS might nicht be loaded yet.
6288 ;; (defadvice efs-ftp-path (around dont-match-tramp-path activate protect)
6289 ;; "Cause efs-ftp-path to fail when the path is a TRAMP path."
6290 ;; (if (tramp-tramp-file-p (ad-get-arg 0))
6291 ;; nil
6292 ;; ad-do-it))
6293
6294 ;; We currently (sometimes) use "[" and "]" in the filename format.
6295 ;; This means that Emacs wants to expand wildcards if
6296 ;; `find-file-wildcards' is non-nil, and then barfs because no
6297 ;; expansion could be found. We detect this situation and do
6298 ;; something really awful: we have `file-expand-wildcards' return the
6299 ;; original filename if it can't expand anything. Let's just hope
6300 ;; that this doesn't break anything else.
6301 ;; CCC: This check is now also really awful; we should search all
6302 ;; of the filename format, not just the prefix.
6303 (when (string-match "\\[" tramp-prefix-format)
6304 (defadvice file-expand-wildcards (around tramp-fix activate)
6305 (let ((name (ad-get-arg 0)))
6306 (if (tramp-tramp-file-p name)
6307 ;; If it's a Tramp file, dissect it and look if wildcards
6308 ;; need to be expanded at all.
6309 (let ((v (tramp-dissect-file-name name)))
6310 (if (string-match "[[*?]" (tramp-file-name-path v))
6311 (let ((res ad-do-it))
6312 (setq ad-return-value (or res (list name))))
6313 (setq ad-return-value (list name))))
6314 ;; If it is not a Tramp file, just run the original function.
6315 (let ((res ad-do-it))
6316 (setq ad-return-value (or res (list name)))))))
6317 )
6318
6319 ;; Tramp version is useful in a number of situations.
6320
6321 (defun tramp-version (arg)
6322 "Print version number of tramp.el in minibuffer or current buffer."
6323 (interactive "P")
6324 (if arg (insert tramp-version) (message tramp-version)))
6325
6326 ;; Make the `reporter` functionality available for making bug reports about
6327 ;; the package. A most useful piece of code.
6328
6329 (unless (fboundp 'reporter-submit-bug-report)
6330 (autoload 'reporter-submit-bug-report "reporter"))
6331
6332 (defun tramp-bug ()
6333 "Submit a bug report to the TRAMP developers."
6334 (interactive)
6335 (require 'reporter)
6336 (let ((reporter-prompt-for-summary-p t))
6337 (reporter-submit-bug-report
6338 tramp-bug-report-address ; to-address
6339 (format "tramp (%s)" tramp-version) ; package name and version
6340 `(;; Current state
6341 tramp-ls-command
6342 tramp-test-groks-nt
6343 tramp-file-exists-command
6344 tramp-current-multi-method
6345 tramp-current-method
6346 tramp-current-user
6347 tramp-current-host
6348
6349 ;; System defaults
6350 tramp-auto-save-directory ; vars to dump
6351 tramp-default-method
6352 tramp-rsh-end-of-line
6353 tramp-password-end-of-line
6354 tramp-remote-path
6355 tramp-login-prompt-regexp
6356 tramp-password-prompt-regexp
6357 tramp-wrong-passwd-regexp
6358 tramp-yesno-prompt-regexp
6359 tramp-yn-prompt-regexp
6360 tramp-temp-name-prefix
6361 tramp-file-name-structure
6362 tramp-file-name-regexp
6363 tramp-multi-file-name-structure
6364 tramp-multi-file-name-hop-structure
6365 tramp-multi-methods
6366 tramp-multi-connection-function-alist
6367 tramp-methods
6368 tramp-end-of-output
6369 tramp-coding-commands
6370 tramp-actions-before-shell
6371 tramp-multi-actions
6372 tramp-terminal-type
6373 tramp-shell-prompt-pattern
6374
6375 ;; Non-tramp variables of interest
6376 shell-prompt-pattern
6377 backup-by-copying
6378 backup-by-copying-when-linked
6379 backup-by-copying-when-mismatch
6380 ,(when (boundp 'backup-by-copying-when-privileged-mismatch)
6381 'backup-by-copying-when-privileged-mismatch)
6382 file-name-handler-alist)
6383 nil ; pre-hook
6384 nil ; post-hook
6385 "\
6386 Enter your bug report in this message, including as much detail as you
6387 possibly can about the problem, what you did to cause it and what the
6388 local and remote machines are.
6389
6390 If you can give a simple set of instructions to make this bug happen
6391 reliably, please include those. Thank you for helping kill bugs in
6392 TRAMP.
6393
6394 Another useful thing to do is to put (setq tramp-debug-buffer t) in
6395 the ~/.emacs file and to repeat the bug. Then, include the contents
6396 of the *tramp/foo* buffer and the *debug tramp/foo* buffer in your bug
6397 report.
6398
6399 --bug report follows this line--
6400 ")))
6401
6402 (defalias 'tramp-submit-bug 'tramp-bug)
6403
6404 (provide 'tramp)
6405
6406 ;; Make sure that we get integration with the VC package.
6407 ;; When it is loaded, we need to pull in the integration module.
6408 ;; This must come after (provide 'tramp) because tramp-vc.el
6409 ;; requires tramp.
6410 (eval-after-load "vc"
6411 '(require 'tramp-vc))
6412
6413 ;;; TODO:
6414
6415 ;; * Autodetect if remote `ls' groks the "--dired" switch.
6416 ;; * Add fallback for inline encodings. This should be used
6417 ;; if the remote end doesn't support mimencode or a similar program.
6418 ;; For reading files from the remote host, we can just parse the output
6419 ;; of `od -b'. For writing files to the remote host, we construct
6420 ;; a shell program which contains only "safe" ascii characters
6421 ;; and which writes the right bytes to the file. We can use printf(1)
6422 ;; or "echo -e" or the printf function in awk and use octal escapes
6423 ;; for the "dangerous" characters. The null byte might be a problem.
6424 ;; On some systems, the octal escape doesn't work. So we try the following
6425 ;; two commands to write a null byte:
6426 ;; dd if=/dev/zero bs=1 count=1
6427 ;; echo | tr '\n' '\000'
6428 ;; * Separate local `tramp-coding-commands' from remote ones. Connect
6429 ;; the two via a format which can be `uu' or `b64'. Then we can search
6430 ;; for the right local commands and the right remote commands separately.
6431 ;; * Cooperate with PCL-CVS. It uses start-process, which doesn't
6432 ;; work for remote files.
6433 ;; * Rewrite `tramp-shell-quote-argument' to abstain from using
6434 ;; `shell-quote-argument'.
6435 ;; * Completion gets confused when you leave out the method name.
6436 ;; * Support `dired-compress-file' filename handler.
6437 ;; * In Emacs 21, `insert-directory' shows total number of bytes used
6438 ;; by the files in that directory. Add this here.
6439 ;; * Avoid screen blanking when hitting `g' in dired. (Eli Tziperman)
6440 ;; * Make ffap.el grok Tramp filenames. (Eli Tziperman)
6441 ;; * When logging in, keep looking for questions according to an alist
6442 ;; and then invoke the right function.
6443 ;; * Case-insensitive filename completion. (Norbert Goevert.)
6444 ;; * Running CVS remotely doesn't appear to work right. It thinks
6445 ;; files are locked by somebody else even if I'm the locking user.
6446 ;; Sometimes, one gets `No CVSROOT specified' errors from CVS.
6447 ;; (Skip Montanaro)
6448 ;; * Don't use globbing for directories with many files, as this is
6449 ;; likely to produce long command lines, and some shells choke on
6450 ;; long command lines.
6451 ;; * Find out about the new auto-save mechanism in Emacs 21 and
6452 ;; do the right thing.
6453 ;; * `vc-directory' does not work. It never displays any files, even
6454 ;; if it does show files when run locally.
6455 ;; * Allow correction of passwords, if the remote end allows this.
6456 ;; (Mark Hershberger)
6457 ;; * Make sure permissions of tmp file are good.
6458 ;; (Nelson Minar <nelson@media.mit.edu>)
6459 ;; * Grok passwd prompts with scp? (David Winter
6460 ;; <winter@nevis1.nevis.columbia.edu>). Maybe just do `ssh -l user
6461 ;; host', then wait a while for the passwd or passphrase prompt. If
6462 ;; there is one, remember the passwd/phrase.
6463 ;; * How to deal with MULE in `insert-file-contents' and `write-region'?
6464 ;; * Do asynchronous `shell-command's.
6465 ;; * Grok `append' parameter for `write-region'.
6466 ;; * Test remote ksh or bash for tilde expansion in `tramp-find-shell'?
6467 ;; * abbreviate-file-name
6468 ;; * grok ~ in tramp-remote-path (Henrik Holm <henrikh@tele.ntnu.no>)
6469 ;; * `C' in dired gives error `not tramp file name'.
6470 ;; * Also allow to omit user names when doing multi-hop. Not sure yet
6471 ;; what the user names should default to, though.
6472 ;; * better error checking. At least whenever we see something
6473 ;; strange when doing zerop, we should kill the process and start
6474 ;; again. (Greg Stark)
6475 ;; * Add caching for filename completion. (Greg Stark)
6476 ;; Of course, this has issues with usability (stale cache bites)
6477 ;; -- <daniel@danann.net>
6478 ;; * Provide a local cache of old versions of remote files for the rsync
6479 ;; transfer method to use. (Greg Stark)
6480 ;; * Remove unneeded parameters from methods.
6481 ;; * Invoke rsync once for copying a whole directory hierarchy.
6482 ;; (Francesco Potortì)
6483 ;; * Should we set PATH ourselves or should we rely on the remote end
6484 ;; to do it?
6485 ;; * Do the autoconf thing.
6486 ;; * Make it work for XEmacs 20, which is missing `with-timeout'.
6487 ;; * Allow non-Unix remote systems. (More a long-term thing.)
6488 ;; * Make it work for different encodings, and for different file name
6489 ;; encodings, too. (Daniel Pittman)
6490 ;; * Change applicable functions to pass a struct tramp-file-name rather
6491 ;; than the individual items MULTI-METHOD, METHOD, USER, HOST, PATH.
6492 ;; * Implement asynchronous shell commands.
6493 ;; * Clean up unused *tramp/foo* buffers after a while. (Pete Forman)
6494 ;; * Progress reports while copying files. (Michael Kifer)
6495 ;; * `Smart' connection method that uses inline for small and out of
6496 ;; band for large files. (Michael Kifer)
6497 ;; * Don't search for perl5 and perl. Instead, only search for perl and
6498 ;; then look if it's the right version (with `perl -v').
6499 ;; * When editing a remote CVS controlled file as a different user, VC
6500 ;; gets confused about the file locking status. Try to find out why
6501 ;; the workaround doesn't work.
6502 ;; * When user is running ssh-agent, it would be useful to add the
6503 ;; passwords typed by the user to that agent. This way, the next time
6504 ;; round, the users don't have to type all this in again.
6505 ;; This would be especially useful for start-process, I think.
6506 ;; An easy way to implement start-process is to open a second shell
6507 ;; connection which is inconvenient if the user has to reenter
6508 ;; passwords.
6509 ;; * Change `copy-file' to grok the case where the filename handler
6510 ;; for the source and the target file are different. Right now,
6511 ;; it looks at the source file and then calls that handler, if
6512 ;; there is one. But since ange-ftp, for instance, does not know
6513 ;; about Tramp, it does not do the right thing if the target file
6514 ;; name is a Tramp name.
6515 ;; * Username and hostname completion.
6516 ;; ** If `partial-completion-mode' isn't loaded, "/foo:bla" tries to
6517 ;; connect to host "blabla" already if that host is unique. No idea
6518 ;; how to suppress. Maybe not an essential problem.
6519 ;; ** Try to avoid usage of `last-input-event' in `tramp-completion-mode'.
6520 ;; ** Handle quoted file names, starting with "/:". Problem is that
6521 ;; `file-name-non-special' calls later on `file-name-all-completions'
6522 ;; without ":". Hmm. Worth a bug report?
6523 ;; ** Acknowledge port numbers.
6524 ;; ** Extend `tramp-get-completion-su' for NIS and shadow passwords.
6525 ;; ** Unify `tramp-parse-{rhosts,shosts,hosts,passwd,netrc}'.
6526 ;; Code is nearly identical.
6527 ;; ** Decide whiche files to take for searching user/host names depending on
6528 ;; operating system (windows-nt) in `tramp-completion-function-alist'.
6529 ;; ** Enhance variables for debug.
6530 ;; ** Implement "/multi:" completion.
6531 ;; ** Add a learning mode for completion. Make results persistent.
6532
6533 ;; Functions for file-name-handler-alist:
6534 ;; diff-latest-backup-file -- in diff.el
6535 ;; dired-compress-file
6536 ;; dired-uncache -- this will be needed when we do insert-directory caching
6537 ;; file-name-as-directory -- use primitive?
6538 ;; file-name-directory -- use primitive?
6539 ;; file-name-nondirectory -- use primitive?
6540 ;; file-name-sans-versions -- use primitive?
6541 ;; file-newer-than-file-p
6542 ;; find-backup-file-name
6543 ;; get-file-buffer -- use primitive
6544 ;; load
6545 ;; unhandled-file-name-directory
6546 ;; vc-registered
6547
6548 ;;; tramp.el ends here