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

Reply via email to