Mercurial > emacs
changeset 42861:3ee90bcdf67d
Added support for BS2000, and for raw ftp
login commands (needed in some circumstances).
(ange-ftp-raw-login): New custom var.
(ange-ftp-normal-login): Perform login with raw ftp commands, if
ange-ftp-raw-login is set and account password is needed.
(ange-ftp-host-type, ange-ftp-guess-host-type): Handle BS2000 hosts.
(ange-ftp-bs2000-filename-pubset-regexp)
(ange-ftp-bs2000-filename-username-regexp)
(ange-ftp-bs2000-filename-prefix-regexp)
(ange-ftp-bs2000-name-template): New consts.
(ange-ftp-bs2000-short-filename-regexp)
(ange-ftp-bs2000-fix-name-regexp-reverse)
(ange-ftp-bs2000-fix-name-regexp): New consts.
(ange-ftp-bs2000-special-prefix): New custom var.
(ange-ftp-fix-name-for-bs2000)
(ange-ftp-fix-dir-name-for-bs2000): New funs.
(ange-ftp-bs2000-host-regexp, ange-ftp-bs2000-posix-host-regexp)
(ange-ftp-bs2000-posix-hook-installed): New vars.
(ange-ftp-parse-bs2000-filename, ange-ftp-parse-bs2000-listing)
(ange-ftp-bs2000-host, ange-ftp-bs2000-posix-host)
(ange-ftp-add-bs2000-host, ange-ftp-add-bs2000-posix-host): New funs.
(ange-ftp-bs2000-filename-regexp): New const.
(ange-ftp-bs2000-additional-pubsets): New custom var.
(ange-ftp-bs2000-cd-to-posix): New fun.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Sun, 20 Jan 2002 22:10:54 +0000 |
parents | fc4a17f3d810 |
children | ca273f84f170 |
files | lisp/net/ange-ftp.el |
diffstat | 1 files changed, 373 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/net/ange-ftp.el Sun Jan 20 18:13:16 2002 +0000 +++ b/lisp/net/ange-ftp.el Sun Jan 20 22:10:54 2002 +0000 @@ -385,6 +385,66 @@ ;; 2. Ange-ftp cannot send "write passwords" for a minidisk. Hopefully, we ;; can fix this. ;; +;; BS2000 support: +;; +;; Ange-ftp has full support for BS2000 hosts. It should be able to +;; automatically recognize any BS2000 machine. However, if it fails to +;; do this, you can use the command ange-ftp-add-bs2000-host. As well, +;; you can set the variable ange-ftp-bs2000-host-regexp in your .emacs +;; file. We would be grateful if you would report any failures to auto- +;; matically recognize a BS2000 host as a bug. +;; +;; If you want to access the POSIX subsystem on BS2000 you MUST use +;; command ange-ftp-add-bs2000-posix-host for that particular +;; hostname. ange-ftp can't decide if you want to access the native +;; filesystem or the POSIX filesystem, so it accesses the native +;; filesystem by default. And if you have an ASCII filesystem in +;; your BS2000 POSIX subsystem you must use +;; ange-ftp-binary-file-name-regexp to access its files. +;; +;; Filename Syntax: +;; +;; For ease of *implementation*, the user enters the BS2000 filename +;; syntax in a UNIX-y way. For example: +;; :PUB:$PUBLIC.ANONYMOUS.SDSCPUB.NEXT.README.TXT +;; would be entered as: +;; /:PUB:/$$PUBLIC/ANONYMOUS.SDSCPUB.NEXT.README.TXT +;; You dont't have to type pubset and account, if they have default values, +;; i.e. to log in as anonymous on bs2000.anywhere.com and grab the file +;; IMPORTANT.TEXT.ON.BS2000 on the default pubset X on userid PUBLIC +;; (there are only 8 characters in a valid username), you could type: +;; C-x C-f /public@bs2000.anywhere.com:/IMPORTANT.TEXT.ON.BS2000 +;; or +;; C-x C-f /anonym@bs2000.anywhere.com:/:X:/$$PUBLIC/IMPORTANT.TEXT.ON.BS2000 +;; +;; If X is not your default pubset, you could add it as 'subdirectory' (BS2000 +;; has a flat architecture) with the command +;; (setq ange-ftp-bs2000-additional-pubsets '(":X:")) +;; and then you could type: +;; C-x C-f /anonym@bs2000.anywhere.com:/:X:/IMPORTANT.TEXT.ON.BS2000 +;; +;; Valid characters in an BS2000 filename are A-Z 0-9 $ # @ . - +;; If the first character in a filename is # or @, this is replaced with +;; ange-ftp-bs2000-special-prefix because names starting with # or @ +;; are reserved for temporary files. +;; This is especially important for auto-save files. +;; Valid file generations are ending with ([+|-|*]0-9...) . +;; File generations are not supported yet! +;; A filename must at least contain one character (A-Z) and cannot be longer +;; than 41 characters. +;; +;; Tips: +;; 1. Although BS2000 is not case sensitive, EMACS running under UNIX is. +;; Therefore, to access a BS2000 file, you must enter the filename with +;; upper case letters. +;; 2. EMACS has a feature in which it does environment variable substitution +;; in filenames. Therefore, to enter a $ in a filename, you must quote it +;; by typing $$. +;; 3. BS2000 machines, with the exception of anonymous accounts, nearly +;; always need an account password. To have ange-ftp send an account +;; password, you can either include it in your .netrc file, or use +;; ange-ftp-set-account. +;; ;; ------------------------------------------------------------------ ;; Bugs: ;; ------------------------------------------------------------------ @@ -1994,6 +2054,13 @@ (make-local-variable 'paragraph-start) (setq paragraph-start comint-prompt-regexp))) +(defcustom ange-ftp-raw-login nil + "*Use raw ftp commands for login, if account password is not nil. +Some ftp implementations need this, e.g. ftp in NT 4.0." + :group 'ange-ftp + :version "21.3" + :type 'boolean) + (defun ange-ftp-smart-login (host user pass account proc) "Connect to the FTP-server on HOST as USER using PASSWORD and ACCOUNT. PROC is the FTP-client's process. This routine uses the smart-gateway @@ -2044,13 +2111,42 @@ (ange-ftp-error host user (concat "OPEN request failed: " (cdr result)))) - (setq result (ange-ftp-raw-send-cmd - proc - (if (and (ange-ftp-use-smart-gateway-p host) - ange-ftp-gateway-host) - (format "user \"%s\"@%s %s %s" user nshost pass account) - (format "user \"%s\" %s %s" user pass account)) - (format "Logging in as user %s@%s" user host))) + (if (not (and ange-ftp-raw-login (string< "" account))) + (setq result (ange-ftp-raw-send-cmd + proc + (if (and (ange-ftp-use-smart-gateway-p host) + ange-ftp-gateway-host) + (format "user \"%s\"@%s %s %s" + user nshost pass account) + (format "user \"%s\" %s %s" user pass account)) + (format "Logging in as user %s@%s" user host))) + (let ((good ange-ftp-good-msgs) + (skip ange-ftp-skip-msgs)) + (setq ange-ftp-good-msgs (concat ange-ftp-good-msgs + "\\|^331 \\|^332 ")) + (if (string-match (regexp-quote "\\|^331 ") ange-ftp-skip-msgs) + (setq ange-ftp-skip-msgs + (replace-match "" t t ange-ftp-skip-msgs))) + (if (string-match (regexp-quote "\\|^332 ") ange-ftp-skip-msgs) + (setq ange-ftp-skip-msgs + (replace-match "" t t ange-ftp-skip-msgs))) + (setq result (ange-ftp-raw-send-cmd + proc + (format "quote \"USER %s\"" user) + (format "Logging in as user %s@%s" user host))) + (and (car result) + (setq result (ange-ftp-raw-send-cmd + proc + (format "quote \"PASS %s\"" pass) + (format "Logging in as user %s@%s" user host))) + (and (car result) + (setq result (ange-ftp-raw-send-cmd + proc + (format "quote \"ACCT %s\"" account) + (format "Logging in as user %s@%s" user host))) + )) + (setq ange-ftp-good-msgs good + ange-ftp-skip-msgs skip))) (or (car result) (progn (ange-ftp-set-passwd host user nil) ;reset password. @@ -2174,6 +2270,12 @@ ((and (fboundp 'ange-ftp-cms-host) (ange-ftp-cms-host host)) 'cms) + ((and (fboundp 'ange-ftp-bs2000-posix-host) + (ange-ftp-bs2000-posix-host host)) + 'text-unix) ; POSIX is a non-ASCII Unix + ((and (fboundp 'ange-ftp-bs2000-host) + (ange-ftp-bs2000-host host)) + 'bs2000) (t 'unix)))))) @@ -2324,6 +2426,20 @@ "^[-A-Z0-9_$]+:\\[[-A-Z0-9_$]+\\(\\.[-A-Z0-9_$]+\\)*\\]$") (defconst ange-ftp-mts-name-template "^[A-Z0-9._][A-Z0-9._][A-Z0-9._][A-Z0-9._]:$") +(defconst ange-ftp-bs2000-filename-pubset-regexp + ":[A-Z0-9]+:" + "Valid pubset for an BS2000 file name.") +(defconst ange-ftp-bs2000-filename-username-regexp + (concat + "\\$[A-Z0-9]*\\.") + "Valid username for an BS2000 file name.") +(defconst ange-ftp-bs2000-filename-prefix-regexp + (concat + ange-ftp-bs2000-filename-pubset-regexp + ange-ftp-bs2000-filename-username-regexp) + "Valid prefix for an BS2000 file name (pubset and user).") +(defconst ange-ftp-bs2000-name-template + (concat "^" ange-ftp-bs2000-filename-prefix-regexp "$")) (defun ange-ftp-guess-host-type (host user) "Guess the host type of HOST. @@ -2370,6 +2486,17 @@ (setq ange-ftp-host-cache host ange-ftp-host-type-cache 'cms)) + ;; try for BS2000-POSIX + ((ange-ftp-bs2000-posix-host host) + (ange-ftp-add-bs2000-host host) + (setq ange-ftp-host-cache host + ange-ftp-host-type-cache 'text-unix)) + ;; try for BS2000 + ((and (string-match ange-ftp-bs2000-name-template dir) + (not (ange-ftp-bs2000-posix-host host))) + (ange-ftp-add-bs2000-host host) + (setq ange-ftp-host-cache host + ange-ftp-host-type-cache 'bs2000)) ;; assume UN*X (t (setq ange-ftp-host-cache host @@ -2825,14 +2952,17 @@ ;;; (or ;;; ;; Deal with dired ;;; (and (boundp 'dired-local-variables-file) ; in the dired-x package -;;; (stringp dired-local-variables-file) -;;; (string-equal dired-local-variables-file efile)) +;;; (stringp dired-local-variables-file) +;;; (string-equal dired-local-variables-file efile)) ;;; ;; No dots in dir names in vms. ;;; (and (eq host-type 'vms) -;;; (string-match "\\." efile)) +;;; (string-match "\\." efile)) ;;; ;; No subdirs in mts of cms. -;;; (and (memq host-type '(mts cms)) -;;; (not (string-equal "/" (nth 2 parsed))))))) +;;; (and (memq host-type '(mts cms)) +;;; (not (string-equal "/" (nth 2 parsed)))) +;;; ;; No dots in pseudo-dir names in bs2000. +;;; (and (eq host-type 'bs2000) +;;; (string-match "\\." efile))))))) (defun ange-ftp-file-entry-p (name) "Given NAME, return whether there is a file entry for it." @@ -5808,6 +5938,237 @@ ;; ange-ftp-dired-get-filename-alist))) ;;;; ------------------------------------------------------------ +;;;; BS2000 support +;;;; ------------------------------------------------------------ + +;; There seems to be an error with regexps. '-' has to be the first +;; character inside of the square brackets. +(defconst ange-ftp-bs2000-short-filename-regexp + "[-A-Z0-9$#@.]*[A-Z][-A-Z0-9$#@.]*" + "Regular expression to match for a valid short BS2000 file name.") + +(defconst ange-ftp-bs2000-fix-name-regexp-reverse + (concat + "^\\(" ange-ftp-bs2000-filename-pubset-regexp "\\)?" + "\\(" ange-ftp-bs2000-filename-username-regexp "\\)?" + "\\(" ange-ftp-bs2000-short-filename-regexp "\\)?") +"Regular expression used in ange-ftp-fix-name-for-bs2000.") + +(defconst ange-ftp-bs2000-fix-name-regexp + (concat + "/?\\(" ange-ftp-bs2000-filename-pubset-regexp "/\\)?" + "\\(\\$[A-Z0-9]*/\\)?" + "\\(" ange-ftp-bs2000-short-filename-regexp "\\)?") +"Regular expression used in ange-ftp-fix-name-for-bs2000.") + +(defcustom ange-ftp-bs2000-special-prefix + "X" + "*Prefix used for filenames starting with '#' or '@'." + :group 'ange-ftp + :type 'string) + +;; Convert NAME from UNIX-ish to BS2000. If REVERSE given then convert from +;; BS2000 to UNIX-ish. +(defun ange-ftp-fix-name-for-bs2000 (name &optional reverse) + (save-match-data + (if reverse + (if (string-match + ange-ftp-bs2000-fix-name-regexp-reverse + name) + (let ((pubset (if (match-beginning 1) + (substring name 0 (match-end 1)))) + (userid (if (match-beginning 2) + (substring name + (match-beginning 2) + (1- (match-end 2))))) + (filename (if (match-beginning 3) + (substring name (match-beginning 3))))) + (concat + "/" + ;; we have to insert "_/" here to prevent expand-file-name to + ;; interpret BS2000 pubsets as the special escape prefix: + (and pubset (concat "_/" pubset "/")) + (and userid (concat userid "/")) + filename)) + (error "name %s didn't match" name)) + ;; and here we (maybe) have to remove the inserted "_/" 'cause + ;; of our prevention of the special escape prefix above: + (if (string-match (concat "^/_/") name) + (setq name (substring name 2))) + (if (string-match + ange-ftp-bs2000-fix-name-regexp + name) + (let ((pubset (if (match-beginning 1) + (substring name + (match-beginning 1) + (1- (match-end 1))))) + (userid (if (match-beginning 2) + (substring name + (match-beginning 2) + (1- (match-end 2))))) + (filename (if (match-beginning 3) + (substring name (match-beginning 3))))) + (if (and (boundp 'filename) + (stringp filename) + (string-match "[#@].+" filename)) + (setq filename (concat ange-ftp-bs2000-special-prefix + (substring filename 1)))) + (upcase + (concat + pubset + (and userid (concat userid ".")) + ;; change every '/' in filename to a '.', normally not neccessary + (and filename + (apply (function concat) + (mapcar (function (lambda (char) + (if (= char ?/) + (vector ?.) + (vector char)))) + filename)))))) + ;; Let's hope that BS2000 recognize this anyway: + name)))) + +(or (assq 'bs2000 ange-ftp-fix-name-func-alist) + (setq ange-ftp-fix-name-func-alist + (cons '(bs2000 . ange-ftp-fix-name-for-bs2000) + ange-ftp-fix-name-func-alist))) + +;; Convert name from UNIX-ish to BS2000 ready for a DIRectory listing. +;; Remember that there are no directories in BS2000. +(defun ange-ftp-fix-dir-name-for-bs2000 (dir-name) + (if (string-equal dir-name "/") + "*" ;; Don't use an empty string here! + (ange-ftp-fix-name-for-bs2000 dir-name))) + +(or (assq 'bs2000 ange-ftp-fix-dir-name-func-alist) + (setq ange-ftp-fix-dir-name-func-alist + (cons '(bs2000 . ange-ftp-fix-dir-name-for-bs2000) + ange-ftp-fix-dir-name-func-alist))) + +(or (memq 'bs2000 ange-ftp-dumb-host-types) + (setq ange-ftp-dumb-host-types + (cons 'bs2000 ange-ftp-dumb-host-types))) + +(defvar ange-ftp-bs2000-host-regexp nil) +(defvar ange-ftp-bs2000-posix-host-regexp nil) + +;; Return non-nil if HOST is running BS2000. +(defun ange-ftp-bs2000-host (host) + (and ange-ftp-bs2000-host-regexp + (save-match-data + (string-match ange-ftp-bs2000-host-regexp host)))) +;; Return non-nil if HOST is running BS2000 with POSIX subsystem. +(defun ange-ftp-bs2000-posix-host (host) + (and ange-ftp-bs2000-posix-host-regexp + (save-match-data + (string-match ange-ftp-bs2000-posix-host-regexp host)))) + +(defun ange-ftp-add-bs2000-host (host) + "Mark HOST as the name of a machine running BS2000." + (interactive + (list (read-string "Host: " + (let ((name (or (buffer-file-name) default-directory))) + (and name (car (ange-ftp-ftp-name name))))))) + (if (not (ange-ftp-bs2000-host host)) + (setq ange-ftp-bs2000-host-regexp + (concat "^" (regexp-quote host) "$" + (and ange-ftp-bs2000-host-regexp "\\|") + ange-ftp-bs2000-host-regexp) + ange-ftp-host-cache nil))) + +(defun ange-ftp-add-bs2000-posix-host (host) + "Mark HOST as the name of a machine running BS2000 with POSIX subsystem." + (interactive + (list (read-string "Host: " + (let ((name (or (buffer-file-name) default-directory))) + (and name (car (ange-ftp-ftp-name name))))))) + (if (not (ange-ftp-bs2000-posix-host host)) + (setq ange-ftp-bs2000-posix-host-regexp + (concat "^" (regexp-quote host) "$" + (and ange-ftp-bs2000-posix-host-regexp "\\|") + ange-ftp-bs2000-posix-host-regexp) + ange-ftp-host-cache nil)) + ;; Install CD hook to cd to posix on connecting: + (and (not ange-ftp-bs2000-posix-hook-installed) + (add-hook 'ange-ftp-process-startup-hook 'ange-ftp-bs2000-cd-to-posix) + (setq ange-ftp-bs2000-posix-hook-installed t)) + host) + +(defconst ange-ftp-bs2000-filename-regexp + (concat + "\\(" ange-ftp-bs2000-filename-prefix-regexp "\\)?" + "\\(" ange-ftp-bs2000-short-filename-regexp "\\)") + "Regular expression to match for a valid BS2000 file name.") + +(defcustom ange-ftp-bs2000-additional-pubsets + nil + "*List of additional pubsets available to all users." + :group 'ange-ftp + :type 'string) + +;; These parsing functions are as general as possible because the syntax +;; of ftp listings from BS2000 hosts is a bit erratic. What saves us is that +;; the BS2000 filename syntax is so rigid. + +;; Extract the next filename from a BS2000 dired-like listing. +(defun ange-ftp-parse-bs2000-filename () + (if (re-search-forward ange-ftp-bs2000-filename-regexp nil t) + (buffer-substring (match-beginning 2) (match-end 2)))) + +;; Parse the current buffer which is assumed to be in (some) BS2000 FTP dir +;; format, and return a hashtable as the result. +(defun ange-ftp-parse-bs2000-listing () + (let ((tbl (ange-ftp-make-hashtable)) + pubset + file) + ;; get current pubset + (goto-char (point-min)) + (if (re-search-forward ange-ftp-bs2000-filename-pubset-regexp nil t) + (setq pubset (buffer-substring (match-beginning 0) (match-end 0)))) + ;; add files to hashtable + (goto-char (point-min)) + (save-match-data + (while (setq file (ange-ftp-parse-bs2000-filename)) + (ange-ftp-put-hash-entry file nil tbl))) + ;; add . and .. + (ange-ftp-put-hash-entry "." t tbl) + (ange-ftp-put-hash-entry ".." t tbl) + ;; add all additional pubsets, if not listing one of them + (if (not (member pubset ange-ftp-bs2000-additional-pubsets)) + (mapcar (function (lambda (pubset) + (ange-ftp-put-hash-entry pubset t tbl))) + ange-ftp-bs2000-additional-pubsets)) + tbl)) + +(or (assq 'bs2000 ange-ftp-parse-list-func-alist) + (setq ange-ftp-parse-list-func-alist + (cons '(bs2000 . ange-ftp-parse-bs2000-listing) + ange-ftp-parse-list-func-alist))) + +(defvar ange-ftp-bs2000-posix-hook-installed nil) +(defun ange-ftp-bs2000-cd-to-posix () + "cd to POSIX subsystem if the current host matches +ange-ftp-bs2000-posix-host-regexp. All BS2000 hosts with POSIX subsystem +MUST BE EXPLICITLY SET with ange-ftp-add-bs2000-posix-host for they cannot +be recognized automatically (they are all valid BS2000 hosts too)." + (if (and host (ange-ftp-bs2000-posix-host host)) + (progn + ;; change to POSIX: +; (ange-ftp-raw-send-cmd proc "cd %POSIX") + (ange-ftp-cd host user "%POSIX") + ;; put new home directory in the expand-dir hashtable. + (ange-ftp-put-hash-entry (concat host "/" user "/~") + (car (ange-ftp-get-pwd host user)) + ange-ftp-expand-dir-hashtable)))) + +;; Not available yet: +;; ange-ftp-bs2000-delete-file-entry +;; ange-ftp-bs2000-add-file-entry +;; ange-ftp-bs2000-file-name-as-directory +;; ange-ftp-bs2000-make-compressed-filename +;; ange-ftp-bs2000-file-name-sans-versions + +;;;; ------------------------------------------------------------ ;;;; Finally provide package. ;;;; ------------------------------------------------------------