|
|
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")))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.