49 |
:type 'string) |
:type 'string) |
50 |
|
|
51 |
;; ... and add it to the method list. |
;; ... and add it to the method list. |
52 |
(add-to-list 'tramp-methods (cons tramp-smb-method nil)) |
(when tramp-use-smb |
53 |
|
(add-to-list 'tramp-methods (cons tramp-smb-method nil))) |
54 |
|
|
55 |
;; Add completion function for SMB method. |
;; Add completion function for SMB method. |
56 |
(unless (memq system-type '(windows-nt)) |
(when tramp-use-smb |
57 |
(tramp-set-completion-function |
(tramp-set-completion-function |
58 |
tramp-smb-method |
tramp-smb-method |
59 |
'((tramp-parse-netrc "~/.netrc")))) |
'((tramp-parse-netrc "~/.netrc")))) |
63 |
:group 'tramp |
:group 'tramp |
64 |
:type 'string) |
:type 'string) |
65 |
|
|
66 |
(defconst tramp-smb-prompt "smb: \\> " |
(defconst tramp-smb-prompt "^smb: \\S-+> " |
67 |
"String used as prompt in smbclient.") |
"Regexp used as prompt in smbclient.") |
68 |
|
|
69 |
|
(defconst tramp-smb-line |
70 |
|
(mapconcat |
71 |
|
'identity |
72 |
|
'("^" |
73 |
|
"\\(\\S-+\\)" ; file name |
74 |
|
"\\([ADHRS]*\\)" ; permissions |
75 |
|
"\\([0-9]+\\)" ; size |
76 |
|
"\\(\\w+\\)" ; weekday |
77 |
|
"\\(\\w+\\)" ; month |
78 |
|
"\\([0-9]+\\)" ; day |
79 |
|
"\\([0-9]+:[0-9]+\\):[0-9]+" ; time |
80 |
|
"\\([0-9]+\\)$") ; year |
81 |
|
"\\s-+") |
82 |
|
"Regexp describing line format of DIR listings in smbclient.") |
83 |
|
|
84 |
|
(defconst tramp-smb-errors |
85 |
|
(mapconcat |
86 |
|
'identity |
87 |
|
'("ERRSRV" "ERRbadpw" "ERRDOS") ; Samba |
88 |
|
"\\|") |
89 |
|
"Regexp for possible error strings of SMB servers. |
90 |
|
Used instead of analyzing error codes of commands.") |
91 |
|
|
92 |
;; New handlers should be added here. |
;; New handlers should be added here. |
93 |
(defconst tramp-smb-file-name-handler-alist |
(defconst tramp-smb-file-name-handler-alist |
94 |
'( |
'( |
95 |
; (load . tramp-handle-load) |
;; `access-file' performed by default handler |
96 |
; (make-symbolic-link . tramp-handle-make-symbolic-link) |
(add-name-to-file . tramp-smb-not-handled) |
97 |
; (file-name-directory . tramp-handle-file-name-directory) |
;; `byte-compiler-base-file-name' performed by default handler |
98 |
; (file-name-nondirectory . tramp-handle-file-name-nondirectory) |
(copy-file . tramp-smb-not-handled) |
99 |
; (file-truename . tramp-handle-file-truename) |
(delete-directory . tramp-smb-not-handled) |
100 |
|
(delete-file . tramp-smb-not-handled) |
101 |
|
(diff-latest-backup-file . tramp-smb-not-handled) |
102 |
|
;; `directory-file-name' performed by default handler |
103 |
|
(directory-files . tramp-smb-not-handled) |
104 |
|
(directory-files-and-attributes . tramp-smb-not-handled) |
105 |
|
(dired-call-process . tramp-smb-not-handled) |
106 |
|
(dired-compress-file . tramp-smb-not-handled) |
107 |
|
;; `dired-uncache' performed by default handler |
108 |
|
;; `expand-file-name' not necessary because we cannot expand "~/" |
109 |
|
(file-accessible-directory-p . tramp-smb-handle-file-directory-p) |
110 |
|
(file-attributes . tramp-smb-not-handled) |
111 |
|
(file-directory-p . tramp-smb-handle-file-directory-p) |
112 |
|
(file-executable-p . tramp-smb-handle-file-exists-p) |
113 |
(file-exists-p . tramp-smb-handle-file-exists-p) |
(file-exists-p . tramp-smb-handle-file-exists-p) |
114 |
; (file-directory-p . tramp-handle-file-directory-p) |
(file-local-copy . tramp-smb-handle-file-local-copy) |
115 |
; (file-executable-p . tramp-handle-file-executable-p) |
(file-modes . tramp-smb-not-handled) |
116 |
; (file-accessible-directory-p . tramp-handle-file-accessible-directory-p) |
(file-name-all-completions . tramp-smb-not-handled) |
117 |
; (file-readable-p . tramp-handle-file-readable-p) |
;; `file-name-as-directory' performed by default handler |
118 |
; (file-regular-p . tramp-handle-file-regular-p) |
(file-name-completion . tramp-smb-not-handled) |
119 |
; (file-symlink-p . tramp-handle-file-symlink-p) |
(file-name-directory . tramp-handle-file-name-directory) |
120 |
; (file-writable-p . tramp-handle-file-writable-p) |
(file-name-nondirectory . tramp-handle-file-name-nondirectory) |
121 |
; (file-ownership-preserved-p . tramp-handle-file-ownership-preserved-p) |
;; `file-name-sans-versions' performed by default handler |
122 |
; (file-newer-than-file-p . tramp-handle-file-newer-than-file-p) |
(file-newer-than-file-p . tramp-smb-not-handled) |
123 |
; (file-attributes . tramp-handle-file-attributes) |
(file-ownership-preserved-p . tramp-smb-not-handled) |
124 |
; (file-modes . tramp-handle-file-modes) |
(file-readable-p . tramp-smb-handle-file-exists-p) |
125 |
; (file-directory-files . tramp-handle-file-directory-files) |
(file-regular-p . tramp-smb-not-handled) |
126 |
; (directory-files . tramp-handle-directory-files) |
(file-symlink-p . tramp-smb-handle-file-symlink-p) |
127 |
; (file-name-all-completions . tramp-handle-file-name-all-completions) |
;; `file-truename' performed by default handler |
128 |
; (file-name-completion . tramp-handle-file-name-completion) |
(file-writable-p . tramp-smb-handle-file-writable-p) |
129 |
; (add-name-to-file . tramp-handle-add-name-to-file) |
(find-backup-file-name . tramp-smb-not-handled) |
130 |
; (copy-file . tramp-handle-copy-file) |
(find-file-noselect . tramp-smb-not-handled) |
131 |
; (rename-file . tramp-handle-rename-file) |
;; `get-file-buffer' performed by default handler |
132 |
; (set-file-modes . tramp-handle-set-file-modes) |
(insert-directory . tramp-smb-handle-insert-directory) |
133 |
; (make-directory . tramp-handle-make-directory) |
(insert-file-contents . tramp-handle-insert-file-contents) |
134 |
; (delete-directory . tramp-handle-delete-directory) |
(load . tramp-smb-not-handled) |
135 |
; (delete-file . tramp-handle-delete-file) |
(make-directory . tramp-smb-not-handled) |
136 |
; (directory-file-name . tramp-handle-directory-file-name) |
(make-directory-internal . tramp-smb-not-handled) |
137 |
; (shell-command . tramp-handle-shell-command) |
(make-symbolic-link . tramp-smb-not-handled) |
138 |
; (insert-directory . tramp-handle-insert-directory) |
(rename-file . tramp-smb-not-handled) |
139 |
; (expand-file-name . tramp-handle-expand-file-name) |
(set-file-modes . tramp-smb-not-handled) |
140 |
; (file-local-copy . tramp-handle-file-local-copy) |
(set-visited-file-modtime . tramp-smb-not-handled) |
141 |
; (insert-file-contents . tramp-handle-insert-file-contents) |
(shell-command . tramp-smb-not-handled) |
142 |
; (write-region . tramp-handle-write-region) |
;; `substitute-in-file-name' performed by default handler |
143 |
; (unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory) |
(unhandled-file-name-directory . tramp-handle-unhandled-file-name-directory) |
144 |
; (dired-call-process . tramp-handle-dired-call-process) |
;; `vc-registered' performed by default handler |
145 |
; (dired-recursive-delete-directory |
(verify-visited-file-modtime . tramp-smb-not-handled) |
146 |
; . tramp-handle-dired-recursive-delete-directory) |
(write-region . tramp-smb-not-handled) |
147 |
; (set-visited-file-modtime . tramp-handle-set-visited-file-modtime) |
) |
148 |
; (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)) |
"Alist of handler functions for Tramp SMB method. |
149 |
) "Alist of handler functions. |
Operations not mentioned here will be handled by the default Emacs primitives.") |
|
Operations not mentioned here will be handled by the normal Emacs functions.") |
|
150 |
|
|
151 |
(defun tramp-smb-file-name-p (filename) |
(defun tramp-smb-file-name-p (filename) |
152 |
"Check if it's a filename for SMB servers." |
"Check if it's a filename for SMB servers." |
163 |
"Invoke the SMB related OPERATION. |
"Invoke the SMB related OPERATION. |
164 |
First arg specifies the OPERATION, second arg is a list of arguments to |
First arg specifies the OPERATION, second arg is a list of arguments to |
165 |
pass to the OPERATION." |
pass to the OPERATION." |
|
; temporarily disable SMB as long as under development |
|
|
(unless tramp-use-smb (error "SMB method not supported yet")) |
|
166 |
(let ((fn (assoc operation tramp-smb-file-name-handler-alist))) |
(let ((fn (assoc operation tramp-smb-file-name-handler-alist))) |
167 |
(if fn |
(if fn |
168 |
(save-match-data (apply (cdr fn) args)) |
(if (equal (cdr fn) 'tramp-smb-not-handled) |
169 |
|
(apply (cdr fn) operation args) |
170 |
|
(save-match-data (apply (cdr fn) args))) |
171 |
(tramp-run-real-handler operation args)))) |
(tramp-run-real-handler operation args)))) |
172 |
|
|
173 |
(add-to-list 'tramp-foreign-file-name-handler-alist |
(when tramp-use-smb |
174 |
(cons 'tramp-smb-file-name-p 'tramp-smb-file-name-handler)) |
(add-to-list 'tramp-foreign-file-name-handler-alist |
175 |
|
(cons 'tramp-smb-file-name-p 'tramp-smb-file-name-handler))) |
176 |
|
|
177 |
;; File name primitives |
;; File name primitives |
178 |
|
|
179 |
|
(defun tramp-smb-not-handled (operation &rest args) |
180 |
|
"Default handler for all functions. |
181 |
|
Used during development in order to get an impression what's left to do." |
182 |
|
(tramp-message 1 "Not handled yet: %s %s" operation args) |
183 |
|
(tramp-run-real-handler operation args)) |
184 |
|
|
185 |
|
(defun tramp-handle-file-attributes (filename &optional nonnumeric) |
186 |
|
"Like `file-attributes' for tramp files. |
187 |
|
Optional argument NONNUMERIC means return user and group name |
188 |
|
rather than as numbers." |
189 |
|
(with-parsed-tramp-file-name filename nil |
190 |
|
(save-excursion |
191 |
|
(let* ((share (tramp-smb-get-share path)) |
192 |
|
(file (tramp-smb-get-path path)) |
193 |
|
(entry (tramp-smb-get-file-entry user host share file))) |
194 |
|
; check result |
195 |
|
(and (nth 1 entry) |
196 |
|
(string-match "D" (nth 1 entry))))))) |
197 |
|
|
198 |
|
(defun tramp-smb-handle-file-directory-p (filename) |
199 |
|
"Like `file-directory-p' for tramp files." |
200 |
|
(with-parsed-tramp-file-name filename nil |
201 |
|
(save-excursion |
202 |
|
(let* ((share (tramp-smb-get-share path)) |
203 |
|
(file (tramp-smb-get-path path)) |
204 |
|
(entry (tramp-smb-get-file-entry user host share file))) |
205 |
|
; check result |
206 |
|
(and (nth 1 entry) |
207 |
|
(string-match "D" (nth 1 entry))))))) |
208 |
|
|
209 |
(defun tramp-smb-handle-file-exists-p (filename) |
(defun tramp-smb-handle-file-exists-p (filename) |
210 |
"Like `file-exists-p' for tramp files." |
"Like `file-exists-p' for tramp files." |
211 |
(with-parsed-tramp-file-name filename nil |
(with-parsed-tramp-file-name filename nil |
214 |
(file (tramp-smb-get-path path)) |
(file (tramp-smb-get-path path)) |
215 |
(entry (tramp-smb-get-file-entry user host share file))) |
(entry (tramp-smb-get-file-entry user host share file))) |
216 |
; check result |
; check result |
217 |
(string-equal (car entry) (file-name-nondirectory file)))))) |
(and file (nth 0 entry) |
218 |
|
(string-equal (file-name-nondirectory file) (nth 0 entry))))))) |
219 |
|
|
220 |
|
(defun tramp-smb-handle-file-local-copy (filename) |
221 |
|
"Like `file-local-copy' for tramp files." |
222 |
|
(with-parsed-tramp-file-name filename nil |
223 |
|
(let ((share (tramp-smb-get-share path)) |
224 |
|
(file (tramp-smb-get-path path)) |
225 |
|
(tmpfil (tramp-make-temp-file))) |
226 |
|
(unless (file-exists-p filename) |
227 |
|
(error "Cannot make local copy of non-existing file `%s'" filename)) |
228 |
|
(tramp-message-for-buffer |
229 |
|
nil tramp-smb-method user host |
230 |
|
5 "Fetching %s to tmp file %s..." filename tmpfil) |
231 |
|
(tramp-smb-maybe-open-connection user host share) |
232 |
|
(tramp-smb-send-command user host (format "get %s %s" file tmpfil)) |
233 |
|
(tramp-message-for-buffer |
234 |
|
nil tramp-smb-method user host |
235 |
|
5 "Fetching %s to tmp file %s...done" filename tmpfil) |
236 |
|
tmpfil))) |
237 |
|
|
238 |
|
(defun tramp-smb-handle-file-symlink-p (filename) |
239 |
|
"Like `file-symlink-p' for tramp files." |
240 |
|
nil) |
241 |
|
|
242 |
|
(defun tramp-smb-handle-file-writable-p (filename) |
243 |
|
"Like `file-writable-p' for tramp files." |
244 |
|
(with-parsed-tramp-file-name filename nil |
245 |
|
(save-excursion |
246 |
|
(let* ((share (tramp-smb-get-share path)) |
247 |
|
(file (tramp-smb-get-path path)) |
248 |
|
(entry (tramp-smb-get-file-entry user host share file))) |
249 |
|
; check result |
250 |
|
(and (nth 1 entry) |
251 |
|
(not (string-match "R" (nth 1 entry)))))))) |
252 |
|
|
253 |
|
(defun tramp-smb-handle-insert-directory |
254 |
|
(filename switches &optional wildcard full-directory-p) |
255 |
|
"Like `insert-directory' for tramp files. |
256 |
|
SWITCHES, WILDCARD and FULL-DIRECTORY-P are not handled." |
257 |
|
(setq filename (expand-file-name filename)) |
258 |
|
(with-parsed-tramp-file-name filename nil |
259 |
|
(save-excursion |
260 |
|
(save-match-data |
261 |
|
(let* ((share (tramp-smb-get-share path)) |
262 |
|
(file (tramp-smb-get-path path)) |
263 |
|
entry list) |
264 |
|
(tramp-message-for-buffer |
265 |
|
nil tramp-smb-method user host 10 |
266 |
|
"Inserting directory `dir %s'" path) |
267 |
|
(tramp-smb-maybe-open-connection user host share) |
268 |
|
(tramp-smb-send-command user host (format "dir %s*" file)) |
269 |
|
(insert-buffer-substring |
270 |
|
(tramp-get-buffer nil tramp-smb-method user host)) |
271 |
|
|
272 |
|
;; read entries |
273 |
|
(beginning-of-buffer) |
274 |
|
(while (setq entry (tramp-smb-read-file-entry)) |
275 |
|
(add-to-list 'list entry) |
276 |
|
(delete-region (point) (1+ (tramp-point-at-eol)))) |
277 |
|
|
278 |
|
(delete-region (point) (re-search-forward "\\s-+")) |
279 |
|
(forward-line 1) |
280 |
|
(delete-region (point) (point-max)) |
281 |
|
|
282 |
|
; print entries |
283 |
|
(mapcar |
284 |
|
'(lambda (x) |
285 |
|
(let ((mode (concat |
286 |
|
(if (string-match "D" (nth 1 x)) "d" "-") "r" |
287 |
|
(if (string-match "R" (nth 1 x)) "-" "w") "x------"))) |
288 |
|
(insert |
289 |
|
(format |
290 |
|
"%10s %3d %-8s %-8s %8s %3s %2s %5s %s\n" |
291 |
|
mode 1 "nouser" "nogroup" |
292 |
|
(nth 2 x) ; size |
293 |
|
(nth 3 x) ; month |
294 |
|
(nth 4 x) ; day |
295 |
|
(if (equal (format-time-string "%Y") |
296 |
|
(nth 6 x)) |
297 |
|
(nth 5 x) ; time |
298 |
|
(nth 6 x)) ; year |
299 |
|
(nth 0 x))) ; file name |
300 |
|
(forward-line) |
301 |
|
(beginning-of-line))) |
302 |
|
(sort list '(lambda (x y) (string-lessp (nth 0 x) (nth 0 y)))))))))) |
303 |
|
|
304 |
;; Internal file name functions |
;; Internal file name functions |
305 |
|
|
306 |
(defun tramp-smb-get-share (path) |
(defun tramp-smb-get-share (path) |
307 |
"Returns the share name of PATH." |
"Returns the share name of PATH." |
308 |
(save-match-data |
(save-match-data |
309 |
(string-match "^/?\\([^/]+\\)" path) |
(when (string-match "^/?\\([^/]+\\)" path) |
310 |
(match-string 1 path))) |
(match-string 1 path)))) |
311 |
|
|
312 |
(defun tramp-smb-get-path (path) |
(defun tramp-smb-get-path (path) |
313 |
"Returns the file name of PATH." |
"Returns the file name of PATH." |
314 |
(save-match-data |
(save-match-data |
315 |
(string-match "^/?[^/]+/\\(.*\\)" path) |
(when (string-match "^/?[^/]+/\\(.*\\)" path) |
316 |
(match-string 1 path))) |
(match-string 1 path)))) |
317 |
|
|
318 |
(defun tramp-smb-get-file-entry (user host share path) |
(defun tramp-smb-get-file-entry (user host share path) |
319 |
"Read entry PATH with the `dir' command. |
"Read entry PATH with the `dir' command. |
320 |
Result is the list (PATH MODE SIZE DATE)." |
Result is the list (PATH MODE SIZE MONTH DAY TIME YEAR)." |
321 |
(tramp-smb-maybe-open-connection user host share) |
(save-excursion |
322 |
(tramp-smb-send-command user host (concat "dir " path)) |
(set-buffer (tramp-get-buffer nil tramp-smb-method user host)) |
323 |
(tramp-smb-wait-for-output 10) |
(tramp-smb-maybe-open-connection user host share) |
324 |
(goto-char (point-min)) |
(tramp-smb-send-command user host (concat "dir " path)) |
325 |
(unless (re-search-forward "ERRDOS" nil t) |
(goto-char (point-min)) |
326 |
(let ((line (buffer-substring (point-min) (tramp-point-at-eol)))) |
(unless (re-search-forward tramp-smb-errors nil t) |
327 |
(string-match |
(tramp-smb-read-file-entry)))) |
328 |
(concat "^[ \t]+\\([^ \t]+\\)" |
|
329 |
"[ \t]+\\([^ \t]+\\)" |
(defun tramp-smb-read-file-entry () |
330 |
"[ \t]+\\([^ \t]+\\)" |
"Parse entry in SMB output buffer. |
331 |
"[ \t]+\\(.+\\)[ \t]*$") |
Result is the list (PATH MODE SIZE MONTH DAY TIME YEAR)." |
332 |
line) |
(let ((line (buffer-substring (point) (tramp-point-at-eol)))) |
333 |
(list (match-string 1 line) (match-string 2 line) |
(when (string-match tramp-smb-line line) |
334 |
(match-string 3 line) (match-string 4 line))))) |
(list |
335 |
|
(match-string 1 line) ; file name |
336 |
|
(match-string 2 line) ; permissions |
337 |
|
(match-string 3 line) ; size |
338 |
|
(match-string 5 line) ; month |
339 |
|
(match-string 6 line) ; day |
340 |
|
(match-string 7 line) ; time |
341 |
|
(match-string 8 line))))) ; year |
342 |
|
|
343 |
|
|
344 |
;; Connection functions |
;; Connection functions |
345 |
|
|
346 |
(defun tramp-smb-send-command (user host command) |
(defun tramp-smb-send-command (user host command) |
347 |
"Send the COMMAND to USER at HOST (logged into an SMB session). |
"Send the COMMAND to USER at HOST (logged into an SMB session). |
348 |
Erases temporary buffer before sending the command." |
Erases temporary buffer before sending the command. |
349 |
(tramp-send-command nil "smb" user host command nil t)) |
Returns nil in case of unsuccessfull execution." |
350 |
|
(save-excursion |
351 |
|
(set-buffer (tramp-get-buffer nil tramp-smb-method user host)) |
352 |
|
(tramp-send-command nil tramp-smb-method user host command nil t) |
353 |
|
(and |
354 |
|
(tramp-smb-wait-for-output user host) |
355 |
|
(save-match-data (not (re-search-forward tramp-smb-errors nil t)))))) |
356 |
|
|
357 |
(defun tramp-smb-maybe-open-connection (user host share) |
(defun tramp-smb-maybe-open-connection (user host share) |
358 |
"Maybe open a connection to HOST, logging in as USER, using `tramp-smb-program'. |
"Maybe open a connection to HOST, logging in as USER, using `tramp-smb-program'. |
359 |
Does not do anything if a connection is already open, but re-opens the |
Does not do anything if a connection is already open, but re-opens the |
360 |
connection if a previous connection has died for some reason." |
connection if a previous connection has died for some reason." |
361 |
(let ((p (get-buffer-process (tramp-get-buffer nil "smb" user host))) |
(let ((p (get-buffer-process |
362 |
|
(tramp-get-buffer nil tramp-smb-method user host))) |
363 |
last-cmd-time) |
last-cmd-time) |
|
;; If too much time has passed since last command was sent, look |
|
|
;; whether process is still alive. If it isn't, kill it. When |
|
|
;; using ssh, it can sometimes happen that the remote end has hung |
|
|
;; up but the local ssh client doesn't recognize this until it |
|
|
;; tries to send some data to the remote end. So that's why we |
|
|
;; try to send a command from time to time, then look again |
|
|
;; whether the process is really alive. |
|
364 |
(save-excursion |
(save-excursion |
365 |
(set-buffer (tramp-get-buffer nil "smb" user host)) |
(set-buffer (tramp-get-buffer nil tramp-smb-method user host)) |
366 |
|
;; Check whether it is still the same share |
367 |
|
(unless (and p (processp p) (string-equal smb-share share)) |
368 |
|
(when (and p (processp p)) |
369 |
|
(delete-process p) |
370 |
|
(setq p nil))) |
371 |
|
;; If too much time has passed since last command was sent, look |
372 |
|
;; whether process is still alive. If it isn't, kill it. |
373 |
(when (and tramp-last-cmd-time |
(when (and tramp-last-cmd-time |
374 |
(> (tramp-time-diff (current-time) tramp-last-cmd-time) 60) |
(> (tramp-time-diff (current-time) tramp-last-cmd-time) 60) |
375 |
p (processp p) (memq (process-status p) '(run open))) |
p (processp p) (memq (process-status p) '(run open))) |
376 |
(tramp-smb-send-command user host "help") |
(unless (tramp-smb-send-command user host "help") |
|
(unless (tramp-smb-wait-for-output 10) |
|
377 |
(delete-process p) |
(delete-process p) |
378 |
(setq p nil)) |
(setq p nil)) |
379 |
(erase-buffer))) |
(erase-buffer))) |
391 |
If USER is nil, uses value returned by `(user-login-name)' instead." |
If USER is nil, uses value returned by `(user-login-name)' instead." |
392 |
|
|
393 |
(save-match-data |
(save-match-data |
394 |
(tramp-pre-connection nil "smb" user host) |
(let* ((user (or user (user-login-name))) |
395 |
(tramp-message 7 "Opening connection for //%s@%s/%s..." |
(buffer (tramp-get-buffer nil tramp-smb-method user host))) |
396 |
(or user (user-login-name)) host share) |
(tramp-pre-connection nil tramp-smb-method user host) |
397 |
(let ((process-environment (copy-sequence process-environment))) |
(tramp-message 7 "Opening connection for //%s@%s/%s..." user host share) |
|
(setenv "TERM" tramp-terminal-type) |
|
398 |
(let* ((default-directory (tramp-temporary-file-directory)) |
(let* ((default-directory (tramp-temporary-file-directory)) |
399 |
;; If we omit the conditional here, then we would use |
;; If we omit the conditional here, then we would use |
400 |
;; `undecided-dos' in some cases. With the conditional, |
;; `undecided-dos' in some cases. With the conditional, |
401 |
;; we use nil in these cases. Which one is right? |
;; we use nil in these cases. Which one is right? |
402 |
(coding-system-for-read (unless (and (not (featurep 'xemacs)) |
(coding-system-for-read (unless (and (not (featurep 'xemacs)) |
403 |
(> emacs-major-version 20)) |
(> emacs-major-version 20)) |
404 |
tramp-dos-coding-system)) |
tramp-dos-coding-system)) |
405 |
(p (funcall 'start-process |
(p (funcall 'start-process |
406 |
(tramp-buffer-name nil "smb" user host) |
(buffer-name buffer) |
407 |
(tramp-get-buffer nil "smb" user host) |
buffer |
408 |
tramp-smb-program |
tramp-smb-program |
409 |
(concat "//" host "/" share) |
(concat "//" host "/" share) |
410 |
"-U" user))) |
"-U" user))) |
411 |
(process-kill-without-query p) |
(process-kill-without-query p) |
412 |
(set-buffer (tramp-get-buffer nil "smb" user host)) |
(set-buffer buffer) |
413 |
|
(set (make-local-variable 'smb-share) share) |
414 |
|
|
415 |
; send password |
; send password |
416 |
(let ((pw-prompt "Password:")) |
(let ((pw-prompt "Password:")) |
417 |
(tramp-message 9 "Sending password") |
(tramp-message 9 "Sending password") |
418 |
(tramp-enter-password p pw-prompt)) |
(tramp-enter-password p pw-prompt)) |
419 |
|
|
420 |
(tramp-smb-wait-for-output 10)))) |
(when (tramp-smb-wait-for-output user host) |
421 |
(erase-buffer)) |
(erase-buffer)))))) |
422 |
|
|
423 |
(defun tramp-smb-wait-for-output (&optional timeout) |
(defun tramp-smb-wait-for-output (user host) |
424 |
"Wait for output from remote smbclient command." |
"Wait for output from smbclient command. |
425 |
(let ((proc (get-buffer-process (current-buffer))) |
Sets position to begin of buffer. Returns nil if `tramp-smb-prompt' |
426 |
(found nil) |
is not found." |
427 |
(start-time (current-time)) |
(save-excursion |
428 |
(end-of-output (concat "^" (regexp-quote tramp-smb-prompt)))) |
(let ((proc (get-buffer-process (current-buffer))) |
429 |
|
(found nil) |
430 |
|
(start-time (current-time)) |
431 |
|
(timeout 10)) |
432 |
;; Algorithm: get waiting output. See if last line contains |
;; Algorithm: get waiting output. See if last line contains |
433 |
;; end-of-output sentinel. If not, wait a bit and again get |
;; tramp-smb-prompt sentinel. If not, wait a bit and again get |
434 |
;; waiting output. Repeat until timeout expires or end-of-output |
;; waiting output. Repeat until timeout expires or tramp-smb-prompt |
435 |
;; sentinel is seen. Will hang if timeout is nil and |
;; sentinel is seen. |
436 |
;; end-of-output sentinel never appears. |
(save-match-data |
437 |
(save-match-data |
;; Work around an XEmacs bug, where the timeout expires |
438 |
(cond (timeout |
;; faster than it should. This degenerates into polling |
439 |
;; Work around an XEmacs bug, where the timeout expires |
;; for buggy XEmacsen, but oh, well. |
440 |
;; faster than it should. This degenerates into polling |
(while (and (not found) |
441 |
;; for buggy XEmacsen, but oh, well. |
(< (tramp-time-diff (current-time) start-time) |
442 |
(while (and (not found) |
timeout)) |
443 |
(< (tramp-time-diff (current-time) start-time) |
(with-timeout (timeout) |
444 |
timeout)) |
(while (not found) |
445 |
(with-timeout (timeout) |
(accept-process-output proc 1) |
446 |
(while (not found) |
(goto-char (point-max)) |
447 |
(accept-process-output proc 1) |
(beginning-of-line) |
448 |
(goto-char (point-max)) |
(setq found (looking-at tramp-smb-prompt)))))) |
449 |
(beginning-of-line) |
;; Add output to debug buffer if appropriate. |
450 |
(setq found (looking-at end-of-output)))))) |
(when tramp-debug-buffer |
451 |
(t |
(append-to-buffer |
452 |
(while (not found) |
(tramp-get-debug-buffer nil tramp-smb-method user host) |
453 |
(accept-process-output proc 1) |
(point-min) (point-max)) |
454 |
(goto-char (point-max)) |
(when (not found) |
455 |
(forward-line -1) |
(save-excursion |
456 |
(setq found (looking-at end-of-output)))))) |
(set-buffer |
457 |
;; Add output to debug buffer if appropriate. |
(tramp-get-debug-buffer nil tramp-smb-method user host)) |
458 |
(when tramp-debug-buffer |
(goto-char (point-max)) |
459 |
(append-to-buffer |
(insert (format "[[Remote prompt `%s' not found in %d secs]]\n" |
460 |
(tramp-get-debug-buffer tramp-current-multi-method tramp-current-method |
tramp-smb-prompt timeout))))) |
461 |
tramp-current-user tramp-current-host) |
(goto-char (point-min)) |
462 |
(point-min) (point-max)) |
;; Return value is whether tramp-smb-prompt sentinel was found. |
463 |
(when (not found) |
found))) |
|
(save-excursion |
|
|
(set-buffer |
|
|
(tramp-get-debug-buffer tramp-current-multi-method tramp-current-method |
|
|
tramp-current-user tramp-current-host)) |
|
|
(goto-char (point-max)) |
|
|
(insert "[[Remote prompt `" end-of-output "' not found" |
|
|
(if timeout (format " in %d secs" timeout) "") |
|
|
"]]")))) |
|
|
(goto-char (point-min)) |
|
|
;; Return value is whether end-of-output sentinel was found. |
|
|
found)) |
|
464 |
|
|
465 |
(provide 'tramp-smb) |
(provide 'tramp-smb) |
466 |
|
|
467 |
;;; TODO: |
;;; TODO: |
468 |
|
|
469 |
;; * Provide a local smb.conf. The default one might not be readable |
;; * Provide a local smb.conf. The default one might not be readable. |
470 |
|
;; * Error handling in most of the functions. Brrrr. |
471 |
|
;; * Read password from "~/.netrc". |
472 |
|
;; * Update documentation. |
473 |
|
;; * Provide variables for debug. |
474 |
|
|
475 |
;;; tramp-smb.el ends here |
;;; tramp-smb.el ends here |