title: Active FTP Client for Node.js
body: <p>I'm trying my hand at writing an ftp client against Filezilla that supports active mode using node.js. I'm new to ftp and node.js. I thought I could get a good understanding of tcp socket communication and the ftp protocol by doing this exercise. Also, <a href="https://github.com/mscdex/node-ftp/issues/62" rel="nofollow">node-ftp</a> an <a href="https://github.com/sergi/jsftp/issues/49" rel="nofollow">jsftp</a> don't seem to support active mode, so I think this will be a nice (though rarely used) addition to npm.</p>
  
  <p>I've got some proof of concept code that works at least sometimes, but not all the time. In the case where it works, the client uploads a file called <code>file.txt</code> with the text 'hi'. 
  When it works, I get this:</p>
  
  <pre><code>220-FileZilla Server version 0.9.41 beta
  220-written by Tim Kosse (Tim.Kosse@gmx.de)
  220 Please visit http://sourceforge.net/projects/filezilla/
  
  331 Password required for testuser
  
  230 Logged on
  
  listening
  200 Port command successful
  
  150 Opening data channel for file transfer.
  
  server close
  226 Transfer OK
  
  half closed
  closed
  
  Process finished with exit code 0
  </code></pre>
  
  <p>When it doesn't work, I get this:</p>
  
  <pre><code>220-FileZilla Server version 0.9.41 beta
  220-written by Tim Kosse (Tim.Kosse@gmx.de)
  220 Please visit http://sourceforge.net/projects/filezilla/
  
  331 Password required for testuser
  
  230 Logged on
  
  listening
  200 Port command successful
  
  150 Opening data channel for file transfer.
  
  server close
  half closed
  closed
  
  Process finished with exit code 0
  </code></pre>
  
  <p>So, I'm not getting the 226, and I'm not sure why I'm getting the inconsistent results.</p>
  
  <p>Forgive the poorly written code. I'll refactor once I'm confident I understand how this should work.:</p>
  
  <pre><code>var net = require('net'),
      Socket = net.Socket;
  
  var cmdSocket = new Socket();
  cmdSocket.setEncoding('binary')
  
  var server = undefined;
  var port = 21;
  var host = "localhost";
  var user = "testuser";
  var password = "Password1*"
  var active = true;
  var supplyUser = true;
  var supplyPassword = true;
  var supplyPassive = true;
  var waitingForCommand = true;
  var sendFile = true;
  
  function onConnect(){
  
  }
  
  var str="";
  function onData(chunk) {
      console.log(chunk.toString('binary'));
  
      //if ftp server return code = 220
      if(supplyUser){
          supplyUser = false;
          _send('USER ' + user, function(){
  
          });
      }else if(supplyPassword){
          supplyPassword = false;
          _send('PASS ' + password, function(){
  
          });
      }
      else if(supplyPassive){
          supplyPassive = false;
          if(active){
              server = net.createServer(function(socket){
                  console.log('new connection');
                  socket.setKeepAlive(true, 5000);
  
                  socket.write('hi', function(){
                      console.log('write done');
                  })
  
                   socket.on('connect', function(){
                      console.log('socket connect');
                  });
  
                  socket.on('data', function(d){
                      console.log('socket data: ' + d);
                  });
  
                  socket.on('error', function(err){
                      console.log('socket error: ' + err);
                  });
  
                  socket.on('end', function() {
                      console.log('socket end');
                  });
  
                  socket.on('drain', function(){
                      console.log('socket drain');
  
                  });
  
                  socket.on('timeout', function(){
                      console.log('socket timeout');
  
                  });
  
                  socket.on('close', function(){
                      console.log('socket close');
  
                  });
              });
  
              server.on('error', function(e){
                 console.log(e);
              });
  
              server.on('close', function(){
                  console.log('server close');
              });
  
              server.listen(function(){
                  console.log('listening');
  
                  var address = server.address();
                  var port = address.port;
                  var p1 = Math.floor(port/256);
                  var p2 = port % 256;
  
                  _sendCommand('PORT 127,0,0,1,' + p1 + ',' + p2, function(){
  
                  });
              });
          }else{
              _send('PASV', function(){
  
              });
          }
      }
      else if(sendFile){
          sendFile = false;
  
          _send('STOR file.txt', function(){
  
          });
      }
      else if(waitingForCommand){
          waitingForCommand = false;
  
          cmdSocket.end(null, function(){
  
          });
  
          if(server)server.close(function(){});
      }
  }
  
  function onEnd() {
      console.log('half closed');
  }
  
  function onClose(){
      console.log('closed');
  }
  
  cmdSocket.once('connect', onConnect);
  cmdSocket.on('data', onData);
  cmdSocket.on('end', onEnd);
  cmdSocket.on('close', onClose);
  
  cmdSocket.connect(port, host);
  
  function _send(cmd, callback){
      cmdSocket.write(cmd + '\r\n', 'binary', callback);
  }
  </code></pre>
  
  <p>Also, is the <code>server</code> appropriate, or should I do it some other way?</p>
  
  <p>EDIT:
  I changed the callback in server.listen to use a random port. This has removed the 425 I was getting previously. However, I am still not getting consistent behavior with the file transfer.</p>