Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

interactive FTP

 [1/3] from: sqlab:gmx at: 15-Jun-2001 10:39


Hi Inspired by the telnet scheme from Frank Sievertsen, the recent discussion about FTP and some problems I had last year with non standard FTP servers I finished this script now. (Un)fortunately I do not use a proxy, so don't ask me about that feature. I hope the formatting is not to much changed by my remailer program. AR REBOL [title: "mFT" date: 15-June-2001 Author: "Anton Reisacher" Email: [sqlab--gmx--net] File: %mftp.r Version: 1.0 Description: {minimal interactive ftp scheme without conversion to Rebol standards should allow usage of any ftp command supported by your host, even Xxxx commands for example just do %mftp.r port: open mftp://user:[pass--host] insert port "HELP" print copy port ; and you see what your server supports insert port "XCWD $volume.subvolume" ; if your host uses a different filesystem copy port insert port "LIST" print copy port ; complete listing got: make string! 1000 insert port "TYPE I" copy port insert port "RETR file" while [get: copy port ] [append got get] ; retrieve all data insert port "TYPE A" ; take care of CRLF in ASCII mode by yourself copy port insert port "STOR Test" insert port data ; you can do repeated inserts until you do a copy copy port close port Proxies are not supported. } Category: 'ftp ] mftp: make root-protocol [ scheme: 'mftp port-id: 21 port-flags: system/standard/port-flags/pass-thru open: func [port [port! url!] /local tmp ] [ open-proto port port/sub-port/state/flags: port/sub-port/state/flags or 2051 port/state/flags: port/state/flags or system/standard/port-flags/direct or 2051 if port/user [ tmp: make string! 512 until [ if not wait [port/sub-port port/timeout] [net-error Timeout ] any [find/any append tmp copy port"log?n" find/any tmp "user" find/any tmp "name" ] ] system/words/insert port/sub-port join "USER " port/user ] if port/pass [ tmp: make string! 256 until [ if not wait [port/sub-port port/timeout] [net-error Timeout ] find/any append tmp copy port"pass" ] system/words/insert port/sub-port join "PASS " port/pass ] tmp: make string! 128 until [ if not wait [port/sub-port port/timeout] [net-error "Timeout"] find/any append tmp copy port"230" ] port/user-data: tmp ] copy: func [port [port!] /part len [integer!] /local tmp ;leng ] [ tmp: make string! 4096 either port/local-service = 'in [ port/local-service: none system/words/close port/remote-service port/remote-service: none if not wait [port/sub-port port/timeout] [net-error "Timeout"] net-utils/net-log append tmp system/words/copy port/sub-port ] [ either port/remote-service [ all [ port/local-service <> 'out port/local-service: 'out not wait [port/remote-service port/timeout] net-error "Timeout" ] either part [ tmp: system/words/copy/part port/remote-service len ][ tmp: system/words/copy port/remote-service ] either tmp [ ; leng: :leng + length? tmp net-utils/net-log to-string tmp ] [ tmp: net-utils/net-log system/words/copy port/sub-port ; if leng <> check length? system/words/close port/remote-service port/remote-service: none ] ] [either port/user-data [ tmp: port/user-data port/user-data: none tmp ] [ net-utils/net-log append tmp system/words/copy port/sub-port ] ] ] ] insert: func [port [port!] data /local listen-port tmp] [ either all [port/remote-service port/local-service <> 'out port/local-service: 'in ] [ system/words/insert port/remote-service data ] [ error? try [catch [close port/remote-service]] port/remote-service: none port/local-service: none ; either all [not proxy not passive] [listen-port: get-port port] [data-connect] listen-port: system/words/open/binary/direct tcp://:0 tmp: form reduce port/sub-port/local-ip append tmp rejoin ["." form to-integer (listen-port/port-id / 256) "." (listen-port/port-id // 256) ] replace/all tmp #"." #"," system/words/insert port/sub-port net-utils/net-log join "PORT " tmp tmp: make string! 128 until [ if not wait [port/sub-port port/timeout] [net-error Timeout ] find/any append tmp copy port"200" ] system/words/insert port/sub-port net-utils/net-log data tmp: make string! 128 until [ if not wait [port/sub-port port/timeout] [net-error Timeout ] find/any append tmp copy port"???" ] either find tmp "150" [ port/remote-service: first listen-port ] [ port/user-data: tmp port/remote-service: none ] system/words/close listen-port ] ] close: func [port [port!] ] [ system/words/insert port/sub-port net-utils/net-log"QUIT" system/words/close port/sub-port error? try [catch [system/words/close data/remote-service]] ] net-utils/net-install 'mFtp self 21 ]

 [2/3] from: fantam:mailandnews at: 18-Jun-2001 1:30


Very good stuff, AR. Thanks. I was also left disappointed by the built-in ftp features. Nothing wrong with the design, but 'exists in the ftp context never worked for me, for example. At RT, they're aware of ftp related bugs. I don't understand why they don't fix them. Probably too busy. Other priorities, maybe.

 [3/3] from: fantam:mailandnews at: 24-Jun-2001 16:02


Excellent. Thanks again, AR. I noticed that Jeff's post on schemes has made it to an article on www.rebolforces.com. I wrote a couple of functions that are meant to be used in conjunction with your scheme (mftp). exists: func [port [port!] file [file! string!] /local content] [ insert port "LIST" content: copy port content: parse/all content "^/" foreach line content [ if (last parse line "") = to-string file [return true] ] return false ] isdir: func [port [port!] file [file! string!] /local content] [ insert port "LIST" content: copy port content: parse/all content "^/" foreach line content [ if find/case line file [ if (first line) = #"d" [return true] ] ] return false ] ftp-bin-upload: func [port [port!] file [file!] /local data] [ data: read/binary file insert port "TYPE I" print copy port insert port reform ["STOR" file] insert port data print copy port ] makedir: func [port [port!] file [file! string!]] [ insert port reform ["MKD" file] print copy port ] The next one is a more sophisticated exists function, that can accept a url, like ftp://ftp.ftp.com/test/test/test.txt and it will navigate to the needed directory, and tell you if the file exists. If you give a url like ftp://ftp.ftp.com/test/test/, it should work as well, and tell you whether the directory path exists or not. exists: func [port [port!] file [file! string! url!] /local content current-exists path] [ current-exists: func [file] [ insert port "LIST" content: copy port content: parse/all content "^/" foreach line content [ if (last parse line "") = to-string file [return true] ] return false ] cdup: does [ insert port "CWD /" copy port ] either url? file [ url-obj: make object! [user: pass: host: port-id: path: target: none] net-utils/url-parser/parse-url url-obj file path: parse url-obj/path "/" foreach item path [ if (current-exists port item) [ insert port reform ["CWD" item] if find/any copy/part copy port 3 "5??" [cdup return false] ] ] either not none? url-obj/target [current-exists url-obj/target] [cdup return true] ] [current-exists file] ] Comments are welcome. I'll probably write more functions like the above. If anyone's interested, let me know. that's it for now. fantam