#!/bin/sh
: ; exec klone $0 "$@"
; The above line finds the klone executable in the $PATH
(setq USAGE "getftp file-descs...
where filedesc can be of the form:
(1) host:path/file
(2) path/file@host
(3) ftp://host/path/file (W3 form)
return status is number of failed transfers
the client will log as user anonymous, password $USER@")
(setq args (getopts USAGE
("-v" () verbose "verbose mode, dumps ftp log")
("-q" () quiet "quiet mode, only status returned")
("-r" () do-reget "do a reget of file instead of a get")
("-t" timeout timeout "timout in seconds (default 0 = none)")
("-c" () redo "continue retrying tranfers until all files transferred")
("-debug" () debug "debug mode")
))
(if (not (>= (length args) 1))
(progn (PF "%0\n" USAGE) (exit 1))
)
(if (not timeout) (setq timeout 0))
(setq doftp:timeout (Int timeout))
(catch 'OK
(dolist (loc #("/usr/ucb/ftp" "/bin/ftp" "/usr/bin/ftp"))
(if (file-stats loc) (throw 'OK (setq ftp-binary loc)))
)
(setq ftp-binary "ftp")
)
(setq status 0)
(defun main ()
(if redo
(with (files (copy args) toretry (list))
(while files
(dolist (file files)
(setq status 0)
(get-desc file)
(if (/= 0 status)
(lappend toretry file)
))
(setq files toretry)
(setq toretry (list))
)
(exit 0)
)
(progn
(dolist (file args)
(get-desc file)
)
(if debug (PV status))
(apply exit (list status)) ;circumvent bug
)))
(defun get-desc (desc &aux
hpf ;host-path-file triplet
)
(setq hpf (or
(match "^ftp:[/][/]([^/]+)([/](.*))[/]([^/]+)$" desc 1 2 3)
(match "^([^:]+):()([^/]+)$" desc 1 2 3)
(match "^([^:]+):(.*)[/]([^/]+)$" desc 1 2 3)
(match "^()([^/@]+)@(.*)$" desc 3 1 2)
(match "^([^@]*)[/]([^/@]+)@(.*)$" desc 3 1 2)
(progn (PF "getftp error: unknown file description: %r0, ignored\n" desc)
()
)
))
(if hpf (apply get-file hpf))
)
(defun get-file (host path file &aux
log
stats
size
)
(setq log (doftp host (+ (getenv "USER") "@") (+ "/" path)
(+ (if do-reget "reget " "get ") file)
))
(if verbose (write-string log))
(if (setq stats (file-stats file))
(if (and (setq size (match (+ "Opening data connection for "
(quote-string-for-regexp file)
"[(][^)]*[)] *[(]([0-9]+) +bytes[)]."
) log 1
))
(/= (Int size) (getn stats 'size))
)
(progn
(if (not quiet) (print-format "getftp: file %0 FAILED (truncated: only %2 bytes receieved instead of %1)!\n" file (getn stats 'size) size))
(if (not (or verbose quiet)) (write-string log))
(incf status)
)
(if (not quiet) (print-format "getftp: file %0 Ok (%1 bytes)\n" file
(get stats 'size)
))
)
(progn
(if (not quiet) (print-format "getftp: file %0 FAILED! (could not get it)\n" file))
(if (not (or verbose quiet)) (write-string log))
(incf status)
)
)
))
(defun doftp (site site:password site:dir &rest commands &aux
fd
pid
(tempfile (+ "/tmp/getftp_" (String *current-process-id*)))
res
timeoutpid
terminated
)
(if (/= 0 doftp:timeout) (setq timeoutpid (system (list "sleep" (String
doftp:timeout
)))))
(setq pid (system (+ ftp-binary " -inv > " tempfile " 2>&1") :input 'fd))
(print-format fd "open %0\n\nuser anonymous %1\nbinary\nprompt\ncd \"%2\"\n"
site
site:password
site:dir
)
(flush fd)
(if debug (print-format fd "pwd\ndir\n"))
(doftp:command commands fd)
(print-format fd "quit\n")
(flush fd)
(setq terminated (wait ()))
(setq res (String (open tempfile :error "Could not find log file!")))
(if (= timeoutpid (getn terminated 0)) (progn ;timeouted
(sh kill ,pid)
(sh sleep 2)
(nconc res "\n *** TIMEOUTED *** \n")
))
(wait (system (list "rm" "-f" tempfile)))
res
)
(defun doftp:command (command fd)
(if (typep command List)
(dolist (com command) (doftp:command com fd))
(progn
(if debug (PV com))
(print-format fd "%0\n" com)
(flush fd)
))
)
(main)
;;; EMACS MODES
;;; Local Variables: ***
;;; mode:lisp ***
;;; End: ***
syntax highlighted by Code2HTML, v. 0.9.1