# How to access the folder and sub-folder of an FTP server

**URL:** https://discourse.nodered.org/t/how-to-access-the-folder-and-sub-folder-of-an-ftp-server/26049
**Category:** Share Your Nodes
**Created:** [4 May 2020 09:26 UTC](https://discourse.nodered.org/t/how-to-access-the-folder-and-sub-folder-of-an-ftp-server/26049 "2020-05-04T09:26:44Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![SuperNinja](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/superninja/32/5761_2.png) [@SuperNinja](https://discourse.nodered.org/u/SuperNinja)
#### Post date: [4 May 2020 09:26 UTC](https://discourse.nodered.org/t/how-to-access-the-folder-and-sub-folder-of-an-ftp-server/26049/1 "2020-05-04T09:26:44Z")

</div>

I wanted to access the sub-folders of an FTP server (created automatically by my surveillance cameras), but the node [https://flows.nodered.org/node/node-red-contrib-ftp](https://flows.nodered.org/node/node-red-contrib-ftp) only displayed the folders root.

@afelix found a proposal to modify the original node on the Github: [https://github.com/joeartsea/node-red-contrib-ftp/issues/19](https://github.com/joeartsea/node-red-contrib-ftp/issues/19)

**You must therefore open the two files** found in (RPI example): `/home/pi/.node-red/node_modules/node-red-contrib-ftp`

1. Copy / paste in `ftp.html` :

```auto
<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>

```

1. and in `ftp.js` :

```auto
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);
}

```

1. **Restart Node-Red**

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/1/d1f7235fdfabbfed13805640216bfbff5a22c171.png)  
_This flow display files in the folder_ `Test\newFolder`

```auto
[{"id":"c00bd000.a5f0c","type":"ftp in","z":"a8b1b208.7036f","ftp":"42562df8.ff98b4","operation":"list","filename":"","localFilename":"","name":"list","x":470,"y":1600,"wires":[["a3de95d2.f1f7a8"]]},{"id":"a3de95d2.f1f7a8","type":"debug","z":"a8b1b208.7036f","name":"complet","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":640,"y":1600,"wires":[]},{"id":"b5da47bd.987978","type":"change","z":"a8b1b208.7036f","name":"pay to filename","rules":[{"t":"move","p":"payload","pt":"msg","to":"filename","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":1600,"wires":[["c00bd000.a5f0c"]]},{"id":"19f7caab.4c1865","type":"inject","z":"a8b1b208.7036f","name":"Test\\newFolder","topic":"","payload":"Test\\newFolder","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":1600,"wires":[["b5da47bd.987978"]]},{"id":"42562df8.ff98b4","type":"ftp","z":"","host":"192.168.1.143","port":"21","secureOptions":"","user":"superninja","connTimeout":"","pasvTimeout":"","keepalive":""}]

```

---

<div class="post-metadata">

### Author: ![afelix](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/afelix/32/9743_2.png) [@afelix](https://discourse.nodered.org/u/afelix)
#### Post date: [4 May 2020 09:31 UTC](https://discourse.nodered.org/t/how-to-access-the-folder-and-sub-folder-of-an-ftp-server/26049/2 "2020-05-04T09:31:13Z")

</div>

Let me fork it really quick and embed that patch.

---

<div class="post-metadata">

### Author: ![SuperNinja](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/superninja/32/5761_2.png) [@SuperNinja](https://discourse.nodered.org/u/SuperNinja)
#### Post date: [4 May 2020 09:31 UTC](https://discourse.nodered.org/t/how-to-access-the-folder-and-sub-folder-of-an-ftp-server/26049/3 "2020-05-04T09:31:52Z")

</div>

Yes of course

---

<div class="post-metadata">

### Author: ![afelix](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/afelix/32/9743_2.png) [@afelix](https://discourse.nodered.org/u/afelix)
#### Post date: [4 May 2020 09:44 UTC](https://discourse.nodered.org/t/how-to-access-the-folder-and-sub-folder-of-an-ftp-server/26049/4 "2020-05-04T09:44:23Z")

</div>

haven't tested anything, just put the patch on it, but feel free to use it. I'm not planning to further support it after offering it as PR to the original package. So switch back to the original node please after the patch gets accepted.  
`npm install boisei0/node-red-contrib-ftp`

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)
#### Post date: [3 July 2020 09:26 UTC](https://discourse.nodered.org/t/how-to-access-the-folder-and-sub-folder-of-an-ftp-server/26049/5 "2020-07-03T09:26:45Z")

</div>

This topic was automatically closed after 60 days. New replies are no longer allowed.
