Copyright | Copyright (C) 2004-2005 John Goerzen |
---|---|
License | GNU LGPL, version 2.1 or above |
Maintainer | John Goerzen <jgoerzen@complete.org> |
Stability | experimental |
Portability | systems with networking |
Safe Haskell | None |
Language | Haskell98 |
This module provides a client-side interface to the File Transfer Protocol as defined by RFC959 and RFC1123.
Written by John Goerzen, jgoerzen@complete.org
Welcome to the FTP module for Haskell.
Here is a quick usage example to get you started. This is a log of a real session with ghci:
(This would be similar in a do
block. You could also save it to a file and
run that with Hugs.)
Prelude> :l Network.FTP.Client ...
The above loads the module.
Next, we enable the debugging. This will turn on all the FTP sent
and
FTP received
messages you'll see.
Prelude Network.FTP.Client> enableFTPDebugging
Now, connect to the server on ftp.kernel.org
.
*Network.FTP.Client> h <- easyConnectFTP "ftp.kernel.org" FTP received: 220 Welcome to ftp.kernel.org.
And log in anonymously.
*Network.FTP.Client> loginAnon h FTP sent: USER anonymous FTP received: 331 Please specify the password. FTP sent: PASS anonymous@ ... FTP received: 230 Login successful.
Change the directory...
Prelude Network.FTP.Client> cwd h "/pub/linux/kernel/Historic" FTP sent: CWD /pub/linux/kernel/Historic FTP received: 250 Directory successfully changed.
Let's look at the directory. nlst
returns a list of strings, each string
corresponding to a filename. Here, putStrLn . unlines
will simply
print them out, one per line.
Prelude Network.FTP.Client> nlst h Nothing >>= putStrLn . unlines FTP sent: TYPE A FTP received: 200 Switching to ASCII mode. FTP sent: PASV FTP received: 227 Entering Passive Mode (204,152,189,116,130,143) FTP sent: NLST FTP received: 150 Here comes the directory listing. linux-0.01.tar.bz2 linux-0.01.tar.bz2.sign linux-0.01.tar.gz linux-0.01.tar.gz.sign linux-0.01.tar.sign old-versions v0.99 FTP received: 226 Directory send OK.
Let's try downloading something and print it to the screen. Again, we use
putStrLn
. We use fst
here because getbinary
returns a tuple consisting
of a string representing the data and a FTPResult
code.
Prelude Network.FTP.Client> getbinary h "linux-0.01.tar.gz.sign" >>= putStrLn . fst FTP sent: TYPE I FTP received: 200 Switching to Binary mode. FTP sent: PASV FTP received: 227 Entering Passive Mode (204,152,189,116,121,121) FTP sent: RETR linux-0.01.tar.gz.sign FTP received: 150 Opening BINARY mode data connection for linux-0.01.tar.gz.sign (248 bytes). -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.0 (GNU/Linux) Comment: See http://www.kernel.org/signature.html for info iD8DBQA54rf0yGugalF9Dw4RAqelAJ9lafFni4f/QyJ2IqDXzW2nz/ZIogCfRPtg uYpWffOhkyByfhUt8Lcelec= =KnLA -----END PGP SIGNATURE----- FTP received: 226 File send OK.
Here's an example showing you what the result code looks like.
Prelude Network.FTP.Client> getbinary h "linux-0.01.tar.gz.sign" >>= print . snd ... (226,["File send OK."])
The first component of the FTPResult
object is the numeric status code from
the server. The second component is a list of message lines from the server.
Now, let's get a more detailed directory listing:
Prelude Network.FTP.Client> dir h Nothing >>= putStrLn . unlines ... -r--r--r-- 1 536 536 63362 Oct 30 1993 linux-0.01.tar.bz2 -r--r--r-- 1 536 536 248 Oct 30 1993 linux-0.01.tar.bz2.sign -r--r--r-- 1 536 536 73091 Oct 30 1993 linux-0.01.tar.gz -r--r--r-- 1 536 536 248 Oct 30 1993 linux-0.01.tar.gz.sign -r--r--r-- 1 536 536 248 Oct 30 1993 linux-0.01.tar.sign drwxrwsr-x 5 536 536 4096 Mar 20 2003 old-versions drwxrwsr-x 2 536 536 4096 Mar 20 2003 v0.99 FTP received: 226 Directory send OK.
And finally, log out:
Prelude Network.FTP.Client> quit h FTP sent: QUIT FTP received: 221 Goodbye.
Here is one big important caution:
/You MUST consume all data from commands that return file data before you issue any other FTP commands./
That's due to the lazy nature of Haskell. This means that, for instance,
you can't just iterate over the items nlst
returns, trying to getbinary
each one of them -- the system is still transferring nlst
data while you
are trying that, and confusion will ensue. Either open two FTP connections
or make sure you consume the nlst
data first.
Here is a partial list of commands effected: nlst
, dir
, getbinary
,
getlines
, downloadbinary
.
The seqList
function could be quite helpful here. For instance:
x <- nlst h Nothing map (\fn -> ...download files from FTP... ) (seqList x)
If you omit the call to seqList
, commands to download files
will be issued before the entire directory listing is read. FTP cannot handle
this.
The corrolary is:
/Actions that yield lazy data for data uploading must not issue FTP commands themselves./
This will be fairly rare. Just be aware of this.
This module logs messages under Network.FTP.Client
for outgoing
traffic and Network.FTP.Client.Parser
for incoming traffic, all with the
DEBUG
priority, so by default, no log messages are seen.
The enableFTPDebugging
function will adjust the priorities of these
two handlers so debug messages are seen. Only control channel conversations
are logged. Data channel conversations are never logged.
All exceptions raised by this module have a string beginning with
"FTP: "
. Most errors will be IO userErrors. In a few extremely rare
cases, errors may be raised by the Prelude error function, though these
will also have a string beginning with "FTP: "
. Exceptions raised by
the underlying networking code will be passed on to you unmodified.
Useful standards:
- RFC959, http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc0959.html
- Passive mode, RFC1579, http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc1579.html
- Extended passive mode, IPv6, RFC2428 http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2428.html
- Feature negotiation, RFC2389, http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2389.html
- Internationalization of FTP, RFC2640, http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2640.html
- FTP security considerations, RFC2577, http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc2577.html
- FTP URLs, RFC1738, http://www.cse.ohio-state.edu/cgi-bin/rfc/rfc1738.html
- easyConnectFTP :: HostName -> IO FTPConnection
- connectFTP :: HostName -> PortNumber -> IO (FTPConnection, FTPResult)
- loginAnon :: FTPConnection -> IO FTPResult
- login :: FTPConnection -> String -> Maybe String -> Maybe String -> IO FTPResult
- quit :: FTPConnection -> IO FTPResult
- setPassive :: FTPConnection -> Bool -> FTPConnection
- isPassive :: FTPConnection -> Bool
- enableFTPDebugging :: IO ()
- nlst :: FTPConnection -> Maybe String -> IO [String]
- dir :: FTPConnection -> Maybe String -> IO [String]
- getlines :: FTPConnection -> String -> IO ([String], FTPResult)
- getbinary :: FTPConnection -> String -> IO (String, FTPResult)
- downloadbinary :: FTPConnection -> String -> IO FTPResult
- downloadlargebinary :: FTPConnection -> FilePath -> IO FTPResult
- putlines :: FTPConnection -> String -> [String] -> IO FTPResult
- putbinary :: FTPConnection -> String -> String -> IO FTPResult
- uploadbinary :: FTPConnection -> String -> IO FTPResult
- rename :: FTPConnection -> String -> String -> IO FTPResult
- delete :: FTPConnection -> String -> IO FTPResult
- size :: (Num a, Read a) => FTPConnection -> String -> IO a
- cwd :: FTPConnection -> String -> IO FTPResult
- mkdir :: FTPConnection -> String -> IO (Maybe String, FTPResult)
- rmdir :: FTPConnection -> String -> IO FTPResult
- pwd :: FTPConnection -> IO (Maybe String, FTPResult)
- data FTPConnection
- transfercmd :: FTPConnection -> String -> IO Handle
- ntransfercmd :: FTPConnection -> String -> IO (Handle, Maybe Integer)
- retrlines :: FTPConnection -> String -> IO ([String], FTPResult)
- storlines :: FTPConnection -> String -> [String] -> IO FTPResult
- sendcmd :: FTPConnection -> [Char] -> IO FTPResult
Establishing/Removing connections
easyConnectFTP :: HostName -> IO FTPConnection Source #
Connect to the remote FTP server and read but discard the welcome. Assumes default FTP port, 21, on remote.
connectFTP :: HostName -> PortNumber -> IO (FTPConnection, FTPResult) Source #
Connect to remote FTP server and read the welcome.
:: FTPConnection | Connection |
-> String | Username |
-> Maybe String | Password |
-> Maybe String | Account (rarely used) |
-> IO FTPResult |
Log in to an FTP account.
Configuration
setPassive :: FTPConnection -> Bool -> FTPConnection Source #
Sets whether passive mode is used (returns new connection object reflecting this)
isPassive :: FTPConnection -> Bool Source #
enableFTPDebugging :: IO () Source #
Enable logging of FTP messages through Logger
.
This sets the log levels of Network.FTP.Client.Parser
and
Network.FTP.Client
to DEBUG. By default, this means that
full protocol dumps will be sent to stderr.
The effect is global and persists until changed.
Directory listing
:: FTPConnection | |
-> Maybe String | The directory to list. If Nothing, list the current directory. |
-> IO [String] |
Retrieves a list of files in the given directory.
FIXME: should this take a list of dirs?
:: FTPConnection | |
-> Maybe String | The directory to list. If Nothing, list the current directory. |
-> IO [String] |
Retrieve the system-specific long form of a directory list.
FIXME: should this take a list of dirs?
File downloads
getlines :: FTPConnection -> String -> IO ([String], FTPResult) Source #
Retrieves the specified file in text mode.
getbinary :: FTPConnection -> String -> IO (String, FTPResult) Source #
Retrieves the specified file in binary mode.
downloadbinary :: FTPConnection -> String -> IO FTPResult Source #
Downloads a file from remote and saves to disk in binary mode. Note: filename is used for both local and remote.
downloadlargebinary :: FTPConnection -> FilePath -> IO FTPResult Source #
Similar to downloadbinary, but downloads the file in blocks of 4096 bytes so that memory usage is limited when downloading large files. Uses Data.ByteString's hGet to read data from the socket and hPut to write data to the file, since it is more space and time efficient than String.
File uploads
putlines :: FTPConnection -> String -> [String] -> IO FTPResult Source #
Puts data in the specified file in text mode. The first string is the filename.
putbinary :: FTPConnection -> String -> String -> IO FTPResult Source #
Puts data in the specified file in binary. The first string is the filename.
uploadbinary :: FTPConnection -> String -> IO FTPResult Source #
Uploads a file from disk in binary mode. Note: filename is used for both local and remote.
File manipulation
:: FTPConnection | |
-> String | Old name |
-> String | New name |
-> IO FTPResult |
Rename or move a file.
size :: (Num a, Read a) => FTPConnection -> String -> IO a Source #
Get the size of a file.
This command is non-standard and may possibly fail.
Directory manipulation
mkdir :: FTPConnection -> String -> IO (Maybe String, FTPResult) Source #
Make new directory. Returns the absolute name of the new directory if possible.
pwd :: FTPConnection -> IO (Maybe String, FTPResult) Source #
Print the current working directory. The first component of the result is the parsed directory name, if the servers response was parsable.
Low-level advanced commands
data FTPConnection Source #
transfercmd :: FTPConnection -> String -> IO Handle Source #
Returns the socket part from calling ntransfercmd
.
ntransfercmd :: FTPConnection -> String -> IO (Handle, Maybe Integer) Source #
Establishes a connection to the remote.
FIXME: need support for rest
retrlines :: FTPConnection -> String -> IO ([String], FTPResult) Source #
Retrieves lines of data from the remote. The string gives the command to issue.