Hello, I was in need of listing subdirectories within FTP and I ended up editing… your **ftp.js** and **ftp.html** code, and implemented this option. If you are interested in using it to update your library, I think it would be interesting :)
Follows the code:
ftp.js:
```
module.exports = function (RED) {
'use strict';
var ftp = require('ftp');
var fs = require('fs');
function FtpNode(n) {
RED.nodes.createNode(this, n);
var node = this;
var credentials = RED.nodes.getCredentials(n.id);
this.options = {
'host': n.host || 'localhost',
'port': n.port || 21,
'secure': n.secure || false,
'secureOptions': n.secureOptions,
'user': n.user || 'anonymous',
'password': credentials.password || 'anonymous@',
'connTimeout': n.connTimeout || 10000,
'pasvTimeout': n.pasvTimeout || 10000,
'keepalive': n.keepalive || 10000
};
}
RED.nodes.registerType('ftp', FtpNode, {
credentials: {
password: { type: 'password' }
}
});
function FtpInNode(n) {
RED.nodes.createNode(this, n);
this.ftp = n.ftp;
this.operation = n.operation;
this.filename = n.filename;
this.localFilename = n.localFilename;
this.ftpConfig = RED.nodes.getNode(this.ftp);
if (this.ftpConfig) {
var node = this;
node.on('input', function (msg) {
var conn = new ftp();
var filename = node.filename || msg.filename || '';
var localFilename = node.localFilename || msg.localFilename || '';
this.sendMsg = function (err, result) {
if (err) {
node.error(err, msg);
node.status({ fill: 'red', shape: 'ring', text: 'failed' });
node.send(err);
return;
}
node.status({});
if (node.operation == 'get') {
result.once('close', function() { conn.end(); });
result.pipe(fs.createWriteStream(localFilename));
msg.payload = 'Get operation successful. ' + localFilename;
} else if (node.operation == 'put') {
conn.end();
msg.payload = 'Put operation successful.';
} else {
conn.end();
msg.message = 'Operation successful.';
msg.payload = result;
}
msg.filename = filename;
msg.localFilename = localFilename;
node.send(msg);
};
conn.on('ready', function () {
switch (node.operation) {
case 'list':
conn.list(filename, node.sendMsg);
break;
case 'get':
conn.get(filename, node.sendMsg);
break;
case 'put':
conn.put(localFilename, filename, node.sendMsg);
break;
case 'delete':
conn.delete(filename, node.sendMsg);
break;
}
});
conn.on('error', function(err) {
node.error(err, msg);
node.status({ fill: 'red', shape: 'ring', text: err.message });
node.send(err);
return;
});
conn.connect(node.ftpConfig.options);
});
} else {
this.error('missing ftp configuration');
}
}
RED.nodes.registerType('ftp in', FtpInNode);
}
```
ftp.html:
```
<script type="text/x-red" data-template-name="ftp">
<div class="form-row">
<label for="node-config-input-host"><i class="fa fa-bookmark"></i> Host</label>
<input type="text" id="node-config-input-host" placeholder="localhost" style="width: 40%;" />
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
<input type="text" id="node-config-input-port" placeholder="21" style="width:45px">
</div>
<div class="form-row">
<label for="node-config-input-user"><i class="fa fa-user"></i> User</label>
<input type="text" id="node-config-input-user" placeholder="anonymous" />
</div>
<div class="form-row">
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
<input type="password" id="node-config-input-password">
</div>
<div class="form-row">
<label for="node-config-input-connTimeout"><i class="fa fa-clock-o"></i> Connection Timeout</label>
<input type="text" id="node-config-input-connTimeout" placeholder="10000">
</div>
<div class="form-row">
<label for="node-config-input-pasvTimeout"><i class="fa fa-clock-o"></i> PASV Timeout</label>
<input type="text" id="node-config-input-pasvTimeout" placeholder="10000">
</div>
<div class="form-row">
<label for="node-config-input-keepalive"><i class="fa fa-clock-o"></i> Keepalive</label>
<input type="text" id="node-config-input-keepalive" placeholder="10000">
</div>
<div class="form-row">
<label for="node-input-secure"><i class="fa fa-key"></i> Data connection encryption</label>
<input type="checkbox" id="node-input-secure" placeholder="once" style="width: 10%; vertical-align: top;">
<label for="node-config-input-secureOptions" style="width: 20%; vertical-align: top;"> Secure Options</label>
<input type="text" id="node-config-input-secureOptions" style="width: 35%; vertical-align: top;">
</div>
</script>
<script type="text/x-red" data-help-name="ftp in">
<p>Allows LIST, GET, PUT and DELETE of files on a remote FTP server.</p>
<p><code>msg.filename</code> is the path/name of the file on the remote FTP server</p>
<p><code>msg.localFilename</code> is the path/name of the file on the local machine</p>
<p>NOTE: the local machine is where NR is running - this might not be the machine where your browser connects to Node Red.</p>
<p></p>
<p>GET uses <code>msg.filename</code> and <code>msg.localFilename</code></p>
<p>PUT uses <code>msg.filename</code> and <code>msg.localFilename</code></p>
<p>DELETE uses only <code>msg.filename</code></p>
<p>LIST uses only <code>msg.filename</code> and returns an array of the file/folders, containing type, name, sticky, rights(an object), acl, owner, group, size and date.</p>
<p></p>
<p>You can pass <code>msg.filename</code> and <code>msg.localFilename</code> to this node, however values entered in the node will take precedence.</p>
<p></p>
<p>If an error occurs, the error message will come out as <code>msg</code>.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('ftp', {
category: 'config',
color:"BurlyWood",
defaults: {
host: { value: '' },
port: { value: '' },
secure: { value: false },
secureOptions: { value: '' },
user: { value: '' },
connTimeout: { value: '' },
pasvTimeout: { value: '' },
keepalive: { value: '' }
},
credentials: {
password: { type: 'password', required: true },
},
label: function() {
return this.host
}
});
</script>
<script type="text/x-red" data-template-name="ftp in">
<div class="form-row">
<label for="node-input-ftp"><i class="fa fa-user"></i> Add new FTP Server</label>
<input type="text" id="node-input-ftp">
</div>
<div class="form-row">
<label for="node-input-operation"><i class="fa fa-wrench"></i> Operation</label>
<select type="text" id="node-input-operation">
<option value="list">list</option>
<option value="get">get</option>
<option value="put">put</option>
<option value="delete">delete</option>
</select>
</div>
<div class="form-row input-filename-row hidden">
<label for="node-input-filename"><i class="fa fa-file"></i> Filename</label>
<input type="text" id="node-input-filename" placeholder="Filename">
</div>
<div class="form-row input-localFilename-row hidden">
<label for="node-input-localFilename"><i class="fa fa-file"></i> Local Filename</label>
<input type="text" id="node-input-localFilename" placeholder="Local Filename">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('ftp in', {
category: 'storage-input',
color:"BurlyWood",
defaults: {
ftp: { type: 'ftp', required: true },
operation: { value: 'list', required: true },
filename: { value: '' },
localFilename: { value: '' },
name: { value: '' }
},
inputs: 1,
outputs: 1,
icon: "file.png",
label: function () {
var ftpNode = RED.nodes.node(this.ftp);
return this.name || 'ftp';
},
labelStyle: function () {
return this.name ? 'node_label_italic' : '';
},
oneditprepare: function () {
var filename = $(".input-filename-row");
var localFilename = $(".input-localFilename-row");
$("#node-input-operation").change(function () {
var id = $("#node-input-operation option:selected").val();
console.log(id);
if (id == 'list') {
filename.show();
localFilename.hide();
} else if (id == 'put' || id == 'get') {
filename.show();
localFilename.show();
} else {
filename.show();
localFilename.hide();
}
});
}
});
</script>
```
Thanks!