Skip to content
RubyLanePublic

About

FTP client for Tcl (RFC 959, RFC 2640 utf-8) with timeouts, usable in coroutines

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

RL_FTP

An FTP client for Tcl (RFC 959, with RFC 2640's utf-8 control channel), with a timeout on every connect and read. Called from a coroutine it yields while it waits, so other coroutines run; called outside one it waits in the event loop (vwait).

Requires Tcl 8.6 or later, and the packages gc_class, parse_args, reuri 0.15+ and aio.

Usage

package require rl_ftp

rl_ftp::client create ftp -timeout 20 ftp://user:secret@ftp.example.com/incoming
try {
	ftp upload photo.jpg $jpeg_bytes
	set listing	[ftp ls]
	set bytes	[ftp download orders.csv]
} finally {
	ftp destroy
}

rl_ftp::client is a gc_class, so rl_ftp::client instvar ftp ... ties the client's life to the variable ftp: it's closed when the variable is unset or goes out of scope.

rl_ftp::client create name ?-timeout seconds? ?-acct acct? url

Connects to the server named in url (ftp://[user[:password]@]host[:port][/path], port 21 by default), logs in when the url has a user, and changes to path (relative to the login directory, as one CWD). The user, password and path are percent-decoded, so encode a :, @ or / in them. -acct gives an account for servers that ask for one (ACCT). -timeout (10 s by default, fractions allowed) bounds the connect and each wait for data.

Transfers

Transfers use passive mode (PASV).

  • upload path bytes: stores bytes at path, in binary (TYPE I).
  • download path: returns the bytes of the file at path, in binary.
  • ls ?pattern?: returns the server's LIST output, a list of lines.

Other commands

The client has a method for each of RFC 959's other commands, named for the command in lower case. Each sends the command with its arguments and returns the server's reply text, or throws (below):

abor, allo, dele, cwd, cdup, smnt, help, mode, noop, pasv, quit, site, port, syst, stat, rmd, mkd, pwd, stru, type, feat, lang.

The commands that transfer data (appe, list, nlst, rein, retr, stor, stou) take ?-tail args? and a script to run once the server is ready for the transfer, and restart -marker m -cmd cmd -path path script resumes one. rename from to renames a file, login user ?pass? ?acct? logs in, feats returns the server's features (FEAT) and has_feat name tests for one. setting name value changes type, mode or stru, sending the command only when the value changes.

To log the conversation with the server, override the method _log {lvl msg} in a subclass.

Errors

Errors carry an errorCode starting RL FTP:

errorCode
RL FTP URL the url isn't an ftp: url with a host, or doesn't parse
RL FTP CONNECT message the connection failed (refused, no such host, ...)
RL FTP TIMEOUT CONNECTION the connect took longer than -timeout (the client is destroyed)
RL FTP TIMEOUT READ the server sent nothing for -timeout (the client is destroyed)
RL FTP CONTROL_DROPPED the server closed the control connection
RL FTP FAIL code the server refused the command (4xx and 5xx replies)
RL FTP ERROR code a reply the command's state diagram doesn't allow there
RL FTP PANIC ... a reply that makes no sense (an unknown code, an unreadable PASV address)
RL FTP SYNTAX cmd restart was given a command other than APPE, STOR or RETR

Building and testing

meson setup builddir
meson test -C builddir
meson install -C builddir

meson install puts rl_ftp-<version>.tm in Tcl's site-tcl module directory, and rl_ftp.pc (for tcl_tm_path) in its pkgconfig. The tests run against a fake FTP server in the test interp, so they need no network beyond the loopback.

License

Copyright Ruby Lane, under a BSD-style license: see LICENSE.

About

FTP client for Tcl (RFC 959, RFC 2640 utf-8) with timeouts, usable in coroutines

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages