FTP Command Demo: Using the FTP Client
An FTP client allows lower-level access to the FTP protocol than the FTP agent provides. The RWFtpClient class is for developers who require complete control over the protocol.
Example 3 demonstrates how to use some of the basic FTP commands in class RWFtpClient, such as USER, PASS, LIST, CWD, PWD, and RETR. First, a connection must be established between a client and an FTP server of interest. Then the USER/PASS protocol command sequence must be performed before most other commands can be issued. If any command is conducted out of order, an exception is thrown.
NOTE: Servers and files shown in the code might not exist and are included as examples only.
Example 3 – Using basic FTP commands
// global variable client
 
RWFtpClient client; // 1
 
bool
ftpConnect(const RWCString& machine)
{
...
reply = client.connect(machine); // 2
...
}
 
bool
ftpUser(const RWCString& user)
{
...
RWFtpReply reply = client.user(user); // 3
...
}
 
bool
ftpPass(const RWCString& pass)
{
...
RWFtpReply reply = client.pass(pass); // 4
...
}
 
bool
ftpList(const RWCString& dir)
{
try {
RWFtpDataReply dataReply = client.list(dir); // 5
cout << dataReply << endl;
if (!dataReply.is1XX()) return FALSE; // 6
 
RWCString line;
RWPortalIStream strm(dataReply.portal()); // 7
while (l) {
line.readline(strm); // 8
if (line.isNull()) break; // 9
cout << line <<endl;
}
RWFtpReply reply = client.dataClose(); //10
cout << reply << endl;
if (!reply.is2XX()) return false; //11
}
catch (const RWxmsg& m) { //12
cout << m.why() << endl;
return false;
}
return true;
}
//1 Constructs an RWFtpClient object. The object is set to an unconnected state. The connect() method of RWFtpClient must be used to establish a connection with an FTP server. When the program exits, the client automatically disconnects from the server.
//2 Establishes a connection with an FTP server.
//3 Performs the USER protocol command. A successful reply from the request signifies that a PASS protocol command should then be attempted.
//4 Performs the PASS protocol command.
//5 Performs the LIST protocol command. The method returns an RWTIOUResult with a redeemable RWFtpDataReply that is redeemed immediately as the dataReply object.
NOTE: The default data connection direction is used. For other ways to specify the data connection direction, see Using Active and Passive Clients. Keep in mind that the direction of data connection is not related to the direction of data transfer. It is purely a connection construction issue.
//6 Checks whether the reply is within the 1XX family (a 3-digit standard reply that starts with 1). A successful reply from the list() method is normally in the 1XX family, which indicates that the data connection has been opened. In this example, a reply other than 1XX is treated as an unacceptable request.
//7 Creates an RWPortalIStream object strm built from a socket portal that is returned as part of the dataReply object in //5, via the portal() method invocation. The object strm becomes the data (directory) source to be read from the portal.
//8 Reads a line of data (a directory entry) off the portal.
//9 Reads data from the portal until no more data is available. The number of times the loop is executed indicates the number of directory entries in dir, which is specified as the argument in the list() method invocation of //5.
//10 Closes the portal contained in the dataReply object. The dataClose() method returns an RWTIOUResult with a redeemable RWFtpReply. By assigning the result of the method to the RWFtpReply object reply, the current execution thread is blocked until the actual result becomes available. This is one way of redeeming an RWTIOUResult.
NOTE: The dataClose() method needs to be invoked for each data transfer session. This is because the FTP protocol creates a data connection for each data transfer session that must be removed afterwards.
//11 Checks whether the reply is within the 2XX family (a 3-digit reply that starts with 2). A successful reply from the dataClose() method is normally in the 2XX family, which indicates that the underlying data channel has been closed for the LIST data transfer session. In this example, a reply other than 2XX is treated as an unacceptable request.
//12 This catch clause catches all FTP package, Networking package, and Threads Module exceptions that could be thrown from within the try block because all Rogue Wave exceptions are derived from RWxmsg.
In this example, the return values of all FTP command requests that return RWTIOUResults with a redeemable RWFtpReply (or its derived class) are assigned to an object of RWFtpReply. This causes the current thread to block until the actual result of the reply becomes available. In other words, the redeemable is redeemed immediately by blocking the thread. This is one way of redeeming an RWTIOUResult object. See Multithreading and IOUs and File Retrieval: Using the FTP Agent (Part II) for other ways of redeeming an RWTIOUResult.