Annotation of GNUtools/emacs/lisp/ftp.el, revision 1.1.1.1

1.1       root        1: ;; File input and output over Internet using FTP
                      2: ;; Copyright (C) 1987 Free Software Foundation, Inc.
                      3: ;; Author [email protected].
                      4: 
                      5: ;; This file is part of GNU Emacs.
                      6: 
                      7: ;; GNU Emacs is free software; you can redistribute it and/or modify
                      8: ;; it under the terms of the GNU General Public License as published by
                      9: ;; the Free Software Foundation; either version 1, or (at your option)
                     10: ;; any later version.
                     11: 
                     12: ;; GNU Emacs is distributed in the hope that it will be useful,
                     13: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     15: ;; GNU General Public License for more details.
                     16: 
                     17: ;; You should have received a copy of the GNU General Public License
                     18: ;; along with GNU Emacs; see the file COPYING.  If not, write to
                     19: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
                     20: 
                     21: 
                     22: ;; you can turn this off by doing
                     23: ;;  (setq ftp-password-alist 'compulsory-urinalysis)
                     24: (defvar ftp-password-alist () "Security sucks")
                     25: 
                     26: (defun read-ftp-user-password (host user new)
                     27:   (let (tem)
                     28:     (if (and (not new)
                     29:             (listp ftp-password-alist)
                     30:             (setq tem (cdr (assoc host ftp-password-alist)))
                     31:             (or (null user)
                     32:                 (string= user (car tem))))
                     33:        tem
                     34:       (or user
                     35:          (progn
                     36:            (setq tem (or (and (listp ftp-password-alist)
                     37:                               (car (cdr (assoc host ftp-password-alist))))
                     38:                          (user-login-name)))
                     39:            (setq user (read-string (format
                     40:                                      "User-name for %s (default \"%s\"): "
                     41:                                      host tem)))
                     42:            (if (equal user "") (setq user tem))))
                     43:       (setq tem (cons user
                     44:                      ;; If you want to use some non-echoing string-reader,
                     45:                      ;; feel free to write it yourself.  I don't care enough.
                     46:                      (read-string (format "Password for %s@%s: " user host)
                     47:                        (if (not (listp ftp-password-alist))
                     48:                            ""
                     49:                          (or (cdr (cdr (assoc host ftp-password-alist)))
                     50:                              (let ((l ftp-password-alist))
                     51:                                (catch 'foo
                     52:                                  (while l
                     53:                                    (if (string= (car (cdr (car l))) user)
                     54:                                        (throw 'foo (cdr (cdr (car l))))
                     55:                                      (setq l (cdr l))))
                     56:                                  nil))
                     57:                              "")))))
                     58:       (message "")
                     59:       (if (and (listp ftp-password-alist)
                     60:               (not (string= (cdr tem) "")))
                     61:          (setq ftp-password-alist (cons (cons host tem)
                     62:                                         ftp-password-alist)))
                     63:       tem)))
                     64: 
                     65: (defun ftp-read-file-name (prompt)
                     66:   (let ((s ""))
                     67:     (while (not (string-match "\\`[ \t]*\\([^ \t:]+\\)[ \t]*:\\(.+\\)\\'" s))
                     68:       (setq s (read-string prompt s)))
                     69:     (list (substring s (match-beginning 1) (match-end 1))
                     70:          (substring s (match-beginning 2) (match-end 2)))))
                     71: 
                     72: 
                     73: (defun ftp-find-file (host file &optional user password)
                     74:   "FTP to HOST to get FILE, logging in as USER with password PASSWORD.
                     75: Interactively, HOST and FILE are specified by reading a string with
                     76:  a colon character separating the host from the filename.
                     77: USER and PASSWORD are defaulted from the values used when
                     78:  last ftping from HOST (unless password-remembering is disabled).
                     79:  Supply a password of the symbol `t' to override this default
                     80:  (interactively, this is done by giving a prefix arg)"
                     81:   (interactive
                     82:        (append (ftp-read-file-name "FTP get host:file: ")
                     83:                (list nil (not (null current-prefix-arg)))))
                     84:   (ftp-find-file-or-directory host file t user password))
                     85: 
                     86: (defun ftp-list-directory (host file &optional user password)
                     87:   "FTP to HOST to list DIRECTORY, logging in as USER with password PASSWORD.
                     88: Interactively, HOST and FILE are specified by reading a string with
                     89:  a colon character separating the host from the filename.
                     90: USER and PASSWORD are defaulted from the values used when
                     91:  last ftping from HOST (unless password-remembering is disabled).
                     92:  Supply a password of the symbol `t' to override this default
                     93:  (interactively, this is done by giving a prefix arg)"
                     94:   (interactive
                     95:        (append (ftp-read-file-name "FTP get host:directory: ")
                     96:                (list nil (not (null current-prefix-arg)))))
                     97:   (ftp-find-file-or-directory host file nil user password))
                     98: 
                     99: (defun ftp-find-file-or-directory (host file filep &optional user password)
                    100:   "FTP to HOST to get FILE.  Third arg is t for file, nil for directory.
                    101: Log in as USER with PASSWORD.  If USER is nil or PASSWORD is nil or t,
                    102: we prompt for the user name and password."
                    103:   (or (and user password (not (eq password t)))
                    104:       (progn (setq user (read-ftp-user-password host user (eq password t))
                    105:                   password (cdr user)
                    106:                   user (car user))))
                    107:   (let ((buffer (get-buffer-create (format "*ftp%s %s:%s*"
                    108:                                           (if filep "" "-directory")
                    109:                                           host file))))
                    110:     (set-buffer buffer)
                    111:     (let ((process (ftp-setup-buffer host file))
                    112:          (case-fold-search nil))
                    113:       (let ((win nil))
                    114:        (unwind-protect
                    115:            (if (setq win (ftp-login process host user password))
                    116:                (message "Logged in")
                    117:              (error "Ftp login lost"))
                    118:          (or win (delete-process process))))
                    119:       (message "Opening %s %s:%s..." (if filep "file" "directory")
                    120:               host file)
                    121:       (if (ftp-command process
                    122:                       (format "%s \"%s\" -\nquit\n" (if filep "get" "dir")
                    123:                               file)
                    124:                       "\\(150\\|125\\).*\n"
                    125:                       "200.*\n")
                    126:          (progn (forward-line 1)
                    127:                 (let ((buffer-read-only nil))
                    128:                   (delete-region (point-min) (point)))
                    129:                 (message "Retrieving %s:%s in background.  Bye!" host file)
                    130:                 (set-process-sentinel process
                    131:                                       'ftp-asynchronous-input-sentinel)
                    132:                 process)
                    133:        (switch-to-buffer buffer)
                    134:        (let ((buffer-read-only nil))
                    135:          (insert-before-markers "<<<Ftp lost>>>"))
                    136:        (delete-process process)
                    137:        (error "Ftp %s:%s lost" host file)))))
                    138: 
                    139: 
                    140: (defun ftp-write-file (host file &optional user password)
                    141:   "FTP to HOST to write FILE, logging in as USER with password PASSWORD.
                    142: Interactively, HOST and FILE are specified by reading a string with colon
                    143: separating the host from the filename.
                    144: USER and PASSWORD are defaulted from the values used when
                    145:  last ftping from HOST (unless password-remembering is disabled).
                    146:  Supply a password of the symbol `t' to override this default
                    147:  (interactively, this is done by giving a prefix arg)"
                    148:   (interactive
                    149:     (append (ftp-read-file-name "FTP write host:file: ")
                    150:            (list nil (not (null current-prefix-arg)))))
                    151:   (or (and user password (not (eq password t)))
                    152:       (progn (setq user (read-ftp-user-password host user (eq password t))
                    153:                   password (cdr user)
                    154:                   user (car user))))
                    155:   (let ((buffer (get-buffer-create (format "*ftp %s:%s*" host file)))
                    156:        (tmp (make-temp-name "/tmp/emacsftp")))
                    157:     (write-region (point-min) (point-max) tmp)
                    158:     (set-buffer buffer)
                    159:     (make-local-variable 'ftp-temp-file-name)
                    160:     (setq ftp-temp-file-name tmp)
                    161:     (let ((process (ftp-setup-buffer host file))
                    162:          (case-fold-search nil))
                    163:       (let ((win nil))
                    164:        (unwind-protect
                    165:            (if (setq win (ftp-login process host user password))
                    166:                (message "Logged in")
                    167:                (error "Ftp login lost"))
                    168:          (or win (delete-process process))))
                    169:       (message "Opening file %s:%s..." host file)
                    170:       (if (ftp-command process
                    171:                       (format "send \"%s\" \"%s\"\nquit\n" tmp file)
                    172:                       "\\(150\\|125\\).*\n"
                    173:                       "200.*\n")
                    174:          (progn (forward-line 1)
                    175:                 (let ((buffer-read-only nil))
                    176:                   (delete-region (point-min) (point)))
                    177:                 (message "Saving %s:%s in background.  Bye!" host file)
                    178:                 (set-process-sentinel process
                    179:                                       'ftp-asynchronous-output-sentinel)
                    180:                 process)
                    181:        (switch-to-buffer buffer)
                    182:        (let ((buffer-read-only nil))
                    183:          (insert-before-markers "<<<Ftp lost>>>"))
                    184:        (delete-process process)
                    185:        (error "Ftp write %s:%s lost" host file)))))
                    186: 
                    187: 
                    188: (defun ftp-setup-buffer (host file)
                    189:   (fundamental-mode)
                    190:   (and (get-buffer-process (current-buffer))
                    191:        (progn (discard-input)
                    192:              (if (y-or-n-p (format "Kill process \"%s\" in %s? "
                    193:                                    (process-name (get-buffer-process
                    194:                                                    (current-buffer)))
                    195:                                    (buffer-name (current-buffer))))
                    196:                  (while (get-buffer-process (current-buffer))
                    197:                    (kill-process (get-buffer-process (current-buffer))))
                    198:                (error "Foo"))))
                    199:   ;(buffer-flush-undo (current-buffer))
                    200:   (setq buffer-read-only nil)
                    201:   (erase-buffer)
                    202:   (make-local-variable 'ftp-host)
                    203:   (setq ftp-host host)
                    204:   (make-local-variable 'ftp-file)
                    205:   (setq ftp-file file)
                    206:   (setq buffer-read-only t)
                    207:   (start-process "ftp" (current-buffer) "ftp" "-i" "-n" "-g"))
                    208: 
                    209: 
                    210: (defun ftp-login (process host user password)
                    211:   (message "FTP logging in as %s@%s..." user host)
                    212:   (if (ftp-command process
                    213:                   (format "open %s\nuser %s %s\n" host user password)
                    214:                   "230.*\n"
                    215:                   "\\(Connected to \\|220\\|331\\).*\n")
                    216:       t
                    217:     (switch-to-buffer (process-buffer process))
                    218:     (delete-process process)
                    219:     (if (listp ftp-password-alist)
                    220:        (setq ftp-password-alist (delq (assoc host ftp-password-alist)
                    221:                                       ftp-password-alist)))
                    222:     nil))
                    223: 
                    224: (defun ftp-command (process command win ignore)
                    225:   (process-send-string process command)
                    226:   (let ((p 1)
                    227:        (case-fold-search t))
                    228:     (while (numberp p)
                    229:       (cond ;((not (bolp)))
                    230:            ((looking-at win)
                    231:             (goto-char (point-max))
                    232:             (setq p t))
                    233:            ((looking-at "^ftp> \\|^\n")
                    234:             (goto-char (match-end 0)))
                    235:            ((looking-at ignore)
                    236:             ;; Ignore status messages whose codes indicate no problem.
                    237:             (forward-line 1))
                    238:            ((looking-at "^[^0-9]")
                    239:             ;; Ignore any lines that don't have status codes.
                    240:             (forward-line 1))
                    241:            ((not (search-forward "\n" nil t))
                    242:             ;; the way asynchronous process-output fucks with (point)
                    243:             ;;  is really really disgusting.
                    244:             (setq p (point))
                    245:             (condition-case ()
                    246:                 (accept-process-output process)
                    247:               (error nil))
                    248:             (goto-char p))
                    249:            (t
                    250:             (setq p nil))))
                    251:     p))
                    252: 
                    253: 
                    254: (defun ftp-asynchronous-input-sentinel (process msg)
                    255:   (ftp-sentinel process msg t t))
                    256: (defun ftp-synchronous-input-sentinel (process msg)
                    257:   (ftp-sentinel process msg nil t))
                    258: (defun ftp-asynchronous-output-sentinel (process msg)
                    259:   (ftp-sentinel process msg t nil))
                    260: (defun ftp-synchronous-output-sentinel (process msg)
                    261:   (ftp-sentinel process msg nil nil))
                    262: 
                    263: (defun ftp-sentinel (process msg asynchronous input)
                    264:   (cond ((null (buffer-name (process-buffer process)))
                    265:         ;; deleted buffer
                    266:         (set-process-buffer process nil))
                    267:        ((and (eq (process-status process) 'exit)
                    268:              (= (process-exit-status process) 0))
                    269:         (save-excursion
                    270:           (set-buffer (process-buffer process))
                    271:           (let (msg
                    272:                 (r (if input "[0-9]+ bytes received in [0-9]+\\.[0-9]+ seconds.*$" "[0-9]+ bytes sent in [0-9]+\\.[0-9]+ seconds.*$")))
                    273:             (goto-char (point-max))
                    274:             (search-backward "226 ")
                    275:             (if (looking-at r)
                    276:                 (search-backward "226 "))
                    277:             (let ((p (point)))
                    278:               (setq msg (concat (format "ftp %s %s:%s done"
                    279:                                         (if input "read" "write")
                    280:                                         ftp-host ftp-file)
                    281:                                 (if (re-search-forward r nil t)
                    282:                                     (concat ": " (buffer-substring
                    283:                                                    (match-beginning 0)
                    284:                                                    (match-end 0)))
                    285:                                     "")))
                    286:               (let ((buffer-read-only nil))
                    287:                 (delete-region p (point-max)))
                    288:               (save-excursion
                    289:                 (set-buffer (get-buffer-create "*ftp log*"))
                    290:                 (let ((buffer-read-only nil))
                    291:                   (insert msg ?\n)))
                    292:               (set-buffer-modified-p nil))
                    293:             (if (not input)
                    294:                 (progn
                    295:                   (condition-case ()
                    296:                       (and (boundp 'ftp-temp-file-name)
                    297:                            ftp-temp-file-name
                    298:                            (delete-file ftp-temp-file-name))
                    299:                     (error nil))
                    300:                   (kill-buffer (current-buffer)))
                    301:               ;; You don't want to look at this.
                    302:               (let ((kludge (generate-new-buffer (format "%s:%s (ftp)"
                    303:                                                          ftp-host ftp-file))))
                    304:                 (setq kludge (prog1 (buffer-name kludge) (kill-buffer kludge)))
                    305:                 (rename-buffer kludge)
                    306:                 ;; ok, you can look again now.
                    307:                 (ftp-setup-write-file-hooks)))
                    308:             (if (and asynchronous
                    309:                      ;(waiting-for-user-input-p)
                    310:                      )
                    311:                 (progn (message "%s" msg)
                    312:                        (sleep-for 2))))))
                    313:        ((memq (process-status process) '(exit signal))
                    314:         (save-excursion
                    315:           (set-buffer (process-buffer process))
                    316:           (setq msg (format "Ftp died (buffer %s): %s"
                    317:                             (buffer-name (current-buffer))
                    318:                             msg))
                    319:           (let ((buffer-read-only nil))
                    320:             (goto-char (point-max))
                    321:             (insert ?\n ?\n msg))
                    322:           (delete-process proc)
                    323:           (set-buffer (get-buffer-create "*ftp log*"))
                    324:           (let ((buffer-read-only nil))
                    325:             (goto-char (point-max))
                    326:             (insert msg))
                    327:           (if (waiting-for-user-input-p)
                    328:               (error "%s" msg))))))
                    329: 
                    330: (defun ftp-setup-write-file-hooks ()
                    331:   (let ((hooks write-file-hooks))
                    332:     (make-local-variable 'write-file-hooks)
                    333:     (setq write-file-hooks (append write-file-hooks
                    334:                                   '(ftp-write-file-hook))))
                    335:   (make-local-variable 'revert-buffer-function)
                    336:   (setq revert-buffer-function 'ftp-revert-buffer)
                    337:   (setq default-directory "/tmp/")
                    338:   (setq buffer-file-name (concat default-directory
                    339:                                 (make-temp-name
                    340:                                  (buffer-name (current-buffer)))))
                    341:   (setq buffer-read-only nil))
                    342: 
                    343: (defun ftp-write-file-hook ()
                    344:   (let ((buffer (current-buffer))
                    345:        (process (ftp-write-file ftp-host ftp-file)))
                    346:     (set-process-sentinel process 'ftp-synchronous-output-sentinel)
                    347:     (message "FTP writing %s:%s..." ftp-host ftp-file)
                    348:     (while (eq (process-status process) 'run)
                    349:       (condition-case ()
                    350:          (accept-process-output process)
                    351:        (error nil)))
                    352:     (and (eq (process-status process) 'exit)
                    353:         (= (process-exit-status process) 0)
                    354:          (save-excursion
                    355:            (set-buffer buffer)
                    356:           (set-buffer-modified-p nil))))
                    357:   (message "Written")
                    358:   t)
                    359: 
                    360: (defun ftp-revert-buffer (&rest ignore)
                    361:   (let ((process (ftp-find-file ftp-host ftp-file)))
                    362:     (set-process-sentinel process 'ftp-synchronous-input-sentinel)
                    363:     (message "FTP reverting %s:%s" ftp-host ftp-file)
                    364:     (while (eq (process-status process) 'run)
                    365:       (condition-case ()
                    366:          (accept-process-output process)
                    367:        (error nil)))
                    368:     (and (eq (process-status process) 'exit)
                    369:         (= (process-exit-status process) 0)
                    370:         (set-buffer-modified-p nil))
                    371:     (message "Reverted")))

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.