Hi Jorge, How was the eye operation? I hope it was a success.
I'm just piping in to tell you that I am going to use this code of yours for simple utility I needed (need 16MB, and growing, of text data to be periodically transferred to a server). My original plan was to transfer the data through the usual web application by compressing it first then J on the server would uncompress it. Unfortunately, the system is now years old and is still using J504. Transferring the data directly looks like a viable plan right now because of the urgency (you know, the type where they needed something to work YESTERDAY). So thanks. :) r/Alex -----Original Message----- From: [email protected] [mailto:[email protected]] On Behalf Of Jorge Arredondo Sent: Saturday, November 28, 2009 12:49 AM To: General forum Subject: Re: [Jgeneral] FTP uploader needed I've written a simple, pure-J FTP class which encapsulates some of the most used FTP commands. I've tested it with FileZilla and ProFTP servers, it uses passive mode to avoid NAT problems, hope it helps you. Here is a file upload & download example: require'files dir' load 'C:\ftp.ijs' HOST =: 'ip or host name' USER =: 'username' PASS =: 'password' localdir =: jpath'~temp/' fn =: 'test.txt' 'hello world' fwrite localdir,fn 11 ftp =: conew 'ftp' connect__ftp HOST;USER;PASS cd__ftp 'ftptest' 250 CWD command successful lcd__ftp localdir Local directory now C:\j64-602-user\temp\ NB. upload example: ls__ftp'' . <dir> 2009 11 27 16 28 31 .. <dir> 2009 11 25 20 21 21 put__ftp fn 226 Transfer complete ls__ftp'' NB.verify the file was written . <dir> 2009 11 27 16 28 31 .. <dir> 2009 11 25 20 21 21 test.txt 11 2009 11 27 16 29 31 ferase localdir,fn 1 NB. download example: dir localdir,'*' jbreak <dir> 27-Nov-09 10:29:07 get__ftp fn 226 Transfer complete dir localdir,'*' NB.verify the file was read jbreak <dir> 27-Nov-09 10:29:07 test.txt 11 27-Nov-09 10:29:24 NB. Hosekeeping ferase localdir,fn 1 delete__ftp fn 250 DELE command successful disconnect__ftp'' 221 Goodbye. destroy__ftp'' 1 Here is the class code: --- ftp.ijs --- NB. ftp class 0 : 0 NB. input lines for a sample session require path-to-this-script ftp =. conew 'ftp' connect__ftp 'host';'user';'password' ls__ftp '' ... disconnect__ftp'' destroy__ftp'' ) require'socket' coclass'ftp' coinsert'jsocket' NB. === Attributes ===================================================== NB. FTP_PORT =: 21 TIMEOUT =: 3000 BUFFSIZE =: 5000 LF =: 10 { a. LO =: _2 ER =: _1 host =: '' connected =: 0 ctrlsk =: 0 datask =: 0 retmsg =: '' ctrlbuff =: '' databuff =: '' fc =: 0 localdir =: '' txmode =: 'ascii' NB. === Initialize - Release =========================================== NB. create=: 3 : '(0 0$0)' destroy=: 3 : 0 disconnect'' codestroy'' ) NB. === Exports ======================================================== NB. NB. connect and log on to FTP server connect=: 3 : 0 'ip user pswd' =. y logonseq =. 0,LO,3, 1,LO,6, 2,LO,ER acct =. '' cmd =. '' logonpoint =. 0 NB. convert name to x x x x if. -.*./ip e. '.0123456789' do. ip =. >2{sdgethostbyname_jsocket_ ip end. ctrlsk =: skclose ctrlsk ctrlsk =: skopen ip;FTP_PORT literal'' while. 1 do. select. logonpoint { logonseq case. 0 do. cmd =. 'USER ',user case. 1 do. cmd =. 'PASS ',pswd case. 2 do. cmd =. 'ACCT ',acct end. if. -.ctrl_write cmd do. error'Write' end. if. -.ctrl_read'' do. error'Read' end. if. fc -...@e. 2 3 do. 0 return. end. logonpoint =. (logonpoint+fc-1) { logonseq select. logonpoint case. ER do. error'Logon failed' case. LO do. break. end. end. host =: ip connected =: 1 localdir =: ((,&PATHSEP_j_)@(1!:43))'' (0 0$0) ) NB. log off & close connection to FTP server disconnect =: 3 : 0 rslt =. (0 0$0) if. ctrlsk do. ctrl_write 'QUIT' ctrl_read'' rslt=. retmsg end. ctrlsk=: skclose ctrlsk datask=: skclose datask host =: '' connected =: 0 rslt ) isConnected =: 3 : 0 connected ) NB. Changes the working directory on the remote computer. cd=: 3 : 0 literal 'CWD ',y ) NB. Deletes a single file on a remote computer. delete=: 3 : 0 literal 'DELE ', y ) NB. Copies a remote file to the local computer using the current file NB. transfer type. get=: 3 : 0 'remote local' =. boxopen y dat=. passive 'RETR ',remote dat fwrite localdir,local retmsg ) NB. Changes the working directory on the local computer. By default, the NB. working directory is the directory in which ftp was started. lcd=: 3 : 0 ps =. PATHSEP_j_ if. 0<#y do. if. '..'-: y do. localdir =: (((}:localdir) >:@i: ps){.localdir) elseif. y e. '/\' do. localdir =: (localdir >:@i. ps) {. localdir elseif. do. localdir =: y end. end. 'Local directory now ', localdir ) NB. Sends arguments, verbatim, to the remote FTP server. literal=: 3 : 0 cmd =. y if. (0~:#cmd) *. (-.ctrl_write cmd) do. error retmsg end. if. (-.ctrl_read'') do. error retmsg end. if. (fc~:2) do. error retmsg end. retmsg ) NB. Returns a list of a remote directory's files and subdirectories. ls=: 3 : 0 dat=. passive 'MLSD' if. 0=#dat do. dat return. end. nms =. dss=. tms=. 0 0$0 for_tokens. }:<;._1@(';'&,);._1 LF,dat do. nm =. }.>((<' ') i.~ {.&.> tokens) { tokens type=. 5}.>((<'type=') i.~ 5&{.&.> tokens) { tokens if. type-:'dir' do. ds =. ' <dir> ' else. ds =. 12":".5}.>((<'size=')i.~5&{.&.>tokens){tokens end. tm =.".7}.>((<'modify=') i.~ 7&{.&.> tokens) { tokens nms =. nms,nm -. CRLF dss =. dss,ds tms =. tms,": 10000 100 100 100 100 100 #: tm end. nms,.dss,.' ',.tms ) NB. Creates a remote directory. mkdir=: 3 : 0 literal 'MKD ',y ) NB. Copies a local file to the remote computer. put=: 3 : 0 'local remote' =. boxopen y dat=. fread (localdir,local) if. dat=_1 do. error 'File not found: ',localdir,local end. dat passive 'STOR ',remote retmsg ) NB. Sets or displays the file transfer type. type=: 3 : 0 name=. tolower y if. 0=#name do. 'Using ', txmode, ' to transfer files.' return. elseif. name-:'ascii' do. mode =. 'A' elseif. name-:'binary' do. mode =. 'I' elseif. do. error 'Invalid argument: ',y end. rslt =. literal 'TYPE ',mode txmode =: name rslt ) NB. === Support ======================================================== NB. error =: (13!:8)&7 NB. Throw 'Interface Error' with optional msg skopen =: 3 : 0 'ip port' =. y sk =. >0{sdcheck sdsocket'' sdcheck sdconnect sk;AF_INET;ip;port sk ) skclose =: 3 : 0 sk =. y if. sk do. sdclose sk end. 0 ) NB. 1 if all data is written to the control channel, otherwise false ctrl_write=: 3 : 0 ctrlsk write toHOST y,LF ) write =: 4 : 0 sk =. x dat =. y if. -.sk e. >2{ sdselect '';sk;'';TIMEOUT do. 0 return. end. while. #dat do. 'ec len'=.dat sdsend sk,0 er=. sderror ec if. er-:'EWOULDBLOCK' do. elseif. er-:'ECONNRESET' do. 0 return. elseif. ec=0 do. dat=. len}.dat elseif. 1 do. dat=.'' end. end. 1 ) NB. return 1 if a line was read from the control channel, otherwise 0 ctrl_read =: 3 : 0 if. -.ctrlsk e.>1{sdselect ctrlsk;'';'';TIMEOUT do. 0 return. end. if. -.ctrlsk recvline'' do. 0 return. end. retcode =. {.0".>;:retmsg if. (retcode=500)*.('creative'+./@:E. retmsg) do. ctrl_read'' return. NB. Ignore "try being more creative" responses end. if. (4 > #retmsg) +. ('-' ~: 3{4{.retmsg) do. 1 return. end. while. 1 do. if. (3<#retmsg)*.(' '=3{4{.retmsg)*.(retcode={.0".>;:retmsg) do. break. end. if. -.ctrlsk recvline'' do. 0 return. end. end. 1 ) read =: 4 : 0 sk =. x dat =. '' while. 1 do. c=. sk recvbytes '' if. (0=#c) do. break. end. dat=. dat, c end. dat ) recvbytes=: 4 : 0 sk =. x len =. >(y-:''){y;BUFFSIZE dat =. '' while. len~:#dat do. NB. use a buffer to minimize calls to sdrecv buff =. (sk=ctrlsk) >@{ databuff;ctrlbuff if. #buff do. ec =. 0 d =. (len <. #buff) {. buff buff =. (len <. #buff) }. buff else. 'ec d' =. sdrecv sk,BUFFSIZE if. (#d) > len do. buff =. buff, len }.d d =. len {. d end. end. if. sk=ctrlsk do. ctrlbuff =: buff else. databuff =: buff end. er =. sderror ec if. er-:'EWOULDBLOCK' do. elseif. (er-:'ECONNRESET')+.(ec=0)*.0=#d do. '' return. elseif. ec~:0 do. ''[retmsg=:er return. elseif. 1 do. dat=. dat,d if. y-:'' do. len=.#dat end. end. end. dat ) recvline=: 4 : 0 sk =. x retmsg =: '' line =. '' while. 1 do. c=. sk recvbytes 1 if. (0=#c) +. (c=LF) do. break. end. line=. line, c end. if. (#line) do. if. (_1{line)=CR do. line =. }:line end. end. retmsg =: line if. #line do. fc =: (a.i. {.line) - 48 else. fc =: 0 end. 1 ) passive=: 3 : 0 '' passive y : dat =. x cmd =. y literal 'PASV' str =. retmsg pos =. str i. '()' if. (#str) e. pos do. error str end. str =. ((>:@[ + ([: i. <:@(-~)))/ pos) { str 'ip port' =. (3 { str I.@:= ',') split str ip =. ip rplc ',';'.' port =. 256#.".port ctrl_write cmd datask =: skclose datask try. datask =: skopen ip;port catch. end. if. -.ctrl_read'' do. error retmsg end. if. fc ~: 1 do. error retmsg end. sdcheck sdioctl datask,FIONBIO,1 if. #dat do. datask write dat else. dat =. datask read '' end. datask =: skclose datask literal'' dat ) ---------------- On Thu, Nov 26, 2009 at 8:44 AM, Ian Clark <[email protected]> wrote: > I need a routine to upload a given file (or better: a J character > string) to a remote FTP site. I don't need a top-end like FileZilla. > The username, password, port, remote directory, filename can all be > hard-coded or passed as parameters. > > I don't need a flexible FTP session, except maybe to debug it when > working with a new site. It just needs to abort if the session goes > wrong. It would be nice if it could download as well as upload, > especially to download the directory of the remote target folder. > > I have just such a routine written in APL+Win which I've found quite > satisfactory in use, but this only works in Windows. I want to port > the APL+Win apps that make use of it to the Macintosh, for which I > don't have development tools nowadays, so (presumably) it needs to be > written in J. > > Ian Clark > ---------------------------------------------------------------------- > For information about J forums see http://www.jsoftware.com/forums.htm > ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
