Skip to content
Plugins (190)

ftp

stable

Encode RFC 959 FTP command strings and parse FTP server responses. Use with a raw TCP socket to build an FTP client without external dependencies.

use plugin ftp
22 functions Networking
Runs with the native Zolo host

Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.

/ filter jk navigate Esc clear
Functions (22)
  1. encode_user Encode a USER command string
  2. encode_pass Encode a PASS command string
  3. encode_list Encode a LIST command string
  4. encode_retr Encode a RETR (download) command string
  5. encode_stor Encode a STOR (upload) command string
  6. encode_cwd Encode a CWD (change directory) command
  7. encode_pwd Encode a PWD command string
  8. encode_quit Encode a QUIT command string
  9. encode_mkd Encode a MKD (make directory) command
  10. encode_rmd Encode a RMD (remove directory) command
  11. encode_dele Encode a DELE (delete file) command
  12. encode_type Encode a TYPE command (A or I)
  13. encode_pasv Encode a PASV command string
  14. encode_noop Encode a NOOP keepalive command
  15. encode_syst Encode a SYST command string
  16. encode_size Encode a SIZE command string
  17. encode_rnfr Encode a RNFR (rename from) command
  18. encode_rnto Encode a RNTO (rename to) command
  19. encode_cdup Encode a CDUP (parent directory) command
  20. parse_response Parse an FTP response line into code + message
  21. parse_list_entry Parse a Unix-style LIST directory entry
  22. parse_pasv_response Parse a PASV 227 response into host + port

From import to result

  1. 01Import only what you use
  2. 02Copy the smallest example
  3. 03Run it with the Zolo CLI

Overview

ftp is a stateless protocol-helper toolkit: it builds the RFC 959 command strings an FTP client sends and parses the text lines an FTP server sends back. It does not open sockets or transfer data itself — you supply the networking (a raw TCP socket from the net/tcp layer) and use these functions to translate between Zolo values and the wire format. Every encode_* function returns a ready-to-send string that already includes the trailing \r\n, and every parse_* function turns one server line into a plain table you can index by field name.

The mental model is a request/response loop: encode a command, write it to the socket, read a reply line, and feed that line to parse_response (or the specialized parse_pasv_response / parse_list_entry) to interpret it. Reach for this plugin when you need a dependency-free FTP client and want full control over the connection.

Common patterns

Log in by encoding the USER/PASS handshake and reading each reply:

use plugin ftp::{encode_user, encode_pass, parse_response}

let user_cmd = encode_user("anonymous")
let pass_cmd = encode_pass("guest@example.com")

// write user_cmd and pass_cmd to your socket, then parse the replies:
let reply = parse_response("230 Login successful")
if reply["code"] == 230 {
  print("logged in: {reply["message"]}")
}

Enter passive mode, then open the data connection at the advertised address:

use plugin ftp::{encode_pasv, parse_pasv_response, encode_list}

let pasv = encode_pasv()
// send pasv, read the 227 reply, then decode where to connect:
let data = parse_pasv_response("227 Entering Passive Mode (192,168,1,1,19,136)")
print("open data socket to {data["host"]}:{data["port"]}")
print(encode_list("/pub"))

Rename a remote file with the two-step RNFR / RNTO exchange:

use plugin ftp::{encode_rnfr, encode_rnto, parse_response}

print(encode_rnfr("/tmp/old.txt"))
let intermediate = parse_response("350 Ready for RNTO")
if intermediate["code"] == 350 {
  print(encode_rnto("/tmp/new.txt"))
}

Encode a USER command string

Returns the RFC 959 USER username\r\n command string ready to send over a TCP socket.

use plugin ftp::{encode_user, encode_pass}

let user_cmd = encode_user("anonymous")
let pass_cmd = encode_pass("guest@example.com")
print(user_cmd)
print(pass_cmd)

Encode a PASS command string

Returns the PASS password\r\n command string.

use plugin ftp::{encode_pass}

let cmd = encode_pass("s3cr3t")
print(cmd)  // PASS s3cr3t\r\n

Encode a LIST command string

Returns LIST path\r\n, or just LIST\r\n when path is empty. Used to request a directory listing over the data connection.

use plugin ftp::{encode_list}

print(encode_list("/pub"))   // LIST /pub\r\n
print(encode_list(""))       // LIST\r\n

Encode a RETR (download) command string

Returns RETR path\r\n to request a file download.

use plugin ftp::{encode_retr}

let cmd = encode_retr("/pub/readme.txt")
print(cmd)

Encode a STOR (upload) command string

Returns STOR path\r\n to initiate a file upload.

use plugin ftp::{encode_stor}

let cmd = encode_stor("/uploads/data.csv")
print(cmd)

Encode a CWD (change directory) command

Returns CWD path\r\n to change the working directory on the server.

use plugin ftp::{encode_cwd, encode_pwd}

let cwd = encode_cwd("/home/user")
let pwd = encode_pwd()
print(cwd)
print(pwd)

Encode a PWD command string

Returns the bare PWD\r\n command to request the current working directory.

use plugin ftp::{encode_pwd}

print(encode_pwd())  // PWD\r\n

Encode a QUIT command string

Returns QUIT\r\n to close the FTP session cleanly.

use plugin ftp::{encode_quit}

print(encode_quit())  // QUIT\r\n

Encode a MKD (make directory) command

Returns MKD path\r\n to create a directory on the server.

use plugin ftp::{encode_mkd}

let cmd = encode_mkd("/backups/2026")
print(cmd)

Encode a RMD (remove directory) command

Returns RMD path\r\n to remove a directory.

use plugin ftp::{encode_rmd}

print(encode_rmd("/tmp/old"))

Encode a DELE (delete file) command

Returns DELE path\r\n to delete a file from the server.

use plugin ftp::{encode_dele}

print(encode_dele("/tmp/stale.log"))

Encode a TYPE command (A or I)

Returns TYPE mode\r\n. Pass "I" for binary (image) mode or "A" for ASCII mode.

use plugin ftp::{encode_type}

print(encode_type("I"))  // TYPE I\r\n  (binary)
print(encode_type("A"))  // TYPE A\r\n  (ascii)

Encode a PASV command string

Returns PASV\r\n to request passive mode. Parse the server reply with parse_pasv_response.

use plugin ftp::{encode_pasv}

print(encode_pasv())  // PASV\r\n

Encode a NOOP keepalive command

Returns NOOP\r\n. Send periodically to keep an idle connection alive.

use plugin ftp::{encode_noop}

print(encode_noop())  // NOOP\r\n

Encode a SYST command string

Returns SYST\r\n to query the server operating system type.

use plugin ftp::{encode_syst}

print(encode_syst())  // SYST\r\n

Encode a SIZE command string

Returns SIZE path\r\n to query the byte size of a remote file.

use plugin ftp::{encode_size}

print(encode_size("/data/archive.tar.gz"))

Encode a RNFR (rename from) command

Returns RNFR path\r\n, the first half of a rename. It names the file to be renamed; the server replies 350 and then expects RNTO.

use plugin ftp::{encode_rnfr}

print(encode_rnfr("/tmp/old.txt"))  // RNFR /tmp/old.txt\r\n

Encode a RNTO (rename to) command

Returns RNTO path\r\n, the second half of a rename. Send it immediately after encode_rnfr to give the file its new name.

use plugin ftp::{encode_rnfr, encode_rnto}

let from = encode_rnfr("/tmp/old.txt")
let to   = encode_rnto("/tmp/new.txt")
print(from)
print(to)

Encode a CDUP (parent directory) command

Returns CDUP\r\n to navigate to the parent directory.

use plugin ftp::{encode_cdup}

print(encode_cdup())  // CDUP\r\n

Parse an FTP response line into code + message

Parses a single FTP response line into {code, message, is_multiline}. code is the 3-digit integer. is_multiline is true when the code is followed by - (RFC 959 multi-line response).

use plugin ftp::{parse_response}

let r = parse_response("220 FTP server ready")
print(r["code"])     // 220
print(r["message"])  // FTP server ready

let m = parse_response("230-Login successful")
print(m["is_multiline"])  // true

Branch on the response code to decide what to do next:

use plugin ftp::{parse_response}

let r = parse_response("550 Requested action not taken")
if r["code"] >= 500 {
  print("error: {r["message"]}")
} else {
  print("ok: {r["message"]}")
}

Parse a Unix-style LIST directory entry

Parses a single Unix-style LIST directory line into {permissions, size, date, name}.

use plugin ftp::{parse_list_entry}

let entry = parse_list_entry("-rw-r--r--  1 user group  4096 Jan  1 12:00 readme.txt")
print(entry["name"])   // readme.txt
print(entry["size"])   // 4096

Parse a PASV 227 response into host + port

Parses the 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2) response into {host, port}. The port is computed as p1 * 256 + p2.

use plugin ftp::{encode_pasv, parse_pasv_response}

// After sending encode_pasv() and receiving the server reply:
let info = parse_pasv_response("227 Entering Passive Mode (192,168,1,1,19,136)")
print(info["host"])  // 192.168.1.1
print(info["port"])  // 5000

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

en